@@ -31,32 +31,66 @@ def get_api_key() -> str:
3131 return api_key
3232
3333
34- def _write_cif_from_struct (structure : Structure , out_path : Path ) -> None :
35- """Write structure to CIF using pymatgen's CifWriter."""
34+ def _write_cif_from_struct (
35+ structure : Structure ,
36+ out_path : Path ,
37+ sg_num : Optional [int ] = None ,
38+ sg_symbol : Optional [str ] = None ,
39+ symprec : float = 0.01 ,
40+ angle_tolerance : float = 5.0 ,
41+ ) -> None :
42+ """
43+ Write structure to CIF using pymatgen's CifWriter, ensuring symmetry metadata (_symmetry_* tags)
44+ are present and reflect the detected space group from SpacegroupAnalyzer.
45+ """
3646 try :
37- CifWriter (structure ).write_file (out_path )
47+ # Write CIF with symmetry detection enabled
48+ CifWriter (structure , symprec = symprec , angle_tolerance = angle_tolerance ).write_file (out_path )
3849 except Exception as e :
3950 raise RuntimeError (f"Failed to write CIF to { out_path } : { e } " )
4051
52+ # Post-process CIF to force writing of symmetry tags
53+ try :
54+ with open (out_path , "r" , errors = "ignore" ) as f :
55+ lines = f .readlines ()
56+
57+ def set_or_insert (tag : str , value : Any , quote : bool = False ) -> None :
58+ val_str = f"'{ value } '" if quote else str (value )
59+ for i , line in enumerate (lines ):
60+ if line .strip ().startswith (tag ):
61+ lines [i ] = f"{ tag } { val_str } \n "
62+ break
63+ else :
64+ # Insert after the first line (typically the data_ line)
65+ insert_idx = 1 if len (lines ) >= 1 else 0
66+ lines .insert (insert_idx , f"{ tag } { val_str } \n " )
67+
68+ if sg_num is not None :
69+ set_or_insert ("_symmetry_Int_Tables_number" , sg_num , quote = False )
70+ if sg_symbol :
71+ set_or_insert ("_symmetry_space_group_name_H-M" , sg_symbol , quote = True )
72+
73+ with open (out_path , "w" ) as f :
74+ f .writelines (lines )
75+ except Exception :
76+ # Non-fatal if symmetry tag insertion fails; CIF already written
77+ pass
78+
4179
4280def niggli_reduce (
4381 structure : Structure ,
4482 symprec : float = 0.01 ,
4583 angle_tolerance : float = 5.0 ,
4684) -> Structure :
4785 """
48- Build Niggli-reduced lattice from the conventional standard structure.
86+ Build the Niggli-reduced structure using pymatgen's canonical workflow:
87+ 1) Convert to conventional standard cell via Structure.to_conventional(...)
88+ 2) Apply Niggli reduction via Structure.get_reduced_structure(reduction_algo='niggli')
89+ This ensures a proper change-of-basis for atomic coordinates, avoiding lattice-only swaps.
4990 """
50- sga = SpacegroupAnalyzer (structure , symprec = symprec , angle_tolerance = angle_tolerance )
51- conv = sga .get_conventional_standard_structure ()
52- red_lat = conv .lattice .get_niggli_reduced_lattice ()
53- reduced = Structure (
54- lattice = red_lat ,
55- species = conv .species ,
56- coords = conv .frac_coords ,
57- to_unit_cell = True ,
58- )
59- return reduced
91+ conventional = structure .to_conventional (symprec = symprec , angle_tolerance = angle_tolerance )
92+ reduced_structure = conventional .get_reduced_structure (reduction_algo = "niggli" )
93+ return reduced_structure
6094
6195
6296def passes_filters (
@@ -310,7 +344,14 @@ def download_cifs_entire_db(
310344 summary ["skipped_existing" ] += 1
311345 continue
312346
313- _write_cif_from_struct (std_struct , out_path )
347+ _write_cif_from_struct (
348+ std_struct ,
349+ out_path ,
350+ sg_num = sg_num ,
351+ sg_symbol = sga_conv .get_space_group_symbol (),
352+ symprec = symprec ,
353+ angle_tolerance = angle_tolerance ,
354+ )
314355 summary ["downloaded" ] += 1
315356
316357 except Exception as e :
0 commit comments