Skip to content

Commit 6b04171

Browse files
committed
Add pymatgen writer
1 parent 92b0c12 commit 6b04171

9 files changed

Lines changed: 347 additions & 0 deletions

File tree

man/mctc-convert.1.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Supported formats:
2828
- Gaussian's external program input (ein)
2929
- JSON input with `qcschema_molecule` or `qcschema_input` structure (json)
3030
- Chemical JSON input (cjson)
31+
- Pymatgen JSON with `Molecule` or `Structure` schema (pmgjson)
3132
- FHI-AIMS' input files (geometry.in)
3233
- Q-Chem molecule block inputs (qchem)
3334

src/mctc/io/read.f90

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module mctc_io_read
2323
use mctc_io_read_qchem, only : read_qchem
2424
use mctc_io_read_qcschema, only : read_qcschema
2525
use mctc_io_read_pdb, only : read_pdb
26+
use mctc_io_read_pymatgen, only : read_pymatgen
2627
use mctc_io_read_turbomole, only : read_coord
2728
use mctc_io_read_vasp, only : read_vasp
2829
use mctc_io_read_xyz, only : read_xyz
@@ -156,6 +157,9 @@ subroutine get_structure_reader(reader, ftype)
156157
case(filetype%pdb)
157158
reader => read_pdb
158159

160+
case(filetype%pymatgen)
161+
reader => read_pymatgen
162+
159163
case(filetype%gen)
160164
reader => read_genformat
161165

src/mctc/io/write.f90

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module mctc_io_write
2121
use mctc_io_write_gaussian, only : write_gaussian_external
2222
use mctc_io_write_genformat, only : write_genformat
2323
use mctc_io_write_pdb, only : write_pdb
24+
use mctc_io_write_pymatgen, only : write_pymatgen
2425
use mctc_io_write_qchem, only : write_qchem
2526
use mctc_io_write_qcschema, only : write_qcschema
2627
use mctc_io_write_turbomole, only : write_coord
@@ -117,6 +118,9 @@ subroutine write_structure_to_unit(self, unit, ftype, error)
117118
case(filetype%pdb)
118119
call write_pdb(self, unit)
119120

121+
case(filetype%pymatgen)
122+
call write_pymatgen(self, unit)
123+
120124
case(filetype%gen)
121125
call write_genformat(self, unit)
122126

