Skip to content

Commit b76b93b

Browse files
authored
Add support for periodic boundary conditions in QCSchema IO (grimme-lab#93)
See MolSSI/QCSchema#86, MolSSI/QCSchema#66
1 parent 5113975 commit b76b93b

9 files changed

Lines changed: 518 additions & 12 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,5 @@
3535
/build*/
3636
/_*/
3737
/docs*/
38+
/subprojects/*/
39+
/subprojects/test-drive.wrap

doc/format-qcschema.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,24 @@ Caffeine molecule in ``qcschema_molecule`` format.
8585
}
8686
```
8787

88+
## Extensions
89+
90+
The reader supports the following extensions:
91+
92+
- Periodic boundary conditions are specified by providing the lattice vectors in Bohr
93+
as extras to the molecule in periodic.lattice as flattened array.
94+
95+
```json
96+
"extras": {
97+
"periodic": {
98+
"lattice": [
99+
5.5900366437622173, 0.0000000000000000, 0.0000000000000000,
100+
0.0000000000000000, 8.6808915904526547, 0.0000000000000000,
101+
0.0000000000000000, 0.0000000000000000, 8.6808915904526547
102+
]
103+
}
104+
}
105+
```
88106

89107
## Missing features
90108

src/mctc/io/read/qcschema.F90

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ subroutine read_qcschema(self, unit, error)
4747

4848
#if WITH_JSON
4949
class(json_value), allocatable :: root
50-
type(json_object), pointer :: object, child
50+
type(json_object), pointer :: object, child, extras, child2
5151
type(json_array), pointer :: array, child_array
5252
type(json_error), allocatable :: parse_error
5353
type(json_keyval), pointer :: val
@@ -58,8 +58,8 @@ subroutine read_qcschema(self, unit, error)
5858
character(len=:), allocatable :: symbol, message, schema_name, comment
5959
character(len=symbol_length), allocatable :: sym(:)
6060
integer, allocatable :: bond(:, :), list(:)
61-
real(wp), allocatable, target :: geo(:)
62-
real(wp), pointer :: xyz(:, :)
61+
real(wp), allocatable, target :: geo(:), lat(:)
62+
real(wp), pointer :: xyz(:, :), lattice(:, :)
6363

6464
call json_load(root, unit, config=json_parser_config(context_detail=1), &
6565
& context=ctx, error=parse_error)
@@ -222,8 +222,45 @@ subroutine read_qcschema(self, unit, error)
222222
end do
223223
end if
224224

225+
nullify(lattice)
226+
nullify(array)
227+
call get_value(child, "extras", extras, stat=stat, origin=origin)
228+
if (stat /= json_stat%success) then
229+
call fatal_error(error, ctx%report("Could not read extras", origin=origin, &
230+
& label="Expected object"))
231+
return
232+
end if
233+
call get_value(extras, "periodic", child2, requested=.false., stat=stat, origin=origin)
234+
if (stat /= json_stat%success) then
235+
call fatal_error(error, ctx%report("Could not read periodic extras", origin=origin, &
236+
& label="Expected object with 'lattice' key"))
237+
return
238+
end if
239+
if (associated(child2)) then
240+
call get_value(child2, "lattice", array, requested=.false., stat=stat, origin=origin)
241+
if (stat /= json_stat%success) then
242+
call fatal_error(error, ctx%report("Could not read lattice from extras", origin=origin, &
243+
& label="Expected array with 9 elements"))
244+
return
245+
end if
246+
end if
247+
if (associated(array)) then
248+
call get_value(array, lat, stat=stat, origin=origin)
249+
if (stat /= json_stat%success) then
250+
call fatal_error(error, ctx%report("Could not read lattice from extras", origin=origin, &
251+
& label="Expected array with 9 elements"))
252+
return
253+
end if
254+
if (size(lat) /= 9) then
255+
call fatal_error(error, ctx%report("Lattice must have 9 elements", origin=array%origin, &
256+
& label="Got "//to_string(size(lat))//" elements"))
257+
return
258+
end if
259+
lattice(1:3, 1:3) => lat(1:9)
260+
end if
261+
225262
xyz(1:3, 1:size(geo)/3) => geo
226-
call new(self, sym, xyz, charge=real(charge, wp), uhf=multiplicity-1)
263+
call new(self, sym, xyz, charge=real(charge, wp), uhf=multiplicity-1, lattice=lattice)
227264
if (len(comment) > 0) self%comment = comment
228265
if (allocated(bond)) then
229266
self%nbd = size(bond, 2)

src/mctc/io/write/qcschema.f90

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pure function json_string(mol, indent) result(string)
9595

9696
string = string // ","
9797
if (present(indent)) string = string // nl // indent
98-
string = string // json_key("geometry", indent) // json_array([mol%xyz], indent)
98+
string = string // json_key("geometry", indent) // json_array([mol%xyz], indent, group=3)
9999

100100
string = string // ","
101101
if (present(indent)) string = string // nl // indent
@@ -129,6 +129,28 @@ pure function json_string(mol, indent) result(string)
129129
string = string // "]"
130130
end if
131131

132+
if (allocated(mol%lattice) .and. any(mol%periodic)) then
133+
! place in "extras": {"periodic": {"lattice": [flattened list...]}
134+
string = string // ","
135+
if (present(indent)) string = string // nl // indent
136+
string = string // json_key("extras", indent) // "{"
137+
if (present(indent)) string = string // nl // indent // indent
138+
string = string // json_key("periodic", indent) // "{"
139+
if (present(indent)) string = string // nl // indent // indent // indent
140+
block
141+
character(len=:), allocatable :: indent3, indent4
142+
if (present(indent)) then
143+
indent3 = indent // indent // indent
144+
indent4 = indent // indent // indent // indent
145+
endif
146+
string = string // json_key("lattice", indent) // json_array([mol%lattice], indent3, indent4, group=3)
147+
end block
148+
if (present(indent)) string = string // nl // indent // indent
149+
string = string // "}"
150+
if (present(indent)) string = string // nl // indent
151+
string = string // "}"
152+
end if
153+
132154
if (present(indent)) string = string // nl
133155
string = string // "}"
134156
end function json_string
@@ -150,18 +172,29 @@ pure function json_array_int_1(array, indent) result(string)
150172
string = string // "]"
151173
end function json_array_int_1
152174

153-
pure function json_array_real_1(array, indent) result(string)
175+
pure function json_array_real_1(array, indent, indent2, group) result(string)
154176
real(wp), intent(in) :: array(:)
155177
character(len=*), intent(in), optional :: indent
178+
character(len=*), intent(in), optional :: indent2
179+
integer, intent(in), optional :: group
156180
character(len=:), allocatable :: string
157181

158-
integer :: i
182+
integer :: i, j, step
183+
184+
step = 1
185+
if (present(group)) step = group
159186

160187
string = "["
161-
do i = 1, size(array)
162-
if (present(indent)) string = string // nl // indent // indent
163-
string = string // json_value(array(i), '(es23.16)')
164-
if (i /= size(array)) string = string // ","
188+
do i = 1, size(array), step
189+
if (present(indent2)) then
190+
string = string // nl // indent2
191+
else if (present(indent)) then
192+
string = string // nl // indent // indent
193+
end if
194+
do j = 1, step, 1
195+
string = string // json_value(array(i + j - 1), '(es23.16)')
196+
if (i + j - 1 /= size(array)) string = string // ","
197+
end do
165198
end do
166199
if (present(indent)) string = string // nl // indent
167200
string = string // "]"

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ set(
4040
"write-genformat"
4141
"write-pdb"
4242
"write-qchem"
43+
"write-qcschema"
4344
"write-turbomole"
4445
"write-vasp"
4546
"write-xyz"

test/main.f90

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ program tester
4343
use test_write_genformat, only : collect_write_genformat
4444
use test_write_pdb, only : collect_write_pdb
4545
use test_write_qchem, only : collect_write_qchem
46+
use test_write_qcschema, only : collect_write_qcschema
4647
use test_write_turbomole, only : collect_write_turbomole
4748
use test_write_vasp, only : collect_write_vasp
4849
use test_write_xyz, only : collect_write_xyz
@@ -80,6 +81,7 @@ program tester
8081
& new_testsuite("write-genformat", collect_write_genformat), &
8182
& new_testsuite("write-pdb", collect_write_pdb), &
8283
& new_testsuite("write-qchem", collect_write_qchem), &
84+
& new_testsuite("write-qcschema", collect_write_qcschema), &
8385
& new_testsuite("write-turbomole", collect_write_turbomole), &
8486
& new_testsuite("write-vasp", collect_write_vasp), &
8587
& new_testsuite("write-xyz", collect_write_xyz) &

test/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ tests = [
3838
'write-genformat',
3939
'write-pdb',
4040
'write-qchem',
41+
'write-qcschema',
4142
'write-turbomole',
4243
'write-vasp',
4344
'write-xyz',

0 commit comments

Comments
 (0)