36 USE ieee_arithmetic,
ONLY: ieee_is_finite
67 LOGICAL :: source_root_argument
69 CHARACTER(LEN=default_path_length) :: filename
71 REAL(kind=
dp) :: error(6)
77 CALL check_core_derivatives()
78 CALL check_projector_addition_theorem()
79 CALL check_atomic_potential()
80 CALL check_upf_units()
82 CALL check_basis_origin()
83 CALL check_basis_derivatives()
84 CALL check_radial_grid_endpoints()
85 CALL check_contracted_basis_reader()
86 CALL check_basis_optimization_export()
88 CALL check_uspp_partial_waves()
91 ALLOCATE (pot%rho_nlcc(3))
93 pot%core_correction = .true.
94 pot%econf = [2, 4, 0, 0]
95 pot%pname =
"previous kind"
97 IF (
ALLOCATED(pot%rho_nlcc)) error stop
"UPF release leaked the core density"
98 IF (pot%core_correction) error stop
"UPF release retained core-correction metadata"
99 IF (any(pot%econf /= 0)) error stop
"UPF release retained the previous electron configuration"
100 IF (pot%pname /=
"") error stop
"UPF release retained the previous potential name"
103 ALLOCATE (sgp%a_nlcc(2), sgp%c_nlcc(2))
104 sgp%has_nlcc = .true.
106 sgp%is_nonlocal(2) = .true.
108 IF (
ASSOCIATED(sgp%a_nlcc) .OR.
ASSOCIATED(sgp%c_nlcc)) error stop
"SGP release leaked NLCC arrays"
109 IF (sgp%has_nlcc .OR. sgp%n_nlcc /= 0) error stop
"SGP release retained NLCC metadata"
110 IF (any(sgp%is_nonlocal)) error stop
"SGP release retained nonlocal channels"
115 DO i = 1, command_argument_count()
116 CALL get_command_argument(i, filename)
119 INQUIRE (file=trim(filename)//
"/tests/UNIT_TESTS", exist=source_root_argument)
120 IF (source_root_argument) cycle
123 IF (abs(sum(pot%econf) - pot%zion) > 1.e-10_dp) error stop
"UPF valence count mismatch"
124 IF (.NOT. all(ieee_is_finite(pot%vlocal))) error stop
"Non-finite UPF local potential"
125 IF (any(pot%r(2:) <= pot%r(:
SIZE(pot%r) - 1))) error stop
"UPF mesh is not increasing"
126 IF (any(pot%rab <= 0.0_dp)) error stop
"Non-positive UPF mesh weights"
127 IF (
ALLOCATED(pot%dion))
THEN
128 IF (.NOT. all(ieee_is_finite(pot%dion))) error stop
"Non-finite UPF projector coefficients"
129 IF (.NOT. all(ieee_is_finite(pot%beta))) error stop
"Non-finite UPF projectors"
130 IF (maxval(abs(pot%dion - transpose(pot%dion))) > 1.e-10_dp) error stop
"Non-Hermitian UPF D matrix"
133 IF (.NOT. all(ieee_is_finite(error))) error stop
"Non-finite UPF transformation errors"
134 IF (pot%core_correction)
THEN
135 IF (.NOT.
ASSOCIATED(sgp%a_nlcc)) error stop
"Missing transformed UPF core density"
136 IF (.NOT. all(ieee_is_finite(sgp%c_nlcc))) error stop
"Non-finite transformed UPF core density"
138 IF (io_unit > 0)
WRITE (io_unit,
'(A,1X,A,1X,6ES16.7)')
"UPF transformation:", trim(filename), error
151 CHARACTER(LEN=*),
PARAMETER :: fixture =
"uspp-augmentation-test.upf"
158 IF (logger%para_env%is_source())
THEN
159 OPEN (newunit=unit, file=fixture, status=
'REPLACE', action=
'WRITE')
160 WRITE (unit,
'(A)') &
161 '<UPF version="2.0.1">', &
162 '<PP_HEADER element="Pt" pseudo_type="USPP" is_ultrasoft="true"', &
163 ' z_valence="16" mesh_size="3" number_of_proj="2" l_max="1" />', &
164 '<PP_MESH mesh="3">', &
172 '<PP_LOCAL type="real" size="3">', &
176 '<PP_BETA.1 type="real" size="3" index="1" angular_momentum="0">', &
179 '<PP_BETA.2 type="real" size="3" index="2" angular_momentum="1">', &
185 '<PP_AUGMENTATION q_with_l="T" nqf="0" nqlc="3">', &
189 '<PP_QIJL.2.2.0 first_index="2" second_index="2" composite_index="3" angular_momentum="0">', &
191 '</PP_QIJL.2.2.0>', &
192 '<PP_QIJL.1.1.0 type="real" size="3" first_index="1" second_index="1"', &
193 ' composite_index="1" angular_momentum="0" is_null="false">', &
195 '</PP_QIJL.1.1.0>', &
196 '<PP_QIJL.1.2.1 first_index="1" second_index="2" composite_index="2" angular_momentum="1">', &
198 '</PP_QIJL.1.2.1>', &
199 '<PP_QIJL.2.2.2 first_index="2" second_index="2" composite_index="3"', &
200 ' angular_momentum="2" is_null="T" size="0"/>', &
201 '</PP_AUGMENTATION>', &
206 CALL logger%para_env%sync()
208 IF (any(pot%econf(0:3) /= [1, 6, 9, 0])) error stop
'Wrong 62-electron core subtraction'
209 IF (any(shape(pot%qijl) /= [3, 3, 3]) .OR. lbound(pot%qijl, 3) /= 0) error stop
'Wrong augmentation shape'
210 IF (maxval(abs(pot%qij - reshape([2._dp, 0._dp, 0._dp, 3._dp], [2, 2]))) > 1.e-14_dp)
THEN
211 error stop
'PP_Q normalization changed'
213 IF (maxval(abs(pot%qijl(:, 1, 0) - [1._dp, 2._dp, 3._dp])) > 1.e-14_dp) error stop
'Wrong s-s augmentation'
214 IF (maxval(abs(pot%qijl(:, 2, 1) - [4._dp, -5._dp, 6._dp])) > 1.e-14_dp) error stop
'Wrong s-p augmentation'
215 IF (maxval(abs(pot%qijl(:, 3, 0) - [-3._dp, 4._dp, 5._dp])) > 1.e-14_dp) error stop
'Wrong p-p augmentation'
216 IF (any(pot%qijl(:, :, 2) /= 0._dp)) error stop
'Null augmentation was not zero initialized'
217 IF (maxval(abs(pot%beta(:, 2) - [4._dp, -1._dp, 2._dp])) > 1.e-14_dp) error stop
'USPP beta normalization changed'
218 IF (abs(pot%dion(2, 2) - 4._dp) > 1.e-14_dp) error stop
'USPP D is not in Hartree'
220 IF (
ALLOCATED(pot%qij) .OR.
ALLOCATED(pot%qijl)) error stop
'Augmentation arrays were not released'
221 CALL logger%para_env%sync()
222 IF (logger%para_env%is_source())
THEN
223 OPEN (newunit=unit, file=fixture, status=
'OLD')
224 CLOSE (unit, status=
'DELETE')
232 SUBROUTINE check_uspp_partial_waves()
233 CHARACTER(LEN=*),
PARAMETER :: fixture =
'uspp-partial-waves-test.upf'
235 CHARACTER(LEN=5) :: has_wfc
236 INTEGER :: unit, variant
243 IF (variant == 1) has_wfc =
'true'
244 IF (logger%para_env%is_source())
THEN
245 OPEN (newunit=unit, file=fixture, status=
'REPLACE', action=
'WRITE')
246 WRITE (unit,
'(A)') &
247 '<UPF version="2.0.1">', &
248 '<PP_HEADER element="H" pseudo_type="US" is_ultrasoft="true" is_paw="false"', &
249 ' has_wfc="'//trim(has_wfc)//
'" z_valence="1" mesh_size="3"', &
250 ' number_of_proj="2" number_of_wfc="1" l_max="1"/>', &
251 '<PP_MESH mesh="3">', &
252 '<PP_R>',
'0.5 1 1.5',
'</PP_R>', &
253 '<PP_RAB>',
'0.5 0.5 0.5',
'</PP_RAB>',
'</PP_MESH>', &
254 '<PP_LOCAL>',
'6 4 2',
'</PP_LOCAL>', &
256 '<PP_BETA.1 index="1" angular_momentum="0" size="3">',
'1 4 9',
'</PP_BETA.1>', &
257 '<PP_BETA.2 index="2" angular_momentum="1" size="3">',
'2 -1 3',
'</PP_BETA.2>', &
258 '<PP_DIJ>',
'2 0 0 8',
'</PP_DIJ>', &
259 '<PP_AUGMENTATION q_with_l="T" nqf="0" nqlc="3">', &
260 '<PP_Q>',
'2 0 0 3',
'</PP_Q>', &
261 '<PP_QIJL.1.1.0 first_index="1" second_index="1" composite_index="1" angular_momentum="0">', &
262 '1 2 3',
'</PP_QIJL.1.1.0>', &
263 '<PP_QIJL.1.2.1 first_index="1" second_index="2" composite_index="2" angular_momentum="1">', &
264 '4 -5 6',
'</PP_QIJL.1.2.1>', &
265 '<PP_QIJL.2.2.0 first_index="2" second_index="2" composite_index="3" angular_momentum="0">', &
266 '-3 4 5',
'</PP_QIJL.2.2.0>', &
267 '<PP_QIJL.2.2.2 first_index="2" second_index="2" composite_index="3" angular_momentum="2">', &
268 '0 0 0',
'</PP_QIJL.2.2.2>',
'</PP_AUGMENTATION>',
'</PP_NONLOCAL>', &
269 '<PP_PSWFC>',
'<PP_CHI.1 l="0">',
'999 999 999',
'</PP_CHI.1>',
'</PP_PSWFC>'
270 IF (variant == 1)
THEN
272 WRITE (unit,
'(A)') &
273 '<PP_FULL_WFC number_of_wfc="2">', &
274 '<PP_PSWFC.2 type="real" size="3" l="1">',
'2 3 -4',
'</PP_PSWFC.2>', &
275 '<PP_AEWFC.1 index="1" l="0">',
'-3 5 -7',
'</PP_AEWFC.1>', &
276 '<PP_AEWFC.2 index="2" l="1">',
'5 -7 9',
'</PP_AEWFC.2>', &
277 '<PP_PSWFC.1 l="0">',
'1 -2 3',
'</PP_PSWFC.1>',
'</PP_FULL_WFC>'
279 WRITE (unit,
'(A)')
'</UPF>'
282 CALL logger%para_env%sync()
283 IF (variant == 1)
THEN
285 IF (
ALLOCATED(potential%partial_waves)) error stop
'USPP full waves imported without augmentation request'
288 CALL atom_read_upf(potential, fixture, read_augmentation=.true.)
289 IF (potential%is_paw) error stop
'USPP full waves were classified as PAW'
290 IF (variant == 1)
THEN
291 IF (.NOT.
ALLOCATED(potential%partial_waves)) error stop
'Missing optional USPP full waves'
292 associate(waves => potential%partial_waves)
293 IF (any(shape(waves%ae_wfc) /= [3, 2])) error stop
'USPP full-wave count differs from beta count'
294 IF (any(waves%ae_wfc /= reshape([-3._dp, 5._dp, -7._dp, 5._dp, -7._dp, 9._dp], [3, 2])))
THEN
295 error stop
'USPP AE full-wave order or original normalization changed'
297 IF (any(waves%ps_wfc /= reshape([1._dp, -2._dp, 3._dp, 2._dp, 3._dp, -4._dp], [3, 2])))
THEN
298 error stop
'USPP PS full waves changed or were confused with atomic guesses'
300 IF (any(waves%angular_momenta /= [0, 1])) error stop
'Wrong USPP full-wave angular momenta'
303 DEALLOCATE (potential%partial_waves%ps_wfc)
307 IF (
ALLOCATED(potential%partial_waves)) error stop
'USPP without full waves allocated partial-wave data'
310 IF (
ALLOCATED(potential%partial_waves)) error stop
'USPP full-wave data not released'
311 CALL logger%para_env%sync()
313 IF (logger%para_env%is_source())
THEN
314 OPEN (newunit=unit, file=fixture, status=
'OLD')
315 CLOSE (unit, status=
'DELETE')
317 END SUBROUTINE check_uspp_partial_waves
322 SUBROUTINE check_radial_grid_endpoints()
323 INTEGER,
PARAMETER :: n = 6400, types(2) = [do_gapw_gct, do_gapw_log]
324 REAL(dp),
PARAMETER :: inner(2) = [4.83458313724687745e-18_dp, 6.97482911687147684e-18_dp], &
325 outer(2) = [2.06843066219244770e17_dp, 57.5213142095328827_dp]
329 TYPE(grid_atom_type),
POINTER :: grid
332 DO i = 1,
SIZE(types)
333 CALL allocate_grid_atom(grid)
334 CALL create_grid_atom(grid, n, 1, 2, 0, types(i))
335 IF (.NOT. all(ieee_is_finite(grid%rad)) .OR. .NOT. all(ieee_is_finite(grid%wr)))
THEN
336 error stop
'Nonfinite radial grid'
338 IF (any(grid%rad <= 0.0_dp) .OR. any(grid%wr <= 0.0_dp)) error stop
'Nonpositive radial grid'
339 IF (any(grid%rad(:n - 1) <= grid%rad(2:))) error stop
'Unordered radial points'
341 error = abs(sum(grid%wr*exp(-grid%rad)) - 2.0_dp)
342 error = max(error, abs(sum(grid%wr*exp(-grid%rad)/grid%rad) - 1.0_dp))
343 error = max(error, abs(sum(grid%wr*exp(-grid%rad2)) - sqrt(pi)/4.0_dp))
344 IF (error > 1.e-10_dp) error stop
'Radial moment error'
346 IF (abs(grid%rad(n)/inner(i) - 1.0_dp) > 1.e-13_dp .OR. &
347 abs(grid%rad(1)/outer(i) - 1.0_dp) > 1.e-13_dp) error stop
'Radial grid endpoint error'
348 CALL deallocate_grid_atom(grid)
350 END SUBROUTINE check_radial_grid_endpoints
355 SUBROUTINE check_basis_origin()
356 INTEGER :: i, l, n, variant
357 REAL(KIND=dp) :: expected(3), r(6001), rab(6001), scale
358 TYPE(atom_basis_type) :: basis, radial
360 CALL init_atom_basis_default_pp(basis)
361 n = maxval(basis%nbas)
363 r = [(0.002_dp*real(i - 1, dp), i=1,
SIZE(r))]
365 CALL atom_basis_gridrep(basis, radial, r, rab)
366 IF (any(radial%grid%rad /= r) .OR. any(radial%grid%wr /= rab*r**2))
THEN
367 error stop
"Supplied UPF mesh changed during basis evaluation"
369 IF (maxval(abs(radial%bf(:, 1, 0) - exp(-basis%am(1, 0)*r**2))) > 1.e-14_dp)
THEN
370 error stop
"Incorrect basis values on long UPF mesh"
372 CALL release_atom_basis(radial)
374 scale = real(variant, dp)
375 IF (variant == 2)
THEN
376 basis%basis_type = cgto_basis
377 ALLOCATE (basis%cm(n, n, 0:ubound(basis%am, 2)))
380 basis%cm(i, i, :) = scale
383 CALL atom_basis_gridrep(basis, radial, [0.0_dp, 1.e-16_dp, 0.1_dp], [0.1_dp, 0.1_dp, 0.1_dp])
384 IF (.NOT. all(ieee_is_finite(radial%bf)) .OR. .NOT. all(ieee_is_finite(radial%dbf)) .OR. &
385 .NOT. all(ieee_is_finite(radial%ddbf))) error stop
"Nonfinite Gaussian derivatives at the UPF origin"
386 DO l = 0, ubound(basis%am, 2)
387 DO i = 1, basis%nbas(l)
389 IF (l == 0) expected = [1.0_dp, 0.0_dp, -2.0_dp*basis%am(i, l)]
390 IF (l == 1) expected(2) = 1.0_dp
391 IF (l == 2) expected(3) = 2.0_dp
392 IF (maxval(abs([radial%bf(1, i, l), radial%dbf(1, i, l), radial%ddbf(1, i, l)] - &
393 scale*expected)) > 1.e-12_dp) error stop
"Incorrect Gaussian origin limit"
396 CALL release_atom_basis(radial)
398 CALL release_atom_basis(basis)
399 END SUBROUTINE check_basis_origin
404 SUBROUTINE check_basis_derivatives()
405 REAL(dp),
PARAMETER :: radius(4) = [0.08_dp, 0.3_dp, 0.9_dp, 2.1_dp], step = 2.e-4_dp
407 INTEGER :: i, k, l, n, variant
408 REAL(dp) :: derivative(5), errors(3), first, lap(5), &
409 r(5), reference, rho(5), second
410 REAL(dp),
ALLOCATABLE :: pmat(:, :, :)
411 TYPE(atom_basis_type) :: basis, radial
413 CALL init_atom_basis_default_pp(basis)
414 n = maxval(basis%nbas)
418 basis%am(1, :) = 0.37_dp
419 basis%am(2, :) = 2.3_dp
420 ALLOCATE (pmat(n, n, 0:ubound(basis%am, 2)))
422 pmat(1, 1, :) = 0.8_dp
423 pmat(2, 2, :) = 0.4_dp
424 pmat(1, 2, :) = -0.17_dp
425 pmat(2, 1, :) = -0.17_dp
428 IF (variant == 2)
THEN
429 basis%basis_type = cgto_basis
430 ALLOCATE (basis%cm(n, n, 0:ubound(basis%am, 2)))
432 basis%cm(1, 1, :) = 0.7_dp
433 basis%cm(2, 1, :) = -0.2_dp
434 basis%cm(1, 2, :) = 0.1_dp
435 basis%cm(2, 2, :) = 1.3_dp
437 DO k = 1,
SIZE(radius)
438 r = radius(k) + step*[-2.0_dp, -1.0_dp, 0.0_dp, 1.0_dp, 2.0_dp]
439 CALL atom_basis_gridrep(basis, radial, r, spread(step, 1, 5))
440 DO l = 0, ubound(basis%am, 2)
442 first = dot_product(radial%bf(:, i, l), [1.0_dp, -8.0_dp, 0.0_dp, 8.0_dp, -1.0_dp])/(12*step)
443 second = dot_product(radial%bf(:, i, l), [-1.0_dp, 16.0_dp, -30.0_dp, 16.0_dp, -1.0_dp])/(12*step**2)
444 errors(1) = max(errors(1), abs(first - radial%dbf(3, i, l))/(1 + abs(first)))
445 errors(2) = max(errors(2), abs(second - radial%ddbf(3, i, l))/(1 + abs(second)))
448 CALL atom_density(rho, pmat, radial, ubound(basis%am, 2), typ=
"RHO")
449 CALL atom_density(derivative, pmat, radial, ubound(basis%am, 2), typ=
"DER")
450 CALL atom_density(lap, pmat, radial, ubound(basis%am, 2), typ=
"LAP", rr=r*r)
451 first = dot_product(rho, [1.0_dp, -8.0_dp, 0.0_dp, 8.0_dp, -1.0_dp])/(12*step)
452 second = dot_product(rho, [-1.0_dp, 16.0_dp, -30.0_dp, 16.0_dp, -1.0_dp])/(12*step**2)
453 errors(1) = max(errors(1), abs(first - derivative(3))/(1 + abs(first)))
454 reference = second + 2*first/radius(k)
455 errors(3) = max(errors(3), abs(reference - lap(3))/(1 + abs(reference)))
456 CALL release_atom_basis(radial)
459 IF (io_unit > 0)
WRITE (io_unit,
'(A,3ES24.15)')
"Atomic radial derivative/Laplacian scaled errors: ", errors
461 CALL release_atom_basis(basis)
462 IF (maxval(errors) > 2.e-7_dp) error stop
"Atomic radial finite-difference derivatives disagree"
463 END SUBROUTINE check_basis_derivatives
470 SUBROUTINE check_nlcc_fit()
471 INTEGER,
PARAMETER :: nr = 1601
472 REAL(dp),
PARAMETER :: amplitudes(3) = [0.02_dp, 1.7_dp, 0.4_dp], &
473 exponents(3) = [0.15_dp, 2.3_dp, 35.0_dp]
476 REAL(dp) :: density_error, derivative, derivative_error, dx, r(nr), rab(nr), radius, &
477 reference, reference_derivative, rho(nr), value
478 REAL(dp),
ALLOCATABLE :: alpha(:), coeff(:)
481 dx = log(20.0_dp/1.e-6_dp)/real(nr - 1, dp)
484 r(i) = 20.0_dp*real(i - 1, dp)/real(nr - 1, dp)
485 rab(i) = 20.0_dp/real(nr - 1, dp)
487 r(i) = 1.e-6_dp*exp(dx*real(i - 1, dp))
490 rho(i) = sum(amplitudes*exp(-exponents*r(i)**2))
492 CALL fit_core_density_gaussians(r, rab, rho, alpha, coeff)
493 density_error = 0.0_dp
494 derivative_error = 0.0_dp
496 radius = real(i, dp)*0.017_dp
497 reference = sum(amplitudes*exp(-exponents*radius**2))
498 reference_derivative = -2.0_dp*radius*sum(exponents*amplitudes*exp(-exponents*radius**2))
499 value = sum(coeff*exp(-alpha*radius**2))
500 derivative = -2.0_dp*radius*sum(alpha*coeff*exp(-alpha*radius**2))
501 density_error = max(density_error, abs(
value - reference))
502 derivative_error = max(derivative_error, abs(derivative - reference_derivative))
504 IF (io_unit > 0)
WRITE (io_unit,
'(A,I2,2ES16.7)') &
505 "Core Gaussian fit, density and derivative:", mesh, density_error, derivative_error
506 IF (density_error > 2.e-7_dp) error stop
"Gaussian core-density fit is inaccurate"
507 IF (derivative_error > 3.e-6_dp) error stop
"Gaussian core-density derivative is inaccurate"
509 CALL fit_core_density_gaussians(r, rab, rho, alpha, coeff)
510 IF (any(coeff /= 0.0_dp)) error stop
"Zero core density generated nonzero Gaussian coefficients"
512 END SUBROUTINE check_nlcc_fit
520 SUBROUTINE check_upf_units()
521 CHARACTER(LEN=*),
PARAMETER :: fixture = &
522 'upf-units-test-with-a-potential-filename-longer-than-'// &
523 'the-default-eighty-character-string-buffer.upf'
526 TYPE(atom_potential_type) :: atomic
527 TYPE(cp_logger_type),
POINTER :: logger
528 TYPE(section_type),
POINTER :: specification
529 TYPE(section_vals_type),
POINTER :: input, potential_section
531 logger => cp_get_default_logger()
532 IF (logger%para_env%is_source())
THEN
533 CALL open_file(fixture, unit_number=unit, file_status=
"REPLACE", file_action=
"WRITE")
534 WRITE (unit,
'(A)') &
535 '<UPF version="2.0.1">', &
536 '<PP_HEADER element="He" pseudo_type="NC" z_valence="2"', &
537 ' mesh_size="3" number_of_proj="2" l_max="0" />', &
538 '<PP_MESH mesh="3">', &
539 '<PP_R type="real" size="3">', &
542 '<PP_RAB type="real" size="3">', &
546 '<PP_LOCAL type="real" size="3">', &
550 '<PP_BETA.1 type="real" size="3" index="1" angular_momentum="0">', &
553 '<PP_BETA.2 type="real" size="3" index="2" angular_momentum="0">', &
556 '<PP_DIJ type="real" size="4">', &
561 CALL close_file(unit)
563 CALL logger%para_env%sync()
564 NULLIFY (specification, input)
565 CALL create_atom_section(specification)
566 CALL section_vals_create(input, specification)
567 potential_section => section_vals_get_subs_vals(input,
'POTENTIAL')
568 CALL section_vals_val_set(potential_section,
'PSEUDO_TYPE', i_val=upf_pseudo)
569 CALL section_vals_val_set(potential_section,
'POTENTIAL_FILE_NAME', c_val=fixture)
570 CALL init_atom_potential(atomic, potential_section, 2)
571 associate(potential => atomic%upf_pot)
572 IF (maxval(abs(potential%vlocal - [3.0_dp, 2.0_dp, 1.0_dp])) > 1.e-14_dp)
THEN
573 error stop
"UPF local potential is not in Hartree"
575 IF (maxval(abs(potential%beta(:, 1) - [2.0_dp, 4.0_dp, 6.0_dp])) > 1.e-14_dp)
THEN
576 error stop
"UPF changed the first tabulated projector amplitude"
578 IF (maxval(abs(potential%beta(:, 2) - [4.0_dp, -1.0_dp, 2.0_dp])) > 1.e-14_dp)
THEN
579 error stop
"UPF changed the second tabulated projector amplitude"
581 IF (maxval(abs(potential%dion - reshape([1.0_dp, 0.2_dp, 0.2_dp, 4.0_dp], [2, 2]))) > 1.e-14_dp)
THEN
582 error stop
"UPF D matrix is not in the tabulated-projector convention"
585 CALL release_atom_potential(atomic)
586 CALL section_vals_release(input)
587 CALL section_release(specification)
588 CALL logger%para_env%sync()
589 IF (logger%para_env%is_source())
THEN
590 CALL open_file(fixture, unit_number=unit, file_status=
"OLD")
591 CALL close_file(unit, file_status=
"DELETE")
593 END SUBROUTINE check_upf_units
600 SUBROUTINE check_atomic_potential()
602 REAL(KIND=dp) :: a, b, p, reference
603 TYPE(atom_basis_type) :: basis
604 TYPE(atom_integrals) :: integrals
605 TYPE(atom_potential_type) :: atomic
606 TYPE(sgp_potential_type),
POINTER :: potential
609 CALL allocate_potential(potential)
610 potential%zeff = 1.0_dp
611 potential%core_charge_radius = 0.4_dp
612 potential%alpha_core_charge = 0.5_dp/potential%core_charge_radius**2
613 potential%n_nonlocal = 1
615 potential%is_nonlocal(0:2) = .true.
616 potential%n_local = 1
617 ALLOCATE (potential%elec_conf(0:3), potential%a_nonlocal(1), &
618 potential%c_nonlocal(1, 1, 0:2), potential%h_nonlocal(1, 0:2), &
619 potential%a_local(1), potential%c_local(1))
620 potential%elec_conf = [1, 0, 0, 0]
621 potential%a_nonlocal = 0.7_dp
622 potential%c_nonlocal = 1.0_dp/sqrt(fourpi)
623 potential%h_nonlocal = 1.0_dp
624 potential%a_local = 1.2_dp
625 potential%c_local = 0.3_dp
626 atomic%ppot_type = sgp_pseudo
627 CALL sgp_potential_conversion(potential, atomic%sgp_pot)
628 CALL init_atom_basis_default_pp(basis)
629 CALL atom_ppint_setup(integrals, basis, atomic)
631 a = basis%am(8, l) + potential%a_nonlocal(1)
632 reference = (
gamma(l + 1.5_dp)/(2.0_dp*a**(l + 1.5_dp)))**2
633 IF (abs(integrals%hnl(8, 8, l) - reference) > 1.e-9_dp*abs(reference))
THEN
634 error stop
"Atomic SGP nonlocal operator differs from analytic Gaussian integrals"
637 p = 2.0_dp*basis%am(8, 0)
638 b = 1.0_dp/(sqrt(2.0_dp)*potential%core_charge_radius)
639 reference = -potential%zeff*b/(2.0_dp*p*sqrt(p + b*b)) + &
640 potential%c_local(1)*
gamma(1.5_dp)/(2.0_dp*(p + potential%a_local(1))**1.5_dp)
641 IF (abs(integrals%core(8, 8, 0) - reference) > 1.e-9_dp*abs(reference))
THEN
642 error stop
"Atomic SGP local operator differs from analytic Gaussian integrals"
644 CALL atom_ppint_release(integrals)
645 CALL release_atom_basis(basis)
646 CALL deallocate_potential(potential)
647 END SUBROUTINE check_atomic_potential
656 SUBROUTINE check_projector_addition_theorem()
657 INTEGER,
PARAMETER :: lmax = 5
659 INTEGER :: i, j, l, lx, ly, lz, nc, ns
660 REAL(KIND=dp) :: cross, diagonal, p(0:lmax), u(3), v(3), x
661 REAL(KIND=dp),
ALLOCATABLE :: pu(:), pv(:)
662 TYPE(sgp_potential_type),
POINTER :: potential
665 CALL init_orbital_pointers(lmax)
666 CALL init_spherical_harmonics(lmax, -1)
667 CALL allocate_potential(potential)
668 potential%n_nonlocal = 1
669 potential%lmax = lmax
670 potential%nppnl = sum(nco(0:lmax))
671 ALLOCATE (potential%c_nonlocal(1, 1, 0:lmax), potential%h_nonlocal(1, 0:lmax))
673 potential%c_nonlocal = 1.0_dp/sqrt(fourpi)
674 potential%h_nonlocal = 1.0_dp
675 CALL init_potential(potential)
676 u = [0.6_dp, 0.0_dp, 0.8_dp]
677 v = [0.3_dp, -0.4_dp, 0.5_dp]
679 x = dot_product(u, v)
683 p(l) = ((2*l - 1)*x*p(l - 1) - (l - 1)*p(l - 2))/l
688 ALLOCATE (pu(nso(l)), pv(nso(l)))
694 i = nc + co(lx, ly, lz)
696 pu(j) = pu(j) + potential%cprj_ppnl(i, ns + j)*u(1)**lx*u(2)**ly*u(3)**lz
697 pv(j) = pv(j) + potential%cprj_ppnl(i, ns + j)*v(1)**lx*v(2)**ly*v(3)**lz
701 diagonal = real(2*l + 1, dp)/fourpi
702 cross = diagonal*p(l)
703 IF (abs(dot_product(pu, pu) - diagonal) > 1.e-12_dp .OR. &
704 abs(dot_product(pv, pv) - diagonal) > 1.e-12_dp .OR. &
705 abs(dot_product(pu, pv) - cross) > 1.e-12_dp)
THEN
706 error stop
"SGP projector kernel violates the spherical-harmonic addition theorem"
712 CALL deallocate_potential(potential)
713 END SUBROUTINE check_projector_addition_theorem
718 SUBROUTINE check_core_derivatives()
719 REAL(kind=dp),
PARAMETER :: h = 1.e-4_dp
721 REAL(kind=dp) :: deriv(4), lap(4), lap_fd(4), minus(4), &
722 plus(4), r(4), rho(4)
723 TYPE(atom_potential_type) :: potential
725 potential%ppot_type = sgp_pseudo
726 potential%sgp_pot%has_nlcc = .true.
727 potential%sgp_pot%n_nlcc = 2
728 potential%sgp_pot%a_nlcc(1:2) = [0.7_dp, 2.3_dp]
729 potential%sgp_pot%c_nlcc(1:2) = [1.8_dp, -0.2_dp]
730 r = [0.0_dp, 0.1_dp, 0.7_dp, 2.0_dp]
736 CALL atom_core_density(rho, potential,
"RHO", r)
737 CALL atom_core_density(plus, potential,
"RHO", r + h)
738 CALL atom_core_density(minus, potential,
"RHO", r - h)
739 CALL atom_core_density(deriv, potential,
"DER", r)
740 CALL atom_core_density(lap, potential,
"LAP", r)
741 IF (maxval(abs(deriv - (plus - minus)/(2.0_dp*h))) > 1.e-7_dp)
THEN
742 error stop
"SGP core-density derivative differs from finite differences"
744 lap_fd = (plus - 2.0_dp*rho + minus)/h**2
745 lap_fd(1) = 3.0_dp*lap_fd(1)
746 lap_fd(2:) = lap_fd(2:) + (plus(2:) - minus(2:))/(h*r(2:))
747 IF (maxval(abs(lap - lap_fd)) > 1.e-6_dp) error stop
"SGP core-density Laplacian differs from finite differences"
748 END SUBROUTINE check_core_derivatives
753 SUBROUTINE check_contracted_basis_reader()
754 INTEGER,
PARAMETER :: contractions(3) = [11, 1, 1], lower_l(3) = [0, 1, 2], &
755 primitives(3) = [11, 41, 2], sets(3) = [1, 1, 21], upper_l(3) = [3, 6, 3]
756 CHARACTER(LEN=1600),
ALLOCATABLE :: lines(:)
757 INTEGER :: b, c, i, j, l, mode, n, nc, np, ns, row, &
759 REAL(dp) :: alpha, coefficient, expected, &
761 TYPE(atom_basis_type) :: basis
762 CHARACTER(LEN=*),
PARAMETER :: fixture =
"atom-contracted-basis-test"
764 TYPE(cp_logger_type),
POINTER :: logger
765 TYPE(section_type),
POINTER :: specification
766 TYPE(section_vals_type),
POINTER :: input, pp_basis
768 logger => cp_get_default_logger()
773 ALLOCATE (lines(1 + ns*(np + 1)))
774 WRITE (lines(1),
'(I0)') ns
778 WRITE (lines(row),
'(*(I0,1X))') 1, lower_l(b), upper_l(b), np, (nc, l=lower_l(b), upper_l(b))
781 alpha = real(10*s + i, dp)/20.0_dp
782 WRITE (lines(row),
'(*(F12.6,1X))') alpha, &
783 ((real(100*s + 10*i + c + 5*l, dp)/1000.0_dp, c=1, nc), l=lower_l(b), upper_l(b))
786 IF (logger%para_env%is_source())
THEN
787 OPEN (newunit=unit, file=fixture, status=
"REPLACE", action=
"WRITE")
788 WRITE (unit,
'(A)')
'H READER-TEST', (trim(lines(i)), i=1,
SIZE(lines))
791 CALL logger%para_env%sync()
793 NULLIFY (specification, input)
794 CALL create_atom_section(specification)
795 CALL section_vals_create(input, specification)
796 pp_basis => section_vals_get_subs_vals(input,
'PP_BASIS')
797 CALL section_vals_val_set(pp_basis,
'BASIS_TYPE', i_val=contracted_gto)
798 CALL section_vals_val_set(pp_basis,
'GRID_POINTS', i_val=32)
799 CALL section_vals_val_set(pp_basis,
'BASIS_SET', c_val=
'READER-TEST')
800 CALL section_vals_val_set(pp_basis,
'BASIS_SET_FILE_NAME', c_val=fixture)
802 DO i = 1,
SIZE(lines)
803 CALL section_vals_val_set(pp_basis,
'BASIS%_DEFAULT_KEYWORD_', i_rep_val=i, c_val=trim(lines(i)))
806 CALL init_atom_basis(basis, pp_basis, 1,
'PP')
807 DO l = 0, ubound(basis%nbas, 1)
809 IF (l >= lower_l(b) .AND. l <= upper_l(b)) n = ns
810 IF (basis%nprim(l) /= n*np .OR. basis%nbas(l) /= n*nc)
THEN
811 error stop
"Incorrect atomic contracted basis dimensions"
815 alpha = real(10*s + i, dp)/20.0_dp
817 IF (abs(basis%am(j, l) - alpha) > 1.e-14_dp) error stop
"Incorrect contracted basis exponent"
819 normalization = sqrt(2.0_dp*(2.0_dp*alpha)**(l + 1.5_dp)/
gamma(l + 1.5_dp))
823 IF (s == t) coefficient = real(100*s + 10*i + c + 5*l, dp)/1000.0_dp
824 expected = normalization*coefficient
825 IF (abs(basis%cm(j, (t - 1)*nc + c, l) - expected) > 1.e-12_dp*max(1.0_dp, abs(expected)))
THEN
826 error stop
"Incorrect contracted basis coefficient or normalization"
833 CALL release_atom_basis(basis)
834 CALL section_vals_release(input)
835 CALL section_release(specification)
837 CALL logger%para_env%sync()
838 IF (logger%para_env%is_source())
THEN
839 OPEN (newunit=unit, file=fixture, status=
"OLD")
840 CLOSE (unit, status=
"DELETE")
844 END SUBROUTINE check_contracted_basis_reader
849 SUBROUTINE check_basis_optimization_export()
850 CHARACTER(LEN=160) :: line
851 INTEGER :: i, j, status, unit
852 REAL(dp) :: alpha(2), coefficient(2), norm
853 REAL(dp),
POINTER :: exponents(:)
854 TYPE(cp_logger_type),
POINTER :: logger
855 TYPE(section_type),
POINTER :: specification
856 TYPE(section_vals_type),
POINTER :: input
858 NULLIFY (specification, input)
859 CALL create_atom_section(specification)
860 CALL section_vals_create(input, specification)
861 CALL section_vals_val_set(input,
'ELEMENT', c_val=
'He')
862 CALL section_vals_val_set(input,
'ELECTRON_CONFIGURATION', c_val=
'1s2')
863 CALL section_vals_val_set(input,
'MAX_ANGULAR_MOMENTUM', i_val=0)
864 CALL section_vals_val_set(input,
'AE_BASIS%NUM_GTO', i_val=2)
865 ALLOCATE (exponents(2))
866 exponents = [2.0_dp, 0.4_dp]
867 CALL section_vals_val_set(input,
'AE_BASIS%S_EXPONENTS', r_vals_ptr=exponents)
868 CALL section_vals_val_set(input,
'METHOD%METHOD_TYPE', i_val=do_rhf_atom)
869 CALL section_vals_val_set(input,
'OPTIMIZATION%EPS_SCF', r_val=1.e-10_dp)
870 CALL section_vals_val_set(input,
'OPTIMIZATION%N_DIIS', i_val=8)
871 CALL section_vals_val_set(input,
'OPTIMIZATION%MAX_ITER', i_val=100)
872 CALL section_vals_val_set(input,
'POWELL%MAX_FUN', i_val=5)
873 CALL section_vals_val_set(input,
'POWELL%STEP_SIZE', r_val=0.15_dp)
874 CALL section_vals_val_set(input,
'POWELL%ACCURACY', r_val=1.e-5_dp)
875 CALL section_vals_val_set(input,
'PRINT%FIT_BASIS%_SECTION_PARAMETERS_', i_val=silent_print_level)
876 CALL atom_basis_opt(input)
877 CALL section_vals_release(input)
878 CALL section_release(specification)
880 logger => cp_get_default_logger()
881 CALL logger%para_env%sync()
882 OPEN (newunit=unit, file=
'OPT_BASIS', status=
'OLD', action=
'READ')
884 READ (unit,
'(A)', iostat=status) line
885 IF (status /= 0) error stop
'Missing optimized basis orbital coefficients'
886 IF (index(line,
'L Quantum Number:') > 0)
EXIT
889 READ (unit, *) alpha(i), coefficient(i)
892 IF (alpha(1) <= 2.0_dp) error stop
'Optimization did not restore the earlier best exponent'
896 norm = norm + coefficient(i)*coefficient(j)* &
897 (2.0_dp*sqrt(alpha(i)*alpha(j))/(alpha(i) + alpha(j)))**1.5_dp
901 IF (.NOT. ieee_is_finite(norm) .OR. abs(norm - 1.0_dp) > 1.e-7_dp)
THEN
902 error stop
'Exported orbital is inconsistent with the optimized basis'
904 CALL logger%para_env%sync()
905 IF (logger%para_env%is_source())
THEN
906 OPEN (newunit=unit, file=
'OPT_BASIS', status=
'OLD')
907 CLOSE (unit, status=
'DELETE')
909 END SUBROUTINE check_basis_optimization_export
subroutine check_uspp_import()
...
program atom_upf_unittest
subroutine, public atom_basis_opt(atom_section)
Optimize the atomic basis set.
calculate the orbitals for a given atomic kind type
subroutine, public sgp_potential_conversion(sgp_potential, sgp_atompot)
...
Calculate the atomic operator matrices.
subroutine, public atom_ppint_release(integrals)
Release memory allocated for atomic integrals (core electrons).
subroutine, public atom_ppint_setup(integrals, basis, potential)
...
subroutine, public atom_sgp_release(sgp_pot)
...
subroutine, public sgp_construction(sgp_pot, ecp_pot, upf_pot, orb_basis, error)
...
subroutine, public fit_core_density_gaussians(r, rab, rho, alpha, coeff)
Fit a tabulated core density without forming ill-conditioned normal equations. Column-normalized,...
Define the atom type and its sub types.
integer, parameter, public cgto_basis
subroutine, public release_atom_potential(potential)
...
subroutine, public init_atom_basis(basis, basis_section, zval, btyp)
Initialize the basis for the atomic code.
subroutine, public init_atom_potential(potential, potential_section, zval)
...
subroutine, public release_atom_basis(basis)
...
subroutine, public init_atom_basis_default_pp(basis)
...
subroutine, public atom_basis_gridrep(basis, gbasis, r, rab)
...
Routines that process Quantum Espresso UPF files.
pure subroutine, public atom_release_upf(upfpot)
...
subroutine, public atom_read_upf(pot, upf_filename, read_header, read_augmentation)
...
Some basic routines for atomic calculations.
subroutine, public atom_core_density(corden, potential, typ, rr)
...
subroutine, public atom_density(density, pmat, basis, maxl, typ, rr)
Map the electron density on an atomic radial grid.
Utility routines to open and close files.
subroutine, public open_file(file_name, unit_number, file_status, file_form, file_action, file_position, file_pad, file_access, debug)
Opens a file and returns its logical unit number.
subroutine, public close_file(unit_number, file_status)
Closes an open file given by its logical unit number.
various routines to log and control the output. The idea is that decisions about where to log should ...
integer function, public cp_logger_get_default_io_unit(logger)
returns the unit nr for the ionode (-1 on all other processors) skips as well checks if the procs cal...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer, parameter, public silent_print_level
Definition of the atomic potential types.
Calculation of the incomplete Gamma function F_n(t) for multi-center integrals over Cartesian Gaussia...
Defines the basic variable types.
integer, parameter, public dp
integer, parameter, public default_path_length
subroutine, public cp2k_finalize()
...
subroutine, public cp2k_init()
...
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
real(kind=dp), parameter, public fourpi
Provides Cartesian and spherical orbital pointers and indices.
subroutine, public init_orbital_pointers(maxl)
Initialize or update the orbital pointers.
integer, dimension(:, :, :), allocatable, public co
integer, dimension(:), allocatable, public nco
integer, dimension(:), allocatable, public nso
subroutine, public deallocate_grid_atom(grid_atom)
Deallocate a Gaussian-type orbital (GTO) basis set data set.
subroutine, public allocate_grid_atom(grid_atom)
Initialize components of the grid_atom_type structure.
subroutine, public create_grid_atom(grid_atom, nr, na, llmax, ll, quadrature)
...
Owned UPF dataset and radial conventions shared by ATOM and Quickstep. Dataset availability does not ...
pure logical function, public upf_has_complete_partial_waves(pot)
Check for a complete projector-indexed pair of original AE and PS waves.
Provides all information about a basis set.
type of a logger, at the moment it contains just a print level starting at which level it should be l...