7
7
import re
8
8
import textwrap
9
9
import warnings
10
- from collections import deque
10
+ from collections import defaultdict , deque
11
11
from datetime import datetime
12
12
from functools import partial
13
13
from inspect import getfullargspec as getargspec
@@ -1313,13 +1313,14 @@ class CifWriter:
1313
1313
1314
1314
def __init__ (
1315
1315
self ,
1316
- struct ,
1317
- symprec = None ,
1318
- write_magmoms = False ,
1319
- significant_figures = 8 ,
1320
- angle_tolerance = 5.0 ,
1321
- refine_struct = True ,
1322
- ):
1316
+ struct : Structure ,
1317
+ symprec : float | None = None ,
1318
+ write_magmoms : bool = False ,
1319
+ significant_figures : int = 8 ,
1320
+ angle_tolerance : float = 5 ,
1321
+ refine_struct : bool = True ,
1322
+ write_site_properties : bool = False ,
1323
+ ) -> None :
1323
1324
"""
1324
1325
Args:
1325
1326
struct (Structure): structure to write
@@ -1335,14 +1336,16 @@ def __init__(
1335
1336
is not None.
1336
1337
refine_struct: Used only if symprec is not None. If True, get_refined_structure
1337
1338
is invoked to convert input structure from primitive to conventional.
1339
+ write_site_properties (bool): Whether to write the Structure.site_properties
1340
+ to the CIF as _atom_site_{property name}. Defaults to False.
1338
1341
"""
1339
1342
if write_magmoms and symprec :
1340
1343
warnings .warn ("Magnetic symmetry cannot currently be detected by pymatgen,disabling symmetry detection." )
1341
1344
symprec = None
1342
1345
1343
1346
format_str = f"{{:.{ significant_figures } f}}"
1344
1347
1345
- block = {}
1348
+ block : dict [ str , Any ] = {}
1346
1349
loops = []
1347
1350
spacegroup = ("P 1" , 1 )
1348
1351
if symprec is not None :
@@ -1367,7 +1370,7 @@ def __init__(
1367
1370
block ["_chemical_formula_sum" ] = no_oxi_comp .formula
1368
1371
block ["_cell_volume" ] = format_str .format (lattice .volume )
1369
1372
1370
- _reduced_comp , fu = no_oxi_comp .get_reduced_composition_and_factor ()
1373
+ _ , fu = no_oxi_comp .get_reduced_composition_and_factor ()
1371
1374
block ["_cell_formula_units_Z" ] = str (int (fu ))
1372
1375
1373
1376
if symprec is None :
@@ -1388,12 +1391,12 @@ def __init__(
1388
1391
loops .append (["_symmetry_equiv_pos_site_id" , "_symmetry_equiv_pos_as_xyz" ])
1389
1392
1390
1393
try :
1391
- symbol_to_oxinum = {str (el ): float (el .oxi_state ) for el in sorted (comp .elements )}
1392
- block ["_atom_type_symbol" ] = list (symbol_to_oxinum )
1393
- block ["_atom_type_oxidation_number" ] = symbol_to_oxinum .values ()
1394
+ symbol_to_oxi_num = {str (el ): float (el .oxi_state or 0 ) for el in sorted (comp .elements )}
1395
+ block ["_atom_type_symbol" ] = list (symbol_to_oxi_num )
1396
+ block ["_atom_type_oxidation_number" ] = symbol_to_oxi_num .values ()
1394
1397
loops .append (["_atom_type_symbol" , "_atom_type_oxidation_number" ])
1395
1398
except (TypeError , AttributeError ):
1396
- symbol_to_oxinum = {el .symbol : 0 for el in sorted (comp .elements )}
1399
+ symbol_to_oxi_num = {el .symbol : 0 for el in sorted (comp .elements )}
1397
1400
1398
1401
atom_site_type_symbol = []
1399
1402
atom_site_symmetry_multiplicity = []
@@ -1406,6 +1409,7 @@ def __init__(
1406
1409
atom_site_moment_crystalaxis_x = []
1407
1410
atom_site_moment_crystalaxis_y = []
1408
1411
atom_site_moment_crystalaxis_z = []
1412
+ atom_site_properties : dict [str , list ] = defaultdict (list )
1409
1413
count = 0
1410
1414
if symprec is None :
1411
1415
for site in struct :
@@ -1437,6 +1441,10 @@ def __init__(
1437
1441
atom_site_moment_crystalaxis_y .append (format_str .format (moment [1 ]))
1438
1442
atom_site_moment_crystalaxis_z .append (format_str .format (moment [2 ]))
1439
1443
1444
+ if write_site_properties :
1445
+ for key , val in site .properties .items ():
1446
+ atom_site_properties [key ].append (format_str .format (val ))
1447
+
1440
1448
count += 1
1441
1449
else :
1442
1450
# The following just presents a deterministic ordering.
@@ -1475,17 +1483,21 @@ def __init__(
1475
1483
block ["_atom_site_fract_y" ] = atom_site_fract_y
1476
1484
block ["_atom_site_fract_z" ] = atom_site_fract_z
1477
1485
block ["_atom_site_occupancy" ] = atom_site_occupancy
1478
- loops .append (
1479
- [
1480
- "_atom_site_type_symbol" ,
1481
- "_atom_site_label" ,
1482
- "_atom_site_symmetry_multiplicity" ,
1483
- "_atom_site_fract_x" ,
1484
- "_atom_site_fract_y" ,
1485
- "_atom_site_fract_z" ,
1486
- "_atom_site_occupancy" ,
1487
- ]
1488
- )
1486
+ loop_labels = [
1487
+ "_atom_site_type_symbol" ,
1488
+ "_atom_site_label" ,
1489
+ "_atom_site_symmetry_multiplicity" ,
1490
+ "_atom_site_fract_x" ,
1491
+ "_atom_site_fract_y" ,
1492
+ "_atom_site_fract_z" ,
1493
+ "_atom_site_occupancy" ,
1494
+ ]
1495
+ if write_site_properties :
1496
+ for key , vals in atom_site_properties .items ():
1497
+ block [f"_atom_site_{ key } " ] = vals
1498
+ loop_labels += [f"_atom_site_{ key } " ]
1499
+ loops .append (loop_labels )
1500
+
1489
1501
if write_magmoms :
1490
1502
block ["_atom_site_moment_label" ] = atom_site_moment_label
1491
1503
block ["_atom_site_moment_crystalaxis_x" ] = atom_site_moment_crystalaxis_x
0 commit comments