From 49f36b667c072825c4be31f69050d8f09fcdbdbc Mon Sep 17 00:00:00 2001 From: Lorenzo Monacelli Date: Fri, 3 Oct 2025 08:54:49 +0200 Subject: [PATCH 1/3] Fixed the spglib symmetrization --- UserGuide/gettingstarted.rst | 8 ++--- cellconstructor/Phonons.py | 6 ++-- cellconstructor/Structure.py | 30 +++++++++++++++++++ cellconstructor/symmetries.py | 2 +- .../test_diagsymmetries.py | 2 +- .../test_impose_symmetries.py | 8 ++--- .../test_double_symmetrization.py | 2 +- .../test_mode_symmetries.py | 2 +- .../_test_pol_supercell.py | 2 +- .../test_qstar_with_spglib.py | 4 +-- .../test_supercell_replica.py | 10 +++---- .../test_check_fc_symmetry.py | 4 +-- tests/test_phonons_bad/test_phonons_bad.py | 2 +- 13 files changed, 56 insertions(+), 26 deletions(-) diff --git a/UserGuide/gettingstarted.rst b/UserGuide/gettingstarted.rst index 17b16748..f5f8760a 100644 --- a/UserGuide/gettingstarted.rst +++ b/UserGuide/gettingstarted.rst @@ -309,20 +309,20 @@ This tutorial requires spglib and the ASE packages installed. struct.has_unit_cell = True # periodic boundary conditions on # Lets see the symmetries that prints spglib - print("Original space group: ", spglib.get_spacegroup(struct.get_ase_atoms())) + print("Original space group: ", spglib.get_spacegroup(struct.get_spglib_cell())) # The previous command should print # Original space group: Im-3m (299) # Lets store the symmetries and convert from spglib to the CellConstructor - syms = spglib.get_symmetry(struct.get_ase_atoms()) + syms = spglib.get_symmetry(struct.get_spglib_cell()) cc_syms = CC.symmetries.GetSymmetriesFromSPGLIB(syms) # We can add a random noise on the atoms struct.coords += np.random.normal(0, 0.01, size = (2, 3)) # Let us print again the symmetry group - print("Space group with noise: ", spglib.get_spacegroup(struct.get_ase_atoms())) + print("Space group with noise: ", spglib.get_spacegroup(struct.get_spglib_cell())) # This time the code will print # Space group with noise: P-1 (2) @@ -333,7 +333,7 @@ This tutorial requires spglib and the ASE packages installed. struct.impose_symmetries(cc_syms) # The previous command will print details on the symmetrization iterations - print("Final group: ", spglib.get_spacegroup(struct.get_ase_atoms())) + print("Final group: ", spglib.get_spacegroup(struct.get_spglib_cell())) # Now the structure will be again in the Im-3m group. You can pass to all spglib commands a threshold for the symmetrization. In this case you can also use a large threshold and get the symmetries of the closest larger space group. You can use them to constrain the symmetries. diff --git a/cellconstructor/Phonons.py b/cellconstructor/Phonons.py index 28cfbe2c..8289e8d0 100644 --- a/cellconstructor/Phonons.py +++ b/cellconstructor/Phonons.py @@ -1371,7 +1371,7 @@ def load_phonopy(self, yaml_filename = "phonopy.yaml", fc_filename = None): It needs two files: the file with the structure information, and the file with the force constant matrix. - TODO: Test properly, possible bugs. + TODO: Not working!! Parameters ---------- @@ -3214,7 +3214,7 @@ def SymmetrizeSupercell(self, supercell_size = None): #qe_sym.SetupQPoint() qe_sym.ApplySymmetriesToV2(superdyn.dynmats[0]) - #spgsym = spglib.get_symmetry(superdyn.structure.get_ase_atoms()) + #spgsym = spglib.get_symmetry(superdyn.structure.get_spglib_cell()) #syms = symmetries.GetSymmetriesFromSPGLIB(spgsym, False) #superdyn.ForceSymmetries(syms) @@ -4804,7 +4804,7 @@ def compute_phonons_finite_displacements_sym(structure, ase_calculator, epsilon= #print("DEBUG:", debug) # Use spglib to get all the symmetry operations - symm = spglib.get_symmetry(super_structure.get_ase_atoms()) + symm = spglib.get_symmetry(super_structure.get_spglib_cell()) symm = symmetries.GetSymmetriesFromSPGLIB(symm) n_syms = len(symm) diff --git a/cellconstructor/Structure.py b/cellconstructor/Structure.py index 3d9dd72e..bee38ed2 100644 --- a/cellconstructor/Structure.py +++ b/cellconstructor/Structure.py @@ -1468,6 +1468,36 @@ def get_ase_atoms(self): return atm + + def get_spglib_cell(self): + """ + Convert the current structure in a valid spglib cell + for computing the symmetries. + + The spglib cell is a standard tuple containing lattice, positions and + atomic numbers. + + Results + ------- + + cell : Tuple + the standard tuple containing (lattice, positions, numbers) for + spglib. + + """ + + lattice = np.copy(self.unit_cell) + + # Positions needs to be in fractional atomic units + positions = CC.Methods.coovariant_coordinates(lattice, self.coords) + + # Numbers: convert atomic labels into integers + mapping = {} + numbers = [mapping.setdefault(s, len(mapping) + 1) for s in self.atoms] + + cell = (lattice, positions, numbers) + return cell + def get_phonopy_calculation(self, supercell = [1,1,1]): """ Convert the CellConstructor structure to a phonopy object diff --git a/cellconstructor/symmetries.py b/cellconstructor/symmetries.py index 307b1cca..bc2391ea 100644 --- a/cellconstructor/symmetries.py +++ b/cellconstructor/symmetries.py @@ -1277,7 +1277,7 @@ def SetupFromSPGLIB(self): raise ImportError("Error, this function works only if spglib is available") # Get the symmetries - spg_syms = spglib.get_symmetry(self.structure.get_ase_atoms(), symprec = self.threshold) + spg_syms = spglib.get_symmetry(self.structure.get_spglib_cell(), symprec = self.threshold) symmetries = GetSymmetriesFromSPGLIB(spg_syms, regolarize= False) trans_irt = 0 diff --git a/tests/TestDiagonalizeSymmetries/test_diagsymmetries.py b/tests/TestDiagonalizeSymmetries/test_diagsymmetries.py index 547f2b72..27a4debf 100644 --- a/tests/TestDiagonalizeSymmetries/test_diagsymmetries.py +++ b/tests/TestDiagonalizeSymmetries/test_diagsymmetries.py @@ -29,7 +29,7 @@ def test_diag_symmetries(): # Get the symmetries supercell_s = dyn.structure.generate_supercell(dyn.GetSupercell()) - spglib_syms = spglib.get_symmetry(dyn.structure.get_ase_atoms()) + spglib_syms = spglib.get_symmetry(dyn.structure.get_spglib_cell()) syms = CC.symmetries.GetSymmetriesFromSPGLIB(spglib_syms) # Get the symmetries on the polarization vectors diff --git a/tests/TestImposeSymmetries/test_impose_symmetries.py b/tests/TestImposeSymmetries/test_impose_symmetries.py index 4ea67d84..cb3f420f 100644 --- a/tests/TestImposeSymmetries/test_impose_symmetries.py +++ b/tests/TestImposeSymmetries/test_impose_symmetries.py @@ -32,13 +32,13 @@ def test_impose_symmetry(): dyn = CC.Phonons.Phonons("old_dyn", full_name=True) # Print the symmetry group at high threshold - GROUP = spglib.get_spacegroup(dyn.structure.get_ase_atoms(), 0.05) - s_group_expected = spglib.get_spacegroup(dyn.structure.get_ase_atoms()) + GROUP = spglib.get_spacegroup(dyn.structure.get_spglib_cell(), 0.05) + s_group_expected = spglib.get_spacegroup(dyn.structure.get_spglib_cell()) print ("Space group with high threshold:", s_group_expected) print ("Space group with low threshold:", GROUP) # Get the symmetries from the new spacegroup - symmetries = spglib.get_symmetry(dyn.structure.get_ase_atoms(), symprec = 0.05) + symmetries = spglib.get_symmetry(dyn.structure.get_spglib_cell(), symprec = 0.05) print("Number of symmetries: {}".format(len(symmetries["rotations"]))) # Transform the spglib symmetries into the CellConstructor data type @@ -47,7 +47,7 @@ def test_impose_symmetry(): dyn.structure.impose_symmetries(sym_mats) # Check once again the symetry - s_group_after = spglib.get_spacegroup(dyn.structure.get_ase_atoms()) + s_group_after = spglib.get_spacegroup(dyn.structure.get_spglib_cell()) print ("New space group with high threshold:", s_group_after) assert s_group_after == GROUP diff --git a/tests/TestModeSymmetries/test_double_symmetrization.py b/tests/TestModeSymmetries/test_double_symmetrization.py index 06ebcf56..b8227cf7 100644 --- a/tests/TestModeSymmetries/test_double_symmetrization.py +++ b/tests/TestModeSymmetries/test_double_symmetrization.py @@ -31,7 +31,7 @@ def test_double_symmetrization(verbose = False): nat = ss.N_atoms # Get the simmetries - spglib_syms = spglib.get_symmetry(ss.get_ase_atoms()) + spglib_syms = spglib.get_symmetry(ss.get_spglib_cell()) syms = CC.symmetries.GetSymmetriesFromSPGLIB(spglib_syms) m = np.tile(ss.get_masses_array(), (3,1)).T.ravel() diff --git a/tests/TestModeSymmetries/test_mode_symmetries.py b/tests/TestModeSymmetries/test_mode_symmetries.py index 7a3d2dc9..c7d4a377 100644 --- a/tests/TestModeSymmetries/test_mode_symmetries.py +++ b/tests/TestModeSymmetries/test_mode_symmetries.py @@ -27,7 +27,7 @@ def test_mode_symmetries(verbose = False): ss = dyn.structure.generate_supercell(dyn.GetSupercell()) # Load the symmetries from the structure - spglib_sym = spglib.get_symmetry(ss.get_ase_atoms()) + spglib_sym = spglib.get_symmetry(ss.get_spglib_cell()) symmetries = CC.symmetries.GetSymmetriesFromSPGLIB(spglib_sym) # Select only one of the problematic symmetries diff --git a/tests/TestPhononSupercell/_test_pol_supercell.py b/tests/TestPhononSupercell/_test_pol_supercell.py index f5a99032..408a78f1 100644 --- a/tests/TestPhononSupercell/_test_pol_supercell.py +++ b/tests/TestPhononSupercell/_test_pol_supercell.py @@ -79,7 +79,7 @@ print("Please, install spglib if you want to run the test on the symmetries.") exit(0) -spglib_sym = spglib.get_symmetry(dyn_realspace.structure.get_ase_atoms()) +spglib_sym = spglib.get_symmetry(dyn_realspace.structure.get_spglib_cell()) symmetries = CC.symmetries.GetSymmetriesFromSPGLIB(spglib_sym, False) diff --git a/tests/TestQStarWithSPGLIB/test_qstar_with_spglib.py b/tests/TestQStarWithSPGLIB/test_qstar_with_spglib.py index 7b89d4e5..7b14d5f3 100644 --- a/tests/TestQStarWithSPGLIB/test_qstar_with_spglib.py +++ b/tests/TestQStarWithSPGLIB/test_qstar_with_spglib.py @@ -20,9 +20,9 @@ def test_qstar_with_spglib(): print("The total number of q:") print(len(cmca_dyn.q_tot)) - print("Space group:", spglib.get_spacegroup(cmca_dyn.structure.get_ase_atoms())) + print("Space group:", spglib.get_spacegroup(cmca_dyn.structure.get_spglib_cell())) print("Number of symmetries:") - syms = spglib.get_symmetry(cmca_dyn.structure.get_ase_atoms()) + syms = spglib.get_symmetry(cmca_dyn.structure.get_spglib_cell()) print(len(syms["rotations"])) assert len(cmca_dyn.q_stars) == 8 diff --git a/tests/TestReplicaSymmetry/test_supercell_replica.py b/tests/TestReplicaSymmetry/test_supercell_replica.py index 6762a937..56ca42d9 100644 --- a/tests/TestReplicaSymmetry/test_supercell_replica.py +++ b/tests/TestReplicaSymmetry/test_supercell_replica.py @@ -22,11 +22,11 @@ def test_supercell_replica(): # Generate a supercell super_struct = struct.generate_supercell((2,2,1)) print ("Space group before:") - print (spglib.get_spacegroup(super_struct.get_ase_atoms()),) - print (len(spglib.get_symmetry(super_struct.get_ase_atoms())["translations"])) + print (spglib.get_spacegroup(super_struct.get_spglib_cell()),) + print (len(spglib.get_symmetry(super_struct.get_spglib_cell())["translations"])) # Get the symmetries in the supercell using spglib - spglib_syms = spglib.get_symmetry(super_struct.get_ase_atoms()) + spglib_syms = spglib.get_symmetry(super_struct.get_spglib_cell()) syms = CC.symmetries.GetSymmetriesFromSPGLIB(spglib_syms, False) nsyms = len(syms) @@ -57,8 +57,8 @@ def test_supercell_replica(): # Get again the symmetries print ("Symmetries after the sum:") - print (spglib.get_spacegroup(new_structure.get_ase_atoms()), ) - print (len(spglib.get_symmetry(new_structure.get_ase_atoms())["translations"])) + print (spglib.get_spacegroup(new_structure.get_spglib_cell()), ) + print (len(spglib.get_symmetry(new_structure.get_spglib_cell())["translations"])) # Lets check if the structure is the same as before # Should be 0 only if the symmeties are enaugh to have 0 force. diff --git a/tests/TestSymmetryPhonons/test_check_fc_symmetry.py b/tests/TestSymmetryPhonons/test_check_fc_symmetry.py index 49ffa96e..c71ea4b2 100644 --- a/tests/TestSymmetryPhonons/test_check_fc_symmetry.py +++ b/tests/TestSymmetryPhonons/test_check_fc_symmetry.py @@ -36,11 +36,11 @@ def test_check_fc_symmetry(): PH = CC.Phonons.Phonons("hydrogen_dyn", nqirr = 1) print ("Loaded hydrogen_dyn1") - print ("Symmetry group:", spglib.get_spacegroup(PH.structure.get_ase_atoms(), 0.01)) + print ("Symmetry group:", spglib.get_spacegroup(PH.structure.get_spglib_cell(), 0.01)) # Get info about the symmetries of the structure - symmetries = spglib.get_symmetry(PH.structure.get_ase_atoms(), 0.01) + symmetries = spglib.get_symmetry(PH.structure.get_spglib_cell(), 0.01) print ("Number of symmetries:", len(symmetries["rotations"])) # Convert the spglib symmetries into the cellconstructor format diff --git a/tests/test_phonons_bad/test_phonons_bad.py b/tests/test_phonons_bad/test_phonons_bad.py index ad8ae9c9..6826b6ed 100644 --- a/tests/test_phonons_bad/test_phonons_bad.py +++ b/tests/test_phonons_bad/test_phonons_bad.py @@ -14,7 +14,7 @@ def test_phonons_bad(verbose=False): # Symmetrize using spglib ase.visualize.view(dyn.structure.get_ase_atoms()) - syms = CC.symmetries.GetSymmetriesFromSPGLIB(spglib.get_symmetry(dyn.structure.get_ase_atoms(), 0.05)) + syms = CC.symmetries.GetSymmetriesFromSPGLIB(spglib.get_symmetry(dyn.structure.get_spglib_cell(), 0.05)) dyn.structure.impose_symmetries(syms) dyn.FixQPoints() From cc4fe44e3bdd3447e05eaeaf2c87703e900a0933 Mon Sep 17 00:00:00 2001 From: Lorenzo Monacelli Date: Fri, 3 Oct 2025 09:05:28 +0200 Subject: [PATCH 2/3] Fixed a bug --- cellconstructor/Structure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cellconstructor/Structure.py b/cellconstructor/Structure.py index bee38ed2..c791ad82 100644 --- a/cellconstructor/Structure.py +++ b/cellconstructor/Structure.py @@ -1489,7 +1489,7 @@ def get_spglib_cell(self): lattice = np.copy(self.unit_cell) # Positions needs to be in fractional atomic units - positions = CC.Methods.coovariant_coordinates(lattice, self.coords) + positions = Methods.coovariant_coordinates(lattice, self.coords) # Numbers: convert atomic labels into integers mapping = {} From 62649f2e65810e7c85bfea7c676993af908d2129 Mon Sep 17 00:00:00 2001 From: Lorenzo Monacelli Date: Fri, 3 Oct 2025 09:22:45 +0200 Subject: [PATCH 3/3] Fix a spelling --- cellconstructor/Structure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cellconstructor/Structure.py b/cellconstructor/Structure.py index c791ad82..2dff57ce 100644 --- a/cellconstructor/Structure.py +++ b/cellconstructor/Structure.py @@ -1489,7 +1489,7 @@ def get_spglib_cell(self): lattice = np.copy(self.unit_cell) # Positions needs to be in fractional atomic units - positions = Methods.coovariant_coordinates(lattice, self.coords) + positions = Methods.covariant_coordinates(lattice, self.coords) # Numbers: convert atomic labels into integers mapping = {}