Octopus
curv_modine.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
27
30 use debug_oct_m
31 use global_oct_m
32 use, intrinsic :: iso_fortran_env
36 use parser_oct_m
39 use unit_oct_m
41
42 implicit none
43
44 private
45 public :: &
48
49 type, extends(coordinate_system_t) :: curv_modine_t
50 private
51 real(real64), allocatable :: lsize(:)
52 real(real64) :: xbar
53 real(real64) :: Jbar
54
55 real(real64), allocatable :: Jlocal(:)
56 real(real64), allocatable :: Jrange(:)
57
58 real(real64), allocatable :: chi_atoms(:,:)
59 real(real64), allocatable :: csi(:,:)
60
61 integer :: npos
62 type(root_solver_t) :: rs
63 contains
64 procedure :: to_cartesian => curv_modine_to_cartesian
65 procedure :: from_cartesian => curv_modine_from_cartesian
66 procedure :: jacobian => curv_modine_jacobian
67 procedure :: jacobian_inverse => curv_modine_jacobian_inverse
68 procedure :: write_info => curv_modine_write_info
69 procedure :: surface_element => curv_modine_surface_element
71 end type curv_modine_t
72
73 interface curv_modine_t
74 procedure curv_modine_constructor
75 end interface curv_modine_t
76
77 ! Auxiliary variables for the root solver.
78 class(curv_modine_t), pointer :: modine_p
79 real(real64), allocatable :: x_p(:)
80
81contains
82
83 ! ---------------------------------------------------------
84 function curv_modine_constructor(namespace, dim, npos, pos, lsize, spacing) result(modine)
85 type(namespace_t), intent(in) :: namespace
86 integer, intent(in) :: dim
87 integer, intent(in) :: npos
88 real(real64), intent(in) :: pos(1:dim,1:npos)
89 real(real64), intent(in) :: lsize(1:dim)
90 real(real64), intent(in) :: spacing(1:dim)
91 class(curv_modine_t), pointer :: modine
92
94
95 safe_allocate(modine)
96
97 modine%dim = dim
98 modine%local_basis = .true.
99 modine%orthogonal = .true. ! This needs to be checked.
100
101 modine%npos = npos
102
103 !%Variable CurvModineXBar
104 !%Type float
105 !%Default 1/3
106 !%Section Mesh::Curvilinear::Modine
107 !%Description
108 !% Size of central flat region (in units of <tt>Lsize</tt>). Must be between 0 and 1.
109 !% See N. A. Modine, G. Zumbach, and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289-10301 (1997).
110 !%End
111 call parse_variable(namespace, 'CurvModineXBar', m_one/m_three, modine%xbar)
112
113 !%Variable CurvModineJBar
114 !%Type float
115 !%Default 1/2
116 !%Section Mesh::Curvilinear::Modine
117 !%Description
118 !% Increase in density of points is inverse of this parameter.
119 !% See N. A. Modine, G. Zumbach, and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289-10301 (1997).
120 !%End
121 call parse_variable(namespace, 'CurvModineJBar', m_half, modine%Jbar)
122
123 safe_allocate(modine%lsize(1:dim))
124 modine%lsize = lsize / modine%Jbar
125
126 if (modine%xbar < m_zero .or. modine%xbar > m_one) then
127 message(1) = 'The parameter "CurvModineXBar" must lie between 0 and 1.'
128 call messages_fatal(1, namespace=namespace)
129 end if
130
131 safe_allocate(modine%Jlocal(1:npos))
132 safe_allocate(modine%Jrange(1:npos))
133
134 ! \warning: the reading has to be done for each atom kind
135
136 !%Variable CurvModineJlocal
137 !%Type float
138 !%Default 0.25
139 !%Section Mesh::Curvilinear::Modine
140 !%Description
141 !% Local refinement around the atoms. Must be between 0 and 1.
142 !% See N. A. Modine, G. Zumbach, and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289-10301 (1997).
143 !%End
144 call parse_variable(namespace, 'CurvModineJlocal', 0.25_real64, modine%Jlocal(1))
146 !%Variable CurvModineJrange
147 !%Type float
148 !%Default 2 b
149 !%Section Mesh::Curvilinear::Modine
150 !%Description
151 !% Local refinement range (a length).
152 !% See N. A. Modine, G. Zumbach, and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289-10301 (1997).
153 !%End
154 call parse_variable(namespace, 'CurvModineJrange', m_two, modine%Jrange(1), units_inp%length)
156 if (modine%Jlocal(1)<m_zero.or.modine%Jlocal(1)>m_one) then
157 message(1) = 'The parameter "CurvModineJlocal" must lie between 0 and 1.'
158 call messages_fatal(1, namespace=namespace)
159 end if
161 modine%Jlocal(:) = modine%Jlocal(1)
162 modine%Jrange(:) = modine%Jrange(1)
164 ! initialize root solver for the optimization
165 call root_solver_init(modine%rs, namespace, dim, &
166 solver_type = root_newton, maxiter = 500, abs_tolerance = 1.0e-10_real64)
167
168 call find_atom_points()
169 call optimize()
170
171 modine%min_mesh_scaling_product = modine%Jbar**modine%dim
174 contains
175
176 subroutine find_atom_points()
177 integer :: iatom, jj
178
180
181 ! Initialize csi
182 safe_allocate(modine%csi(1:modine%dim, 1:modine%npos))
183 modine%csi = npos
184
185 ! get first estimate for chi_atoms
186 safe_allocate(modine%chi_atoms(1:modine%dim, 1:modine%npos))
187 do jj = 1, 10 ! \warning: make something better
188 do iatom = 1, modine%npos
189 modine%chi_atoms(:, iatom) = modine%from_cartesian(pos(:, iatom))
190 end do
191 modine%csi(:,:) = modine%chi_atoms(:,:)
192 end do
193
194 do iatom = 1, modine%npos
195 ! These are the chi positions where we want the atoms.
196 modine%chi_atoms(:, iatom) = nint(modine%chi_atoms(:, iatom) / spacing(:)) * spacing(:)
197 end do
198
200 end subroutine find_atom_points
201
202 subroutine optimize()
203 logical :: conv
204 integer :: iatom, idim, index
205 real(real64), allocatable :: my_csi(:), start_csi(:)
206
208
209 modine_p => modine
210
211 safe_allocate(x_p(1:modine%dim*modine%npos))
212 safe_allocate(my_csi(1:modine%dim*modine%npos))
213 safe_allocate(start_csi(1:modine%dim*modine%npos))
214
215 do iatom = 1, modine%npos
216 do idim = 1, modine%dim
217 index = (iatom-1)*dim + idim
218 x_p(index) = pos(idim, iatom)
219 start_csi(index) = modine%chi_atoms(idim, iatom)
220 end do
221 end do
222
223 call droot_solver_run(modine%rs, getf2, my_csi, conv, startval=start_csi)
224
225 if (.not. conv) then
226 message(1) = "During the construction of the adaptive grid, the Newton-Raphson"
227 message(2) = "method did not converge."
228 call messages_fatal(2, namespace=namespace)
229 end if
230
231 ! Now set csi to the new values
232 do iatom = 1, modine%npos
233 do idim = 1, modine%dim
234 index = (iatom-1)*modine%dim + idim
235 modine_p%csi(idim, iatom) = my_csi(index)
236 end do
237 end do
238
239 safe_deallocate_a(x_p)
240 safe_deallocate_a(my_csi)
241 safe_deallocate_a(start_csi)
242
243 nullify(modine_p)
244
246 end subroutine optimize
247
248 end function curv_modine_constructor
249
250 ! ---------------------------------------------------------
251 subroutine curv_modine_copy(this_out, this_in)
252 type(curv_modine_t), intent(inout) :: this_out
253 type(curv_modine_t), intent(in) :: this_in
254
255 push_sub(curv_modine_copy)
256
257 this_out%dim = this_in%dim
258 this_out%local_basis = this_in%local_basis
259 safe_allocate_source_a(this_out%lsize, this_in%lsize)
260 this_out%xbar = this_in%xbar
261 this_out%Jbar = this_in%Jbar
262 safe_allocate_source_a(this_out%Jlocal, this_in%Jlocal)
263 safe_allocate_source_a(this_out%Jrange, this_in%Jrange)
264 safe_allocate_source_a(this_out%chi_atoms, this_in%chi_atoms)
265 safe_allocate_source_a(this_out%csi, this_in%csi)
266 this_out%npos = this_in%npos
267
268 pop_sub(curv_modine_copy)
269 end subroutine curv_modine_copy
270
271 ! ---------------------------------------------------------
272 subroutine curv_modine_finalize(this)
273 type(curv_modine_t), intent(inout) :: this
274
275 push_sub(curv_modine_finalize)
276
277 safe_deallocate_a(this%lsize)
278 safe_deallocate_a(this%Jlocal)
279 safe_deallocate_a(this%Jrange)
280 safe_deallocate_a(this%chi_atoms)
281 safe_deallocate_a(this%csi)
282
283 pop_sub(curv_modine_finalize)
284 end subroutine curv_modine_finalize
285
286 ! ---------------------------------------------------------
287 function curv_modine_to_cartesian(this, chi) result(xx)
288 class(curv_modine_t), target, intent(in) :: this
289 real(real64), intent(in) :: chi(:)
290 real(real64) :: xx(1:this%dim)
291
292 real(real64) :: chi2(this%dim), rr2, dd
293 integer :: iatom
294
295 ! no PUSH_SUB, called too often
296
297 call curv_modine_chi2chi2(this, chi, chi2)
298
299 xx(:) = chi2(:)
300 do iatom = 1, this%npos
301 rr2 = sum((chi2(:) - this%csi(:, iatom))**2)
302 dd = exp(-rr2/(m_two*this%Jrange(iatom)**2))
303
304 xx(:) = xx(:) - this%Jlocal(iatom)*(chi2(:) - this%csi(:, iatom)) * dd
305 end do
306
307 end function curv_modine_to_cartesian
308
309 ! ---------------------------------------------------------
310 function curv_modine_from_cartesian(this, xx) result(chi)
311 class(curv_modine_t), target, intent(in) :: this
312 real(real64), intent(in) :: xx(:)
313 real(real64) :: chi(1:this%dim)
314
315 logical :: conv
316
317 ! no PUSH_SUB, called too often
318
319 modine_p => this
320 safe_allocate(x_p(1:this%dim))
321 x_p(:) = xx(:)
322
323 call droot_solver_run(this%rs, getf, chi, conv, startval = xx)
324
325 safe_deallocate_a(x_p)
326 nullify(modine_p)
327
328 if (.not. conv) then
329 message(1) = "During the construction of the adaptive grid, the Newton-Raphson"
330 message(2) = "method did not converge for point:"
331 write(message(3),'(3f14.6)') xx(1:this%dim)
332 call messages_fatal(3)
333 end if
334
335 end function curv_modine_from_cartesian
336
337 ! ---------------------------------------------------------
338 subroutine curv_modine_write_info(this, iunit, namespace)
339 class(curv_modine_t), intent(in) :: this
340 integer, optional, intent(in) :: iunit
341 type(namespace_t), optional, intent(in) :: namespace
342
343 push_sub(curv_modine_write_info)
345 write(message(1), '(a)') ' Curvilinear Method = modine'
346 call messages_info(1, iunit=iunit, namespace=namespace)
347
349 end subroutine curv_modine_write_info
350
351 ! ---------------------------------------------------------
352 real(real64) function curv_modine_surface_element(this, idir) result(ds)
353 class(curv_modine_t), intent(in) :: this
354 integer, intent(in) :: idir
355
356 ds = m_zero
357 message(1) = 'Surface element with modine curvilinear coordinates not implemented'
358 call messages_fatal(1)
359
360 end function curv_modine_surface_element
361
362 ! ---------------------------------------------------------
363 pure subroutine curv_modine_chi2chi2(this, chi_, chi2, Jac)
364 class(curv_modine_t), intent(in) :: this
365 real(real64), intent(in) :: chi_(:)
366 real(real64), intent(out) :: chi2(:)
367 real(real64), optional, intent(out) :: Jac(:)
368
369 integer, parameter :: qq = 3
370 real(real64) :: chibar(this%dim), rr, chi
371 logical :: neg
372 integer :: i
373
374 ! no PUSH_SUB, called too often
375
376 chibar = this%xbar*this%lsize
377
378 do i = 1, this%dim
379 neg = (chi_(i) < 0)
380 chi = abs(chi_(i))
381
382 chi2(i) = this%Jbar * chi
383 if (present(jac)) jac(i) = this%Jbar
384
385 if (chi > chibar(i)) then
386 rr = (chi - chibar(i))/(this%lsize(i) - chibar(i))
387
388 chi2(i) = chi2(i) + this%lsize(i)/m_two*(1 - this%Jbar) * rr**qq * &
389 (qq + m_one - (qq - m_one)*rr)
390
391 if (present(jac)) then
392 jac(i) = jac(i) + this%lsize(i)/m_two*(m_one - this%Jbar) * rr**(qq - 1)/(this%lsize(i) - chibar(i)) * &
393 (qq*(qq + m_one) - (qq**2 - m_one)*rr)
394 end if
395 end if
396
397 if (neg) chi2(i) = -chi2(i)
398 ! CHECK if Jacobian does not have to be negated!
399 end do
400
401 end subroutine curv_modine_chi2chi2
402
403 ! ---------------------------------------------------------
404 pure subroutine curv_modine_jacobian_inv(this, chi, xx, Jac)
405 type(curv_modine_t), intent(in) :: this
406 real(real64), intent(in) :: chi(:)
407 real(real64), intent(out) :: xx(:)
408 real(real64), intent(out) :: jac(:, :)
409
410 real(real64) :: chi2(this%dim), rr2, dd, j2(this%dim)
411 integer :: iatom, idim, idim2
412
413 ! no PUSH_SUB, called too often
414
415 call curv_modine_chi2chi2(this, chi, chi2, j2)
416
417 ! initialize both xx and the Jacobian
418 xx(:) = chi2(:)
419 jac(:,:) = m_zero
420 do idim = 1, this%dim
421 jac(idim, idim) = m_one
422 end do
423
424 do iatom = 1, this%npos
425 rr2 = sum((chi2(:) - this%csi(:, iatom))**2)
426 dd = exp(-rr2/(m_two*this%Jrange(iatom)**2))
427
428 xx(:) = xx(:) - this%Jlocal(iatom)*(chi2(:) - this%csi(:, iatom)) * dd
429
430 do idim = 1, this%dim
431 jac(idim, idim) = jac(idim, idim) - this%Jlocal(iatom) * dd
432 do idim2 = 1, this%dim
433 jac(idim, idim2) = jac(idim, idim2) + &
434 this%Jlocal(iatom)*(chi2(idim) - this%csi(idim, iatom))*(chi2(idim2) - this%csi(idim2, iatom)) * &
435 m_two/(m_two*this%Jrange(iatom)**2) * dd
436 end do
437 end do
438 end do
439
440 do idim = 1, this%dim
441 jac(idim, :) = jac(idim, :) * j2(:)
442 end do
443
444 end subroutine curv_modine_jacobian_inv
446 ! ---------------------------------------------------------
447 pure subroutine getf(yy, ff, jf)
448 real(real64), intent(in) :: yy(:)
449 real(real64), intent(out) :: ff(:), jf(:, :)
450
451 ! no PUSH_SUB, called too often
452
453 call curv_modine_jacobian_inv(modine_p, yy, ff, jf)
454 ff(:) = ff(:) - x_p(:)
455
456 end subroutine getf
457
458 ! ---------------------------------------------------------
459 subroutine getf2(csi, ff, jf)
460 real(real64), intent(in) :: csi(:)
461 real(real64), intent(out) :: ff(:), jf(:, :)
462
463 integer :: i1, j1, i2, j2, index1, index2
464 real(real64) :: rr2, dd, dd2
465 real(real64), allocatable :: xx(:), chi2(:)
466
467 ! no PUSH_SUB, called too often
468
469 safe_allocate(xx(1:modine_p%dim))
470 safe_allocate(chi2(1:modine_p%dim))
471
472 ! first we fill in coord_system%csi with the values we have
473 index1 = 1
474 do i1 = 1, modine_p%npos
475 do j1 = 1, modine_p%dim
476 modine_p%csi(j1, i1) = csi(index1)
477 index1 = index1 + 1
478 end do
479 end do
480
481 ! get ff and jf
482 jf(:,:) = m_zero
483 do i1 = 1, modine_p%npos
484 call curv_modine_chi2chi2(modine_p, modine_p%chi_atoms(:,i1), chi2)
485 xx(:) = chi2(:)
486
487 do i2 = 1, modine_p%npos
488 rr2 = sum((chi2 - modine_p%csi(:,i2))**2)
489 dd = exp(-rr2/(m_two*modine_p%Jrange(i2)**2))
490
491 xx = xx - modine_p%Jlocal(i2)*(chi2 - modine_p%csi(:,i2)) * dd
492 end do
493
494 do j1 = 1, modine_p%dim
495 index1 = (i1 - 1)*modine_p%dim + j1
496 ff(index1) = xx(j1) - x_p(index1)
498 do i2 = 1, modine_p%npos
499 rr2 = sum((chi2 - modine_p%csi(:,i2))**2)
500 dd = exp(-rr2/(m_two*modine_p%Jrange(i2)**2))
501 dd2 = -m_two/(m_two*modine_p%Jrange(i2)**2)*dd
502
503 index2 = (i2 - 1)*modine_p%dim + j1
504 jf(index1, index2) = modine_p%Jlocal(i2) * dd
505
506 do j2 = 1, modine_p%dim
507 index2 = (i2 - 1)*modine_p%dim + j2
508
509 jf(index1, index2) = jf(index1, index2) + modine_p%Jlocal(i2) * dd2 * &
510 (chi2(j1) - modine_p%csi(j1,i2))*(chi2(j2) - modine_p%csi(j2,i2))
511 end do
512 end do
513 end do
514 end do
515
516 safe_deallocate_a(xx)
517 safe_deallocate_a(chi2)
518
519 end subroutine getf2
520
521 ! ---------------------------------------------------------
522 function curv_modine_jacobian(this, chi) result(jacobian)
523 class(curv_modine_t), intent(in) :: this
524 real(real64), intent(in) :: chi(:)
525 real(real64) :: jacobian(1:this%dim, 1:this%dim)
526
527 real(real64) :: dummy(this%dim)
528
529 call curv_modine_jacobian_inv(this, chi, dummy, jacobian)
530
531 end function curv_modine_jacobian
532
533 ! ---------------------------------------------------------
534 function curv_modine_jacobian_inverse(this, chi) result(jacobian_inverse)
535 class(curv_modine_t), intent(in) :: this
536 real(real64), intent(in) :: chi(:)
537 real(real64) :: jacobian_inverse(1:this%dim, 1:this%dim)
538
539 real(real64) :: dummy(this%dim)
541 call curv_modine_jacobian_inv(this, chi, dummy, jacobian_inverse)
542 call lalg_inverse(this%dim, jacobian_inverse, "dir")
543
545
546end module curv_modine_oct_m
547
548!! Local Variables:
549!! mode: f90
550!! coding: utf-8
551!! End:
subroutine optimize()
subroutine find_atom_points()
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)
subroutine getf2(csi, ff, jf)
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
Definition: global.F90:190
real(real64), parameter, public m_zero
Definition: global.F90:188
real(real64), parameter, public m_half
Definition: global.F90:194
real(real64), parameter, public m_one
Definition: global.F90:189
real(real64), parameter, public m_three
Definition: global.F90:191
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:414
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:616
integer, parameter, public root_newton
subroutine, public root_solver_init(rs, namespace, dimensionality, solver_type, maxiter, rel_tolerance, abs_tolerance)
subroutine, public droot_solver_run(rs, func, root, success, startval)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
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
int true(void)