src/mctc/io/write/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ list(
2222
"${dir}/gaussian.f90"
2323
"${dir}/genformat.f90"
2424
"${dir}/pdb.f90"
25+
"${dir}/pymatgen.f90"
2526
"${dir}/qchem.f90"
2627
"${dir}/qcschema.f90"
2728
"${dir}/turbomole.f90"

src/mctc/io/write/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ srcs += files(
1919
'gaussian.f90',
2020
'genformat.f90',
2121
'pdb.f90',
22+
'pymatgen.f90',
2223
'qchem.f90',
2324
'qcschema.f90',
2425
'turbomole.f90',

src/mctc/io/write/pymatgen.f90

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
! This file is part of mctc-lib.
2+
!
3+
! Licensed under the Apache License, Version 2.0 (the "License");
4+
! you may not use this file except in compliance with the License.
5+
! You may obtain a copy of the License at
6+
!
7+
! http://www.apache.org/licenses/LICENSE-2.0
8+
!
9+
! Unless required by applicable law or agreed to in writing, software
10+
! distributed under the License is distributed on an "AS IS" BASIS,
11+
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
! See the License for the specific language governing permissions and
13+
! limitations under the License.
14+
15+
module mctc_io_write_pymatgen
16+
use mctc_env_accuracy, only : wp
17+
use mctc_io_convert, only : autoaa
18+
use mctc_io_math, only : matinv_3x3, matdet_3x3
19+
use mctc_io_structure, only : structure_type
20+
use mctc_version, only : get_mctc_version
21+
implicit none
22+
private
23+
24+
public :: write_pymatgen
25+
26+
27+
interface json_value
28+
module procedure :: json_value_char
29+
module procedure :: json_value_int
30+
module procedure :: json_value_real
31+
end interface json_value
32+
33+
interface json_array
34+
module procedure :: json_array_char_1
35+
module procedure :: json_array_int_1
36+
module procedure :: json_array_real_1
37+
end interface json_array
38+
39+
character(len=*), parameter :: nl = new_line('a')
40+
41+
contains
42+
43+
44+
subroutine write_pymatgen(mol, unit)
45+
type(structure_type), intent(in) :: mol
46+
integer, intent(in) :: unit
47+
48+
write(unit, '(a)') json_string(mol, " ")
49+
end subroutine write_pymatgen
50+
51+
pure function json_string(mol, indent) result(string)
52+
type(structure_type), intent(in) :: mol
53+
character(len=*), intent(in), optional :: indent
54+
character(len=:), allocatable :: string
55+
integer :: iat, isp, ilt
56+
real(wp) :: cellpar(6), volume, vec(3)
57+
real(wp), allocatable :: invlat(:, :)
58+
59+
string = "{"
60+
if (present(indent)) string = string // nl // indent
61+
string = string // json_key("@module", indent) // json_value("pymatgen.core.structure")
62+
63+
string = string // ","
64+
if (present(indent)) string = string // nl // indent
65+
if (any(mol%periodic)) then
66+
string = string // json_key("@class", indent) // json_value("Structure")
67+
invlat = matinv_3x3(mol%lattice)
68+
else
69+
string = string // json_key("@class", indent) // json_value("Molecule")
70+
string = string // ","
71+
72+
if (present(indent)) string = string // nl // indent
73+
string = string // json_key("charge", indent) // json_value(nint(mol%charge))
74+
string = string // ","
75+
76+
if (present(indent)) string = string // nl // indent
77+
string = string // json_key("spin_multiplicity", indent) // json_value(mol%uhf + 1)
78+
end if
79+
80+
string = string // ","
81+
82+
if (present(indent)) string = string // nl // indent
83+
string = string // json_key("sites", indent) // "["
84+
85+
do iat = 1, mol%nat
86+
isp = mol%id(iat)
87+
if (present(indent)) string = string // nl // indent // indent
88+
string = string // "{"
89+
90+
if (present(indent)) string = string // nl // indent // indent // indent
91+
string = string // json_key("name", indent) // json_value(trim(mol%sym(isp)))
92+
93+
string = string // ","
94+
if (present(indent)) string = string // " "
95+
string = string // json_key("label", indent) // json_value(trim(mol%sym(isp)))
96+
97+
string = string // ","
98+
if (present(indent)) string = string // " "
99+
string = string // json_key("species", indent) // "[{"
100+
string = string // json_key("element", indent) // json_value(trim(mol%sym(isp))) // ","
101+
if (present(indent)) string = string // " "
102+
string = string // json_key("occu", indent) // json_value(1)
103+
string = string // "}]"
104+
105+
string = string // ","
106+
if (present(indent)) string = string // nl // indent // indent // indent
107+
string = string // json_key("xyz", indent) // &
108+
& "[" // json_value(mol%xyz(1, iat) * autoaa, '(es23.16)') // "," // &
109+
& json_value(mol%xyz(2, iat) * autoaa, '(es23.16)') // "," // &
110+
& json_value(mol%xyz(3, iat) * autoaa, '(es23.16)') // "]"
111+
112+
! if (allocated(invlat)) then
113+
! vec = matmul(invlat, mol%xyz(:, iat))
114+
! if (present(indent)) string = string // nl // indent // indent // indent
115+
! string = string // json_key("abc", indent) // &
116+
! & "[" // json_value(vec(1), '(es23.16)') // "," // &
117+
! & json_value(vec(2), '(es23.16)') // "," // &
118+
! & json_value(vec(3), '(es23.16)') // "]"
119+
! end if
120+
121+
string = string // ","
122+
if (present(indent)) string = string // nl // indent // indent // indent
123+
string = string // json_key("properties", indent) // "{}"
124+
125+
if (present(indent)) string = string // nl // indent // indent
126+
string = string // "}"
127+
if (iat /= mol%nat) then
128+
string = string // ","
129+
end if
130+
end do
131+
if (present(indent)) string = string // nl // indent
132+
string = string // "]"
133+
134+
if (any(mol%periodic)) then
135+
call dlat_to_cell(mol%lattice, cellpar)
136+
volume = matdet_3x3(mol%lattice)
137+
string = string // ","
138+
if (present(indent)) string = string // nl // indent
139+
string = string // json_key("lattice", indent) // "{"
140+
if (present(indent)) string = string // nl // indent // indent
141+
string = string // json_key("matrix", indent) // "["
142+
if (present(indent)) string = string // nl // indent // indent // indent
143+
do ilt = 1, 3
144+
string = string // "[" // &
145+
& json_value(mol%lattice(1, ilt) * autoaa, '(es23.16)') // "," // &
146+
& json_value(mol%lattice(2, ilt) * autoaa, '(es23.16)') // "," // &
147+
& json_value(mol%lattice(3, ilt) * autoaa, '(es23.16)') // "]"
148+
if (ilt < 3) then
149+
string = string // ","
150+
if (present(indent)) string = string // nl // indent // indent // indent
151+
end if
152+
end do
153+
if (present(indent)) string = string // nl // indent // indent
154+
string = string // "],"
155+
if (present(indent)) string = string // nl // indent // indent
156+
string = string // json_key("a", indent) // json_value(cellpar(1) * autoaa, '(es23.16)') // ","
157+
if (present(indent)) string = string // nl // indent // indent
158+
string = string // json_key("b", indent) // json_value(cellpar(2) * autoaa, '(es23.16)') // ","
159+
if (present(indent)) string = string // nl // indent // indent
160+
string = string // json_key("c", indent) // json_value(cellpar(3) * autoaa, '(es23.16)') // ","
161+
if (present(indent)) string = string // nl // indent // indent
162+
string = string // json_key("alpha", indent) // json_value(cellpar(4), '(es23.16)') // ","
163+
if (present(indent)) string = string // nl // indent // indent
164+
string = string // json_key("beta", indent) // json_value(cellpar(5), '(es23.16)') // ","
165+
if (present(indent)) string = string // nl // indent // indent
166+
string = string // json_key("gamma", indent) // json_value(cellpar(6), '(es23.16)') // ","
167+
if (present(indent)) string = string // nl // indent // indent
168+
string = string // json_key("volume", indent) // json_value(volume * autoaa**3, '(es23.16)')
169+
if (present(indent)) string = string // nl // indent
170+
string = string // "}"
171+
end if
172+
173+
string = string // ","
174+
if (present(indent)) string = string // nl // indent
175+
string = string // json_key("properties", indent) // "{}"
176+
177+
if (present(indent)) string = string // nl
178+
string = string // "}"
179+
end function json_string
180+
181+
pure function json_array_int_1(array, indent) result(string)
182+
integer, intent(in) :: array(:)
183+
character(len=*), intent(in), optional :: indent
184+
character(len=:), allocatable :: string
185+
186+
integer :: i
187+
188+
string = "["
189+
do i = 1, size(array)
190+
if (present(indent)) string = string // nl // indent // indent
191+
string = string // json_value(array(i))
192+
if (i /= size(array)) string = string // ","
193+
end do
194+
if (present(indent)) string = string // nl // indent
195+
string = string // "]"
196+
end function json_array_int_1
197+
198+
pure function json_array_real_1(array, indent, indent2, group) result(string)
199+
real(wp), intent(in) :: array(:)
200+
character(len=*), intent(in), optional :: indent
201+
character(len=*), intent(in), optional :: indent2
202+
integer, intent(in), optional :: group
203+
character(len=:), allocatable :: string
204+
205+
integer :: i, j, step
206+
207+
step = 1
208+
if (present(group)) step = group
209+
210+
string = "["
211+
do i = 1, size(array), step
212+
if (present(indent2)) then
213+
string = string // nl // indent2
214+
else if (present(indent)) then
215+
string = string // nl // indent // indent
216+
end if
217+
do j = 1, step, 1
218+
string = string // json_value(array(i + j - 1), '(es23.16)')
219+
if (i + j - 1 /= size(array)) string = string // ","
220+
end do
221+
end do
222+
if (present(indent)) string = string // nl // indent
223+
string = string // "]"
224+
end function json_array_real_1
225+
226+
pure function json_array_char_1(array, indent) result(string)
227+
character(len=*), intent(in) :: array(:)
228+
character(len=*), intent(in), optional :: indent
229+
character(len=:), allocatable :: string
230+
231+
integer :: i
232+
233+
string = "["
234+
do i = 1, size(array)
235+
if (present(indent)) string = string // nl // indent // indent
236+
string = string // json_value(trim(array(i)))
237+
if (i /= size(array)) string = string // ","
238+
end do
239+
if (present(indent)) string = string // nl // indent
240+
string = string // "]"
241+
end function json_array_char_1
242+
243+
pure function json_key(key, indent) result(string)
244+
character(len=*), intent(in) :: key
245+
character(len=*), intent(in), optional :: indent
246+
character(len=:), allocatable :: string
247+
248+
if (present(indent)) then
249+
string = json_value(key) // ": "
250+
else
251+
string = json_value(key) // ":"
252+
end if
253+
end function json_key
254+
255+
pure function json_value_char(val) result(string)
256+
character(len=*), intent(in) :: val
257+
character(len=:), allocatable :: string
258+
259+
string = """" // val // """"
260+
end function json_value_char
261+
262+
pure function json_value_real(val, format) result(str)
263+
real(wp), intent(in) :: val
264+
character(len=*), intent(in) :: format
265+
character(len=:), allocatable :: str
266+
267+
character(len=128) :: buffer
268+
integer :: stat
269+
270+
write(buffer, format, iostat=stat) val
271+
if (stat == 0) then
272+
str = trim(buffer)
273+
else
274+
str = """*"""
275+
end if
276+
end function json_value_real
277+
278+
pure function json_value_int(val) result(string)
279+
integer, intent(in) :: val
280+
character(len=:), allocatable :: string
281+
integer, parameter :: buffer_len = range(val)+2
282+
character(len=buffer_len) :: buffer
283+
integer :: pos
284+
integer :: n
285+
character(len=1), parameter :: numbers(0:9) = &
286+
["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
287+
288+
if (val == 0) then
289+
string = numbers(0)
290+
return
291+
end if
292+
293+
n = abs(val)
294+
buffer = ""
295+
296+
pos = buffer_len + 1
297+
do while (n > 0)
298+
pos = pos - 1
299+
buffer(pos:pos) = numbers(mod(n, 10))
300+
n = n/10
301+
end do
302+
if (val < 0) then
303+
pos = pos - 1
304+
buffer(pos:pos) = '-'
305+
end if
306+
307+
string = buffer(pos:)
308+
end function json_value_int
309+
310+
!> Convert direct lattice to cell parameters
311+
pure subroutine dlat_to_cell(lattice,cellpar)
312+
implicit none
313+
real(wp),intent(in) :: lattice(3,3) !< direct lattice
314+
real(wp),intent(out) :: cellpar(6) !< cell parameters
315+
316+
associate( alen => cellpar(1), blen => cellpar(2), clen => cellpar(3), &
317+
& alp => cellpar(4), bet => cellpar(5), gam => cellpar(6) )
318+
319+
alen = norm2(lattice(:,1))
320+
blen = norm2(lattice(:,2))
321+
clen = norm2(lattice(:,3))
322+
323+
alp = acos(dot_product(lattice(:,2),lattice(:,3))/(blen*clen))
324+
bet = acos(dot_product(lattice(:,1),lattice(:,3))/(alen*clen))
325+
gam = acos(dot_product(lattice(:,1),lattice(:,2))/(alen*blen))
326+
327+
end associate
328+
329+
end subroutine dlat_to_cell
330+
331+
end module mctc_io_write_pymatgen
332+

0 commit comments

Comments
 (0)