29 use,
intrinsic :: iso_fortran_env
50 real(real64),
public :: A
51 real(real64),
public :: alpha
52 real(real64),
public :: beta
53 real(real64),
allocatable :: pos(:, :)
55 type(root_solver_t) :: rs
68 procedure curv_gygi_constructor
75 class(curv_gygi_t),
pointer :: gygi_p
76 type(curv_gygi_t),
allocatable,
target :: gygi_relaxed
77 real(real64),
allocatable :: chi_p(:)
84 type(namespace_t),
intent(in) :: namespace
85 integer,
intent(in) :: dim
86 integer,
intent(in) :: npos
87 real(real64),
intent(in) :: pos(1:dim,1:npos)
88 class(curv_gygi_t),
pointer :: gygi
95 gygi%local_basis = .
true.
96 gygi%orthogonal = .
true.
99 safe_allocate(gygi%pos(1:dim, 1:gygi%npos))
100 gygi%pos(:, :) = pos(:, :)
148 gygi%min_mesh_scaling_product = (
m_one / (
m_one + gygi%A))**gygi%dim
163 this_out%A = this_in%A
164 this_out%alpha = this_in%alpha
165 this_out%beta = this_in%beta
166 safe_allocate_source_a(this_out%pos, this_in%pos)
167 this_out%pos = this_in%pos
168 this_out%npos = this_in%npos
169 this_out%dim = this_in%dim
170 this_out%local_basis = this_in%local_basis
171 this_out%orthogonal = this_in%orthogonal
173 maxiter = 500, abs_tolerance = 1.0e-10_real64)
184 safe_deallocate_a(this%pos)
190 real(real64)
pure function
gygi_f(this, r)
192 real(real64),
intent(in) :: r
196 if (r < 1.0e-4_real64)
then
202 gygi_f = this%A * this%alpha/r *
tanh(r/this%alpha) *
exp(-(r/this%beta)**2)
210 real(real64),
intent(in) :: r
214 if (r < 3.0e-3_real64)
then
217 gygi_dfdr_over_r = this%A * ((-m_two/(m_three*this%alpha**2) - m_two/this%beta**2) + &
218 (8._real64/(15._real64*this%alpha**4) + m_four/(m_three*this%alpha**2*this%beta**2) &
219 + m_two/this%beta**4) * r**2)
220 else if (-(r/this%beta)**2 <= m_min_exp_arg)
then
224 this%alpha*(this%beta**2+m_two*r**2) *
tanh(r/this%alpha)) &
225 / (this%beta**2*r**3) *
exp(-(r/this%beta)**2)
234 real(real64),
intent(in) :: r
238 if (r < 3.0e-3_real64)
then
242 m_two*(8._real64/(15._real64*this%alpha**4) + m_four/(m_three*this%alpha**2*this%beta**2) &
243 + m_two/this%beta**4) &
244 - m_four*(34._real64/(105._real64*this%alpha**6) + m_four/(m_five*this%alpha**4*this%beta**2) &
245 + m_one/(this%alpha**2*this%beta**4) + m_one/this%beta**6) * r**2 &
247 else if (-(r/this%beta)**2 <= m_min_exp_arg)
then
251 -m_two*
tanh(r/this%alpha)/(
cosh(r/this%alpha)**2*this%alpha*r) &
252 +
tanh(r/this%alpha)*(m_three*this%alpha/r**3+m_four*this%alpha/(this%beta**2*r)+m_four*this%alpha*r/this%beta**4) &
253 + m_one/
cosh(r/this%alpha)**2*(-m_three/r**2-m_four/this%beta**2))/r**2
261 real(real64),
intent(in) :: chi(:)
262 real(real64) :: xx(1:this%dim)
269 safe_allocate(
chi_p(1:this%dim))
272 call droot_solver_run(this%rs,
getf, xx, conv, startval = chi)
277 safe_deallocate_a(
chi_p)
280 message(1) =
"During the construction of the adaptive grid, the Newton-Raphson"
281 message(2) =
"method did not converge for point:"
282 write(message(3),
'(9f14.6)') xx(1:this%dim)
283 message(4) =
"Try varying the Gygi parameters -- usually reducing CurvGygiA or"
284 message(5) =
"CurvGygiAlpha (or both) solves the problem."
285 call messages_fatal(5)
296 real(real64),
intent(in) :: chi(:)
297 real(real64),
intent(inout) :: xx(:)
298 logical,
intent(out) :: conv
300 real(real64) :: xx_start(1:this%dim)
301 integer :: i_conv, n_conv
308 do i_conv = 1, n_conv
310 call droot_solver_run(
gygi_p%rs,
getf, xx, conv, startval = chi)
318 do i_conv = n_conv, 1, -1
321 call droot_solver_run(
gygi_p%rs,
getf, xx, conv, startval = xx_start)
333 real(real64),
intent(in) :: xx(:)
334 real(real64) :: chi(1:this%dim)
337 real(real64) :: diff(this%dim),
f
341 chi(1:this%dim) = xx(1:this%dim)
343 diff = xx(1:this%dim) - this%pos(1:this%dim, ia)
346 chi(i) = chi(i) + diff(i) *
f
355 integer,
optional,
intent(in) :: iunit
356 type(namespace_t),
optional,
intent(in) :: namespace
360 write(message(1),
'(a)')
' Curvilinear Method = gygi'
361 write(message(2),
'(a)')
' Gygi Parameters:'
362 write(message(3),
'(4x,a,f6.3)')
'A = ', this%a
363 write(message(4),
'(4x,3a,f6.3)')
'alpha [', trim(units_abbrev(units_out%length)),
'] = ', &
364 units_from_atomic(units_out%length, this%alpha)
365 write(message(5),
'(4x,3a,f6.3)')
'beta [', trim(units_abbrev(units_out%length)),
'] = ', &
366 units_from_atomic(units_out%length, this%beta)
367 call messages_info(5, iunit=iunit, namespace=namespace)
375 integer,
intent(in) :: idir
378 message(1) =
'Surface element with gygi curvilinear coordinates not implemented'
379 call messages_fatal(1)
386 real(real64),
intent(in) :: chi(:)
387 real(real64) :: jacobian(1:this%dim, 1:this%dim)
389 jacobian = this%jacobian_inverse(chi)
390 call lalg_inverse(this%dim, jacobian,
"dir")
396 real(real64),
intent(in) :: chi(:)
397 real(real64) :: jacobian_inverse(1:this%dim, 1:this%dim)
399 real(real64) :: xx(1:this%dim)
403 xx(:) = this%to_cartesian(chi)
411 real(real64),
intent(in) :: xx(:)
412 real(real64) :: jacobian_inverse(1:this%dim, 1:this%dim)
415 real(real64) :: r, diff(1:this%dim), dfdr_over_r, f
419 jacobian_inverse(1:this%dim, 1:this%dim) = diagonal_matrix(this%dim, m_one)
422 diff = xx(1:this%dim) - this%pos(1:this%dim, i)
429 jacobian_inverse(ix, ix) = jacobian_inverse(ix, ix) + f
431 jacobian_inverse(ix, iy) = jacobian_inverse(ix, iy) + diff(ix)*diff(iy)*dfdr_over_r
442 real(real64),
contiguous,
intent(in) :: xx(:)
443 real(real64),
contiguous,
intent(out) :: hessian(:, :, :)
444 integer,
optional,
intent(in) :: natoms
446 integer :: ia, i, j, k, natoms_
447 real(real64) :: r, diff(this%dim), dfdr_over_r, d2fdr2_combination
451 hessian(1:this%dim, 1:this%dim, 1:this%dim) = m_zero
454 if (
present(natoms)) natoms_ = natoms
457 diff = xx(1:this%dim) - this%pos(1:this%dim, ia)
467 hessian(i, j, k) = hessian(i, j, k) + diff(k)*dfdr_over_r
470 hessian(i, j, k) = hessian(i, j, k) + diff(j)*dfdr_over_r
473 hessian(i, j, k) = hessian(i, j, k) + diff(i)*dfdr_over_r
475 hessian(i, j, k) = hessian(i, j, k) + diff(i)*diff(j)*diff(k)*d2fdr2_combination
486 real(real64),
intent(in) :: chi(:)
487 real(real64) :: trace_hessian(1:this%dim)
490 real(real64) :: r, xx(this%dim), diff(this%dim), dfdr_over_r, d2fdr2_combination
494 xx(:) = this%to_cartesian(chi)
495 trace_hessian(:) = m_zero
498 diff = xx(1:this%dim) - this%pos(1:this%dim, ia)
507 trace_hessian(i) = trace_hessian(i) + m_two*diff(k)*dfdr_over_r
509 trace_hessian(i) = trace_hessian(i) + diff(i)*dfdr_over_r
510 trace_hessian(i) = trace_hessian(i) + diff(i)*diff(k)*diff(k)*d2fdr2_combination
518 subroutine getf(y, f, jf)
519 real(real64),
intent(in) :: y(:)
520 real(real64),
intent(out) ::
f(:), jf(:, :)
double exp(double __x) __attribute__((__nothrow__
double tanh(double __x) __attribute__((__nothrow__
double cosh(double __x) __attribute__((__nothrow__
This module implements the curvilinear coordinates given in F. Gygi and G. Galli, PRB 52 R2229 (1996)...
subroutine curv_gygi_write_info(this, iunit, namespace)
real(real64), dimension(:), allocatable chi_p
real(real64) pure function gygi_f(this, r)
real(real64) pure function gygi_d2fdr2_combination(this, r)
real(real64) pure function gygi_dfdr_over_r(this, r)
pure subroutine, public curv_gygi_hessian(this, xx, hessian, natoms)
real(real64) function, dimension(1:this%dim, 1:this%dim) curv_gygi_jacobian_inverse_cartesian(this, xx)
real(real64) function, dimension(1:this%dim) curv_gygi_trace_hessian(this, chi)
pure real(real64) function, dimension(1:this%dim) curv_gygi_from_cartesian(this, xx)
subroutine, public curv_gygi_copy(this_out, this_in)
real(real64) function, dimension(1:this%dim) curv_gygi_to_cartesian(this, chi)
subroutine getf(y, f, jf)
real(real64) function curv_gygi_surface_element(this, idir)
subroutine curv_gygi_to_cartesian_relaxed(this, chi, xx, conv)
Retry the root search with a reduced A, then increase A back. Kept out of curv_gygi_to_cartesian,...
class(curv_gygi_t) function, pointer curv_gygi_constructor(namespace, dim, npos, pos)
type(curv_gygi_t), allocatable, target gygi_relaxed
class(curv_gygi_t), pointer gygi_p
real(real64) function, dimension(1:this%dim, 1:this%dim) curv_gygi_jacobian(this, chi)
real(real64) function, dimension(1:this%dim, 1:this%dim) curv_gygi_jacobian_inverse(this, chi)
subroutine curv_gygi_finalize(this)
real(real64), parameter, public m_two
real(real64), parameter, public m_zero
real(real64), parameter, public m_four
real(real64), parameter, public m_min_exp_arg
real(real64), parameter, public m_half
real(real64), parameter, public m_one
real(real64), parameter, public m_three
This module is intended to contain "only mathematical" functions and procedures.
subroutine, public messages_input_error(namespace, var, details, row, column)
type(namespace_t), public global_namespace
integer, parameter, public root_newton
subroutine, public root_solver_init(rs, namespace, dimensionality, solver_type, maxiter, rel_tolerance, abs_tolerance)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
This module defines the unit system, used for input and output.
type(unit_system_t), public units_inp
the units systems for reading and writing
static double f(double w, void *p)
abstract class to describe coordinate systems