Octopus
helmholtz_decomposition_test.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
23
25 use blas_oct_m
26 use box_oct_m
28 use debug_oct_m
30 use global_oct_m
31 use grid_oct_m
33 use io_oct_m
35 use, intrinsic :: iso_fortran_env
37 use loct_oct_m
38 use math_oct_m
39 use mesh_oct_m
44 use parser_oct_m
47 use space_oct_m
48 use unit_oct_m
50
51 implicit none
52
53 private
54 public :: &
58
60 private
61 real(real64), allocatable :: total_field(:,:)
62 real(real64), allocatable :: trans_field(:,:)
63 real(real64), allocatable :: long_field(:,:)
64 real(real64), allocatable :: vector_potential(:,:)
65 real(real64), allocatable :: scalar_potential(:)
66 real(real64) :: abs_norm_self_consistency, abs_norm_long_field, abs_norm_trans_field, abs_norm_scal_pot, abs_norm_vec_pot
67 real(real64) :: rel_norm_self_consistency, rel_norm_long_field, rel_norm_trans_field, rel_norm_scal_pot, rel_norm_vec_pot
68 contains
69 procedure :: init => helmholtz_test_init
71 end type helmholtz_test_t
72
73contains
74
75 subroutine helmholtz_test_init(this, np_part, dim)
76 class(helmholtz_test_t), intent(inout) :: this
77 integer, intent(in) :: np_part
78 integer, intent(in) :: dim
79
80 push_sub(helmholtz_test_init)
81
82 ! Scalar potential
83 safe_allocate(this%scalar_potential(1:np_part))
84 this%scalar_potential = m_zero
85 ! Vector potential
86 safe_allocate(this%vector_potential(1:np_part, 1:dim))
87 this%vector_potential = m_zero
88 ! Total Field
89 safe_allocate(this%total_field(1:np_part, 1:dim))
90 this%total_field = m_zero
91 ! Transverse field
92 safe_allocate(this%trans_field(1:np_part, 1:dim))
93 this%trans_field = m_zero
94 ! Longitudinal field
95 safe_allocate(this%long_field(1:np_part, 1:dim))
96 this%long_field = m_zero
97
98 pop_sub(helmholtz_test_init)
99 end subroutine helmholtz_test_init
100
101 subroutine helmholtz_test_finalize(this)
102 type(helmholtz_test_t), intent(inout) :: this
103
105
106 safe_deallocate_a(this%total_field)
107 safe_deallocate_a(this%trans_field)
108 safe_deallocate_a(this%long_field)
109 safe_deallocate_a(this%vector_potential)
110 safe_deallocate_a(this%scalar_potential)
111
113 end subroutine helmholtz_test_finalize
114
115 subroutine hertzian_dipole_test(helmholtz, sys_grid, namespace, space)
116 class(helmholtz_decomposition_t), intent(inout) :: helmholtz
117 type(grid_t), intent(in) :: sys_grid
118 type(namespace_t), intent(in) :: namespace
119 class(space_t), intent(in) :: space
120
121 ! Fields
122 type(helmholtz_test_t) :: helm_analytical
123 type(helmholtz_test_t) :: helm_comp_test_1
124 type(helmholtz_test_t) :: helm_comp_test_2
125 ! Vector potential computed from the magnetic field. Surface correction is never needed for this test
126 type(helmholtz_test_t) :: helm_comp_vec_pot_from_trans_field
127
128 character(len=20) :: test_case
129
130 push_sub(hertzian_dipole_test)
131 assert(space%dim == 3)
132
133 ! Allocate and initialize the fields
134 call helm_analytical%init(sys_grid%np_part, sys_grid%box%dim)
135 call helm_comp_test_1%init(sys_grid%np_part, sys_grid%box%dim)
136 call helm_comp_vec_pot_from_trans_field%init(sys_grid%np_part, sys_grid%box%dim)
137 ! Define the field to be tested (Hertzian dipole).
138 ! Reference: The Helmholtz Decomposition and the Coulomb Gauge, Kirk T. McDonald, Joseph Henry Laboratories, Princeton (2008)
139 ! http://kirkmcd.princeton.edu/examples/helmholtz.pdf
140 call init_hertzian_dipole_field(helm_analytical, sys_grid)
141 call io_mkdir("hertzian_dipole_test", namespace=namespace)
142 ! Output analytical fields
143 call io_mkdir("hertzian_dipole_test/exact_fields", namespace=namespace)
144 call output_fields(sys_grid, helm_analytical, space, namespace, "hertzian_dipole_test/exact_fields")
145
146 ! TEST 1
147 ! Compute the transverse and longitudinal fields numerically
148 call helmholtz%get_trans_field(namespace, helm_comp_test_1%trans_field, total_field=helm_analytical%total_field, &
149 apply_boundary=.false.)
150 call helmholtz%get_long_field(namespace, helm_comp_test_1%long_field, total_field=helm_analytical%total_field, &
151 apply_boundary=.false.)
152 ! Compute the scalar and vector potential numerically
153 call helmholtz%get_vector_potential(namespace, helm_comp_test_1%vector_potential, total_field=helm_analytical%total_field, &
154 apply_boundary=.false.)
155 call helmholtz%get_scalar_potential(namespace, helm_comp_test_1%scalar_potential, helm_analytical%total_field, &
156 apply_boundary=.false.)
157 ! Output fields
158 test_case = "no_surf_corr"
159 if (helmholtz%compute_surface_correction) test_case = "with_surf_corr"
160 call io_mkdir("hertzian_dipole_test/" // trim(test_case), namespace=namespace)
161 call output_fields(sys_grid, helm_comp_test_1, space, namespace, "hertzian_dipole_test/" // trim(test_case))
162 call compute_norms(helmholtz, sys_grid, helm_analytical, helm_comp_test_1, namespace, "hertzian_dipole_test/"//trim(test_case))
164 ! TEST VECTOR POTENTIAL COMPUTED FROM THE MAGNETIC FIELD
165 call helmholtz%get_vector_potential(namespace, helm_comp_vec_pot_from_trans_field%vector_potential, &
166 trans_field=helm_analytical%trans_field, apply_boundary=.true.)
167 ! Output fields
168 test_case = "vec_pot_from_b_field"
169 call io_mkdir("hertzian_dipole_test/" // trim(test_case), namespace=namespace)
170 call output_fields(sys_grid, helm_comp_vec_pot_from_trans_field, space, namespace, "hertzian_dipole_test/" // trim(test_case))
171 call compute_norms(helmholtz, sys_grid, helm_analytical, helm_comp_vec_pot_from_trans_field, namespace, &
172 "hertzian_dipole_test/"//trim(test_case), apply_stencil_for_vec_pot=.true.)
173
174 ! TEST 2
175 ! If the TEST 1 was done with surface correction, then perform a second one without surface correction. This allows to test
176 ! that the surface correction actualy brings some improvements
177 if (helmholtz%compute_surface_correction) then
178 helmholtz%compute_surface_correction = .false.
179 call helm_comp_test_2%init(sys_grid%np_part, sys_grid%box%dim)
180 ! Compute the transverse and longitudinal fields numerically
181 call helmholtz%get_trans_field(namespace, helm_comp_test_2%trans_field, total_field=helm_analytical%total_field, &
182 apply_boundary=.false.)
183 call helmholtz%get_long_field(namespace, helm_comp_test_2%long_field, total_field=helm_analytical%total_field, &
184 apply_boundary=.false.)
185 ! Compute the scalar and vector potential numerically
186 call helmholtz%get_vector_potential(namespace, helm_comp_test_2%vector_potential, trans_field=helm_analytical%trans_field, &
187 apply_boundary=.false.)
188 call helmholtz%get_scalar_potential(namespace, helm_comp_test_2%scalar_potential, helm_analytical%total_field, &
189 apply_boundary=.false.)
190 ! Output fields
191 test_case = "no_surf_corr"
192 call io_mkdir("hertzian_dipole_test/" // trim(test_case), namespace=namespace)
193 call output_fields(sys_grid, helm_comp_test_2, space, namespace, "hertzian_dipole_test/" // trim(test_case))
194 call compute_norms(helmholtz,sys_grid,helm_analytical, helm_comp_test_2, namespace, "hertzian_dipole_test/"//trim(test_case))
195 ! After the test is done, reset the compute_surface_correction flag
196 helmholtz%compute_surface_correction = .true.
197 ! If we are here, we did a test with surface correction and one without. So we should test that with surface correction
198 ! we got better results
199 call compare_norms(helm_comp_test_1, helm_comp_test_2, namespace, "hertzian_dipole_test/")
200 end if
201
202 pop_sub(hertzian_dipole_test)
203 end subroutine hertzian_dipole_test
204
205 subroutine init_hertzian_dipole_field(this, sys_grid)
206 class(helmholtz_test_t), intent(inout) :: this
207 type(grid_t), intent(in) :: sys_grid
209 real(real64) :: lambda, omega, kk, rr, time, norm
210 real(real64) :: xx(sys_grid%box%dim), xx_origin(sys_grid%box%dim), pp(sys_grid%box%dim), cross_p(sys_grid%box%dim)
211 integer :: ip
212 real(real64), parameter :: nearly_zero = 1e-14_real64
213
215
216 ! Parameters that define the dipole
217 lambda = 1.55_real64
218 omega = m_two * m_pi * (p_c / lambda)
219 kk = m_two * m_pi / lambda
220 time = m_zero
221 pp = cos(omega * time)
222 xx_origin(2:sys_grid%box%dim) = m_zero
223 xx_origin(1) = 3.11_real64
224
225 do ip = 1, sys_grid%np_part
226 call mesh_r(sys_grid, ip, rr, coords = xx, origin = xx_origin)
227 if (rr >= sys_grid%spacing(1)) then
228 xx = xx / rr
229 ! Longitudinal field - equation 31 of reference paper
230 this%long_field(ip, :) = (m_three * dot_product(pp, xx) * xx - pp) * cos(omega*time)/(rr**3)
231 ! Transverse field - equation 32 of reference paper
232 cross_p = dcross_product(xx, pp)
233 this%trans_field(ip, :) = (kk**2) * cross_p * (cos(kk*rr - omega*time)/rr - sin(kk*rr - omega*time)/(kk * rr**2))
234 ! Vector potential - equation 53 of reference paper
235 this%vector_potential(ip, :) = kk * (pp - dot_product(pp, xx)*xx) * sin(kk*rr - omega*time)/rr
236 this%vector_potential(ip, :) = this%vector_potential(ip, :) * (pp - m_three*dot_product(pp, xx)*xx) * &
237 (cos(kk*rr - omega*time)/(rr**2) - (sin(kk*rr - omega*time) - sin(omega*time))/(kk * rr**3))
238 ! Scalar potential - equation 51 of reference paper
239 this%scalar_potential(ip) = dot_product(pp, xx) * cos(omega*time) / (rr**2)
240 ! Total field
241 this%total_field = this%trans_field + this%long_field
242 end if
243 end do
244 ! Check that the exact fields ere defined correctly
245 norm = dmf_nrm2(sys_grid, sys_grid%box%dim, this%total_field - this%trans_field - this%long_field)
246 assert(norm < nearly_zero)
247
249 end subroutine init_hertzian_dipole_field
250
251 subroutine gaussian_test(helmholtz, sys_grid, namespace, space)
252 class(helmholtz_decomposition_t), intent(inout) :: helmholtz
253 type(grid_t), intent(in) :: sys_grid
254 type(namespace_t), intent(in) :: namespace
255 class(space_t), intent(in) :: space
256
257 ! Fields
258 type(helmholtz_test_t) :: helm_analytical
259 type(helmholtz_test_t) :: helm_comp_test_1
260 type(helmholtz_test_t) :: helm_comp_test_2
261 ! Vector potential computed from the magnetic field. Surface correction is never needed for this test
262 type(helmholtz_test_t) :: helm_comp_vec_pot_from_trans_field
263
264 character(len=20) :: test_case
265
266 push_sub(gaussian_test)
267 assert(space%dim == 3)
268
269 ! Allocate and initialize the fields
270 call helm_analytical%init(sys_grid%np_part, sys_grid%box%dim)
271 call helm_comp_test_1%init(sys_grid%np_part, sys_grid%box%dim)
272 call helm_comp_vec_pot_from_trans_field%init(sys_grid%np_part, sys_grid%box%dim)
273
274 ! Define the field to be tested
275 ! https://gitlab.com/octopus-code/octopus-hackathons/-/blob/main/01-full-minimal-coupling-2022-07-04-2022-07-08/documentation/francesco/Helmholtz_Decomposition_Coulomb_Gauge.pdf
276 call init_gaussian_field(helm_analytical, sys_grid)
277 call io_mkdir("gaussian_field_test", namespace=namespace)
278 ! Output analytical fields
279 call io_mkdir("gaussian_field_test/exact_fields", namespace=namespace)
280 call output_fields(sys_grid, helm_analytical, space, namespace, "gaussian_field_test/exact_fields")
281
282 ! TEST 1
283 ! Compute the transverse and longitudinal fields numerically
284 call helmholtz%get_trans_field(namespace, helm_comp_test_1%trans_field, total_field=helm_analytical%total_field, &
285 apply_boundary=.false.)
286 call helmholtz%get_long_field(namespace, helm_comp_test_1%long_field, total_field=helm_analytical%total_field, &
287 apply_boundary=.false.)
288 ! Compute the scalar and vector potential numerically
289 call helmholtz%get_vector_potential(namespace, helm_comp_test_1%vector_potential, total_field=helm_analytical%total_field, &
290 apply_boundary=.false.)
291 call helmholtz%get_scalar_potential(namespace, helm_comp_test_1%scalar_potential, helm_analytical%total_field, &
292 apply_boundary=.false.)
293 ! Output fields
294 test_case = "no_surf_corr"
295 if (helmholtz%compute_surface_correction) test_case = "with_surf_corr"
296 call io_mkdir("gaussian_field_test/" // trim(test_case), namespace=namespace)
297 call output_fields(sys_grid, helm_comp_test_1, space, namespace, "gaussian_field_test/" // trim(test_case))
298 call compute_norms(helmholtz, sys_grid, helm_analytical, helm_comp_test_1, namespace, "gaussian_field_test/"//trim(test_case))
299
300 ! TEST VECTOR POTENTIAL COMPUTED FROM THE MAGNETIC FIELD
301 call helmholtz%get_vector_potential(namespace, helm_comp_vec_pot_from_trans_field%vector_potential, &
302 trans_field=helm_analytical%trans_field, apply_boundary=.true.)
303 ! Output fields
304 test_case = "vec_pot_from_b_field"
305 call io_mkdir("gaussian_field_test/" // trim(test_case), namespace=namespace)
306 call output_fields(sys_grid, helm_comp_vec_pot_from_trans_field, space, namespace, "gaussian_field_test/" // trim(test_case))
307 call compute_norms(helmholtz, sys_grid, helm_analytical, helm_comp_vec_pot_from_trans_field, namespace, &
308 "gaussian_field_test/"//trim(test_case), apply_stencil_for_vec_pot=.true.)
309
310 ! TEST 2
311 ! If the TEST 1 was done with surface correction, then perform a second one without surface correction. This allows to test
312 ! that the surface correction actualy brings some improvements
313 if (helmholtz%compute_surface_correction) then
314 helmholtz%compute_surface_correction = .false.
315 call helm_comp_test_2%init(sys_grid%np_part, sys_grid%box%dim)
316 ! Compute the transverse and longitudinal fields numerically
317 call helmholtz%get_trans_field(namespace, helm_comp_test_2%trans_field, total_field=helm_analytical%total_field, &
318 apply_boundary=.false.)
319 call helmholtz%get_long_field(namespace, helm_comp_test_2%long_field, total_field=helm_analytical%total_field, &
320 apply_boundary=.false.)
321 ! Compute the scalar and vector potential numerically
322 call helmholtz%get_vector_potential(namespace, helm_comp_test_2%vector_potential, helm_analytical%total_field, &
323 apply_boundary=.false.)
324 call helmholtz%get_scalar_potential(namespace, helm_comp_test_2%scalar_potential, helm_analytical%total_field, &
325 apply_boundary=.false.)
326 ! Output fields
327 test_case = "no_surf_corr"
328 call io_mkdir("gaussian_field_test/" // trim(test_case), namespace=namespace)
329 call output_fields(sys_grid, helm_comp_test_2, space, namespace, "gaussian_field_test/" // trim(test_case))
330 call compute_norms(helmholtz,sys_grid, helm_analytical, helm_comp_test_2, namespace, "gaussian_field_test/"//trim(test_case))
331 ! After the test is done, reset the compute_surface_correction flag
332 helmholtz%compute_surface_correction = .true.
333 ! If we are here, we did a test with surface correction and one without. So we should test that with surface correction
334 ! we got better results
335 call compare_norms(helm_comp_test_1, helm_comp_test_2, namespace, "gaussian_field_test/")
336 end if
337
338 pop_sub(gaussian_test)
339 end subroutine gaussian_test
340
341 subroutine init_gaussian_field(this, sys_grid)
342 class(helmholtz_test_t), intent(inout) :: this
343 type(grid_t), intent(in) :: sys_grid
345 real(real64) :: alpha, beta, a_prefactor, b_prefactor, ra, rb, norm
346 real(real64) :: aa(sys_grid%box%dim), a_origin(sys_grid%box%dim), bb(sys_grid%box%dim), b_origin(sys_grid%box%dim)
347 integer :: ip
348
349 push_sub(init_gaussian_field)
350
351 ! Parameters that define the gaussian
352 alpha = 0.3_real64
353 a_prefactor = 1.5_real64
354 a_origin = m_one / 10
355 beta = 0.3_real64
356 b_prefactor = 1.7_real64
357 b_origin = -m_one / 10
358
359 ! Define the field to be tested
360 do ip = 1, sys_grid%np_part
361 call mesh_r(sys_grid, ip, ra, coords = aa, origin = a_origin)
362 ! Longitudinal field
363 this%long_field(ip, :) = (2 * a_prefactor / (alpha**2)) * aa(:) * exp(-(ra / alpha)**2)
364 ! Analytical scalar potential
365 this%scalar_potential(ip) = a_prefactor * exp(-(ra / alpha)**2)
366
367 call mesh_r(sys_grid, ip, rb, coords = bb, origin = b_origin)
368 ! Transverse field
369 this%trans_field(ip, 1) = - (2 * b_prefactor / (beta**2)) * bb(1) * bb(3) * exp(-(rb / beta)**2)
370 this%trans_field(ip, 2) = - (2 * b_prefactor / (beta**2)) * bb(2) * bb(3) * exp(-(rb / beta)**2)
371 this%trans_field(ip, 3) = (2 * b_prefactor / (beta**2)) * (bb(1)**2 + bb(2)**2 - beta**2) * exp(-(rb / beta)**2)
372 ! Analytical vector potential
373 this%vector_potential(ip, 1) = b_prefactor * bb(2) * exp(-(rb / beta)**2)
374 this%vector_potential(ip, 2) = - b_prefactor * bb(1) * exp(-(rb / beta)**2)
375
376 ! Total field
377 this%total_field(ip, :) = this%long_field(ip, :) + this%trans_field(ip, :)
378 end do
379
380 ! Check that the exact fields ere defined correctly
381 norm = dmf_nrm2(sys_grid, sys_grid%box%dim, this%total_field - this%trans_field - this%long_field)
382 assert(norm < m_epsilon)
383
384 pop_sub(init_gaussian_field)
385 end subroutine init_gaussian_field
386
387 subroutine output_fields(sys_grid, test, space, namespace, path)
388 type(grid_t), intent(in) :: sys_grid
389 type(helmholtz_test_t), intent(in) :: test
390 class(space_t), intent(in) :: space
391 type(namespace_t), intent(in) :: namespace
392 character(len=*), intent(in) :: path
393
394 integer :: ierr
395
396 push_sub(output_fields)
397
398 ! Output the values of the fields on the grid
399 call io_function_output_vector (io_function_fill_how('PlaneZ'), ".", trim(path) // "/total_field", namespace, space, &
400 sys_grid, test%total_field, unit_one, ierr)
401 call io_function_output_vector (io_function_fill_how('PlaneZ'), ".", trim(path) // "/trans_field", namespace, space, &
402 sys_grid, test%trans_field, unit_one, ierr)
403 call io_function_output_vector (io_function_fill_how('PlaneZ'), ".", trim(path) // "/long_field", namespace, space, &
404 sys_grid, test%long_field, unit_one, ierr)
405 call io_function_output_vector (io_function_fill_how('PlaneZ'), ".", trim(path) // "/vector_potential", namespace, space, &
406 sys_grid, test%vector_potential, unit_one, ierr)
407 call dio_function_output (io_function_fill_how('PlaneZ'), ".", trim(path) // "/scalar_potential", namespace, space, &
408 sys_grid, test%scalar_potential, unit_one, ierr)
409
410 pop_sub(output_fields)
411 end subroutine output_fields
412
413 subroutine compute_norms(helmholtz, sys_grid, analytical, test, namespace, path, apply_stencil_for_vec_pot)
414 type(helmholtz_decomposition_t), intent(inout) :: helmholtz
415 type(grid_t), intent(in) :: sys_grid
416 type(helmholtz_test_t), intent(in) :: analytical
417 type(helmholtz_test_t), intent(inout) :: test
418 type(namespace_t), intent(in) :: namespace
419 character(len=*), intent(in) :: path
420 logical, optional, intent(in) :: apply_stencil_for_vec_pot
421
422 integer :: iunit, dim, np
423 real(real64), allocatable :: local_field(:,:)
424
425 push_sub(compute_norms)
426 safe_allocate(local_field(1:sys_grid%np, 1:sys_grid%box%dim))
427
428 dim = sys_grid%box%dim ! All boxes have the same dimension
429 np = sys_grid%np
430
431 ! First, compute the norms
432 ! Transverse field
433 local_field = analytical%trans_field(1:np,:)
434 call helmholtz%apply_inner_stencil_mask(local_field)
435 test%abs_norm_trans_field = dmf_nrm2(sys_grid, dim, test%trans_field(1:np,:) - local_field(1:np,:))
436 test%rel_norm_trans_field = test%abs_norm_trans_field / dmf_nrm2(sys_grid, dim, local_field(1:np, :))
437 ! Longitudinal field
438 local_field = analytical%long_field(1:np,:)
439 call helmholtz%apply_inner_stencil_mask(local_field)
440 test%abs_norm_long_field = dmf_nrm2(sys_grid, dim, test%long_field(1:np, :) - local_field(1:np, :))
441 test%rel_norm_long_field = test%abs_norm_long_field / dmf_nrm2(sys_grid, dim, local_field(1:np, :))
442 ! Vector potential
443 local_field = analytical%vector_potential(1:np,:)
444 if (optional_default(apply_stencil_for_vec_pot, .false.)) then
445 call helmholtz%apply_inner_stencil_mask(local_field)
446 end if
447 test%abs_norm_vec_pot = dmf_nrm2(sys_grid, dim, test%vector_potential(1:np,:) - local_field(1:np,:))
448 test%rel_norm_vec_pot = test%abs_norm_vec_pot / dmf_nrm2(sys_grid, dim, local_field(1:np, :))
449 ! Scalar potential
450 test%abs_norm_scal_pot = dmf_nrm2(sys_grid, test%scalar_potential(1:np) - analytical%scalar_potential(1:np))
451 test%rel_norm_scal_pot = test%abs_norm_scal_pot / dmf_nrm2(sys_grid, analytical%scalar_potential(1:np))
452 ! Self consistency
453 local_field = analytical%total_field(1:np,:)
454 call helmholtz%apply_inner_stencil_mask(local_field)
455 test%abs_norm_self_consistency = dmf_nrm2(sys_grid,dim,local_field(1:np,:)-test%trans_field(1:np,:)-test%long_field(1:np,:))
456 test%rel_norm_self_consistency = test%abs_norm_self_consistency / dmf_nrm2(sys_grid, dim, local_field(1:np, :))
457
458 safe_deallocate_a(local_field)
459
460 ! Output the norms to file
461 iunit = io_open(path // "/norms", namespace, action='write')
462 write(iunit, '(a,f19.13)') 'Transverse field test (abs.). = ', test%abs_norm_trans_field
463 write(iunit, '(a,f19.13)') 'Transverse field test (rel.). = ', test%rel_norm_trans_field
464 write(iunit, '(a,f19.13)') 'Longitudinal field test (abs.). = ', test%abs_norm_long_field
465 write(iunit, '(a,f19.13)') 'Longitudinal field test (rel.). = ', test%rel_norm_long_field
466 write(iunit, '(a,f19.13)') 'Vector potential test (abs.). = ', test%abs_norm_vec_pot
467 write(iunit, '(a,f19.13)') 'Vector potential test (rel.). = ', test%rel_norm_vec_pot
468 write(iunit, '(a,f19.13)') 'Scalar potential test (abs.). = ', test%abs_norm_scal_pot
469 write(iunit, '(a,f19.13)') 'Scalar potential test (rel.). = ', test%rel_norm_scal_pot
470 write(iunit, '(a,f19.13)') 'Self consistency test (abs.). = ', test%abs_norm_self_consistency
471 write(iunit, '(a,f19.13)') 'Self consistency test (rel.). = ', test%rel_norm_self_consistency
472
473 call io_close(iunit)
474
475 pop_sub(compute_norms)
476 end subroutine compute_norms
477
478 subroutine compare_norms(test_with_sc, test_no_sc, namespace, path)
479 type(helmholtz_test_t), intent(in) :: test_with_sc
480 type(helmholtz_test_t), intent(in) :: test_no_sc
481 type(namespace_t), intent(in) :: namespace
482 character(len=*), intent(in) :: path
483
484 integer :: iunit
485 character(len=24), parameter :: form = '(a,f19.13,a,f19.13)'
486
487 push_sub(compare_norms)
488
489 ! Output the norms to file
490 iunit = io_open(path // "norm_comparison", namespace, action='write')
491 ! Trans field
492 write(iunit, form) 'Transverse field test (abs.). No surf correction = ', test_no_sc%abs_norm_trans_field, &
493 " ;With surf correction = ", test_with_sc%abs_norm_trans_field
494 write(iunit, form) 'Transverse field test (rel.). No surf correction = ', test_no_sc%rel_norm_trans_field, &
495 " ;With surf correction = ", test_with_sc%rel_norm_trans_field
496 ! Long field
497 write(iunit, form) 'Longitudinal field test (abs.). No surf correction = ', test_no_sc%abs_norm_long_field, &
498 " ;With surf correction = ", test_with_sc%abs_norm_long_field
499 write(iunit, form) 'Longitudinal field test (rel.). No surf correction = ', test_no_sc%rel_norm_long_field, &
500 " ;With surf correction = ", test_with_sc%rel_norm_long_field
501 ! Vector potential
502 write(iunit, form) 'Vector potential test (abs.). No surf correction = ', test_no_sc%abs_norm_vec_pot, &
503 " ;With surf correction = ", test_with_sc%abs_norm_vec_pot
504 write(iunit, form) 'Vector potential test (rel.). No surf correction = ', test_no_sc%rel_norm_vec_pot, &
505 " ;With surf correction = ", test_with_sc%rel_norm_vec_pot
506 ! Scalar potential
507 write(iunit, form) 'Scalar potential test (abs.). No surf correction = ', test_no_sc%abs_norm_scal_pot, &
508 " ;With surf correction = ", test_with_sc%abs_norm_scal_pot
509 write(iunit, form) 'Scalar potential test (rel.). No surf correction = ', test_no_sc%rel_norm_scal_pot, &
510 " ;With surf correction = ", test_with_sc%rel_norm_scal_pot
511 ! Self consistency
512 write(iunit, form) 'Self consistency test (abs.). No surf correction = ', test_no_sc%abs_norm_self_consistency, &
513 " ;With surf correction = ", test_with_sc%abs_norm_self_consistency
514 write(iunit, form) 'Self consistency test (rel.). No surf correction = ', test_no_sc%rel_norm_self_consistency, &
515 " ;With surf correction = ", test_with_sc%rel_norm_self_consistency
516 call io_close(iunit)
517
518 ! Trans field
519 assert(test_with_sc%abs_norm_trans_field < test_no_sc%abs_norm_trans_field)
520 assert(test_with_sc%rel_norm_trans_field < test_no_sc%rel_norm_trans_field)
521 ! Long field
522 assert(test_with_sc%abs_norm_long_field < test_no_sc%abs_norm_long_field)
523 assert(test_with_sc%rel_norm_long_field < test_no_sc%rel_norm_long_field)
524 ! Vector potential
525 assert(test_with_sc%abs_norm_vec_pot < test_no_sc%abs_norm_vec_pot)
526 assert(test_with_sc%rel_norm_vec_pot < test_no_sc%rel_norm_vec_pot)
527 ! Scalar potential
528 assert(test_with_sc%abs_norm_scal_pot < test_no_sc%abs_norm_scal_pot)
529 assert(test_with_sc%rel_norm_scal_pot < test_no_sc%rel_norm_scal_pot)
530 ! Self Consistency
531 assert(test_with_sc%abs_norm_self_consistency < test_no_sc%abs_norm_self_consistency)
532 assert(test_with_sc%rel_norm_self_consistency < test_no_sc%rel_norm_self_consistency)
533
534 pop_sub(compare_norms)
535 end subroutine compare_norms
536
537#include "undef.F90"
538#include "complex.F90"
539
540#include "undef.F90"
541#include "real.F90"
542
544
545!! Local Variables:
546!! mode: f90
547!! coding: utf-8
548!! End:
double exp(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
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.
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_pi
some mathematical constants
Definition: global.F90:185
real(real64), parameter, public m_epsilon
Definition: global.F90:203
real(real64), parameter, public p_c
Electron gyromagnetic ratio, see Phys. Rev. Lett. 130, 071801 (2023)
Definition: global.F90:223
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...
Test suit for the Helmholtz decomposition module.
subroutine compare_norms(test_with_sc, test_no_sc, namespace, path)
subroutine helmholtz_test_init(this, np_part, dim)
subroutine init_gaussian_field(this, sys_grid)
subroutine, public gaussian_test(helmholtz, sys_grid, namespace, space)
subroutine init_hertzian_dipole_field(this, sys_grid)
subroutine compute_norms(helmholtz, sys_grid, analytical, test, namespace, path, apply_stencil_for_vec_pot)
subroutine, public hertzian_dipole_test(helmholtz, sys_grid, namespace, space)
subroutine output_fields(sys_grid, test, space, namespace, path)
subroutine, public dio_function_output(how, dir, fname, namespace, space, mesh, ff, unit, ierr, pos, atoms, grp, root)
Top-level IO routine for functions defined on the mesh.
integer(int64) function, public io_function_fill_how(where)
Use this function to quickly plot functions for debugging purposes: call dio_function_output(io_funct...
Definition: io.F90:114
subroutine, public io_close(iunit, grp)
Definition: io.F90:468
subroutine, public io_mkdir(fname, namespace, parents)
Definition: io.F90:354
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
pure real(real64) function, dimension(1:3), public dcross_product(a, b)
Definition: math.F90:1833
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
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
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_t), public unit_one
some special units required for particular quantities
Description of the grid, containing information on derivatives, stencil, and symmetries.
Definition: grid.F90:168
int true(void)