Octopus
grid.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2021 S. Ohlmann
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
23
24module grid_oct_m
25 use accel_oct_m
27 use box_oct_m
29 use debug_oct_m
32 use cube_oct_m
37 use global_oct_m
39 use mesh_oct_m
42 use mpi_oct_m
46 use parser_oct_m
48 use space_oct_m
53 use unit_oct_m
56
57 implicit none
58
59 private
60 public :: &
61 grid_t, &
65 grid_end, &
74
76 type, extends(mesh_t) :: grid_t
77 ! Components are public by default
78 type(derivatives_t) :: der
79 type(stencil_t) :: stencil
80 type(symmetries_t) :: symm
81 type(symmetrizer_t) :: symmetrizer
82 end type grid_t
83
84 integer, parameter :: &
85 CURV_AFFINE = 1, &
86 curv_gygi = 2, &
87 curv_briggs = 3, &
88 curv_modine = 4
89
90contains
91
92 !-------------------------------------------------------------------
101 subroutine grid_init_stage_1(gr, namespace, space, grp, symm, latt, n_sites, site_position)
102 type(grid_t), intent(inout) :: gr
103 type(namespace_t), intent(in) :: namespace
104 class(space_t), intent(in) :: space
105 type(mpi_grp_t), intent(in) :: grp
106 type(symmetries_t), optional, intent(in) :: symm
107 type(lattice_vectors_t), optional, intent(in) :: latt
108 integer, optional, intent(in) :: n_sites
109 real(real64), optional, intent(in) :: site_position(:,:)
110
111 type(stencil_t) :: cube
112 integer :: enlarge(space%dim)
113 type(block_t) :: blk
114 integer :: idir
115 real(real64) :: grid_spacing(space%dim)
116
117 push_sub(grid_init_stage_1)
118
119 gr%box => box_factory_create(namespace, space, latt=latt, n_sites=n_sites, site_position=site_position)
120
121 if (present(symm)) then
122 gr%symm = symm
123 end if
124
125 !%Variable Spacing
126 !%Type float
127 !%Section Mesh
128 !%Description
129 !% The spacing between the points in the mesh. This controls the
130 !% quality of the discretization: smaller spacing gives more
131 !% precise results but increased computational cost.
132 !%
133 !% When using curvilinear coordinates, this is a canonical spacing
134 !% that will be changed locally by the transformation. In periodic
135 !% directions, your spacing may be slightly different than what
136 !% you request here, since the box size must be an integer
137 !% multiple of the spacing.
138 !%
139 !% There is no special default otherwise.
140 !%
141 !% It is possible to have a different spacing in each one of the Cartesian directions
142 !% if we define <tt>Spacing</tt> as block of the form
143 !%
144 !% <tt>%Spacing
145 !% <br>&nbsp;&nbsp;spacing_x | spacing_y | spacing_z
146 !% <br>%</tt>
147 !%End
148
149 if(parse_block(namespace, 'Spacing', blk) == 0) then
150 if(parse_block_cols(blk,0) < space%dim) call messages_input_error(namespace, 'Spacing')
151 do idir = 1, space%dim
152 call parse_block_float(blk, 0, idir - 1, grid_spacing(idir), units_inp%length)
153 end do
154 call parse_block_end(blk)
155 else
156 call parse_variable(namespace, 'Spacing', -m_one, grid_spacing(1), units_inp%length)
157 grid_spacing = grid_spacing(1)
158 end if
159
160 if (any(grid_spacing(1:space%dim) < m_epsilon)) then
161 message(1) = " Your input for 'Spacing' is negative or zero."
162 call messages_fatal(1, namespace=namespace)
163 end if
164
165 !%Variable PeriodicBoundaryMask
166 !%Type block
167 !%Section Mesh
168 !%Description
169 !% (Experimental) Defines a mask for which periodic boundaries are replaced by zero boundary conditions.
170 !%End
171 if (parse_block(namespace, 'PeriodicBoundaryMask', blk) < 0) then
172 gr%masked_periodic_boundaries = .false.
173 else
174 gr%masked_periodic_boundaries = .true.
175 call parse_block_string(blk, 0, 0, gr%periodic_boundary_mask)
176 call messages_experimental('PeriodicBoundaryMask')
177 call parse_block_end(blk)
178 end if
180 ! Initialize coordinate system
181 call initialize_coordinate_system(gr, namespace, space, grid_spacing, latt, n_sites, site_position)
182
183 ! initialize derivatives
184 call nl_operator_global_init(namespace)
185 call derivatives_init(gr%der, namespace, space, gr%coord_system)
186 ! the stencil used to generate the grid is a union of a cube (for
187 ! multigrid) and the Laplacian
188 call stencil_cube_get_lapl(cube, space%dim, order = 2)
189 call stencil_union(cube, gr%der%lapl%stencil, gr%stencil)
190 call stencil_end(cube)
191
192 enlarge = 2
193 enlarge = max(enlarge, gr%der%n_ghost)
194
195 call mesh_init_stage_1(gr, namespace, space, gr%box, gr%coord_system, grid_spacing, enlarge)
196 call mesh_init_stage_2(gr, namespace, space, gr%box, gr%stencil, grp)
197
198 pop_sub(grid_init_stage_1)
199 end subroutine grid_init_stage_1
200
201 !--------------------------------------------------------------------
203 subroutine grid_init_from_grid_stage_1(gr, original_gr, namespace, space, grp, &
204 box, spacing_prefactor, latt, n_sites, site_position)
205 type(grid_t), intent(inout) :: gr
206 type(grid_t), intent(in) :: original_gr
207 type(namespace_t), intent(in) :: namespace
208 class(space_t), intent(in) :: space
209 type(mpi_grp_t), intent(in) :: grp
210 class(box_t), target, optional, intent(in) :: box
211 real(real64), optional, intent(in) :: spacing_prefactor(:)
212 type(lattice_vectors_t), optional, intent(in) :: latt
213 integer, optional, intent(in) :: n_sites
214 real(real64), optional, intent(in) :: site_position(:,:)
215
216 type(stencil_t) :: cube
217 integer :: enlarge(space%dim)
218
220
221 ! First of all, create and associate the box that contains the grid
222 if (.not. present(box)) then
223 gr%box => box_factory_create(namespace, space)
224 else
225 gr%box => box
226 end if
227
228 !!! Copy all data !!!
229 ! Symmetries
230 gr%symm = original_gr%symm
231 ! Spacing
232 if (present(spacing_prefactor)) then
233 gr%spacing = spacing_prefactor * original_gr%spacing
234 if (any(abs(spacing_prefactor - m_one) > m_epsilon)) then
235 write(message(1), '(a)') "The two grids have different spacings, it will not be possible to establish a map between them"
236 call messages_warning(1)
237 end if
238 else
239 gr%spacing = original_gr%spacing
240 end if
241 ! Periodic boundaries
242 gr%masked_periodic_boundaries = original_gr%masked_periodic_boundaries
243 if (gr%masked_periodic_boundaries) gr%periodic_boundary_mask = original_gr%periodic_boundary_mask
244 ! Coordinate System
245 call initialize_coordinate_system(gr, namespace, space, gr%spacing, latt, n_sites, site_position)
246
247 ! initialize derivatives
248 call nl_operator_global_init(namespace)
249 call derivatives_init(gr%der, namespace, space, gr%coord_system)
250 ! the stencil used to generate the grid is a union of a cube (for
251 ! multigrid) and the Laplacian
252 call stencil_cube_get_lapl(cube, space%dim, order = 2)
253 call stencil_union(cube, gr%der%lapl%stencil, gr%stencil)
254 call stencil_end(cube)
255
256 enlarge = 2
257 enlarge = max(enlarge, gr%der%n_ghost)
258
259 call mesh_init_stage_1(gr, namespace, space, gr%box, gr%coord_system, gr%spacing, enlarge)
260 call mesh_init_stage_2(gr, namespace, space, gr%box, gr%stencil, grp)
261
263 end subroutine grid_init_from_grid_stage_1
264
265
266 !--------------------------------------------------------------------
270 subroutine initialize_coordinate_system(gr, namespace, space, grid_spacing, latt, n_sites, site_position)
271 type(grid_t), intent(inout) :: gr
272 type(namespace_t), intent(in) :: namespace
273 class(space_t), intent(in) :: space
274 real(real64), intent(in) :: grid_spacing(:)
275 type(lattice_vectors_t), optional, intent(in) :: latt
276 integer, optional, intent(in) :: n_sites
277 real(real64), optional, intent(in) :: site_position(:,:)
278
279 integer :: cv_method
280
282
283 !%Variable CurvMethod
284 !%Type integer
285 !%Default curv_uniform
286 !%Section Mesh::Curvilinear
287 !%Description
288 !% The relevant functions in octopus are represented on a mesh in real space.
289 !% This mesh may be an evenly spaced regular rectangular grid (standard mode),
290 !% or else an adaptive or curvilinear grid. We have implemented
291 !% three kinds of adaptive meshes, although only one is currently working,
292 !% the one invented by F. Gygi (<tt>curv_gygi</tt>). The code will stop if any of
293 !% the other two is invoked. All are experimental with domain parallelization.
294 !%Option curv_affine 1
295 !% Regular, uniform rectangular grid.
296 !%Option curv_gygi 2
297 !% The deformation of the grid is done according to the scheme described by
298 !% F. Gygi [F. Gygi and G. Galli, <i>Phys. Rev. B</i> <b>52</b>, R2229 (1995)].
299 !%Option curv_briggs 3
300 !% The deformation of the grid is done according to the scheme described by
301 !% Briggs [E.L. Briggs, D.J. Sullivan, and J. Bernholc, <i>Phys. Rev. B</i> <b>54</b> 14362 (1996)]
302 !%Option curv_modine 4
303 !% The deformation of the grid is done according to the scheme described by
304 !% Modine [N.A. Modine, G. Zumbach and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289 (1997)]
305 !%End
306 call parse_variable(namespace, 'CurvMethod', curv_affine, cv_method)
307 if (.not. varinfo_valid_option('CurvMethod', cv_method)) call messages_input_error(namespace, 'CurvMethod')
308 if (cv_method /= curv_affine .and. accel_is_enabled()) then
309 call messages_write('Curvilinear coordinates on GPUs is not implemented')
310 call messages_fatal(namespace=namespace)
311 end if
312 if (present(latt)) then
313 if (cv_method /= curv_affine .and. latt%nonorthogonal) then
314 call messages_input_error(namespace, 'CurvMethod', 'Curvilinear coordinates with non-orthogonal cells are not implemented')
315 end if
316 end if
317 call messages_print_var_option("CurvMethod", cv_method, namespace=namespace)
318
319 ! FIXME: The other two methods are apparently not working
320 if (cv_method > curv_gygi) then
321 call messages_experimental('Selected curvilinear coordinates method')
322 end if
323
324 select case (cv_method)
325 case (curv_briggs)
326 gr%coord_system => curv_briggs_t(namespace, space%dim, &
327 gr%box%bounding_box_l(1:space%dim), grid_spacing(1:space%dim))
328 case (curv_gygi)
329 if (present(site_position) .and. present(n_sites)) then
330 gr%coord_system => curv_gygi_t(namespace, space%dim, n_sites, site_position)
331 else
332 message(1) = "Option CurvMethod = curv_gygi is not currently implemented without ions present."
333 call messages_fatal(1, namespace=namespace)
334 end if
335 case (curv_modine)
336 if (present(site_position) .and. present(n_sites)) then
337 gr%coord_system => curv_modine_t(namespace, space%dim, n_sites, site_position, &
338 gr%box%bounding_box_l(1:space%dim), grid_spacing(1:space%dim))
339 else
340 message(1) = "Option CurvMethod = curv_modine is not currently implemented without ions present."
341 call messages_fatal(1, namespace=namespace)
342 end if
343 case (curv_affine)
344 if (present(latt)) then
345 if (latt%nonorthogonal) then
346 gr%coord_system => affine_coordinates_t(namespace, space%dim, latt%rlattice_primitive)
347 else
348 gr%coord_system => cartesian_t(namespace, space%dim)
349 end if
350 else
351 gr%coord_system => cartesian_t(namespace, space%dim)
352 end if
353 end select
354
356 end subroutine initialize_coordinate_system
357
358
359 !-------------------------------------------------------------------
367 subroutine grid_init_stage_2(gr, namespace, space, mc, qvector)
368 type(grid_t), target, intent(inout) :: gr
369 type(namespace_t), intent(in) :: namespace
370 class(space_t), intent(in) :: space
371 type(multicomm_t), intent(in) :: mc
372 real(real64), optional, intent(in) :: qvector(:)
373
374 push_sub(grid_init_stage_2)
375
376 call mesh_init_stage_3(gr, namespace, space, gr%stencil, mc)
377
378 call derivatives_build(gr%der, namespace, space, gr, qvector)
379
380 ! print info concerning the grid
381 call grid_write_info(gr, namespace=namespace)
382
383 if(space%dim == 3) then
384 call symmetrizer_init(gr%symmetrizer, gr, gr%symm)
385 end if
386
387 pop_sub(grid_init_stage_2)
388 end subroutine grid_init_stage_2
389
390
391 !-------------------------------------------------------------------
394 subroutine grid_end(gr)
395 type(grid_t), intent(inout) :: gr
396
397 class(coordinate_system_t), pointer :: coord_system
398 class(box_t), pointer :: box
399
400 push_sub(grid_end)
401
403
404 call derivatives_end(gr%der)
405
406 ! We need to take a pointer here, otherwise we run into a gfortran bug.
407 coord_system => gr%coord_system
408 safe_deallocate_p(coord_system)
409 box => gr%box
410 safe_deallocate_p(box)
411
412 call mesh_end(gr)
413
414 call stencil_end(gr%stencil)
415
416 call symmetrizer_end(gr%symmetrizer)
417
418 pop_sub(grid_end)
419 end subroutine grid_end
420
421
422 !-------------------------------------------------------------------
423 subroutine grid_write_info(gr, iunit, namespace)
424 type(grid_t), intent(in) :: gr
425 integer, optional, intent(in) :: iunit
426 type(namespace_t), optional, intent(in) :: namespace
427
428 push_sub(grid_write_info)
429
430 call messages_print_with_emphasis(msg="Grid", iunit=iunit, namespace=namespace)
431
432 message(1) = 'Simulation Box:'
433 call messages_info(1, iunit=iunit, namespace=namespace)
434 call gr%box%write_info(iunit, namespace)
435
436 message(1) = "Main mesh:"
437 call messages_info(1, iunit=iunit, namespace=namespace)
438 call mesh_write_info(gr, iunit, namespace)
439
440 if (gr%use_curvilinear) then
441 call gr%coord_system%write_info(iunit, namespace)
442 end if
443
444 call messages_print_with_emphasis(iunit=iunit, namespace=namespace)
445
446 pop_sub(grid_write_info)
447 end subroutine grid_write_info
448
449 !-------------------------------------------------------------------
453 subroutine grid_lattice_vectors_update(gr, space, namespace, mc, new_latt)
454 type(grid_t), intent(inout) :: gr
455 type(space_t), intent(in) :: space
456 type(namespace_t), intent(in) :: namespace
457 type(multicomm_t), intent(in) :: mc
458 type(lattice_vectors_t), intent(in) :: new_latt
459
460 real(real64) :: new_box_bounds(2, space%dim)
461
463
464 call new_latt%write_info(namespace)
465
466 ! Regenerate the coordinate system
467 select type (coord_system=>gr%coord_system)
468 type is (affine_coordinates_t)
469 if (new_latt%nonorthogonal) then
470 deallocate(gr%coord_system)
471 gr%coord_system => affine_coordinates_t(namespace, space%dim, new_latt%rlattice_primitive)
472 end if
473 end select
474
475 ! Regenerate the grid keeping the same number of points
476 select type (coord_system=>gr%coord_system)
477 class is (affine_coordinates_t)
478 new_box_bounds = gr%box%bounds(coord_system%basis)
479 gr%spacing = (new_box_bounds(2,:)-new_box_bounds(1,:))/gr%idx%ll(:)
480 write(message(1), '(a)') trim(gr%box%short_info(unit_angstrom))
481 call messages_info(1, namespace=namespace)
482 call messages_new_line()
483 end select
484
485 safe_deallocate_a(gr%x)
486 safe_deallocate_a(gr%x_t)
487 safe_deallocate_a(gr%chi)
488 safe_deallocate_a(gr%vol_pp)
489 safe_deallocate_a(gr%jacobian_inverse)
490 call mesh_init_stage_3(gr, namespace, space, gr%stencil, mc, regenerate=.true.)
491
492 call derivates_set_coordinates_system(gr%der, gr%coord_system)
493 call derivatives_build(gr%der, namespace, space, gr, regenerate=.true., verbose=.false.)
494
496 end subroutine grid_lattice_vectors_update
497
498#include "undef.F90"
499#include "real.F90"
500#include "grid_inc.F90"
501
502#include "undef.F90"
503#include "complex.F90"
504#include "grid_inc.F90"
505
506end module grid_oct_m
507
508!! Local Variables:
509!! mode: f90
510!! coding: utf-8
511!! End:
pure logical function, public accel_is_enabled()
Definition: accel.F90:403
Module, implementing a factory for boxes.
class(box_t) function, pointer, public box_factory_create(namespace, space, latt, n_sites, site_position)
initialize a box of any type
This module implements the curvilinear coordinates given in E.L. Briggs, D.J. Sullivan,...
This module implements the curvilinear coordinates given in F. Gygi and G. Galli, PRB 52 R2229 (1996)...
Definition: curv_gygi.F90:120
This module implements the curvilinear coordinates given in N. A. Modine, G. Zumbach,...
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public derivatives_build(der, namespace, space, mesh, qvector, regenerate, verbose)
build the derivatives object:
subroutine, public derivatives_init(der, namespace, space, coord_system, order)
subroutine, public derivatives_end(der)
subroutine, public derivates_set_coordinates_system(der, coord_system)
real(real64), parameter, public m_epsilon
Definition: global.F90:216
real(real64), parameter, public m_one
Definition: global.F90:201
This module implements the underlying real-space grid.
Definition: grid.F90:119
subroutine initialize_coordinate_system(gr, namespace, space, grid_spacing, latt, n_sites, site_position)
this subroutine initializes the coordinate system
Definition: grid.F90:366
integer, parameter curv_gygi
Definition: grid.F90:179
integer, parameter curv_briggs
Definition: grid.F90:179
subroutine, public zgrid_symmetrize_scalar_field(gr, field, suppress_warning)
Definition: grid.F90:801
subroutine, public grid_init_from_grid_stage_1(gr, original_gr, namespace, space, grp, box, spacing_prefactor, latt, n_sites, site_position)
this subroutine allows to create a grid from an existing grid
Definition: grid.F90:300
subroutine, public grid_init_stage_1(gr, namespace, space, grp, symm, latt, n_sites, site_position)
First stage of the grid initialization.
Definition: grid.F90:197
subroutine, public zgrid_symmetrize_single(gr, iop, field, symm_field)
Definition: grid.F90:855
subroutine, public zgrid_symmetrize_vector_field(gr, field, suppress_warning)
Definition: grid.F90:827
subroutine, public grid_init_stage_2(gr, namespace, space, mc, qvector)
Second stage of the grid initialization.
Definition: grid.F90:463
subroutine, public dgrid_symmetrize_vector_field(gr, field, suppress_warning)
Definition: grid.F90:688
subroutine, public grid_write_info(gr, iunit, namespace)
Definition: grid.F90:519
subroutine, public grid_lattice_vectors_update(gr, space, namespace, mc, new_latt)
Regenerate the grid information after update of the lattice vectors.
Definition: grid.F90:549
subroutine, public dgrid_symmetrize_single(gr, iop, field, symm_field)
Definition: grid.F90:716
subroutine, public grid_end(gr)
finalize a grid object
Definition: grid.F90:490
subroutine, public dgrid_symmetrize_scalar_field(gr, field, suppress_warning)
Definition: grid.F90:662
integer, parameter curv_modine
Definition: grid.F90:179
This module contains subroutines, related to the initialization of the mesh.
Definition: mesh_init.F90:119
subroutine, public mesh_init_stage_3(mesh, namespace, space, stencil, mc, parent, regenerate)
When running parallel in domains, stencil and np_stencil are needed to compute the ghost points....
Definition: mesh_init.F90:531
subroutine, public mesh_init_stage_1(mesh, namespace, space, box, coord_system, spacing, enlarge)
First stage mesh initialization.
Definition: mesh_init.F90:172
subroutine, public mesh_init_stage_2(mesh, namespace, space, box, stencil, grp, regenerate)
This subroutine creates the global array of spatial indices and the inverse mapping.
Definition: mesh_init.F90:292
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public mesh_write_info(this, iunit, namespace)
Definition: mesh.F90:310
recursive subroutine, public mesh_end(this)
Definition: mesh.F90:686
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
Definition: messages.F90:898
character(len=512), private msg
Definition: messages.F90:167
subroutine, public messages_warning(no_lines, all_nodes, namespace)
Definition: messages.F90:525
subroutine, public messages_new_line()
Definition: messages.F90:1089
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:410
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:691
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1040
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:594
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:147
This module defines non-local operators.
subroutine, public nl_operator_global_init(namespace)
initialize global settings for non-local operators
subroutine, public nl_operator_global_end()
subroutine, public parse_block_string(blk, l, c, res, convert_to_c)
Definition: parser.F90:818
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:623
This module defines routines, generating operators for a cubic stencil.
subroutine, public stencil_cube_get_lapl(this, dim, order)
This module defines stencils used in Octopus.
Definition: stencil.F90:137
subroutine, public stencil_end(this)
Definition: stencil.F90:217
subroutine, public stencil_union(st1, st2, stu)
Definition: stencil.F90:229
subroutine, public symmetrizer_end(this)
subroutine, public symmetrizer_init(this, mesh, symm)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
This module defines the unit system, used for input and output.
type(unit_t), public unit_angstrom
For XYZ files.
type(unit_system_t), public units_inp
the units systems for reading and writing
class to tell whether a point is inside or outside
Definition: box.F90:143
abstract class to describe coordinate systems
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:171
Describes mesh distribution to nodes.
Definition: mesh.F90:187
This is defined even when running serial.
Definition: mpi.F90:144
Stores all communicators and groups.
Definition: multicomm.F90:208
The class representing the stencil, which is used for non-local mesh operations.
Definition: stencil.F90:165
int true(void)