(git:6344619)
Loading...
Searching...
No Matches
cell_opt_utils_unittest.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
10 USE cell_opt_utils, ONLY: &
14 USE cell_types, ONLY: &
19 USE kinds, ONLY: default_string_length,&
20 dp
22
23 IMPLICIT NONE
24
25 REAL(kind=dp), PARAMETER :: initial(6) = [1.0_dp, 2.0_dp, 3.0_dp, 4.0_dp, 5.0_dp, 6.0_dp]
26 REAL(kind=dp), DIMENSION(:), POINTER :: gradient => null()
27 TYPE(cell_type), POINTER :: cell => null()
28
29 CALL cell_create(cell)
30 ALLOCATE (gradient(6))
31 CALL check_parser()
32 CALL check_projections()
33 CALL check_guards()
34 DEALLOCATE (gradient)
35 CALL cell_release(cell)
36
37CONTAINS
38
39! **************************************************************************************************
40!> \brief Check token masks, label round trips, rejections and 2D defaults.
41! **************************************************************************************************
42 SUBROUTINE check_parser()
43 CHARACTER(LEN=4), PARAMETER :: &
44 legacy(7) = ["NONE", " X", " Y", " Z", " XY", " XZ", " YZ"], names(18) = [ &
45 CHARACTER(LEN=4) :: "NONE", "X", "Y", "Z", "XY", "XZ", "YZ", "a", "AX", "B", "BX", "BY", &
46 "C", "CX", "CY", "CZ", "none", " z "]
47 CHARACTER(LEN=5), PARAMETER :: &
48 invalid(5) = [character(len=5) :: "AY", "AZ", "BZ", "ALPHA", "YX"]
49 INTEGER, PARAMETER :: &
50 masks(18) = [0, 11, 22, 56, 31, 59, 62, 1, 1, 6, 2, 4, 56, 8, 16, 32, 0, 56]
51
52 CHARACTER(LEN=default_string_length) :: label, reason, tokens(6)
53 INTEGER :: i, mask, n, wanted
54 LOGICAL :: accepted
55
56! Bits 0..5 represent AX, BX, BY, CX, CY, CZ, respectively.
57
58 cell%perd = 1
59 DO i = 1, SIZE(names)
60 CALL parse_cell_constraint([names(i)], cell, .true., mask)
61 IF (mask /= masks(i)) error stop "Incorrect constraint token mask"
62 IF (i <= SIZE(legacy)) THEN
63 IF (cell_opt_constraint_label(mask) /= legacy(i)) error stop "Legacy constraint label changed"
64 END IF
65 END DO
66 CALL parse_cell_constraint(["AX", "BY", "CZ"], cell, .true., mask)
67 IF (mask /= 37) error stop "Constraint components were not combined"
68 CALL parse_cell_constraint(["a ", "b ", "ax"], cell, .true., mask)
69 IF (mask /= 7) error stop "Redundant constraint changed the mask"
70 CALL parse_cell_constraint(["X", "B"], cell, .true., mask)
71 IF (mask /= 15) error stop "Partially overlapping constraint lost components"
72
73 DO wanted = 0, 63
74 label = adjustl(cell_opt_constraint_label(wanted))
75 n = 0
76 DO WHILE (len_trim(label) > 0)
77 n = n + 1
78 READ (label, *) tokens(n)
79 CALL remove_word(label)
80 label = adjustl(label)
81 END DO
82 CALL parse_cell_constraint(tokens(:n), cell, .true., mask)
83 IF (mask /= wanted) error stop "Constraint label round trip failed"
84 END DO
85 DO i = 1, SIZE(invalid)
86 CALL parse_token(invalid(i), accepted, mask, reason)
87 IF (accepted .OR. len_trim(reason) == 0) error stop "Invalid constraint token accepted"
88 END DO
89 DO i = 1, 3
90 cell%perd = 1
91 cell%perd(i) = 0
92 CALL parse_cell_constraint(["NONE"], cell, .false., mask)
93 IF (mask /= masks(i + 1)) error stop "Incorrect 2D default constraint"
94 CALL parse_cell_constraint([names(i + 1)], cell, .true., mask)
95 IF (mask /= masks(i + 1)) error stop "Explicit 2D constraint changed"
96 CALL parse_cell_constraint(["A", "B", "C"], cell, .true., mask)
97 IF (mask /= mask_all) error stop "Explicit 2D constraint superset changed"
98 END DO
99 END SUBROUTINE check_parser
100
101! **************************************************************************************************
102!> \brief Check each projection against a known gradient and apply it twice.
103! **************************************************************************************************
104 SUBROUTINE check_projections()
105 REAL(KIND=dp) :: a, normal(3), reference(6), root3
106
107 root3 = sqrt(3.0_dp)
108 cell%perd = 1
109 cell%orthorhombic = .false.
110 cell%hmat = reshape([2.0_dp, 0.0_dp, 0.0_dp, 1.0_dp, 2.0_dp, 0.0_dp, 1.0_dp, 2.0_dp, 2.0_dp], [3, 3])
111 CALL check_projection(cell_sym_none, initial, .false., 0)
112 CALL check_projection(cell_sym_triclinic, initial, .false., 0)
113 CALL check_projection(cell_sym_triclinic, &
114 [1.0_dp, 8.0_dp/5, 16.0_dp/5, 26.0_dp/9, 52.0_dp/9, 52.0_dp/9], .true., 0)
115 CALL check_projection(cell_sym_triclinic, [0.0_dp, 2.0_dp, 0.0_dp, 4.0_dp, 5.0_dp, 0.0_dp], &
116 .false., comp_ax + comp_by + comp_cz)
117 CALL check_projection(cell_sym_triclinic, [0.0_dp, 8.0_dp/5, 16.0_dp/5, 0.0_dp, 0.0_dp, 0.0_dp], &
118 .true., comp_ax + mask_c)
119 cell%hmat = reshape([2.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 2.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 2.0_dp], [3, 3])
120 cell%orthorhombic = .true.
121 CALL check_projection(cell_sym_cubic, [10.0_dp/3, 0.0_dp, 10.0_dp/3, 0.0_dp, 0.0_dp, 10.0_dp/3], .false., 0)
122 CALL check_projection(cell_sym_tetragonal_ab, [2.0_dp, 0.0_dp, 2.0_dp, 0.0_dp, 0.0_dp, 6.0_dp], .false., 0)
123 CALL check_projection(cell_sym_tetragonal_ac, [3.5_dp, 0.0_dp, 3.0_dp, 0.0_dp, 0.0_dp, 3.5_dp], .false., 0)
124 CALL check_projection(cell_sym_tetragonal_bc, [1.0_dp, 0.0_dp, 4.5_dp, 0.0_dp, 0.0_dp, 4.5_dp], .false., 0)
125 CALL check_projection(cell_sym_monoclinic, [1.0_dp, 0.0_dp, 3.0_dp, 4.0_dp, 0.0_dp, 6.0_dp], .false., 0)
126 cell%hmat = reshape([1.0_dp, 0.0_dp, 0.0_dp, 0.5_dp, root3/2, 0.0_dp, 0.0_dp, 0.0_dp, 2.0_dp], [3, 3])
127 cell%orthorhombic = .false.
128 a = 1.0_dp + 0.75_dp*root3
129 CALL check_projection(cell_sym_hexagonal_gamma_60, [a, a/2, root3*a/2, 0.0_dp, 0.0_dp, 6.0_dp], .false., 0)
130 a = 0.75_dp*root3
131 cell%hmat(1, 2) = -0.5_dp
132 CALL check_projection(cell_sym_hexagonal_gamma_120, [a, -a/2, root3*a/2, 0.0_dp, 0.0_dp, 6.0_dp], .false., 0)
133
134 cell%hmat = reshape([1.0_dp, 0.0_dp, 0.0_dp, 0.5_dp, root3/2, 0.0_dp, &
135 0.5_dp, root3/6, sqrt(2.0_dp/3)], [3, 3])
136 ! Equal lengths and 60-degree angles leave one radial direction.
137 reference = [1.0_dp, 0.5_dp, root3/2, 0.5_dp, root3/6, sqrt(2.0_dp/3)]
138 reference = reference*dot_product(reference, initial)/3.0_dp
139 CALL check_projection(cell_sym_rhombohedral, reference, .false., 0)
140 cell%hmat(:, 3) = [0.0_dp, 0.0_dp, 2.0_dp]
141 ! Equal a/b lengths require -dAX + cos(gamma)*dBX + sin(gamma)*dBY = 0.
142 normal = [-1.0_dp, 0.5_dp, root3/2]
143 reference = initial
144 reference(1:3) = initial(1:3) - normal*dot_product(normal, initial(1:3))/2.0_dp
145 reference(4:5) = 0.0_dp
146 CALL check_projection(cell_sym_monoclinic_gamma_ab, reference, .false., 0)
147
148 cell%hmat = 0.0_dp
149 cell%hmat(1, 1) = 2.0_dp
150 cell%hmat(2, 2) = 3.0_dp
151 cell%hmat(3, 3) = 4.0_dp
152 cell%orthorhombic = .true.
153 CALL check_projection(cell_sym_orthorhombic, [1.0_dp, 0.0_dp, 3.0_dp, 0.0_dp, 0.0_dp, 6.0_dp], .false., 0)
154 CALL check_projection(cell_sym_orthorhombic, [1.0_dp, 0.0_dp, 3.0_dp, 0.0_dp, 0.0_dp, 6.0_dp], .true., 0)
155 CALL check_projection(cell_sym_cubic, [0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp], .true., mask_all)
156 END SUBROUTINE check_projections
157
158! **************************************************************************************************
159!> \brief Compare projected and expected gradients, including idempotence.
160!> \param symmetry cell symmetry
161!> \param expected projected gradient
162!> \param keep_angles apply the angle projection instead of the symmetry projection
163!> \param mask fixed components
164! **************************************************************************************************
165 SUBROUTINE check_projection(symmetry, expected, keep_angles, mask)
166 INTEGER, INTENT(IN) :: symmetry
167 REAL(KIND=dp), INTENT(IN) :: expected(6)
168 LOGICAL, INTENT(IN) :: keep_angles
169 INTEGER, INTENT(IN) :: mask
170
171 INTEGER :: repeat
172
173 cell%symmetry_id = symmetry
174 gradient = initial
175 DO repeat = 1, 2
176 CALL apply_cell_constraints(gradient, cell, keep_angles,.NOT. keep_angles, mask)
177 IF (.NOT. all(abs(gradient - expected) <= 1.0e-12_dp)) THEN
178 print *, "Incorrect cell projection: symmetry, mask, repetition:", symmetry, mask, repeat
179 error stop 1
180 END IF
181 END DO
182 END SUBROUTINE check_projection
183
184! **************************************************************************************************
185!> \brief Check representative legal/conflicting constraints and pressure warnings.
186! **************************************************************************************************
187 SUBROUTINE check_guards()
188 INTEGER, PARAMETER :: &
189 masks(8) = [0, comp_ax, mask_b, mask_c, comp_bx, comp_by, comp_cz, mask_all], &
190 partial(12) = [1, 1, 1, 4, 2, 2, 2, 32, 1, 1, 1, 1], systems(12) = [cell_sym_cubic, &
195 LOGICAL, PARAMETER :: angle_conflict(8) = [.false., .false., .false., .false., .true., .true.&
196 , .true., .false.], &
197 pressure(8) = [.false., .false., .true., .true., .true., .false., .false., .false.]
198
199 INTEGER :: i
200
201 DO i = 1, SIZE(systems)
202 IF (keep_symmetry_conflict(0, systems(i))) error stop "Unconstrained symmetry rejected"
203 IF (keep_symmetry_conflict(mask_all, systems(i))) error stop "Fully fixed symmetry rejected"
204 IF (keep_symmetry_conflict(partial(i), systems(i)) .NEQV. (i <= 8)) error stop "Incorrect symmetry conflict"
205 END DO
206 IF (keep_symmetry_conflict(comp_ax + comp_by, cell_sym_tetragonal_ab)) error stop "Complete ab constraint rejected"
207 DO i = 1, SIZE(masks)
208 IF (keep_angles_conflict(masks(i), .false.) .NEQV. angle_conflict(i)) error stop "Incorrect angle conflict"
209 IF (keep_angles_conflict(masks(i), .true.)) error stop "Orthorhombic angle constraint rejected"
210 IF (pres_crit_shear_pinned(masks(i), .false., .false.) .NEQV. pressure(i)) error stop "Incorrect pressure warning"
211 IF (pres_crit_shear_pinned(masks(i), .true., .true.)) error stop "Orthorhombic pressure warning"
212 END DO
213 IF (.NOT. pres_crit_shear_pinned(comp_ax, .false., .true.)) error stop "Missing pinned-angle pressure warning"
214 IF (pres_crit_shear_pinned(37 + comp_bx, .false., .true.)) error stop "Pressure warning with all diagonals fixed"
215 END SUBROUTINE check_guards
216
217END PROGRAM cell_opt_utils_test
subroutine check_parser()
Check token masks, label round trips, rejections and 2D defaults.
program cell_opt_utils_test
Handles all functions related to the CELL.
subroutine, public cell_create(cell, hmat, periodic, tag)
allocates and initializes a cell
contains a functional that calculates the energy and its derivatives for the geometry optimizer
pure logical function, public keep_symmetry_conflict(mask, symmetry_id)
Whether a CONSTRAINT mask conflicts with the KEEP_SYMMETRY projection.
integer, parameter, public comp_cz
integer, parameter, public comp_bx
integer, parameter, public comp_ax
subroutine, public apply_cell_constraints(gradient, cell, keep_angles, keep_symmetry, constraint_id)
Apply cell constraints.
subroutine, public parse_cell_constraint(constraint_tokens, cell, explicit, mask)
Parses the tokens of the CONSTRAINT keyword into a cell component mask.
pure logical function, public pres_crit_shear_pinned(mask, orthorhombic, keep_angles)
Whether the masked pressure criterion is structurally off target.
integer, parameter, public comp_by
integer, parameter, public mask_b
integer, parameter, public mask_c
pure subroutine, public parse_token(token, accepted, token_mask, reject_reason)
Classify one CONSTRAINT token without aborting (decision half of the parser).
pure logical function, public keep_angles_conflict(mask, orthorhombic)
Whether a CONSTRAINT mask conflicts with the KEEP_ANGLES projection.
pure character(len=default_string_length) function, public cell_opt_constraint_label(mask)
Returns the label of the consolidated cell constraint mask.
integer, parameter, public mask_all
Handles all functions related to the CELL.
Definition cell_types.F:15
integer, parameter, public cell_sym_monoclinic
Definition cell_types.F:29
integer, parameter, public cell_sym_triclinic
Definition cell_types.F:29
integer, parameter, public cell_sym_tetragonal_ab
Definition cell_types.F:29
integer, parameter, public cell_sym_rhombohedral
Definition cell_types.F:29
subroutine, public cell_release(cell)
releases the given cell (see doc/ReferenceCounting.html)
Definition cell_types.F:704
integer, parameter, public cell_sym_tetragonal_ac
Definition cell_types.F:29
integer, parameter, public cell_sym_hexagonal_gamma_60
Definition cell_types.F:29
integer, parameter, public cell_sym_orthorhombic
Definition cell_types.F:29
integer, parameter, public cell_sym_none
Definition cell_types.F:29
integer, parameter, public cell_sym_hexagonal_gamma_120
Definition cell_types.F:29
integer, parameter, public cell_sym_monoclinic_gamma_ab
Definition cell_types.F:29
integer, parameter, public cell_sym_cubic
Definition cell_types.F:29
integer, parameter, public cell_sym_tetragonal_bc
Definition cell_types.F:29
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
integer, parameter, public default_string_length
Definition kinds.F:57
Utilities for string manipulations.
subroutine, public remove_word(string)
remove a word from a string (words are separated by white spaces)
Type defining parameters related to the simulation cell.
Definition cell_types.F:60