15 USE ieee_arithmetic,
ONLY: ieee_is_finite
19#include "./base/base_uses.f90"
23 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'topology_snapshot'
24 REAL(KIND=
dp),
PARAMETER :: pi = 3.1415926535897932384626433832795_dp, cell_tol = 1.e-10_dp
25 TYPE :: snapshot_shell_type
26 INTEGER :: first = 0, count = 0, lmin = 0, lmax = 0
27 REAL(KIND=
dp) :: center(3) = 0.0_dp, radius = 0.0_dp
28 REAL(KIND=
dp),
ALLOCATABLE :: exponent(:), radii(:), contraction(:, :)
29 END TYPE snapshot_shell_type
30 TYPE :: snapshot_atom_type
31 INTEGER :: kind = 0, count = 0
32 REAL(KIND=
dp) :: center(3) = 0.0_dp
33 TYPE(snapshot_shell_type),
ALLOCATABLE :: shells(:)
34 END TYPE snapshot_atom_type
36 INTEGER :: nao = 0, rank = 0, nspin = 0, channel = 0
37 INTEGER :: periodic(3) = 0
38 REAL(kind=
dp) :: cell(3, 3) = 0.0_dp, inverse(3, 3) = 0.0_dp, k(3) = 0.0_dp
39 TYPE(snapshot_atom_type),
ALLOCATABLE :: atoms(:)
40 INTEGER,
ALLOCATABLE :: bands(:)
41 REAL(kind=
dp),
ALLOCATABLE :: energies(:)
42 COMPLEX(KIND=dp),
ALLOCATABLE :: coefficients(:, :)
54 CHARACTER(LEN=*),
INTENT(IN) :: filename
55 INTEGER,
INTENT(IN) :: point
58 CHARACTER(LEN=256) ::
header
59 INTEGER :: first, i, ia, ic, ios, ip, iset, ix, j, &
60 nat, nc, nk, np, ns, nt, offset, p, &
61 powers(3), refpowers(3), unit
62 LOGICAL,
ALLOCATABLE :: covered(:)
63 REAL(kind=
dp) :: det, k(3), pair(2)
64 REAL(kind=
dp),
ALLOCATABLE :: energies(:), row(:)
66 CALL open_file(filename, unit_number=unit, file_status=
'OLD', file_action=
'READ')
67 READ (unit,
'(A)', iostat=ios)
header
69 IF (trim(
header) /=
'CP2K_TOPOLOGY_STATE 1')
THEN
70 cpabort(
'Unsupported topology snapshot version')
72 READ (unit, *, iostat=ios) nat, state%nao, state%rank, nk, state%nspin, nt, state%channel
74 IF (min(nat, state%nao, state%rank, nk, nt, state%channel) < 1)
THEN
75 cpabort(
'Invalid snapshot dimensions')
77 IF (state%rank > nt .OR. point < 1 .OR. point > nk)
THEN
78 cpabort(
'Invalid snapshot point or rank')
80 IF (state%nspin /= 1 .AND. state%nspin /= 2)
THEN
81 cpabort(
'Invalid snapshot spin components')
83 ALLOCATE (state%bands(state%rank), state%energies(nt), energies(nt), &
84 state%coefficients(state%nao*state%nspin, state%rank), state%atoms(nat))
85 READ (unit, *, iostat=ios) state%bands
87 IF (any(state%bands < 1) .OR. any(state%bands > nt))
THEN
88 cpabort(
'Invalid snapshot band indices')
91 IF (state%bands(i) <= state%bands(i - 1))
THEN
92 cpabort(
'Snapshot bands must be strictly ordered')
96 READ (unit, *, iostat=ios) state%cell(:, j)
99 IF (.NOT. all(ieee_is_finite(state%cell)))
THEN
100 cpabort(
'Nonfinite snapshot cell')
102 associate(a => state%cell, b => state%inverse)
103 b(1, :) = [a(2, 2)*a(3, 3) - a(2, 3)*a(3, 2), a(1, 3)*a(3, 2) - a(1, 2)*a(3, 3), a(1, 2)*a(2, 3) - a(1, 3)*a(2, 2)]
104 b(2, :) = [a(2, 3)*a(3, 1) - a(2, 1)*a(3, 3), a(1, 1)*a(3, 3) - a(1, 3)*a(3, 1), a(1, 3)*a(2, 1) - a(1, 1)*a(2, 3)]
105 b(3, :) = [a(2, 1)*a(3, 2) - a(2, 2)*a(3, 1), a(1, 2)*a(3, 1) - a(1, 1)*a(3, 2), a(1, 1)*a(2, 2) - a(1, 2)*a(2, 1)]
106 det = dot_product(a(:, 1), b(1, :))
107 IF (abs(det) < cell_tol)
THEN
108 cpabort(
'Singular snapshot cell')
112 READ (unit, *, iostat=ios) state%periodic
114 IF (any(state%periodic < 0) .OR. any(state%periodic > 1))
THEN
115 cpabort(
'Invalid snapshot periodicity')
119 associate(
atom => state%atoms(ia))
120 READ (unit, *, iostat=ios) ix,
atom%kind, ns,
atom%count
122 IF (ix /= ia .OR. min(
atom%kind, ns,
atom%count) < 1)
THEN
123 cpabort(
'Invalid snapshot atom')
125 READ (unit, *, iostat=ios)
atom%center
127 IF (.NOT. all(ieee_is_finite(
atom%center)))
THEN
128 cpabort(
'Nonfinite atom center')
130 ALLOCATE (
atom%shells(ns), covered(
atom%count))
133 associate(s =>
atom%shells(iset))
134 READ (unit, *, iostat=ios) first, s%count, np, nc, s%lmin, s%radius
136 IF (min(first, s%count, np, nc) < 1 .OR. s%lmin < 0)
THEN
137 cpabort(
'Invalid Gaussian shell')
139 IF (.NOT. ieee_is_finite(s%radius) .OR. s%radius <= 0)
THEN
140 cpabort(
'Invalid shell screening radius')
142 IF (first + s%count - 1 >
atom%count)
THEN
143 cpabort(
'Shell AO range exceeds atom')
145 IF (any(covered(first:first + s%count - 1)))
THEN
146 cpabort(
'Overlapping shell AO ranges')
148 covered(first:first + s%count - 1) = .true.
150 DO WHILE ((s%lmax + 1)*(s%lmax + 2)*(s%lmax + 3)/6 < nc)
153 IF ((s%lmax + 1)*(s%lmax + 2)*(s%lmax + 3)/6 /= nc .OR. s%lmin > s%lmax)
THEN
154 cpabort(
'Invalid Cartesian Gaussian count')
157 s%first = offset + first
158 s%center(:) =
atom%center
159 ALLOCATE (s%exponent(np), s%radii(np), s%contraction(nc*np, s%count), row(s%count))
161 READ (unit, *, iostat=ios) s%exponent(ip), s%radii(ip)
163 IF (.NOT. ieee_is_finite(s%exponent(ip)) .OR. .NOT. ieee_is_finite(s%radii(ip)))
THEN
164 cpabort(
'Nonfinite primitive Gaussian')
166 IF (s%exponent(ip) <= 0 .OR. s%radii(ip) <= 0)
THEN
167 cpabort(
'Invalid primitive Gaussian')
170 READ (unit, *, iostat=ios) powers, row
172 refpowers(:) =
indco(:, ic)
173 IF (any(powers /= refpowers))
THEN
174 cpabort(
'Unexpected Cartesian Gaussian ordering')
176 IF (.NOT. all(ieee_is_finite(row)))
THEN
177 cpabort(
'Nonfinite contraction')
179 s%contraction((ip - 1)*nc + ic, :) = row
185 IF (.NOT. all(covered))
THEN
186 cpabort(
'Incomplete atom AO coverage')
189 offset = offset +
atom%count
192 IF (offset /= state%nao)
THEN
193 cpabort(
'Snapshot AO count mismatch')
196 READ (unit, *, iostat=ios) ix, k
198 IF (ix /= p .OR. .NOT. all(ieee_is_finite(k)))
THEN
199 cpabort(
'Invalid snapshot k-point')
201 READ (unit, *, iostat=ios) energies
203 IF (.NOT. all(ieee_is_finite(energies)))
THEN
204 cpabort(
'Nonfinite snapshot spectrum')
206 IF (any(energies(2:) < energies(:nt - 1)))
THEN
207 cpabort(
'Unordered snapshot spectrum')
211 state%energies(:) = energies
214 DO i = 1, state%nao*state%nspin
215 READ (unit, *, iostat=ios) pair
217 IF (.NOT. all(ieee_is_finite(pair)))
THEN
218 cpabort(
'Nonfinite state coefficient')
220 IF (p == point) state%coefficients(i, j) = cmplx(pair(1), pair(2), dp)
225 READ (unit,
'(A)', iostat=ios)
header
227 IF (ios /= 0 .OR. len_trim(
header) /= 0)
THEN
228 cpabort(
'Unexpected trailing snapshot content')
231 CALL close_file(unit)
244 REAL(kind=dp),
INTENT(IN) :: ka(3), kb(3)
245 COMPLEX(KIND=dp),
INTENT(OUT) :: overlap(:, :)
247 COMPLEX(KIND=dp) :: part(size(overlap, 1), size(overlap, 2))
250 IF (any(shape(overlap) /= [a%rank, b%rank]))
THEN
251 cpabort(
'Incorrect overlap output dimensions')
253 IF (a%nspin /= b%nspin .OR. a%channel /= b%channel .OR. a%rank /= b%rank)
THEN
254 cpabort(
'Changed spin or rank')
256 IF (any(a%bands /= b%bands))
THEN
257 cpabort(
'Changed selected band indices')
259 IF (
SIZE(a%atoms) /=
SIZE(b%atoms) .OR. a%nao /= b%nao)
THEN
260 cpabort(
'Changed atom or AO count')
262 IF (maxval(abs(a%cell - b%cell)) > cell_tol .OR. any(a%periodic /= b%periodic))
THEN
263 cpabort(
'Changed cell')
265 IF (.NOT. all(ieee_is_finite(ka)) .OR. .NOT. all(ieee_is_finite(kb)))
THEN
266 cpabort(
'Nonfinite k-point')
268 IF (maxval(abs(ka - a%k - anint(ka - a%k))) > cell_tol .OR. &
269 maxval(abs(kb - b%k - anint(kb - b%k))) > cell_tol)
THEN
270 cpabort(
'Frame k-point does not match request')
272 overlap(:, :) = 0.0_dp
274 DO ia = 1,
SIZE(a%atoms)
275 CALL atom_overlap(a, b, ia, ka, kb, part)
276 overlap(:, :) = overlap + part
290 SUBROUTINE atom_overlap(a, b, ia, ka, kb, atom_link)
292 INTEGER,
INTENT(IN) :: ia
293 REAL(kind=dp),
INTENT(IN) :: ka(3), kb(3)
294 COMPLEX(KIND=dp),
INTENT(OUT) :: atom_link(:, :)
296 COMPLEX(KIND=dp) :: phase
297 COMPLEX(KIND=dp),
ALLOCATABLE :: block(:, :), oc(:, :, :)
298 INTEGER :: af, bf, hi(3), i, ib, image(3), j, k, &
299 lo(3), nc_a, nc_b, s, sa, sb
300 REAL(kind=dp) :: bounds(3), cutoff, disp(3), q(3), rb(3)
301 REAL(kind=dp),
ALLOCATABLE :: cosine(:, :), sine(:, :)
303 q(:) = 2.0_dp*pi*matmul(transpose(a%inverse), kb - ka)
304 atom_link(:, :) = 0.0_dp
305 DO sa = 1,
SIZE(a%atoms(ia)%shells)
306 associate(left => a%atoms(ia)%shells(sa))
307 ALLOCATE (oc(left%count, b%rank, a%nspin))
309 nc_a =
SIZE(left%contraction, 1)
310 DO ib = 1,
SIZE(b%atoms)
311 DO sb = 1,
SIZE(b%atoms(ib)%shells)
312 associate(right => b%atoms(ib)%shells(sb))
313 cutoff = left%radius + right%radius
314 disp(:) = matmul(a%inverse, right%center - left%center)
316 bounds(i) = cutoff*norm2(a%inverse(i, :))
318 lo(:) = ceiling(-disp - bounds)
319 hi(:) = floor(-disp + bounds)
320 WHERE (a%periodic == 0)
324 nc_b =
SIZE(right%contraction, 1)
325 ALLOCATE (cosine(nc_a, nc_b), sine(nc_a, nc_b), block(left%count, right%count))
331 rb(:) = right%center + matmul(a%cell, real(image, dp))
332 IF (norm2(rb - left%center) > cutoff) cycle
333 CALL cossin(left%lmax,
SIZE(left%exponent), left%exponent, left%radii, left%lmin, &
334 right%lmax,
SIZE(right%exponent), right%exponent, right%radii, right%lmin, &
335 left%center, rb, q, cosine, sine)
336 phase = exp(cmplx(0.0_dp, 2.0_dp*pi*dot_product(kb, real(image, dp)), dp))
337 block(:, :) = block + phase*matmul(transpose(left%contraction), &
338 matmul(cmplx(cosine, -sine, dp), right%contraction))
343 bf = right%first + (s - 1)*b%nao
344 oc(:, :, s) = oc(:, :, s) + matmul(block, b%coefficients(bf:bf + right%count - 1, :))
346 DEALLOCATE (cosine, sine, block)
351 af = left%first + (s - 1)*a%nao
352 atom_link(:, :) = atom_link + matmul(conjg(transpose(a%coefficients(af:af + left%count - 1, :))), oc(:, :, s))
357 END SUBROUTINE atom_overlap
369 REAL(kind=dp),
INTENT(IN) :: metric_tol, gap_tol
370 REAL(kind=dp),
INTENT(OUT) :: metric_error, gap
373 LOGICAL :: selected(size(a%energies))
374 COMPLEX(KIND=dp) :: metric(a%rank, a%rank)
378 metric(i, i) = metric(i, i) - 1.0_dp
380 metric_error = maxval(abs(metric))
381 IF (.NOT. ieee_is_finite(metric_error) .OR. metric_error > metric_tol)
THEN
382 cpabort(
'Frame is not AO-metric normalized')
384 selected(:) = .false.
385 selected(a%bands) = .true.
387 DO i = 1,
SIZE(a%energies) - 1
388 IF (selected(i) .NEQV. selected(i + 1)) gap = min(gap, a%energies(i + 1) - a%energies(i))
390 IF (gap == huge(1.0_dp) .OR. gap <= gap_tol)
THEN
391 cpabort(
'No verified sampled subspace isolation')
404 INTEGER,
INTENT(IN) :: permutation(:)
405 REAL(kind=dp),
INTENT(IN) :: tolerance
407 INTEGER :: i, j, n, s
408 REAL(kind=dp) :: delta(3), shift(3)
411 IF (
SIZE(b%atoms) /= n .OR.
SIZE(permutation) /= n)
THEN
412 cpabort(
'Seam atom count mismatch')
414 IF (any(permutation < 1) .OR. any(permutation > n))
THEN
415 cpabort(
'Invalid seam permutation')
418 IF (count(permutation == i) /= 1)
THEN
419 cpabort(
'Seam atom map is not a permutation')
422 IF (maxval(abs(a%cell - b%cell)) > tolerance .OR. any(a%periodic /= b%periodic))
THEN
423 cpabort(
'Seam cell mismatch')
427 associate(left => a%atoms(j), right => b%atoms(i))
428 IF (left%kind /= right%kind .OR. left%count /= right%count)
THEN
429 cpabort(
'Seam changes atom kind or AO count')
431 IF (
SIZE(left%shells) /=
SIZE(right%shells))
THEN
432 cpabort(
'Seam changes basis')
434 delta(:) = right%center - left%center
435 shift(:) = anint(matmul(a%inverse, delta))
436 WHERE (a%periodic == 0) shift = 0.0_dp
437 IF (maxval(abs(delta - matmul(a%cell, shift))) > tolerance)
THEN
438 cpabort(
'Geometry does not close at seam')
440 DO s = 1,
SIZE(left%shells)
441 associate(x => left%shells(s), y => right%shells(s))
442 IF (x%count /= y%count .OR. x%lmin /= y%lmin .OR. x%lmax /= y%lmax)
THEN
443 cpabort(
'Seam changes shell')
445 IF (any(shape(x%contraction) /= shape(y%contraction)))
THEN
446 cpabort(
'Seam changes contractions')
448 IF (
SIZE(x%exponent) /=
SIZE(y%exponent))
THEN
449 cpabort(
'Seam changes primitives')
451 IF (maxval(abs(x%radii - y%radii)) > tolerance .OR. abs(x%radius - y%radius) > tolerance)
THEN
452 cpabort(
'Seam changes Gaussian screening radii')
454 IF (maxval(abs(x%exponent - y%exponent)) > tolerance .OR. &
455 maxval(abs(x%contraction - y%contraction)) > tolerance)
THEN
456 cpabort(
'Seam changes physical basis')
Calculation of the moment integrals over Cartesian Gaussian-type functions.
subroutine, public cossin(la_max_set, npgfa, zeta, rpgfa, la_min_set, lb_max, npgfb, zetb, rpgfb, lb_min, rac, rbc, kvec, cosab, sinab, dcosab, dsinab)
...
Utility routines to open and close files. Tracking of preconnections.
subroutine, public open_file(file_name, file_status, file_form, file_action, file_position, file_pad, unit_number, debug, skip_get_unit_number, file_access)
Opens the requested file using a free unit number.
subroutine, public close_file(unit_number, file_status, keep_preconnection)
Close an open file given by its logical unit number. Optionally, keep the file and unit preconnected.
Defines the basic variable types.
integer, parameter, public dp
Provides Cartesian and spherical orbital pointers and indices.
subroutine, public init_orbital_pointers(maxl)
Initialize or update the orbital pointers.
integer, dimension(:, :), allocatable, public indco
Reader and physical moving-basis links for version-1 topology snapshots.
subroutine, public check_snapshot_seam(a, b, permutation, tolerance)
Check explicitly prescribed atom permutation, periodic translations and basis at a seam.
subroutine, public snapshot_overlap(a, b, ka, kb, overlap)
Apply screened Gaussian cross-geometry operator by atom blocks, without a dense AO matrix.
subroutine, public check_snapshot(a, metric_tol, gap_tol, metric_error, gap)
Check AO-metric normalization and separation at every selected/excluded boundary.
subroutine, public read_snapshot(filename, point, state)
Read a single point, retaining only its states; reject malformed/truncated exports.