def test_xyz(self): op=SymmOp([[1, -1, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]) s=op.as_xyz_string() self.assertEqual(s, 'x-y, -y, -z') self.assertEqual(op, SymmOp.from_xyz_string(s)) op2=SymmOp([[0, -1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5 + 1e-7], [0, 0, 0, 1]]) s2=op2.as_xyz_string() self.assertEqual(s2, '-y+1/2, x+1/2, z+1/2') self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op2=SymmOp([[3, -2, -1, 0.5], [-1, 0, 0, 12. / 13], [0, 0, 1, 0.5 + 1e-7], [0, 0, 0, 1]]) s2=op2.as_xyz_string() self.assertEqual(s2, '3x-2y-z+1/2, -x+12/13, z+1/2') self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op3=SymmOp.from_xyz_string('3x - 2y - z+1 /2 , -x+12/ 13, z+1/2') self.assertEqual(op2, op3) # Ensure strings can be read in any order op4=SymmOp.from_xyz_string('1 /2 + 3X - 2y - z , 12/ 13-x, z+1/2') op5=SymmOp.from_xyz_string('+1 /2 + 3x - 2y - z , 12/ 13-x, +1/2+z') self.assertEqual(op4, op3) self.assertEqual(op4, op5) self.assertEqual(op3, op5) self.assertRaises(ValueError, self.op.as_xyz_string) o=SymmOp.from_xyz_string('0.5+x, 0.25+y, 0.75+z') self.assertArrayAlmostEqual(o.translation_vector, [0.5, 0.25, 0.75]) o=SymmOp.from_xyz_string('x + 0.5, y + 0.25, z + 0.75') self.assertArrayAlmostEqual(o.translation_vector, [0.5, 0.25, 0.75])
def test_xyz(self): op = SymmOp([[1, -1, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]) s = op.as_xyz_string() self.assertEqual(s, 'x-y, -y, -z') self.assertEqual(op, SymmOp.from_xyz_string(s)) op2 = SymmOp([[0, -1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5 + 1e-7], [0, 0, 0, 1]]) s2 = op2.as_xyz_string() self.assertEqual(s2, '-y+1/2, x+1/2, z+1/2') self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op2 = SymmOp([[3, -2, -1, 0.5], [-1, 0, 0, 12. / 13], [0, 0, 1, 0.5 + 1e-7], [0, 0, 0, 1]]) s2 = op2.as_xyz_string() self.assertEqual(s2, '3x-2y-z+1/2, -x+12/13, z+1/2') self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op3 = SymmOp.from_xyz_string('3x - 2y - z+1 /2 , -x+12/ 13, z+1/2') self.assertEqual(op2, op3) # Ensure strings can be read in any order op4 = SymmOp.from_xyz_string('1 /2 + 3X - 2y - z , 12/ 13-x, z+1/2') op5 = SymmOp.from_xyz_string('+1 /2 + 3x - 2y - z , 12/ 13-x, +1/2+z') self.assertEqual(op4, op3) self.assertEqual(op4, op5) self.assertEqual(op3, op5) self.assertRaises(ValueError, self.op.as_xyz_string) o = SymmOp.from_xyz_string('0.5+x, 0.25+y, 0.75+z') self.assertArrayAlmostEqual(o.translation_vector, [0.5, 0.25, 0.75]) o = SymmOp.from_xyz_string('x + 0.5, y + 0.25, z + 0.75') self.assertArrayAlmostEqual(o.translation_vector, [0.5, 0.25, 0.75])
def get_wyckoffs(sg): wyckoff_strings = eval(wyckoff_df["0"][sg]) wyckoffs = [] for x in wyckoff_strings: wyckoffs.append([]) for y in x: wyckoffs[-1].append(SymmOp.from_xyz_string(y)) return wyckoffs
def test_xyz(self): op = SymmOp([[1, -1, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]) s = op.as_xyz_string() self.assertEqual(s, 'x-y, -y, -z') self.assertEqual(op, SymmOp.from_xyz_string(s)) op2 = SymmOp([[0, -1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5+1e-7], [0, 0, 0, 1]]) s2 = op2.as_xyz_string() self.assertEqual(s2, '-y+1/2, x+1/2, z+1/2') self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op2 = SymmOp([[3, -2, -1, 0.5], [-1, 0, 0, 12./13], [0, 0, 1, 0.5+1e-7], [0, 0, 0, 1]]) s2 = op2.as_xyz_string() self.assertEqual(s2, '3x-2y-z+1/2, -x+12/13, z+1/2') self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op3 = SymmOp.from_xyz_string('3x - 2y - z+1 /2 , -x+12/ 13, z+1/2') self.assertEqual(op2, op3) self.assertRaises(ValueError, self.op.as_xyz_string)
def get_wyckoff_generators(sg): ''' Returns a list of Wyckoff generators for a given space group. 1st index: index of WP in sg (0 is the WP with largest multiplicity) 2nd index: a generator for the WP ''' generators_strings = eval(wyckoff_generators_df["0"][sg]) generators = [] #Loop over Wyckoff positions for wp in generators_strings: generators.append([]) #Loop over points in WP for op in wp: generators[-1].append(SymmOp.from_xyz_string(op)) return generators
def test_xyz(self): op = SymmOp([[1, -1, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]) s = op.as_xyz_string() self.assertEqual(s, "x-y, -y, -z") self.assertEqual(op, SymmOp.from_xyz_string(s)) op2 = SymmOp( [[0, -1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5 + 1e-7], [0, 0, 0, 1]] ) s2 = op2.as_xyz_string() self.assertEqual(s2, "-y+1/2, x+1/2, z+1/2") self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op2 = SymmOp( [ [3, -2, -1, 0.5], [-1, 0, 0, 12.0 / 13], [0, 0, 1, 0.5 + 1e-7], [0, 0, 0, 1], ] ) s2 = op2.as_xyz_string() self.assertEqual(s2, "3x-2y-z+1/2, -x+12/13, z+1/2") self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op3 = SymmOp.from_xyz_string("3x - 2y - z+1 /2 , -x+12/ 13, z+1/2") self.assertEqual(op2, op3) # Ensure strings can be read in any order op4 = SymmOp.from_xyz_string("1 /2 + 3X - 2y - z , 12/ 13-x, z+1/2") op5 = SymmOp.from_xyz_string("+1 /2 + 3x - 2y - z , 12/ 13-x, +1/2+z") self.assertEqual(op4, op3) self.assertEqual(op4, op5) self.assertEqual(op3, op5) # TODO: assertWarns not in Python 2.x unittest # update PymatgenTest for unittest2? # self.assertWarns(UserWarning, self.op.as_xyz_string) o = SymmOp.from_xyz_string("0.5+x, 0.25+y, 0.75+z") self.assertArrayAlmostEqual(o.translation_vector, [0.5, 0.25, 0.75]) o = SymmOp.from_xyz_string("x + 0.5, y + 0.25, z + 0.75") self.assertArrayAlmostEqual(o.translation_vector, [0.5, 0.25, 0.75])
def get_symmetry(mol, already_oriented=False): ''' Return a list of SymmOps for a molecule's point symmetry already_oriented: whether or not the principle axes of mol are already reoriented ''' pga = PointGroupAnalyzer(mol) #Handle linear molecules if '*' in pga.sch_symbol: if already_oriented == False: #Reorient the molecule oriented_mol, P = reoriented_molecule(mol) pga = PointGroupAnalyzer(oriented_mol) pg = pga.get_pointgroup() symm_m = [] for op in pg: symm_m.append(op) #Add 12-fold and reflections in place of ininitesimal rotation for axis in [[1, 0, 0], [0, 1, 0], [0, 0, 1]]: op = SymmOp.from_rotation_and_translation(aa2matrix(axis, pi / 6), [0, 0, 0]) if pga.is_valid_op(op): symm_m.append(op) #Any molecule with infinitesimal symmetry is linear; #Thus, it possess mirror symmetry for any axis perpendicular #To the rotational axis. pymatgen does not add this symmetry #for all linear molecules - for example, hydrogen if axis == [1, 0, 0]: symm_m.append(SymmOp.from_xyz_string('x,-y,z')) symm_m.append(SymmOp.from_xyz_string('x,y,-z')) elif axis == [0, 1, 0]: symm_m.append(SymmOp.from_xyz_string('-x,y,z')) symm_m.append(SymmOp.from_xyz_string('x,y,-z')) elif axis == [0, 0, 1]: symm_m.append(SymmOp.from_xyz_string('-x,y,z')) symm_m.append(SymmOp.from_xyz_string('x,-y,z')) #Generate a full list of SymmOps for the molecule's pointgroup symm_m = generate_full_symmops(symm_m, 1e-3) break #Reorient the SymmOps into mol's original frame if not already_oriented: new = [] for op in symm_m: new.append(P.inverse * op * P) return new elif already_oriented: return symm_m #Handle nonlinear molecules else: pg = pga.get_pointgroup() symm_m = [] for op in pg: symm_m.append(op) return symm_m
def get_wyckoff_symmetry(sg): ''' Returns a list of Wyckoff position site symmetry for a given space group. 1st index: index of WP in sg (0 is the WP with largest multiplicity) 2nd index: a point within the WP 3rd index: a site symmetry SymmOp of the point ''' symmetry_strings = eval(wyckoff_symmetry_df["0"][sg]) symmetry = [] #Loop over Wyckoff positions for x in symmetry_strings: symmetry.append([]) #Loop over points in WP for y in x: symmetry[-1].append([]) #Loop over for z in y: symmetry[-1][-1].append(SymmOp.from_xyz_string(z)) return symmetry
def test_inverse(self): coord0 = [0.35, 0.1, 0.4] coords = np.array([ [0.350, 0.100, 0.400], [0.350, 0.100, 0.000], [0.350, 0.100, 0.000], [0.350, 0.000, 0.667], [0.350, 0.000, 0.250], [0.350, 0.350, 0.400], [0.350, 0.350, 0.500], [0.350, 0.350, 0.000], [0.350, 0.350, 0.350], [0.100, 0.100, 0.100], [0.400, 0.400, 0.400], [0.350, 0.000, 0.000], [0.000, 0.100, 0.400], [0.350, 0.000, 0.400], ]) xyzs = [ 'x,y,z', 'x,y,0', 'y,x,0', 'x,0,2/3', '0,x,1/4', 'x,x,z', 'x,-x,1/2', '2x,x,0', '-2x,-0.5x,-x+1/4', '-2y,-0.5y,-y+1/4', '-2z,-0.5z,-z+1/4', '0,0,x', '-y/2+1/2,-z,0', '-z,-x/2+1/2,0', ] for i, xyz in enumerate(xyzs): op = SymmOp.from_xyz_string(xyz) inv_op = get_inverse(op) coord1 = op.operate(coord0) coord2 = inv_op.operate(coord1) self.assertTrue(np.allclose(coord2, coords[i], rtol=1e-2))
def test_xyz(self): op = SymmOp([[1, -1, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]) s = op.as_xyz_string() self.assertEqual(s, 'x-y, -y, -z') self.assertEqual(op, SymmOp.from_xyz_string(s)) op2 = SymmOp([[0, -1, 0, 0.5], [1, 0, 0, 0.5], [0, 0, 1, 0.5 + 1e-7], [0, 0, 0, 1]]) s2 = op2.as_xyz_string() self.assertEqual(s2, '-y+1/2, x+1/2, z+1/2') self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op2 = SymmOp([[3, -2, -1, 0.5], [-1, 0, 0, 12. / 13], [0, 0, 1, 0.5 + 1e-7], [0, 0, 0, 1]]) s2 = op2.as_xyz_string() self.assertEqual(s2, '3x-2y-z+1/2, -x+12/13, z+1/2') self.assertEqual(op2, SymmOp.from_xyz_string(s2)) op3 = SymmOp.from_xyz_string('3x - 2y - z+1 /2 , -x+12/ 13, z+1/2') self.assertEqual(op2, op3) # Ensure strings can be read in any order op4 = SymmOp.from_xyz_string('1 /2 + 3X - 2y - z , 12/ 13-x, z+1/2') op5 = SymmOp.from_xyz_string('+1 /2 + 3x - 2y - z , 12/ 13-x, +1/2+z') self.assertEqual(op4, op3) self.assertEqual(op4, op5) self.assertEqual(op3, op5) # TODO: assertWarns not in Python 2.x unittest # update PymatgenTest for unittest2? # self.assertWarns(UserWarning, self.op.as_xyz_string) o = SymmOp.from_xyz_string('0.5+x, 0.25+y, 0.75+z') self.assertArrayAlmostEqual(o.translation_vector, [0.5, 0.25, 0.75]) o = SymmOp.from_xyz_string('x + 0.5, y + 0.25, z + 0.75') self.assertArrayAlmostEqual(o.translation_vector, [0.5, 0.25, 0.75])
def get_wyckoff_symmetry(sg, molecular=False): ''' Returns a list of Wyckoff position site symmetry for a given space group. 1st index: index of WP in sg (0 is the WP with largest multiplicity) 2nd index: a point within the WP 3rd index: a site symmetry SymmOp of the point molecular: whether or not to return the Euclidean point symmetry operations If True, cuts off translational part of operation, and converts non-orthogonal (3-fold and 6-fold rotation) operations to pure rotations ''' P = SymmOp.from_rotation_and_translation( [[1, -.5, 0], [0, sqrt(3) / 2, 0], [0, 0, 1]], [0, 0, 0]) symmetry_strings = eval(wyckoff_symmetry_df["0"][sg]) symmetry = [] convert = False if molecular is True: if sg >= 143 and sg <= 194: convert = True #Loop over Wyckoff positions for x in symmetry_strings: symmetry.append([]) #Loop over points in WP for y in x: symmetry[-1].append([]) #Loop over ops for z in y: op = SymmOp.from_xyz_string(z) if convert is True: #Convert non-orthogonal trigonal/hexagonal operations op = P * op * P.inverse if molecular is False: symmetry[-1][-1].append(op) elif molecular is True: op = SymmOp.from_rotation_and_translation( op.rotation_matrix, [0, 0, 0]) symmetry[-1][-1].append(op) return symmetry
def get_wyckoffs(sg, organized=False): ''' Returns a list of Wyckoff positions for a given space group. 1st index: index of WP in sg (0 is the WP with largest multiplicity) 2nd index: a SymmOp object in the WP ''' wyckoff_strings = eval(wyckoff_df["0"][sg]) wyckoffs = [] for x in wyckoff_strings: wyckoffs.append([]) for y in x: wyckoffs[-1].append(SymmOp.from_xyz_string(y)) if organized: wyckoffs_organized = [[]] #2D Array of WP's organized by multiplicity old = len(wyckoffs[0]) for wp in wyckoffs: mult = len(wp) if mult != old: wyckoffs_organized.append([]) old = mult wyckoffs_organized[-1].append(wp) return wyckoffs_organized else: return wyckoffs
from structure import * from pymatgen.core.operations import SymmOp print("---Site Symmetry for a point in a space group---") sg = input("Space group Number (1-230): ") point = input("Point (can have x,y,z variables): ") gen_pos = get_wyckoff_positions(int(sg))[0][0] point = SymmOp.from_xyz_string(point) mylist = site_symm(point, gen_pos) print("Found symmetry:") for x in mylist: print(x.as_xyz_string())
def get_symops(self, data): """ In order to generate symmetry equivalent positions, the symmetry operations are parsed. If the symops are not present, the space group symbol is parsed, and symops are generated. """ symops = [] for symmetry_label in ["_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_"]: if data.data.get(symmetry_label): xyz = data.data.get(symmetry_label) if isinstance(xyz, six.string_types): warnings.warn("A 1-line symmetry op P1 CIF is detected!") xyz = [xyz] try: symops = [SymmOp.from_xyz_string(s) for s in xyz] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in ["_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_"]: sg = data.data.get(symmetry_label) if sg: sg = sub_spgrp(sg) try: spg = space_groups.get(sg) if spg: symops = SpaceGroup(spg).symmetry_ops warnings.warn( "No _symmetry_equiv_pos_as_xyz type key found. " "Spacegroup from %s used." % symmetry_label) break except ValueError: # Ignore any errors pass try: for d in _get_cod_data(): if sg == re.sub("\s+", "", d["hermann_mauguin"]) : xyz = d["symops"] symops = [SymmOp.from_xyz_string(s) for s in xyz] warnings.warn( "No _symmetry_equiv_pos_as_xyz type key found. " "Spacegroup from %s used." % symmetry_label) break except Exception as ex: continue if symops: break if not symops: # Try to parse International number for symmetry_label in ["_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_"]: if data.data.get(symmetry_label): try: i = int(str2float(data.data.get(symmetry_label))) symops = SpaceGroup.from_int_number(i).symmetry_ops break except ValueError: continue if not symops: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def test_modules(): print("====== Testing functionality for pyXtal version 0.1dev ======") global failed_package failed_package = False # Record if errors occur at any level reset() print("Importing sys...") try: import sys print("Success!") except Exception as e: fail(e) sys.exit(0) print("Importing numpy...") try: import numpy as np print("Success!") except Exception as e: fail(e) sys.exit(0) I = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) print("Importing pymatgen...") try: import pymatgen print("Success!") except Exception as e: fail(e) sys.exit(0) try: from pymatgen.core.operations import SymmOp except Exception as e: fail(e) sys.exit(0) print("Importing pandas...") try: import pandas print("Success!") except Exception as e: fail(e) sys.exit(0) print("Importing spglib...") try: import spglib print("Success!") except Exception as e: fail(e) sys.exit(0) print("Importing openbabel...") try: import ase print("Success!") except: print( "Error: could not import openbabel. Try reinstalling the package.") print("Importing pyxtal...") try: import pyxtal print("Success!") except Exception as e: fail(e) sys.exit(0) print("=== Testing modules ===") # =====database.element===== print("pyxtal.database.element") reset() try: import pyxtal.database.element except Exception as e: fail(e) print(" class Element") try: from pyxtal.database.element import Element except Exception as e: fail(e) if passed(): for i in range(1, 95): if passed(): try: ele = Element(i) except: fail("Could not access Element # " + str(i)) try: y = ele.sf y = ele.z y = ele.short_name y = ele.long_name y = ele.valence y = ele.valence_electrons y = ele.covalent_radius y = ele.vdw_radius y = ele.get_all(0) except: fail("Could not access attribute for element # " + str(i)) try: ele.all_z() ele.all_short_names() ele.all_long_names() ele.all_valences() ele.all_valence_electrons() ele.all_covalent_radii() ele.all_vdw_radii() except: fail("Could not access class methods") check() # =====database.hall===== print("pyxtal.database.hall") reset() try: import pyxtal.database.hall except Exception as e: fail(e) print(" hall_from_hm") try: from pyxtal.database.hall import hall_from_hm except Exception as e: fail(e) if passed(): for i in range(1, 230): if passed(): try: hall_from_hm(i) except: fail("Could not access hm # " + str(i)) check() # =====database.collection===== print("pyxtal.database.collection") reset() try: import pyxtal.database.collection except Exception as e: fail(e) print(" Collection") try: from pyxtal.database.collection import Collection except Exception as e: fail(e) if passed(): for i in range(1, 230): if passed(): try: molecule_collection = Collection("molecules") except: fail("Could not access hm # " + str(i)) check() # =====operations===== print("pyxtal.operations") reset() try: import pyxtal.operations except Exception as e: fail(e) print(" random_vector") try: from pyxtal.operations import random_vector except Exception as e: fail(e) if passed(): try: for i in range(10): random_vector() except Exception as e: fail(e) check() print(" angle") try: from pyxtal.operations import angle except Exception as e: fail(e) if passed(): try: for i in range(10): v1 = random_vector() v2 = random_vector() angle(v1, v2) except Exception as e: fail(e) check() print(" random_shear_matrix") try: from pyxtal.operations import random_shear_matrix except Exception as e: fail(e) if passed(): try: for i in range(10): random_shear_matrix() except Exception as e: fail(e) check() print(" is_orthogonal") try: from pyxtal.operations import is_orthogonal except Exception as e: fail(e) if passed(): try: a = is_orthogonal([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) b = is_orthogonal([[0, 0, 1], [1, 0, 0], [1, 0, 0]]) if a is True and b is False: pass else: fail() except Exception as e: fail(e) check() print(" aa2matrix") try: from pyxtal.operations import aa2matrix except Exception as e: fail(e) if passed(): try: for i in range(10): aa2matrix(1, 1, random=True) except Exception as e: fail(e) check() print(" matrix2aa") try: from pyxtal.operations import matrix2aa except Exception as e: fail(e) if passed(): try: for i in range(10): m = aa2matrix(1, 1, random=True) aa = matrix2aa(m) except Exception as e: fail(e) check() print(" rotate_vector") try: from pyxtal.operations import rotate_vector except Exception as e: fail(e) if passed(): try: for i in range(10): v1 = random_vector() v2 = random_vector() rotate_vector(v1, v2) except Exception as e: fail(e) check() print(" are_equal") try: from pyxtal.operations import are_equal except Exception as e: fail(e) if passed(): try: op1 = SymmOp.from_xyz_string("x,y,z") op2 = SymmOp.from_xyz_string("x,y,z+1") a = are_equal(op1, op2, PBC=[0, 0, 1]) b = are_equal(op1, op2, PBC=[1, 0, 0]) if a is True and b is False: pass else: fail() except Exception as e: fail(e) check() print(" class OperationAnalyzer") try: from pyxtal.operations import OperationAnalyzer except Exception as e: fail(e) if passed(): try: for i in range(10): m = aa2matrix(1, 1, random=True) t = random_vector() op1 = SymmOp.from_rotation_and_translation(m, t) OperationAnalyzer(op1) except Exception as e: fail(e) check() print(" class Orientation") try: from pyxtal.operations import Orientation except Exception as e: fail(e) if passed(): try: for i in range(10): v1 = random_vector() c1 = random_vector() o = Orientation.from_constraint(v1, c1) except Exception as e: fail(e) check() # =====symmetry===== print("pyxtal.symmetry") reset() try: import pyxtal.symmetry except Exception as e: fail(e) print(" get_wyckoffs (may take a moment)") try: from pyxtal.symmetry import get_wyckoffs except Exception as e: fail(e) if passed(): try: for i in [1, 2, 229, 230]: get_wyckoffs(i) get_wyckoffs(i, organized=True) except: fail(" Could not access Wyckoff positions for space group # " + str(i)) check() print(" get_wyckoff_symmetry (may take a moment)") try: from pyxtal.symmetry import get_wyckoff_symmetry except Exception as e: fail(e) if passed(): try: for i in [1, 2, 229, 230]: get_wyckoff_symmetry(i) get_wyckoff_symmetry(i, molecular=True) except: fail("Could not access Wyckoff symmetry for space group # " + str(i)) check() print(" get_wyckoffs_generators (may take a moment)") try: from pyxtal.symmetry import get_wyckoff_generators except Exception as e: fail(e) if passed(): try: for i in [1, 2, 229, 230]: get_wyckoff_generators(i) except: fail("Could not access Wyckoff generators for space group # " + str(i)) check() print(" letter_from_index") try: from pyxtal.symmetry import letter_from_index except Exception as e: fail(e) if passed(): try: if letter_from_index(0, get_wyckoffs(47)) == "A": pass else: fail() except Exception as e: fail(e) check() print(" index_from_letter") try: from pyxtal.symmetry import index_from_letter except Exception as e: fail(e) if passed(): try: if index_from_letter("A", get_wyckoffs(47)) == 0: pass else: fail() except Exception as e: fail(e) check() print(" jk_from_i") try: from pyxtal.symmetry import jk_from_i except Exception as e: fail(e) if passed(): try: w = get_wyckoffs(2, organized=True) j, k = jk_from_i(1, w) if j == 1 and k == 0: pass else: print(j, k) fail() except Exception as e: fail(e) check() print(" i_from_jk") try: from pyxtal.symmetry import i_from_jk except Exception as e: fail(e) if passed(): try: w = get_wyckoffs(2, organized=True) j, k = jk_from_i(1, w) i = i_from_jk(j, k, w) if i == 1: pass else: print(j, k) fail() except Exception as e: fail(e) check() print(" ss_string_from_ops") try: from pyxtal.symmetry import ss_string_from_ops except Exception as e: fail(e) if passed(): try: strings = ["1", "4 . .", "2 3 ."] for i, sg in enumerate([1, 75, 195]): ops = get_wyckoffs(sg)[0] ss_string_from_ops(ops, sg, dim=3) except Exception as e: fail(e) check() print(" Wyckoff_position") try: from pyxtal.symmetry import Wyckoff_position except Exception as e: fail(e) if passed(): try: wp = Wyckoff_position.from_group_and_index(20, 1) except Exception as e: fail(e) check() print(" Group") try: from pyxtal.symmetry import Group except Exception as e: fail(e) if passed(): try: g3 = Group(230) g2 = Group(80, dim=2) g1 = Group(75, dim=1) except Exception as e: fail(e) check() # =====crystal===== print("pyxtal.crystal") reset() try: import pyxtal.crystal except Exception as e: fail(e) print(" random_crystal") try: from pyxtal.crystal import random_crystal except Exception as e: fail(e) if passed(): try: c = random_crystal(1, ["H"], [1], 10.0) if c.valid is True: pass else: fail() except Exception as e: fail(e) check() print(" random_crystal_2D") try: from pyxtal.crystal import random_crystal_2D except Exception as e: fail(e) if passed(): try: c = random_crystal_2D(1, ["H"], [1], 10.0) if c.valid is True: pass else: fail() except Exception as e: fail(e) check() # =====molecule===== print("pyxtal.molecule") reset() try: import pyxtal.molecule except Exception as e: fail(e) check() print(" Collections") try: from pyxtal.molecule import mol_from_collection except Exception as e: fail(e) if passed(): try: h2o = mol_from_collection("H2O") ch4 = mol_from_collection("CH4") except Exception as e: fail(e) print(" get_inertia_tensor") try: from pyxtal.molecule import get_inertia_tensor except Exception as e: fail(e) if passed(): try: get_inertia_tensor(h2o) get_inertia_tensor(ch4) except Exception as e: fail(e) check() print(" get_moment_of_inertia") try: from pyxtal.molecule import get_moment_of_inertia except Exception as e: fail(e) if passed(): try: v = random_vector() get_moment_of_inertia(h2o, v) get_moment_of_inertia(ch4, v) except Exception as e: fail(e) check() print(" reoriented_molecule") try: from pyxtal.molecule import reoriented_molecule except Exception as e: fail(e) if passed(): try: reoriented_molecule(h2o) reoriented_molecule(ch4) except Exception as e: fail(e) check() print(" orientation_in_wyckoff_position") try: from pyxtal.molecule import orientation_in_wyckoff_position except Exception as e: fail(e) if passed(): try: w = get_wyckoffs(20) ws = get_wyckoff_symmetry(20, molecular=True) wp = Wyckoff_position.from_group_and_index(20, 1) orientation_in_wyckoff_position(h2o, wp) orientation_in_wyckoff_position(ch4, wp) except Exception as e: fail(e) check() # =====molecular_crystal===== print("pyxtal.molecular_crystal") reset() try: import pyxtal.crystal except Exception as e: fail(e) print(" molecular_crystal") try: from pyxtal.molecular_crystal import molecular_crystal except Exception as e: fail(e) if passed(): try: c = molecular_crystal(1, ["H2O"], [1], 10.0) if c.valid is True: pass else: fail() except Exception as e: fail(e) check() print(" molecular_crystal_2D") try: from pyxtal.molecular_crystal import molecular_crystal_2D except Exception as e: fail(e) if passed(): try: c = molecular_crystal_2D(1, ["H2O"], [1], 10.0) if c.valid is True: pass else: fail() except Exception as e: fail(e) check() end(condition=2)
def _get_structure(self, data, primitive): """ Generate structure from part of the cif. """ lengths = [ str2float(data["_cell_length_" + i]) for i in ["a", "b", "c"] ] angles = [ str2float(data["_cell_angle_" + i]) for i in ["alpha", "beta", "gamma"] ] lattice = Lattice.from_lengths_and_angles(lengths, angles) try: sympos = data["_symmetry_equiv_pos_as_xyz"] except KeyError: try: sympos = data["_symmetry_equiv_pos_as_xyz_"] except KeyError: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") sympos = ['x, y, z'] self.symmetry_operations = [SymmOp.from_xyz_string(s) for s in sympos] def parse_symbol(sym): # capitalization conventions are not strictly followed, eg Cu will be CU m = re.search("([A-Za-z]*)", sym) if m: return m.group(1)[:2].capitalize() return "" try: oxi_states = { data["_atom_type_symbol"][i]: str2float(data["_atom_type_oxidation_number"][i]) for i in range(len(data["_atom_type_symbol"])) } except (ValueError, KeyError): oxi_states = None coord_to_species = OrderedDict() for i in range(len(data["_atom_site_label"])): symbol = parse_symbol(data["_atom_site_label"][i]) # make sure symbol was properly parsed from _atom_site_label # otherwise get it from _atom_site_type_symbol try: Element(symbol) except KeyError: symbol = parse_symbol(data["_atom_site_type_symbol"][i]) if oxi_states is not None: # sometimes the site doesn't have the type_symbol. # we then hope the type_symbol can be parsed from the label if "_atom_site_type_symbol" in data.data.keys(): k = data["_atom_site_type_symbol"][i] else: k = symbol el = Specie(symbol, oxi_states[k]) else: el = Element(symbol) x = str2float(data["_atom_site_fract_x"][i]) y = str2float(data["_atom_site_fract_y"][i]) z = str2float(data["_atom_site_fract_z"][i]) try: occu = str2float(data["_atom_site_occupancy"][i]) except (KeyError, ValueError): occu = 1 if occu > 0: coord = (x, y, z) if coord not in coord_to_species: coord_to_species[coord] = {el: occu} else: coord_to_species[coord][el] = occu allspecies = [] allcoords = [] for coord, species in coord_to_species.items(): coords = self._unique_coords(coord) allcoords.extend(coords) allspecies.extend(len(coords) * [species]) #rescale occupancies if necessary for species in allspecies: totaloccu = sum(species.values()) if 1 < totaloccu <= self._occupancy_tolerance: for key, value in six.iteritems(species): species[key] = value / totaloccu struct = Structure(lattice, allspecies, allcoords) if primitive: struct = struct.get_primitive_structure().get_reduced_structure() return struct.get_sorted_structure()
def get_symops(self, data): """ In order to generate symmetry equivalent positions, the symmetry operations are parsed. If the symops are not present, the space group symbol is parsed, and symops are generated. """ symops = [] for symmetry_label in [ "_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_" ]: if data.data.get(symmetry_label): xyz = data.data.get(symmetry_label) if isinstance(xyz, six.string_types): warnings.warn("A 1-line symmetry op P1 CIF is detected!") xyz = [xyz] try: symops = [SymmOp.from_xyz_string(s) for s in xyz] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in [ "_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_" ]: sg = data.data.get(symmetry_label) if sg: sg = sub_spgrp(sg) try: spg = space_groups.get(sg) if spg: symops = SpaceGroup(spg).symmetry_ops warnings.warn( "No _symmetry_equiv_pos_as_xyz type key found. " "Spacegroup from %s used." % symmetry_label) break except ValueError: # Ignore any errors pass try: for d in _get_cod_data(): if sg == re.sub(r"\s+", "", d["hermann_mauguin"]): xyz = d["symops"] symops = [ SymmOp.from_xyz_string(s) for s in xyz ] warnings.warn( "No _symmetry_equiv_pos_as_xyz type key found. " "Spacegroup from %s used." % symmetry_label) break except Exception as ex: continue if symops: break if not symops: # Try to parse International number for symmetry_label in [ "_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_" ]: if data.data.get(symmetry_label): try: i = int(str2float(data.data.get(symmetry_label))) symops = SpaceGroup.from_int_number(i).symmetry_ops break except ValueError: continue if not symops: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def __init__(self, int_symbol): """ Initializes a Space Group from its full or abbreviated international symbol. Only standard settings are supported. Args: int_symbol (str): Full International (e.g., "P2/m2/m2/m") or Hermann-Mauguin Symbol ("Pmmm") or abbreviated symbol. The notation is a LaTeX-like string, with screw axes being represented by an underscore. For example, "P6_3/mmc". Note that for rhomohedral cells, the hexagonal setting can be accessed by adding a "H", e.g., "R-3mH". """ gen_matrices = get_symm_data("generator_matrices") # POINT_GROUP_ENC = SYMM_DATA["point_group_encoding"] sgencoding = get_symm_data("space_group_encoding") abbrev_sg_mapping = get_symm_data("abbreviated_spacegroup_symbols") translations = {k: Fraction(v) for k, v in get_symm_data( "translations").items()} full_sg_mapping = { v["full_symbol"]: k for k, v in get_symm_data("space_group_encoding").items()} int_symbol = re.sub(" ", "", int_symbol) if int_symbol in abbrev_sg_mapping: int_symbol = abbrev_sg_mapping[int_symbol] elif int_symbol in full_sg_mapping: int_symbol = full_sg_mapping[int_symbol] for spg in SpaceGroup.SYMM_OPS: if re.sub(" ", "", spg["hermann_mauguin"]) == int_symbol or re.sub(":", "", re.sub(" ", "", spg["universal_h_m"])) == int_symbol: ops = [SymmOp.from_xyz_string(s) for s in spg["symops"]] self.symbol = re.sub(":", "", re.sub(" ", "", spg["universal_h_m"])) if int_symbol in sgencoding: self.full_symbol = sgencoding[int_symbol]["full_symbol"] self.point_group = sgencoding[int_symbol]["point_group"] else: self.full_symbol = re.sub(" ", "", spg["universal_h_m"]) self.point_group = spg["schoenflies"] self.int_number = spg["number"] self.order = len(ops) self._symmetry_ops = ops break else: if int_symbol not in sgencoding: raise ValueError("Bad international symbol %s" % int_symbol) data = sgencoding[int_symbol] self.symbol = int_symbol # TODO: Support different origin choices. enc = list(data["enc"]) inversion = int(enc.pop(0)) ngen = int(enc.pop(0)) symm_ops = [np.eye(4)] if inversion: symm_ops.append(np.array( [[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])) for i in range(ngen): m = np.eye(4) m[:3, :3] = gen_matrices[enc.pop(0)] m[0, 3] = translations[enc.pop(0)] m[1, 3] = translations[enc.pop(0)] m[2, 3] = translations[enc.pop(0)] symm_ops.append(m) self.generators = symm_ops self.full_symbol = data["full_symbol"] self.int_number = data["int_number"] self.order = data["order"] self._symmetry_ops = None
def __init__(self, int_symbol): """ Initializes a Space Group from its full or abbreviated international symbol. Only standard settings are supported. Args: int_symbol (str): Full International (e.g., "P2/m2/m2/m") or Hermann-Mauguin Symbol ("Pmmm") or abbreviated symbol. The notation is a LaTeX-like string, with screw axes being represented by an underscore. For example, "P6_3/mmc". Alternative settings can be access by adding a ":identifier". For example, the hexagonal setting for rhombohedral cells can be accessed by adding a ":H", e.g., "R-3m:H". To find out all possible settings for a spacegroup, use the get_settings classmethod. Alternative origin choices can be indicated by a translation vector, e.g., 'Fm-3m(a-1/4,b-1/4,c-1/4)'. """ int_symbol = re.sub(r" ", "", int_symbol) if int_symbol in SpaceGroup.abbrev_sg_mapping: int_symbol = SpaceGroup.abbrev_sg_mapping[int_symbol] elif int_symbol in SpaceGroup.full_sg_mapping: int_symbol = SpaceGroup.full_sg_mapping[int_symbol] for spg in SpaceGroup.SYMM_OPS: if int_symbol in [spg["hermann_mauguin"], spg["universal_h_m"]]: ops = [SymmOp.from_xyz_string(s) for s in spg["symops"]] self.symbol = re.sub(r":", "", re.sub(r" ", "", spg["universal_h_m"])) if int_symbol in SpaceGroup.sgencoding: self.full_symbol = SpaceGroup.sgencoding[int_symbol]["full_symbol"] self.point_group = SpaceGroup.sgencoding[int_symbol]["point_group"] else: self.full_symbol = re.sub(r" ", "", spg["universal_h_m"]) self.point_group = spg["schoenflies"] self.int_number = spg["number"] self.order = len(ops) self._symmetry_ops = ops break else: if int_symbol not in SpaceGroup.sgencoding: raise ValueError("Bad international symbol %s" % int_symbol) data = SpaceGroup.sgencoding[int_symbol] self.symbol = int_symbol # TODO: Support different origin choices. enc = list(data["enc"]) inversion = int(enc.pop(0)) ngen = int(enc.pop(0)) symm_ops = [np.eye(4)] if inversion: symm_ops.append(np.array( [[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])) for i in range(ngen): m = np.eye(4) m[:3, :3] = SpaceGroup.gen_matrices[enc.pop(0)] m[0, 3] = SpaceGroup.translations[enc.pop(0)] m[1, 3] = SpaceGroup.translations[enc.pop(0)] m[2, 3] = SpaceGroup.translations[enc.pop(0)] symm_ops.append(m) self.generators = symm_ops self.full_symbol = data["full_symbol"] self.int_number = data["int_number"] self.order = data["order"] self._symmetry_ops = None
from pymatgen import Structure from pymatgen import symmetry from pymatgen.ext.matproj import MPRester from pymatgen.io.cif import CifWriter from pymatgen.symmetry.analyzer import SpacegroupAnalyzer from pymatgen.core.operations import SymmOp from IPython.display import Image with MPRester("izD7mJmnjhUOKyWGtZ") as m: # Structure for material id structure = m.get_structure_by_material_id("mp-27869") w = CifWriter(structure) w.write_file('mp-27869.cif') sGP = SpacegroupAnalyzer(structure) print("2ème élément de symétrie (Ci:0 0 0):") Op1 = SymmOp.from_xyz_string("-x, -y, -z") print("Effet sur P1 #2:") Eff1 = Op1.operate((0, 0, 1 / 2)) print(Eff1) display(Image(filename='sym1.jpg')) print("4ème élément de symétrie (3-bar axis:y,-x+y,-z):") Op2 = SymmOp.from_xyz_string("y,-x+y,-z") print("Effet sur BaO1 #4:") Eff2 = Op2.operate((0, 0, 0.24)) print(Eff2) display(Image(filename='sym2.jpg')) print("5ème élément de symétrie (3-bar axis:-x+y,-x,z):") Op3 = SymmOp.from_xyz_string("-x+y,-x,z") print("Effet sur BaO6 #5:") Eff3 = Op3.operate((0.67, 0.33, 0.57)) print(Eff3)
def get_symops(self, data): """ In order to generate symmetry equivalent positions, the symmetry operations are parsed. If the symops are not present, the space group symbol is parsed, and symops are generated. """ symops = [] for symmetry_label in ["_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_"]: if data.data.get(symmetry_label): try: symops = [SymmOp.from_xyz_string(s) for s in data.data.get(symmetry_label)] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in ["_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_"]: if data.data.get(symmetry_label): try: spg = space_groups.get(sub_spgrp( data.data.get(symmetry_label))) if spg: symops = SpaceGroup(spg).symmetry_ops break except ValueError: continue if not symops: # Try to parse International number for symmetry_label in ["_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_"]: if data.data.get(symmetry_label): try: i = int(str2float(data.data.get(symmetry_label))) symops = SpaceGroup.from_int_number(i).symmetry_ops break except ValueError: continue if not symops: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def get_symops(self, data): """ In order to generate symmetry equivalent positions, the symmetry operations are parsed. If the symops are not present, the space group symbol is parsed, and symops are generated. """ symops = [] for symmetry_label in [ "_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_" ]: if data.data.get(symmetry_label): try: symops = [ SymmOp.from_xyz_string(s) for s in data.data.get(symmetry_label) ] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in [ "_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_" ]: if data.data.get(symmetry_label): try: spg = space_groups.get( sub_spgrp(data.data.get(symmetry_label))) if spg: symops = SpaceGroup(spg).symmetry_ops break except ValueError: continue if not symops: # Try to parse International number for symmetry_label in [ "_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_" ]: if data.data.get(symmetry_label): try: symops = SpaceGroup.from_int_number( str2float( data.data.get(symmetry_label))).symmetry_ops break except ValueError: continue if not symops: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def get_symmop(data): symops = [] for symmetry_label in [ "_symmetry_equiv_pos_as_xyz", "_symmetry_equiv_pos_as_xyz_", "_space_group_symop_operation_xyz", "_space_group_symop_operation_xyz_" ]: if data.get(symmetry_label): xyz = data.get(symmetry_label) if isinstance(xyz, str): msg = "A 1-line symmetry op P1 CIF is detected!" warnings.warn(msg) xyz = [xyz] try: symops = [SymmOp.from_xyz_string(s) for s in xyz] break except ValueError: continue if not symops: # Try to parse symbol for symmetry_label in [ "_symmetry_space_group_name_H-M", "_symmetry_space_group_name_H_M", "_symmetry_space_group_name_H-M_", "_symmetry_space_group_name_H_M_", "_space_group_name_Hall", "_space_group_name_Hall_", "_space_group_name_H-M_alt", "_space_group_name_H-M_alt_", "_symmetry_space_group_name_hall", "_symmetry_space_group_name_hall_", "_symmetry_space_group_name_h-m", "_symmetry_space_group_name_h-m_" ]: sg = data.get(symmetry_label) if sg: sg = sub_spgrp(sg) try: spg = space_groups.get(sg) if spg: symops = SpaceGroup(spg).symmetry_ops msg = "No _symmetry_equiv_pos_as_xyz type key found. " \ "Spacegroup from %s used." % symmetry_label warnings.warn(msg) break except ValueError: # Ignore any errors pass try: for d in _get_cod_data(): if sg == re.sub(r"\s+", "", d["hermann_mauguin"]): xyz = d["symops"] symops = [SymmOp.from_xyz_string(s) for s in xyz] msg = "No _symmetry_equiv_pos_as_xyz type key found. " \ "Spacegroup from %s used." % symmetry_label warnings.warn(msg) break except Exception: continue if symops: break if not symops: # Try to parse International number for symmetry_label in [ "_space_group_IT_number", "_space_group_IT_number_", "_symmetry_Int_Tables_number", "_symmetry_Int_Tables_number_" ]: if data.get(symmetry_label): try: i = int(braket2float(data.get(symmetry_label))) symops = SpaceGroup.from_int_number(i).symmetry_ops break except ValueError: continue if not symops: msg = "No _symmetry_equiv_pos_as_xyz type key found. " \ "Defaulting to P1." warnings.warn(msg) symops = [SymmOp.from_xyz_string(s) for s in ['x', 'y', 'z']] return symops
def __init__(self, int_symbol): """ Initializes a Space Group from its full or abbreviated international symbol. Only standard settings are supported. Args: int_symbol (str): Full International (e.g., "P2/m2/m2/m") or Hermann-Mauguin Symbol ("Pmmm") or abbreviated symbol. The notation is a LaTeX-like string, with screw axes being represented by an underscore. For example, "P6_3/mmc". Alternative settings can be access by adding a ":identifier". For example, the hexagonal setting for rhombohedral cells can be accessed by adding a ":H", e.g., "R-3m:H". To find out all possible settings for a spacegroup, use the get_settings classmethod. Alternative origin choices can be indicated by a translation vector, e.g., 'Fm-3m(a-1/4,b-1/4,c-1/4)'. """ int_symbol = re.sub(r" ", "", int_symbol) if int_symbol in SpaceGroup.abbrev_sg_mapping: int_symbol = SpaceGroup.abbrev_sg_mapping[int_symbol] elif int_symbol in SpaceGroup.full_sg_mapping: int_symbol = SpaceGroup.full_sg_mapping[int_symbol] for spg in SpaceGroup.SYMM_OPS: if int_symbol in [spg["hermann_mauguin"], spg["universal_h_m"]]: ops = [SymmOp.from_xyz_string(s) for s in spg["symops"]] self.symbol = re.sub(r":", "", re.sub(r" ", "", spg["universal_h_m"])) if int_symbol in SpaceGroup.sgencoding: self.full_symbol = SpaceGroup.sgencoding[int_symbol][ "full_symbol"] self.point_group = SpaceGroup.sgencoding[int_symbol][ "point_group"] else: self.full_symbol = re.sub(r" ", "", spg["universal_h_m"]) self.point_group = spg["schoenflies"] self.int_number = spg["number"] self.order = len(ops) self._symmetry_ops = ops break else: if int_symbol not in SpaceGroup.sgencoding: raise ValueError("Bad international symbol %s" % int_symbol) data = SpaceGroup.sgencoding[int_symbol] self.symbol = int_symbol # TODO: Support different origin choices. enc = list(data["enc"]) inversion = int(enc.pop(0)) ngen = int(enc.pop(0)) symm_ops = [np.eye(4)] if inversion: symm_ops.append( np.array([[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])) for i in range(ngen): m = np.eye(4) m[:3, :3] = SpaceGroup.gen_matrices[enc.pop(0)] m[0, 3] = SpaceGroup.translations[enc.pop(0)] m[1, 3] = SpaceGroup.translations[enc.pop(0)] m[2, 3] = SpaceGroup.translations[enc.pop(0)] symm_ops.append(m) self.generators = symm_ops self.full_symbol = data["full_symbol"] self.point_group = data["point_group"] self.int_number = data["int_number"] self.order = data["order"] self._symmetry_ops = None
def _get_structure(self, data, primitive): """ Generate structure from part of the cif. """ lengths = [str2float(data["_cell_length_" + i]) for i in ["a", "b", "c"]] angles = [str2float(data["_cell_angle_" + i]) for i in ["alpha", "beta", "gamma"]] lattice = Lattice.from_lengths_and_angles(lengths, angles) try: sympos = data["_symmetry_equiv_pos_as_xyz"] except KeyError: try: sympos = data["_symmetry_equiv_pos_as_xyz_"] except KeyError: warnings.warn("No _symmetry_equiv_pos_as_xyz type key found. " "Defaulting to P1.") sympos = ['x, y, z'] self.symmetry_operations = [SymmOp.from_xyz_string(s) for s in sympos] def parse_symbol(sym): m = re.search("([A-Z][a-z]*)", sym) if m: return m.group(1) return "" try: oxi_states = { data["_atom_type_symbol"][i]: str2float(data["_atom_type_oxidation_number"][i]) for i in range(len(data["_atom_type_symbol"]))} except (ValueError, KeyError): oxi_states = None coord_to_species = OrderedDict() for i in range(len(data["_atom_site_type_symbol"])): symbol = parse_symbol(data["_atom_site_type_symbol"][i]) if oxi_states is not None: el = Specie(symbol, oxi_states[data["_atom_site_type_symbol"][i]]) else: el = Element(symbol) x = str2float(data["_atom_site_fract_x"][i]) y = str2float(data["_atom_site_fract_y"][i]) z = str2float(data["_atom_site_fract_z"][i]) try: occu = str2float(data["_atom_site_occupancy"][i]) except (KeyError, ValueError): occu = 1 if occu > 0: coord = (x, y, z) if coord not in coord_to_species: coord_to_species[coord] = {el: occu} else: coord_to_species[coord][el] = occu allspecies = [] allcoords = [] for coord, species in coord_to_species.items(): coords = self._unique_coords(coord) allcoords.extend(coords) allspecies.extend(len(coords) * [species]) #rescale occupancies if necessary for species in allspecies: totaloccu = sum(species.values()) if 1 < totaloccu <= self._occupancy_tolerance: for key, value in six.iteritems(species): species[key] = value / totaloccu struct = Structure(lattice, allspecies, allcoords) if primitive: struct = struct.get_primitive_structure().get_reduced_structure() return struct.get_sorted_structure()