33 use,
intrinsic :: iso_fortran_env
52 real(real64),
allocatable :: lsize(:)
56 real(real64),
allocatable :: Jlocal(:)
57 real(real64),
allocatable :: Jrange(:)
59 real(real64),
allocatable :: xi(:,:)
60 real(real64),
allocatable :: Q(:,:,:)
63 type(root_solver_t) :: rs, rs_init
75 procedure curv_modine_constructor
82 class(curv_modine_t),
pointer :: modine_p
83 real(real64),
allocatable :: x_p(:)
90 type(namespace_t),
intent(in) :: namespace
91 integer,
intent(in) :: dim
92 integer,
intent(in) :: npos
93 real(real64),
intent(in) :: pos(1:dim,1:npos)
94 real(real64),
intent(in) :: lsize(1:dim)
95 real(real64),
intent(in) :: spacing(1:dim)
96 class(curv_modine_t),
pointer :: modine
99 real(real64) :: kappa(1:npos)
104 safe_allocate(modine)
107 modine%local_basis = .
true.
108 modine%orthogonal = .
true.
112 safe_allocate(modine%lsize(1:dim))
135 if (modine%xbar <
m_zero .or. modine%xbar >
m_one)
then
136 message(1) =
'The parameter "CurvModineXBar" must lie between 0 and 1.'
139 if (modine%Jbar <= modine%xbar)
then
140 message(1) =
'The parameter "CurvModineJBar" must be larger than the parameter "CurvModineXBar".'
144 safe_allocate(modine%Jlocal(1:npos))
145 safe_allocate(modine%Jrange(1:npos))
156 if (
parse_block(namespace,
"CurvModineJlocal", blk) == 0)
then
160 modine%Jlocal(:) = modine%Jlocal(1)
161 else if (n == npos)
then
166 write(
message(1),
'(3a,i2)')
'Error in block CurvModineJlocal: number of lines must be 1 or ', npos
171 modine%Jlocal(:) = 0.125_real64
175 if (modine%Jlocal(iatom)<
m_zero.or.modine%Jlocal(iatom)>
m_one)
then
176 message(1) =
'The parameter "CurvModineJlocal" must lie between 0 and 1.'
190 if (
parse_block(namespace,
"CurvModineJrange", blk) == 0)
then
195 else if (n == npos)
then
200 write(
message(1),
'(3a,i2)')
'Error in block CurvModineJrange: number of lines must be 1 or ', npos
205 kappa(:) = 1.2_real64
210 if (modine%Jlocal(iatom) >
m_one-1e-5_real64)
then
211 modine%Jrange(iatom) = kappa(iatom)
213 modine%Jrange(iatom) = kappa(iatom) / &
221 solver_type =
root_newton, maxiter = 500, abs_tolerance = 1.0e-13_real64)
223 safe_allocate(modine%xi(1:modine%dim, 1:modine%npos))
224 safe_allocate(modine%Q(1:modine%dim, 1:modine%dim, 1:modine%npos))
227 modine%min_mesh_scaling_product = modine%Jbar**modine%dim
234 real(real64),
intent(in) :: x
243 integer :: iatom, idim
244 real(real64),
allocatable :: xi_tmp(:, :), q_tmp(:, :, :)
245 real(real64) :: residue, rr2, dd
246 integer :: iter, nu, mu, idim1, idim2
247 integer,
parameter :: maxiter = 1000
248 real(real64),
parameter :: tolerance = 1.0e-10_real64
252 safe_allocate(xi_tmp(1:modine%dim, 1:modine%npos))
253 safe_allocate(q_tmp(1:modine%dim, 1:modine%dim, 1:modine%npos))
256 modine%Q(:, :, :) =
m_zero
257 do iatom = 1, modine%npos
258 modine%xi(:, iatom) = pos(:, iatom)
259 do idim = 1, modine%dim
260 modine%Q(idim, idim, iatom) =
m_one-modine%Jlocal(iatom)**(
m_one/real(modine%dim, real64))
267 xi_tmp(:, :) = modine%xi(:, :)
268 q_tmp(:, :, :) = modine%Q(:, :, :)
270 modine%Q(:, :, :) =
m_zero
271 do mu = 1, modine%npos
273 modine%xi(:, mu) = pos(:, mu)
274 do idim = 1, modine%dim
276 modine%Q(idim, idim, mu) =
m_one-modine%Jlocal(mu)**(
m_one/real(modine%dim, real64))
278 do nu = 1, modine%npos
280 rr2 = sum((xi_tmp(:, mu) - xi_tmp(:, nu))**2)
281 dd =
exp(-rr2/(
m_two*modine%Jrange(nu)**2))
283 modine%xi(:, mu) = modine%xi(:, mu) + &
284 matmul(modine%Q(:, :, mu), xi_tmp(:, mu) - xi_tmp(:, nu)) * dd
286 do idim1 = 1, modine%dim
287 do idim2 = 1, modine%dim
288 modine%Q(idim1, idim2, mu) = modine%Q(idim1, idim2, mu) - q_tmp(idim1, idim2, nu) * dd
289 modine%Q(idim1, idim2, mu) = modine%Q(idim1, idim2, mu) + &
290 sum(q_tmp(idim1, :, nu)*(xi_tmp(:, mu) - xi_tmp(:, nu)))*(xi_tmp(idim2, mu) - xi_tmp(idim2, nu)) * &
291 m_one/modine%Jrange(nu) * dd
298 residue = norm2(xi_tmp(:, :) - modine%xi(:, :)) / real(modine%dim*modine%npos, real64)
299 residue = residue + norm2(q_tmp(:, :, :) - modine%Q(:, :, :)) / real(modine%dim*modine%dim*modine%npos, real64)
300 if (residue <= tolerance)
exit
304 if (residue > tolerance)
then
305 message(1) =
"During the construction of the adaptive grid, the relaxation"
306 message(2) =
"method did not converge."
307 message(3) =
"This might be due to values of CurvModineJrange that are too large"
308 message(4) =
"or CurvModineJlocal that are too small."
313 safe_deallocate_a(xi_tmp)
314 safe_deallocate_a(q_tmp)
328 this_out%dim = this_in%dim
329 this_out%local_basis = this_in%local_basis
330 safe_allocate_source_a(this_out%lsize, this_in%lsize)
331 this_out%xbar = this_in%xbar
332 this_out%Jbar = this_in%Jbar
333 safe_allocate_source_a(this_out%Jlocal, this_in%Jlocal)
334 safe_allocate_source_a(this_out%Jrange, this_in%Jrange)
335 safe_allocate_source_a(this_out%xi, this_in%xi)
336 safe_allocate_source_a(this_out%Q, this_in%Q)
337 this_out%npos = this_in%npos
348 safe_deallocate_a(this%lsize)
349 safe_deallocate_a(this%Jlocal)
350 safe_deallocate_a(this%Jrange)
351 safe_deallocate_a(this%xi)
352 safe_deallocate_a(this%Q)
360 real(real64),
intent(in) :: chi(:)
361 real(real64) :: xx(1:this%dim)
363 real(real64) :: chi2(this%dim), rr2, dd
373 do iatom = 1, this%npos
374 rr2 = sum((chi2(:) - this%xi(:, iatom))**2)
375 dd =
exp(-rr2/(m_two*this%Jrange(iatom)**2))
377 xx(:) = xx(:) - matmul(this%Q(:, :, iatom), chi2(:) - this%xi(:, iatom)) * dd
385 real(real64),
intent(in) :: xx(:)
386 real(real64) :: chi(1:this%dim)
389 real(real64) :: start(1:this%dim)
395 safe_allocate(
x_p(1:this%dim))
400 if (abs(xx(i)) > this%lsize(i))
then
402 else if (abs(xx(i)) > this%xbar*this%lsize(i))
then
404 start(i) = sign(m_one, xx(i)) * (abs(xx(i))/this%Jbar + abs(xx(i)) *(m_one - m_one/this%Jbar) * &
405 (abs(xx(i)) - this%xbar*this%lsize(i)) / (this%lsize(i) - this%xbar*this%lsize(i)))
407 if (abs(start(i)) >= this%lsize(i))
then
408 start(i) = sign(this%lsize(i), xx(i))
411 start(i) = xx(i)/this%Jbar
415 call droot_solver_run(this%rs,
getf, chi, conv, startval=start)
421 message(1) =
"During the construction of the adaptive grid, the Newton-Raphson"
422 message(2) =
"method did not converge for point:"
423 write(message(3),
'(3f14.6)') xx(1:this%dim)
424 call messages_fatal(3)
432 integer,
optional,
intent(in) :: iunit
433 type(namespace_t),
optional,
intent(in) :: namespace
437 write(message(1),
'(a)')
' Curvilinear Method = modine'
438 call messages_info(1, iunit=iunit, namespace=namespace)
444 real(real64) function curv_modine_surface_element(this, idir) result(ds)
446 integer,
intent(in) :: idir
449 message(1) =
'Surface element with modine curvilinear coordinates not implemented'
450 call messages_fatal(1)
457 real(real64),
intent(in) :: chi_(:)
458 real(real64),
contiguous,
intent(out) :: chi2(:)
459 real(real64),
contiguous,
optional,
intent(out) :: jac(:)
461 integer,
parameter :: qq = 3
462 real(real64) :: chibar(this%dim), rr, chi
468 chibar = this%xbar*this%lsize/this%Jbar
474 chi2(i) = this%Jbar * chi
475 if (
present(jac)) jac(i) = this%Jbar
477 if (chi > this%lsize(i))
then
480 if (
present(jac)) jac(i) = m_one
481 else if (chi > chibar(i))
then
482 rr = (chi - chibar(i))/(this%lsize(i) - chibar(i))
484 chi2(i) = chi2(i) + this%lsize(i)/m_two*(1 - this%Jbar) * rr**qq * &
485 (qq + m_one - (qq - m_one)*rr)
487 if (
present(jac))
then
488 jac(i) = jac(i) + this%lsize(i)/m_two*(m_one - this%Jbar) * rr**(qq - 1)/(this%lsize(i) - chibar(i)) * &
489 (qq*(qq + m_one) - (qq**2 - m_one)*rr)
493 if (neg) chi2(i) = -chi2(i)
503 real(real64),
intent(in) :: chi(:)
504 real(real64),
intent(out) :: xx(:)
505 real(real64),
intent(out) :: jac(:, :)
507 real(real64) :: chi2(this%dim), rr2, dd, j2(this%dim)
508 integer :: iatom, idim, idim2
517 do idim = 1, this%dim
518 jac(idim, idim) = m_one
521 do iatom = 1, this%npos
522 rr2 = sum((chi2(:) - this%xi(:, iatom))**2)
523 dd =
exp(-rr2/(m_two*this%Jrange(iatom)**2))
525 xx(:) = xx(:) - matmul(this%Q(:, :, iatom), chi2(:) - this%xi(:, iatom)) * dd
527 do idim = 1, this%dim
528 do idim2 = 1, this%dim
529 jac(idim, idim2) = jac(idim, idim2) - this%Q(idim, idim2, iatom) * dd
530 jac(idim, idim2) = jac(idim, idim2) + &
531 sum(this%Q(idim, :, iatom)*(chi2(:) - this%xi(:, iatom)))*(chi2(idim2) - this%xi(idim2, iatom)) * &
532 m_one/this%Jrange(iatom) * dd
537 do idim = 1, this%dim
538 jac(idim, :) = jac(idim, :) * j2(:)
544 pure subroutine getf(yy, ff, jf)
545 real(real64),
intent(in) :: yy(:)
546 real(real64),
intent(out) :: ff(:), jf(:, :)
551 ff(:) = ff(:) -
x_p(:)
558 real(real64),
intent(in) :: chi(:)
559 real(real64) :: jacobian(1:this%dim, 1:this%dim)
561 real(real64) :: dummy(this%dim)
570 real(real64),
intent(in) :: chi(:)
571 real(real64) :: jacobian_inverse(1:this%dim, 1:this%dim)
573 real(real64) :: dummy(this%dim)
576 call lalg_inverse(this%dim, jacobian_inverse,
"dir")
real(real64) pure function product_log(x)
double exp(double __x) __attribute__((__nothrow__
This module implements the curvilinear coordinates given in N. A. Modine, G. Zumbach,...
class(curv_modine_t), pointer modine_p
real(real64) function, dimension(1:this%dim) curv_modine_from_cartesian(this, xx)
real(real64) function curv_modine_surface_element(this, idir)
real(real64) function, dimension(1:this%dim, 1:this%dim) curv_modine_jacobian_inverse(this, chi)
pure subroutine curv_modine_jacobian_inv(this, chi, xx, Jac)
real(real64) function, dimension(1:this%dim, 1:this%dim) curv_modine_jacobian(this, chi)
class(curv_modine_t) function, pointer curv_modine_constructor(namespace, dim, npos, pos, lsize, spacing)
pure subroutine getf(yy, ff, jf)
subroutine curv_modine_finalize(this)
real(real64), dimension(:), allocatable x_p
pure subroutine curv_modine_chi2chi2(this, chi_, chi2, Jac)
subroutine, public curv_modine_copy(this_out, this_in)
subroutine curv_modine_write_info(this, iunit, namespace)
real(real64) function, dimension(1:this%dim) curv_modine_to_cartesian(this, chi)
real(real64), parameter, public m_two
real(real64), parameter, public m_zero
real(real64), parameter, public m_four
real(real64), parameter, public m_third
real(real64), parameter, public m_half
real(real64), parameter, public m_one
real(real64), parameter, public m_three
real(real64), parameter, public m_e
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
integer function, public parse_block(namespace, name, blk, check_varinfo_)
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
abstract class to describe coordinate systems