Octopus
helmholtz_decomposition.F90
Go to the documentation of this file.
1!! Copyright (C) 2019 R. Jestaedt, H. Appel, F. Bonafe, M. Oliveira, N. Tancogne-Dejean
2!! Copyright (C) 2022-2023 F. Troisi
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
58
59! TODO: Issue 705 (ftroisi): Add a test for non Coulomb Gauge
61 use blas_oct_m
62 use box_oct_m
64 use debug_oct_m
66 use global_oct_m
67 use grid_oct_m
68 use io_oct_m
70 use, intrinsic :: iso_fortran_env
72 use loct_oct_m
73 use math_oct_m
74 use mesh_oct_m
79 use parser_oct_m
82 use space_oct_m
83 use unit_oct_m
85
86 implicit none
87
88 private
90
92 private
93 ! Helmholtz solution handling
94 type(grid_t), pointer :: sys_grid
95 logical, public :: compute_surface_correction
96 integer, allocatable :: surface_points(:)
97 integer, allocatable :: inner_stencil(:)
98 ! Coulomb Gauge
99 logical :: enforce_coulomb_gauge
101 real(real64) :: coulomb_gauge_tolerance
103 ! Poisson Solver
104 real(real64) :: poisson_prefactor
105 type(poisson_t) :: poisson_solver
106
107 contains
108 ! Init
109 procedure :: init => helmholtz_decomposition_init
110 ! Apply mask
111 procedure :: dapply_inner_stencil_mask, zapply_inner_stencil_mask
112 generic :: apply_inner_stencil_mask => dapply_inner_stencil_mask, zapply_inner_stencil_mask
113 ! Vector potential
114 procedure :: dget_vector_potential, zget_vector_potential
115 generic :: get_vector_potential => dget_vector_potential, zget_vector_potential
116 ! Scalar potential
117 procedure :: dget_scalar_potential, zget_scalar_potential
118 generic :: get_scalar_potential => dget_scalar_potential, zget_scalar_potential
119 ! Transverse field
120 procedure :: dget_trans_field, zget_trans_field
121 generic :: get_trans_field => dget_trans_field, zget_trans_field
122 ! Longitudinal field
123 procedure :: dget_long_field, zget_long_field
124 generic :: get_long_field => dget_long_field, zget_long_field
125 ! Finalize
126 final :: helmholtz_finalize
128
129contains
130
132 subroutine helmholtz_decomposition_init(this, namespace, sys_grid, system_mc, space)
133 class(helmholtz_decomposition_t), intent(inout) :: this
134 type(namespace_t), intent(in) :: namespace
135 type(grid_t), target, intent(in) :: sys_grid
136 type(multicomm_t), intent(in) :: system_mc
137 class(space_t), intent(in) :: space
138
139 logical, allocatable :: mask(:)
140 logical :: visualize_boxes
141 integer :: number_of_points
142
144
145 ! Allocate pointer to system grid
146 this%sys_grid => sys_grid
147
148 ! 1. Initialize poisson solver
149 call poisson_init(this%poisson_solver, namespace, space, sys_grid%der, system_mc, sys_grid%stencil, label = "Helmholtz")
150
151 ! 2. Create a mask for the points contained in a layer of the width of the stencil between the innermost layer of points and
152 ! last row of points in the grid.
153 safe_allocate(mask(1:sys_grid%np))
154 ! Get the mask
155 mask = derivatives_get_inner_boundary_mask(sys_grid%der)
156 number_of_points = count(mask)
157 ! Store the indices of the mask points
158 safe_allocate(this%inner_stencil(1:number_of_points))
159 call get_indices_from_mask(sys_grid%np, mask, this%inner_stencil)
160
161 ! 3. Coulomb Gauge
162 !%Variable HelmholtzEnforceCoulombGauge
163 !%Type logical
164 !%Default yes
165 !%Section Calculation Modes::Test
166 !%Description
167 !% If true, the Vector Potential is enforced to be in Coulomb Gauge.
168 !% See proof of eq 30 of: https://www.scirp.org/pdf/jmp_2016053115275279.pdf
169 !%End
170 call parse_variable(namespace, 'HelmholtzEnforceCoulombGauge', .true., this%enforce_coulomb_gauge)
171 if (this%enforce_coulomb_gauge) then
172 !%Variable HelmholtzCoulombGaugeTolerance
173 !%Type float
174 !%Default 1e-5
175 !%Section Calculation Modes::Test
176 !%Description
177 !% If the vector potential should enforced to be in Coulomb Gauge, this variable defines the tolerance. The code will
178 !% evaluate the following expression: $spacing * \frac{\nabla \cdot A}{|A|}$
179 !%End
180 call parse_variable(namespace, 'HelmholtzCoulombGaugeTolerance', 1e-5_real64, this%coulomb_gauge_tolerance)
181 end if
182
183 ! 3. Surface correction TODO: See Issue 705 (@ftroisi)
185 !%Variable SurfaceCorrection
186 !%Type logical
187 !%Default no
188 !%Section Calculation Modes::Test
189 !%Description
190 !% Compute the surface correction for Helmholtz decomposition?
191 !%End
192 call parse_variable(namespace, 'SurfaceCorrection', .false., this%compute_surface_correction)
193 if (this%compute_surface_correction) then
194 call messages_not_implemented("Surface correction for Helmholtz decomposition")
195 end if
196
197 if (this%compute_surface_correction) then
198 ! First of all we have to get the surface points
199 mask = sys_grid%box%get_surface_points(namespace, sys_grid%spacing, sys_grid%np, sys_grid%x)
200 number_of_points = count(mask)
201
202 ! Allocate array surface_points and assign those points
203 safe_allocate(this%surface_points(1:number_of_points))
204 call get_indices_from_mask(sys_grid%np, mask, this%surface_points)
206 ! Initialize the poisson prefactor to treat the singular points (for the surface correction)
207 select case (sys_grid%box%dim)
208 case (3)
209 this%poisson_prefactor = m_two * m_pi * (m_three / (m_pi * m_four))**(m_twothird)
210 case (2)
211 this%poisson_prefactor = m_two * sqrt(m_pi)
212 case (1)
213 this%poisson_prefactor = m_one
214 case default
215 message(1) = "Internal error: surface correction for helmholtz decomposition can only be called for 1D, 2D or 3D."
216 call messages_fatal(1, namespace = namespace)
217 end select
218 end if
219 safe_deallocate_a(mask)
220
221 ! 4. Optionally, the user may want to visualize the relevant regions used to compute the Helmholtz decomposition
222 !%Variable HelmholtzVisualizeBoxes
223 !%Type logical
224 !%Default no
225 !%Section Calculation Modes::Test
226 !%Description
227 !% If true, output the volume points for the three boxes of the Helmholtz surface correction.
228 !% 1) The volume points of the system box
229 !% 2) The inner mask for the system box. This region has the thickness of the stencil and it is used to set to zero
230 !% the longitudinal or transverse field after computing the final divergence or curl (to avoid spikes)
231 !% 3) The surface points of the system box
232 !%
233 !%End
234 call parse_variable(namespace, 'HelmholtzVisualizeBoxes', .false., visualize_boxes)
235 if (visualize_boxes) then
236 call helmholtz_visualize_boxes(this, namespace, space)
237 end if
238
240 end subroutine helmholtz_decomposition_init
241
242 subroutine get_indices_from_mask(np, mask, indices)
243 integer, intent(in) :: np
244 logical, intent(in) :: mask(:)
245 integer, intent(out) :: indices(:)
246
247 integer :: ip, j
248 push_sub(get_indices_from_mask)
249
250 j = 1
251 do ip = 1, np
252 if (mask(ip)) then
253 indices(j) = ip
254 j = j + 1
255 end if
256 end do
257
258 pop_sub(get_indices_from_mask)
259 end subroutine get_indices_from_mask
260
261 subroutine helmholtz_finalize(this)
262 type(helmholtz_decomposition_t), intent(inout) :: this
263 push_sub(helmholtz_finalize)
264
265 call poisson_end(this%poisson_solver)
266
267 safe_deallocate_a(this%inner_stencil)
268 safe_deallocate_a(this%surface_points)
269
270 pop_sub(helmholtz_finalize)
271 end subroutine helmholtz_finalize
272
274 subroutine helmholtz_visualize_boxes(this, namespace, space)
275 type(helmholtz_decomposition_t), intent(inout) :: this
276 type(namespace_t), intent(in) :: namespace
277 class(space_t), intent(in) :: space
278
279 real(real64) :: coords(space%dim), normal_vector(space%dim), surface_element, ra
280 integer :: ip, ii, iunit
281
283
284 ! SYSTEM BOX - Volume points
285 iunit = io_open("system_box_volume_points", namespace, action='write')
286 write(iunit, '(a6, 5X, a1, 12X, a1, 12X, a1)') "#point", "x", "y", "z"
287 do ip = 1, this%sys_grid%np
288 call mesh_r(this%sys_grid, ip, ra, coords = coords)
289 write(iunit, '(i7, 3f12.7)') ip, coords(:)
290 end do
291 call io_close(iunit)
292
293 ! SYSTEM BOX - Mask for inner stencil
294 iunit = io_open("system_box_inner_stencil", namespace, action='write')
295 write(iunit, '(a6, 5X, a1, 12X, a1, 12X, a1)') "#point", "x", "y", "z"
296 do ip = 1, SIZE(this%inner_stencil, dim = 1)
297 ii = this%inner_stencil(ip)
298 call mesh_r(this%sys_grid, ii, ra, coords = coords)
299 write(iunit, '(i7, 3f12.7)') ip, coords(:)
300 end do
301 call io_close(iunit)
302
303 ! SYSTEM BOX - Surface Points
304 if (this%compute_surface_correction) then
305 iunit = io_open("system_box_surface_points", namespace, action='write')
306 write(iunit, '(a,12X,a,12X,a,12X,a,12X,a,12X,a,12X,a)') "x", "y", "z", "norm_x", "norm_y", "norm_z", "surf_element"
307 do ip = 1, SIZE(this%surface_points, dim = 1)
308 ii = this%surface_points(ip)
309 call mesh_r(this%sys_grid, ii, ra, coords = coords)
310 call this%sys_grid%box%get_surface_point_info(coords, this%sys_grid%spacing, normal_vector, surface_element)
311 write(iunit, '(7f12.7)') coords(:), normal_vector(:), surface_element
312 end do
313 call io_close(iunit)
314 end if
315
317 end subroutine helmholtz_visualize_boxes
318
319#include "undef.F90"
320#include "complex.F90"
321#include "helmholtz_decomposition_inc.F90"
322
323#include "undef.F90"
324#include "real.F90"
325#include "helmholtz_decomposition_inc.F90"
326
328
329!! Local Variables:
330!! mode: f90
331!! coding: utf-8
332!! End:
This module contains interfaces for BLAS routines You should not use these routines directly....
Definition: blas.F90:118
Module, implementing a factory for boxes.
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
logical function, dimension(1:this%mesh%np), public derivatives_get_inner_boundary_mask(this)
This function tells whether a point in the grid is contained in a layer of the width of the stencil b...
real(real64), parameter, public m_two
Definition: global.F90:189
real(real64), parameter, public m_four
Definition: global.F90:191
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:185
real(real64), parameter, public m_twothird
Definition: global.F90:195
real(real64), parameter, public m_one
Definition: global.F90:188
real(real64), parameter, public m_three
Definition: global.F90:190
This module implements the underlying real-space grid.
Definition: grid.F90:117
The Helmholtz decomposition is intended to contain "only mathematical" functions and procedures to co...
subroutine get_indices_from_mask(np, mask, indices)
subroutine helmholtz_decomposition_init(this, namespace, sys_grid, system_mc, space)
Initialize Helmholtz decomposition object.
subroutine helmholtz_visualize_boxes(this, namespace, space)
Visualise boxes for use in Helmholtz Decomposition.
Definition: io.F90:114
subroutine, public io_close(iunit, grp)
Definition: io.F90:468
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
Definition: io.F90:395
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
Definition: mesh.F90:336
subroutine, public messages_not_implemented(feature, namespace)
Definition: messages.F90:1125
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
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
subroutine, public poisson_init(this, namespace, space, der, mc, stencil, qtot, label, solver, verbose, force_serial, force_cmplx)
Definition: poisson.F90:238
subroutine, public poisson_end(this)
Definition: poisson.F90:714
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.
int true(void)