Octopus
curv_gygi.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
23
24module curv_gygi_oct_m
26 use debug_oct_m
27 use global_oct_m
28 use, intrinsic :: iso_fortran_env
30 use math_oct_m
33 use parser_oct_m
36 use unit_oct_m
38
39 implicit none
40
41 private
42 public :: &
45
46 type, extends(coordinate_system_t) :: curv_gygi_t
47 private
48 real(real64), public :: A
49 real(real64), public :: alpha
50 real(real64), public :: beta
51 real(real64), allocatable :: pos(:, :)
52 integer :: npos
53 type(root_solver_t) :: rs
54 contains
55 procedure :: to_cartesian => curv_gygi_to_cartesian
56 procedure :: from_cartesian => curv_gygi_from_cartesian
57 procedure :: det_jac => curv_gygi_det_jac
58 procedure :: write_info => curv_gygi_write_info
59 procedure :: surface_element => curv_gygi_surface_element
60 final :: curv_gygi_finalize
61 end type curv_gygi_t
62
63 interface curv_gygi_t
64 procedure curv_gygi_constructor
65 end interface curv_gygi_t
66
67 ! Auxiliary variables for the root solver.
68 class(curv_gygi_t), pointer :: gygi_p
69 integer :: i_p
70 real(real64), allocatable :: chi_p(:)
71
72contains
73
74 ! ---------------------------------------------------------
75 function curv_gygi_constructor(namespace, dim, npos, pos) result(gygi)
76 type(namespace_t), intent(in) :: namespace
77 integer, intent(in) :: dim
78 integer, intent(in) :: npos
79 real(real64), intent(in) :: pos(1:dim,1:npos)
80 class(curv_gygi_t), pointer :: gygi
81
82 push_sub(curv_gygi_constructor)
83
84 safe_allocate(gygi)
85
86 gygi%dim = dim
87 gygi%local_basis = .true.
88 gygi%orthogonal = .true. ! This needs to be checked.
89
90 gygi%npos = npos
91 safe_allocate(gygi%pos(1:dim, 1:gygi%npos))
92 gygi%pos = pos
93
94 !%Variable CurvGygiA
95 !%Type float
96 !%Default 0.5
97 !%Section Mesh::Curvilinear::Gygi
98 !%Description
99 !% The grid spacing is reduced locally around each atom, and the reduction is
100 !% given by 1/(1+<i>A</i>), where <i>A</i> is specified by this variable. So, if
101 !% <i>A</i>=1/2 (the default), the grid spacing is reduced to two thirds = 1/(1+1/2).
102 !% [This is the <math>A_{\alpha}</math> variable in Eq. 2 of F. Gygi and G. Galli, <i>Phys.
103 !% Rev. B</i> <b>52</b>, R2229 (1995)]. It must be larger than zero.
104 !%End
105 call parse_variable(namespace, 'CurvGygiA', m_half, gygi%A)
106
107 !%Variable CurvGygiAlpha
108 !%Type float
109 !%Default 2.0 a.u.
110 !%Section Mesh::Curvilinear::Gygi
111 !%Description
112 !% This number determines the region over which the grid is enhanced (range of
113 !% enhancement of the resolution). That is, the grid is enhanced on a sphere
114 !% around each atom, whose radius is given by this variable. [This is the <math>a_{\alpha}</math>
115 !% variable in Eq. 2 of F. Gygi and G. Galli, <i>Phys. Rev. B</i> <b>52</b>, R2229 (1995)].
116 !% It must be larger than zero.
117 !%End
118
119 call parse_variable(namespace, 'CurvGygiAlpha', m_two, gygi%alpha, units_inp%length)
120 !%Variable CurvGygiBeta
121 !%Type float
122 !%Default 4.0 a.u.
123 !%Section Mesh::Curvilinear::Gygi
124 !%Description
125 !% This number determines the distance over which Euclidean coordinates are
126 !% recovered. [This is the <math>b_{\alpha}</math> variable in Eq. 2 of F. Gygi and G. Galli,
127 !% <i>Phys. Rev. B</i> <b>52</b>, R2229 (1995)]. It must be larger than zero.
128 !%End
129 call parse_variable(namespace, 'CurvGygiBeta', m_four, gygi%beta, units_inp%length)
130
131 if (gygi%a <= m_zero) call messages_input_error(namespace, 'CurvGygiA')
132 if (gygi%alpha <= m_zero) call messages_input_error(namespace, 'CurvGygiAlpha')
133 if (gygi%beta <= m_zero) call messages_input_error(namespace, 'CurvGygiBeta')
134
135 gygi%min_mesh_scaling_product = (m_one / (m_one + gygi%A))**gygi%dim
136
137 ! initialize root solver
138 call root_solver_init(gygi%rs, namespace, dim, solver_type = root_newton, maxiter = 500, abs_tolerance = 1.0e-10_real64)
140 pop_sub(curv_gygi_constructor)
143 ! ---------------------------------------------------------
144 subroutine curv_gygi_copy(this_out, this_in)
145 type(curv_gygi_t), intent(inout) :: this_out
146 type(curv_gygi_t), intent(in) :: this_in
147
150 this_out%A = this_in%A
151 this_out%alpha = this_in%alpha
152 this_out%beta = this_in%beta
153 safe_allocate_source_a(this_out%pos, this_in%pos)
154 this_out%npos = this_in%npos
155
156 pop_sub(curv_gygi_copy)
157 end subroutine curv_gygi_copy
158
159 ! ---------------------------------------------------------
160 subroutine curv_gygi_finalize(this)
161 type(curv_gygi_t), intent(inout) :: this
164
165 safe_deallocate_a(this%pos)
166
167 pop_sub(curv_gygi_finalize)
168 end subroutine curv_gygi_finalize
169
170 ! ---------------------------------------------------------
171 function curv_gygi_to_cartesian(this, chi) result(xx)
172 class(curv_gygi_t), target, intent(in) :: this
173 real(real64), intent(in) :: chi(:)
174 real(real64) :: xx(1:this%dim)
175
176 integer :: i
177 logical :: conv
178
179 ! no PUSH_SUB, called too often
180
181 gygi_p => this
182 i_p = this%npos
183 safe_allocate(chi_p(1:this%dim))
184 chi_p(:) = chi(:)
185
186 call droot_solver_run(this%rs, getf, xx, conv, startval = chi)
187
188 if (.not. conv) then
189 do i = 1, this%npos
190 conv = .false.
191 i_p = i
192 call droot_solver_run(this%rs, getf, xx, conv, startval = xx(1:this%dim))
193 end do
194 end if
195
196 nullify(gygi_p)
197 safe_deallocate_a(chi_p)
198
199 if (.not. conv) then
200 message(1) = "During the construction of the adaptive grid, the Newton-Raphson"
201 message(2) = "method did not converge for point:"
202 write(message(3),'(9f14.6)') xx(1:this%dim)
203 message(4) = "Try varying the Gygi parameters -- usually reducing CurvGygiA or"
204 message(5) = "CurvGygiAlpha (or both) solves the problem."
205 call messages_fatal(5)
206 end if
207
208 end function curv_gygi_to_cartesian
209
210 ! ---------------------------------------------------------
211 pure function curv_gygi_from_cartesian(this, xx) result(chi)
212 class(curv_gygi_t), target, intent(in) :: this
213 real(real64), intent(in) :: xx(:)
214 real(real64) :: chi(1:this%dim)
215
216 integer :: i, ia
217 real(real64) :: r, ar, th, ex
218
219 ! no PUSH_SUB, called too often
220
221 chi(1:this%dim) = xx(1:this%dim)
222 do ia = 1, this%npos
223 r = max(norm2(xx(1:this%dim) - this%pos(1:this%dim, ia)), 1e-6_real64)
224 ar = this%A*this%alpha/r
225 th = tanh(r/this%alpha)
226 ex = exp(-(r/this%beta)**2)
227 do i = 1, this%dim
228 chi(i) = chi(i) + (xx(i) - this%pos(i, ia)) * this%a * ar * th * ex
229 end do
230 end do
231
232 end function curv_gygi_from_cartesian
233
234 ! ---------------------------------------------------------
235 real(real64) function curv_gygi_det_jac(this, xx, chi) result(jdet)
236 class(curv_gygi_t), intent(in) :: this
237 real(real64), intent(in) :: xx(:)
238 real(real64), intent(in) :: chi(:)
239
240 real(real64) :: dummy(this%dim)
241 real(real64) :: jac(1:this%dim, 1:this%dim)
242
243 ! no PUSH_SUB, called too often
244
245 call curv_gygi_jacobian(this, xx, dummy, jac)
246 jdet = m_one/lalg_determinant(this%dim, jac, preserve_mat = .false.)
247
248 end function curv_gygi_det_jac
249
250 ! ---------------------------------------------------------
251 subroutine curv_gygi_write_info(this, iunit, namespace)
252 class(curv_gygi_t), intent(in) :: this
253 integer, optional, intent(in) :: iunit
254 type(namespace_t), optional, intent(in) :: namespace
255
256 push_sub(curv_gygi_write_info)
257
258 write(message(1), '(a)') ' Curvilinear Method = gygi'
259 write(message(2), '(a)') ' Gygi Parameters:'
260 write(message(3), '(4x,a,f6.3)') 'A = ', this%a
261 write(message(4), '(4x,3a,f6.3)') 'alpha [', trim(units_abbrev(units_out%length)), '] = ', &
262 units_from_atomic(units_out%length, this%alpha)
263 write(message(5), '(4x,3a,f6.3)') 'beta [', trim(units_abbrev(units_out%length)), '] = ', &
264 units_from_atomic(units_out%length, this%beta)
265 call messages_info(5, iunit=iunit, namespace=namespace)
266
267 pop_sub(curv_gygi_write_info)
268 end subroutine curv_gygi_write_info
269
270 ! ---------------------------------------------------------
271 real(real64) function curv_gygi_surface_element(this, idir) result(ds)
272 class(curv_gygi_t), intent(in) :: this
273 integer, intent(in) :: idir
274
275 ds = m_zero
276 message(1) = 'Surface element with gygi curvilinear coordinates not implemented'
277 call messages_fatal(1)
278
279 end function curv_gygi_surface_element
280
281 ! ---------------------------------------------------------
282 pure subroutine curv_gygi_jacobian(this, xx, chi, jac, natoms)
283 class(curv_gygi_t), intent(in) :: this
284 real(real64), intent(in) :: xx(:)
285 real(real64), intent(out) :: chi(:)
286 real(real64), intent(out) :: jac(:, :)
287 integer, optional, intent(in) :: natoms
288
289 integer :: i, ix, iy, natoms_
290 real(real64) :: r, f_alpha, df_alpha
291 real(real64) :: th, ex, ar
292
293 ! no PUSH_SUB, called too often
294
295 jac(1:this%dim, 1:this%dim) = diagonal_matrix(this%dim, m_one)
296 chi(1:this%dim) = xx(1:this%dim)
297
298 natoms_ = this%npos
299 if (present(natoms)) natoms_ = natoms
300
301 do i = 1, natoms_
302 r = max(norm2(xx(1:this%dim) - this%pos(1:this%dim, i)), 1e-6_real64)
303
304 ar = this%A*this%alpha/r
305 th = tanh(r/this%alpha)
306 ex = exp(-(r/this%beta)**2)
307
308 f_alpha = ar * th * ex
309 df_alpha = ar*(-th*ex/r + ex/(this%alpha*cosh(r/this%alpha)**2) - th*m_two*r*ex/this%beta**2)
310
311 do ix = 1, this%dim
312 chi(ix) = chi(ix) + f_alpha*(xx(ix) - this%pos(ix, i))
313
314 jac(ix, ix) = jac(ix, ix) + f_alpha
315 do iy = 1, this%dim
316 jac(ix, iy) = jac(ix, iy) + (xx(ix) - this%pos(ix, i))*(xx(iy) - this%pos(iy, i))/r*df_alpha
317 end do
318 end do
319 end do
320
321 end subroutine curv_gygi_jacobian
322
323 ! ---------------------------------------------------------
324 pure subroutine getf(y, f, jf)
325 real(real64), intent(in) :: y(:)
326 real(real64), intent(out) :: f(:), jf(:, :)
327
328 ! no PUSH_SUB, called too often
329
330 call curv_gygi_jacobian(gygi_p, y, f, jf, i_p)
331 f(1:gygi_p%dim) = f(1:gygi_p%dim) - chi_p(1:gygi_p%dim)
332
333 end subroutine getf
334
335end module curv_gygi_oct_m
336
337!! Local Variables:
338!! mode: f90
339!! coding: utf-8
340!! End:
Note that lalg_determinant and lalg_inverse are just wrappers over the same routine.
Definition: lalg_adv.F90:187
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)...
Definition: curv_gygi.F90:117
subroutine curv_gygi_write_info(this, iunit, namespace)
Definition: curv_gygi.F90:345
real(real64), dimension(:), allocatable chi_p
Definition: curv_gygi.F90:163
pure subroutine getf(y, f, jf)
Definition: curv_gygi.F90:418
real(real64) function curv_gygi_det_jac(this, xx, chi)
Definition: curv_gygi.F90:329
pure subroutine curv_gygi_jacobian(this, xx, chi, jac, natoms)
Definition: curv_gygi.F90:376
pure real(real64) function, dimension(1:this%dim) curv_gygi_from_cartesian(this, xx)
Definition: curv_gygi.F90:305
subroutine, public curv_gygi_copy(this_out, this_in)
Definition: curv_gygi.F90:238
real(real64) function, dimension(1:this%dim) curv_gygi_to_cartesian(this, chi)
Definition: curv_gygi.F90:265
real(real64) function curv_gygi_surface_element(this, idir)
Definition: curv_gygi.F90:365
class(curv_gygi_t) function, pointer curv_gygi_constructor(namespace, dim, npos, pos)
Definition: curv_gygi.F90:169
class(curv_gygi_t), pointer gygi_p
Definition: curv_gygi.F90:161
subroutine curv_gygi_finalize(this)
Definition: curv_gygi.F90:254
real(real64), parameter, public m_two
Definition: global.F90:189
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_four
Definition: global.F90:191
real(real64), parameter, public m_half
Definition: global.F90:193
real(real64), parameter, public m_one
Definition: global.F90:188
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
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:420
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
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)