def add_snl(self, snl, force_new=False, snlgroup_guess=None): try: self.lock_db() snl_id = self._get_next_snl_id() spstruc = snl.structure.copy() spstruc.remove_oxidation_states() sf = SpacegroupAnalyzer(spstruc, SPACEGROUP_TOLERANCE) sf.get_space_group_operations() sgnum = sf.get_space_group_number() if sf.get_space_group_number() \ else -1 sgsym = sf.get_space_group_symbol() if sf.get_space_group_symbol() \ else 'unknown' sghall = sf.get_hall() if sf.get_hall() else 'unknown' sgxtal = sf.get_crystal_system() if sf.get_crystal_system() \ else 'unknown' sglatt = sf.get_lattice_type() if sf.get_lattice_type( ) else 'unknown' sgpoint = sf.get_point_group_symbol() mpsnl = MPStructureNL.from_snl(snl, snl_id, sgnum, sgsym, sghall, sgxtal, sglatt, sgpoint) snlgroup, add_new, spec_group = self.add_mpsnl( mpsnl, force_new, snlgroup_guess) self.release_lock() return mpsnl, snlgroup.snlgroup_id, spec_group except: self.release_lock() traceback.print_exc() raise ValueError("Error while adding SNL!")
def create_saturated_interstitial_structure(interstitial_def, dist_tol=0.1): """ this takes a Interstitial defect object and generates the sublattice for it based on the structure's space group. Useful for understanding multiplicity of an interstitial defect in thermodynamic analysis. NOTE: if large relaxation happens to interstitial or defect involves a complex then there may be additional degrees of freedom that need to be considered for the multiplicity. Args: dist_tol: changing distance tolerance of saturated structure, allowing for possibly overlapping sites but ensuring space group is maintained Returns: Structure object decorated with interstitial site equivalents """ sga = SpacegroupAnalyzer(interstitial_def.bulk_structure.copy()) sg_ops = sga.get_symmetry_operations(cartesian=True) # copy bulk structure to make saturated interstitial structure out of # artificially lower distance_tolerance to allow for distinct interstitials # with lower symmetry to be replicated - This is OK because one would never # actually use this structure for a practical calcualtion... saturated_defect_struct = interstitial_def.bulk_structure.copy() saturated_defect_struct.DISTANCE_TOLERANCE = dist_tol for sgo in sg_ops: new_interstit_coords = sgo.operate(interstitial_def.site.coords[:]) poss_new_site = PeriodicSite( interstitial_def.site.specie, new_interstit_coords, saturated_defect_struct.lattice, to_unit_cell=True, coords_are_cartesian=True, ) try: # will raise value error if site already exists in structure saturated_defect_struct.append( poss_new_site.specie, poss_new_site.coords, coords_are_cartesian=True, validate_proximity=True, ) except ValueError: pass # do final space group analysis to make sure symmetry not lowered by saturating defect structure saturated_sga = SpacegroupAnalyzer(saturated_defect_struct) if saturated_sga.get_space_group_number() != sga.get_space_group_number(): raise ValueError( "Warning! Interstitial sublattice generation " "has changed space group symmetry. Recommend " "reducing dist_tol and trying again..." ) return saturated_defect_struct
def add_snl(self, snl, force_new=False, snlgroup_guess=None): try: self.lock_db() snl_id = self._get_next_snl_id() spstruc = snl.structure.copy() spstruc.remove_oxidation_states() sf = SpacegroupAnalyzer(spstruc, SPACEGROUP_TOLERANCE) sf.get_space_group_operations() sgnum = sf.get_space_group_number() if sf.get_space_group_number() \ else -1 sgsym = sf.get_space_group_symbol() if sf.get_space_group_symbol() \ else 'unknown' sghall = sf.get_hall() if sf.get_hall() else 'unknown' sgxtal = sf.get_crystal_system() if sf.get_crystal_system() \ else 'unknown' sglatt = sf.get_lattice_type() if sf.get_lattice_type() else 'unknown' sgpoint = sf.get_point_group_symbol() mpsnl = MPStructureNL.from_snl(snl, snl_id, sgnum, sgsym, sghall, sgxtal, sglatt, sgpoint) snlgroup, add_new, spec_group = self.add_mpsnl(mpsnl, force_new, snlgroup_guess) self.release_lock() return mpsnl, snlgroup.snlgroup_id, spec_group except: self.release_lock() traceback.print_exc() raise ValueError("Error while adding SNL!")
def test_tricky_structure(self): # for some reason this structure kills spglib1.9 # 1.7 can't find symmetry either, but at least doesn't kill python s = Structure.from_file(os.path.join(PymatgenTest.TEST_FILES_DIR, "POSCAR.tricky_symmetry")) sa = SpacegroupAnalyzer(s, 0.1) sa.get_space_group_symbol() sa.get_space_group_number() sa.get_point_group_symbol() sa.get_crystal_system() sa.get_hall()
def test_tricky_structure(self): # for some reason this structure kills spglib1.9 # 1.7 can't find symmetry either, but at least doesn't kill python s = Structure.from_file(os.path.join(test_dir, 'POSCAR.tricky_symmetry')) sa = SpacegroupAnalyzer(s, 0.1) sa.get_space_group_symbol() sa.get_space_group_number() sa.get_point_group_symbol() sa.get_crystal_system() sa.get_hall()
def test_tricky_structure(self): # for some reason this structure kills spglib1.9 # 1.7 can't find symmetry either, but at least doesn't kill python s = Structure.from_file(test_dir / 'POSCAR.tricky_symmetry') sa = SpacegroupAnalyzer(s, 0.1) sa.get_space_group_symbol() sa.get_space_group_number() sa.get_point_group_symbol() sa.get_crystal_system() sa.get_hall()
def create_saturated_interstitial_structure( interstitial_def, dist_tol=0.1): """ this takes a Interstitial defect object and generates the sublattice for it based on the structure's space group. Useful for understanding multiplicity of an interstitial defect in thermodynamic analysis. NOTE: if large relaxation happens to interstitial or defect involves a complex then there may be additional degrees of freedom that need to be considered for the multiplicity. Args: dist_tol: changing distance tolerance of saturated structure, allowing for possibly overlapping sites but ensuring space group is maintained Returns: Structure object decorated with interstitial site equivalents """ sga = SpacegroupAnalyzer( interstitial_def.bulk_structure.copy()) sg_ops = sga.get_symmetry_operations( cartesian=True) # copy bulk structure to make saturated interstitial structure out of # artificially lower distance_tolerance to allow for distinct interstitials # with lower symmetry to be replicated - This is OK because one would never # actually use this structure for a practical calcualtion... saturated_defect_struct = interstitial_def.bulk_structure.copy() saturated_defect_struct.DISTANCE_TOLERANCE = dist_tol for sgo in sg_ops: new_interstit_coords = sgo.operate( interstitial_def.site.coords[:]) poss_new_site = PeriodicSite( interstitial_def.site.specie, new_interstit_coords, saturated_defect_struct.lattice, to_unit_cell=True, coords_are_cartesian=True) try: #will raise value error if site already exists in structure saturated_defect_struct.append( poss_new_site.specie, poss_new_site.coords, coords_are_cartesian=True, validate_proximity=True) except ValueError: pass # do final space group analysis to make sure symmetry not lowered by saturating defect structure saturated_sga = SpacegroupAnalyzer( saturated_defect_struct) if saturated_sga.get_space_group_number() != sga.get_space_group_number(): raise ValueError("Warning! Interstitial sublattice generation " "has changed space group symmetry. Recommend " "reducing dist_tol and trying again...") return saturated_defect_struct
def set_output_data(self, d_calc, d): """ set the 'output' key """ d["output"] = { "structure": d_calc["output"]["structure"], "density": d_calc.pop("density"), "energy": d_calc["output"]["energy"], "energy_per_atom": d_calc["output"]["energy_per_atom"] } d["output"].update(self.get_basic_processed_data(d)) sg = SpacegroupAnalyzer( Structure.from_dict(d_calc["output"]["structure"]), 0.1) if not sg.get_symmetry_dataset(): sg = SpacegroupAnalyzer( Structure.from_dict(d_calc["output"]["structure"]), 1e-3, 1) d["output"]["spacegroup"] = { "source": "spglib", "symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall() } if d["input"]["parameters"].get("LEPSILON"): for k in [ 'epsilon_static', 'epsilon_static_wolfe', 'epsilon_ionic' ]: d["output"][k] = d_calc["output"][k]
def set_space_group_from_structure(self, structure): spga = SpacegroupAnalyzer(structure=structure) self.crystal_system = spga.get_crystal_system() self.hall = spga.get_hall() self.number = spga.get_space_group_number() self.source = "spglib" self.symbol = spga.get_space_group_symbol()
def set_material_data_from_structure(self, structure, space_group=True, symprec=1e-3, angle_tolerance=5): """ Sets the fields of the Document using a Structure and Spglib to determine the space group properties Args: structure: A |Structure| space_group: if True sets the spacegroup fields using spglib_. symprec (float): Tolerance for symmetry finding. angle_tolerance (float): Angle tolerance for symmetry finding. """ comp = structure.composition el_amt = structure.composition.get_el_amt_dict() self.unit_cell_formula = comp.as_dict() self.reduced_cell_formula = comp.to_reduced_dict self.elements = list(el_amt.keys()) self.nelements = len(el_amt) self.pretty_formula = comp.reduced_formula self.anonymous_formula = comp.anonymized_formula self.nsites = comp.num_atoms self.chemsys = "-".join(sorted(el_amt.keys())) if space_group: sym = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance) self.spacegroup = SpaceGroupDocument(crystal_system=sym.get_crystal_system(), hall=sym.get_hall(), number=sym.get_space_group_number(), point_group=sym.get_point_group_symbol(), symbol=sym.get_space_group_symbol(), source="spglib")
def __init__(self, band: BandStructureSymmLine, band2: BandStructureSymmLine = None, absolute: bool = False, y_range: list = None, legend: bool = False, symprec: float = SYMMETRY_TOLERANCE, angle_tolerance: float = ANGLE_TOL): bs_plotter = ModBSPlotter(band) composition = str(band.structure.composition) sga = SpacegroupAnalyzer(structure=band.structure, symprec=symprec, angle_tolerance=angle_tolerance) sg_symbol = sga.get_space_group_symbol() sg_num = sga.get_space_group_number() kwargs = { "ylim": y_range, "legend": legend, "zero_to_efermi": absolute, "title": f"{composition} SG: {sg_symbol} ({sg_num})" } if not band2: self.plotter = bs_plotter.get_plot(**kwargs) else: bs_plotter2 = ModBSPlotter(band2) self.plotter = bs_plotter2.plot_compare(bs_plotter, **kwargs)
def get_structure_data(structure): sga = SpacegroupAnalyzer(structure) return { "xtal_system": sga.get_crystal_system(), "spacegroup_sym": sga.get_space_group_symbol(), "spacegroup_num": sga.get_space_group_number() }
def from_structure(cls, structure: Structure) -> "SymmetryData": symprec = SETTINGS.SYMPREC sg = SpacegroupAnalyzer(structure, symprec=symprec) symmetry: Dict[str, Any] = {"symprec": symprec} if not sg.get_symmetry_dataset(): sg = SpacegroupAnalyzer(structure, 1e-3, 1) symmetry["symprec"] = 1e-3 symmetry.update({ "source": "spglib", "symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "crystal_system": CrystalSystem(sg.get_crystal_system().title()), "hall": sg.get_hall(), "version": spglib.__version__, }) return SymmetryData(**symmetry)
def poscar(self): """ generating poscar for relaxation calculations """ print( '--------------------------------------------------------------------------------------------------------' ) print("Generation of VASP files for the cell relaxation:") print( '--------------------------------------------------------------------------------------------------------' ) self.symData.structure = Structure.from_file(self.args.pos[0]) sym1 = float(self.args.sympre[0]) sym2 = float(self.args.symang[0]) aa = SpacegroupAnalyzer(self.symData.structure, symprec=sym1, angle_tolerance=sym2) self.symData.space_group = aa.get_space_group_number() print("Space group number =", self.symData.space_group) spg = aa.get_space_group_symbol() print("Space group symbol =", str(spg)) self.symData.number_of_species = len(self.symData.structure.species) print("Number of atoms = {}".format(len( self.symData.structure.species))) pos_name = "POSCAR" structure00 = Poscar(self.symData.structure) structure00.write_file(filename=pos_name, significant_figures=16) return self.symData
def get_energy(self, structure): """ :param structure: Structure :return: Energy value """ f = SpacegroupAnalyzer(structure, symprec=self.symprec, angle_tolerance=self.angle_tolerance) return -f.get_space_group_number()
def set_space_group_from_structure(self, structure): spga = SpacegroupAnalyzer(structure=structure) self.crystal_system = spga.get_crystal_system() self.hall = spga.get_hall() self.number = spga.get_space_group_number() self.source = "spglib" self.symbol = spga.get_space_group_symbol()
def test_apply_transformation(self): trans = MagOrderingTransformation({"Fe": 5}) p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) s = p.structure alls = trans.apply_transformation(s, 10) self.assertEqual(len(alls), 3) f = SpacegroupAnalyzer(alls[0]["structure"], 0.1) self.assertEqual(f.get_space_group_number(), 31) model = IsingModel(5, 5) trans = MagOrderingTransformation({"Fe": 5}, energy_model=model) alls2 = trans.apply_transformation(s, 10) # Ising model with +J penalizes similar neighbor magmom. self.assertNotEqual(alls[0]["structure"], alls2[0]["structure"]) self.assertEqual(alls[0]["structure"], alls2[2]["structure"]) s = self.get_structure('Li2O') # Li2O doesn't have magnetism of course, but this is to test the # enumeration. trans = MagOrderingTransformation({"Li+": 1}, max_cell_size=3) alls = trans.apply_transformation(s, 100) # TODO: check this is correct, unclear what len(alls) should be self.assertEqual(len(alls), 12) trans = MagOrderingTransformation({"Ni": 5}) alls = trans.apply_transformation(self.NiO.get_primitive_structure(), return_ranked_list=10) self.assertArrayAlmostEqual(self.NiO_AFM_111.lattice.parameters, alls[0]["structure"].lattice.parameters) self.assertArrayAlmostEqual(self.NiO_AFM_001.lattice.parameters, alls[1]["structure"].lattice.parameters)
def __init__(self, group_uuid, structure, sc_size, process_label, energy_threshold=0.01, symprec=1e-3, if_with_energy=True): """ Parameters: ----------- uuid : int A uuid of a given group to generate the cluster structure : Structure A structure object to generate the symmetry operations sc_size : int A list of supercell size to generate symmetry operations process_label : str workchain name to query calculation from energy_threshold : float Tolerance of energy difference threshold. Default = 0.01 symprec : float Tolerance in atomic distance to test if atoms are symmetrically similar. Default = 0.1 (if for positions obtain from electronic structure) if_with_energy : bool If False, to not query energy . Default=True """ self.group_uuid = group_uuid self.structure = structure self.process_label = process_label self.energy_threshold = energy_threshold self.symprec = symprec self.if_with_energy = if_with_energy #self.frac_coords = frac_coords if sc_size is None or sc_size == "": self.sc_size = "1 1 1" else: self.sc_size = sc_size self.structure_sc = structure.copy() self.structure_sc.make_supercell( [int(x) for x in self.sc_size.split()]) # Query nodes, energy, positions QG = QueryCalculationsFromGroup(self.group_uuid, self.process_label) self.uuid = QG.get_relaxed_nodes() self.positions = QG.get_positions() if self.if_with_energy: self.energies = QG.get_energies() else: self.energies = np.zeros([len(self.uuid)]) """#To find the space group symmetry operations of the structure """ SA = SpacegroupAnalyzer(self.structure_sc) self.SG = SpacegroupOperations( SA.get_space_group_number(), SA.get_space_group_symbol(), SA.get_symmetry_operations(cartesian=False))
def test_apply_transformation(self): trans = MagOrderingTransformation({"Fe": 5}) p = Poscar.from_file(os.path.join(test_dir, 'POSCAR.LiFePO4'), check_for_POTCAR=False) s = p.structure alls = trans.apply_transformation(s, 10) self.assertEqual(len(alls), 3) f = SpacegroupAnalyzer(alls[0]["structure"], 0.1) self.assertEqual(f.get_space_group_number(), 31) model = IsingModel(5, 5) trans = MagOrderingTransformation({"Fe": 5}, energy_model=model) alls2 = trans.apply_transformation(s, 10) # Ising model with +J penalizes similar neighbor magmom. self.assertNotEqual(alls[0]["structure"], alls2[0]["structure"]) self.assertEqual(alls[0]["structure"], alls2[2]["structure"]) s = self.get_structure('Li2O') # Li2O doesn't have magnetism of course, but this is to test the # enumeration. trans = MagOrderingTransformation({"Li+": 1}, max_cell_size=3) alls = trans.apply_transformation(s, 100) # TODO: check this is correct, unclear what len(alls) should be self.assertEqual(len(alls), 12) trans = MagOrderingTransformation({"Ni": 5}) alls = trans.apply_transformation(self.NiO.get_primitive_structure(), return_ranked_list=10) self.assertEqual(self.NiO_AFM_111.lattice, alls[0]["structure"].lattice) self.assertEqual(self.NiO_AFM_001.lattice, alls[1]["structure"].lattice)
def set_material_data_from_structure(self, structure, space_group=True, symprec=1e-3, angle_tolerance=5): comp = structure.composition el_amt = structure.composition.get_el_amt_dict() self.unit_cell_formula = comp.as_dict() self.reduced_cell_formula = comp.to_reduced_dict self.elements = list(el_amt.keys()) self.nelements = len(el_amt) self.pretty_formula = comp.reduced_formula self.anonymous_formula = comp.anonymized_formula self.nsites = comp.num_atoms self.chemsys = "-".join(sorted(el_amt.keys())) if space_group: sym = SpacegroupAnalyzer(structure, symprec=symprec, angle_tolerance=angle_tolerance) self.spacegroup = SpaceGroupDocument( crystal_system=sym.get_crystal_system(), hall=sym.get_hall(), number=sym.get_space_group_number(), point_group=sym.get_point_group_symbol(), symbol=sym.get_space_group_symbol(), source="spglib")
def print_info(struc): """ Read a Structure object and print structure information. Args: struc : pymatgen Structure object. Returns: None. """ print(struc) print('\n') sga = SpacegroupAnalyzer(struc) print('The space group: {} {}\n'.format(sga.get_space_group_number(), sga.get_space_group_symbol())) equi_sites = sga.get_symmetrized_structure().equivalent_sites for sites in equi_sites: print('the symmtry equivalent sites are \n{}\n'.format(sites)) sym_operations = sga.get_symmetry_operations() print('there are {} symmetry operations: \n {} \n'.format( len(sym_operations), sym_operations))
def __init__(self, folder_name): """ Run irvsp to compute irreducible representations (irreps) of electronic states from wavefunctions (WAVECAR) and symmetry operations (OUTCAR). Requires a calculation with ISYM=1,2 and LWAVE=.TRUE. Something like "phonopy --tolerance 0.01 --symmetry -c POSCAR" should be used to ensure the crystal is in a standard setting before the calculation. irvsp v2 is needed to handle all 230 space groups (including nonsymmorphic sgs). Args: folder_name (str): Path to directory with POSCAR, OUTCAR and WAVECAR at kpts where irreps should be computed. """ # Check for OUTCAR and WAVECAR if (not path.isfile(folder_name + "/OUTCAR") or not path.isfile(folder_name + "/WAVECAR") or not path.isfile(folder_name + "/POSCAR")): raise FileNotFoundError() os.chdir(folder_name) # Get sg number of structure s = Structure.from_file("POSCAR") sga = SpacegroupAnalyzer(s, symprec=0.01) sgn = sga.get_space_group_number() v = 1 # version 1 of irvsp, symmorphic symmetries # Check if symmorphic (same symm elements as corresponding point group) # REF: http://kuchem.kyoto-u.ac.jp/kinso/weda/data/group/space.pdf fpath = os.path.join(os.path.dirname(__file__), "symmorphic_spacegroups.json") ssgs = loadfn(fpath)["ssgs"] # Remove SGOs from OUTCAR other than identity and inversion to avoid errors #if sgn not in ssgs: # non-symmorphic; this doesn't work! self.modify_outcar() sgn = 2 # SG 2 (only E and I) # Call irvsp cmd_list = ["irvsp", "-sg", str(sgn), "-v", str(v)] with open("outir.txt", "w") as out, open("err.txt", "w") as err: process = subprocess.Popen(cmd_list, stdout=out, stderr=err) process.communicate() # pause while irvsp is executing self.output = None # Process output if path.isfile("outir.txt"): self.output = IRVSPOutput("outir.txt") else: raise FileNotFoundError()
def run_task(self, fw_spec): additional_fields = self.get("additional_fields", {}) # pass the additional_fields first to avoid overriding BoltztrapAnalyzer items d = additional_fields.copy() btrap_dir = os.path.join(os.getcwd(), "boltztrap") d["boltztrap_dir"] = btrap_dir bta = BoltztrapAnalyzer.from_files(btrap_dir) d.update(bta.as_dict()) d["scissor"] = bta.intrans["scissor"] # trim the output for x in ['cond', 'seebeck', 'kappa', 'hall', 'mu_steps', 'mu_doping', 'carrier_conc']: del d[x] if not self.get("hall_doping"): del d["hall_doping"] bandstructure_dir = os.getcwd() d["bandstructure_dir"] = bandstructure_dir # add the structure v, o = get_vasprun_outcar(bandstructure_dir, parse_eigen=False, parse_dos=False) structure = v.final_structure d["structure"] = structure.as_dict() d["formula_pretty"] = structure.composition.reduced_formula d.update(get_meta_from_structure(structure)) # add the spacegroup sg = SpacegroupAnalyzer(Structure.from_dict(d["structure"]), 0.1) d["spacegroup"] = {"symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "source": "spglib", "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall()} d["created_at"] = datetime.utcnow() db_file = env_chk(self.get('db_file'), fw_spec) if not db_file: del d["dos"] with open(os.path.join(btrap_dir, "boltztrap.json"), "w") as f: f.write(json.dumps(d, default=DATETIME_HANDLER)) else: mmdb = VaspCalcDb.from_db_file(db_file, admin=True) # dos gets inserted into GridFS dos = json.dumps(d["dos"], cls=MontyEncoder) fsid, compression = mmdb.insert_gridfs(dos, collection="dos_boltztrap_fs", compress=True) d["dos_boltztrap_fs_id"] = fsid del d["dos"] mmdb.db.boltztrap.insert(d)
def run_task(self, fw_spec): additional_fields = self.get("additional_fields", {}) # pass the additional_fields first to avoid overriding BoltztrapAnalyzer items d = additional_fields.copy() btrap_dir = os.path.join(os.getcwd(), "boltztrap") d["boltztrap_dir"] = btrap_dir bta = BoltztrapAnalyzer.from_files(btrap_dir) d.update(bta.as_dict()) d["scissor"] = bta.intrans["scissor"] # trim the output for x in ['cond', 'seebeck', 'kappa', 'hall', 'mu_steps', 'mu_doping', 'carrier_conc']: del d[x] if not self.get("hall_doping"): del d["hall_doping"] bandstructure_dir = os.getcwd() d["bandstructure_dir"] = bandstructure_dir # add the structure v, o = get_vasprun_outcar(bandstructure_dir, parse_eigen=False, parse_dos=False) structure = v.final_structure d["structure"] = structure.as_dict() d["formula_pretty"] = structure.composition.reduced_formula d.update(get_meta_from_structure(structure)) # add the spacegroup sg = SpacegroupAnalyzer(Structure.from_dict(d["structure"]), 0.1) d["spacegroup"] = {"symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "source": "spglib", "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall()} d["created_at"] = datetime.utcnow() db_file = env_chk(self.get('db_file'), fw_spec) if not db_file: del d["dos"] with open(os.path.join(btrap_dir, "boltztrap.json"), "w") as f: f.write(json.dumps(d, default=DATETIME_HANDLER)) else: mmdb = VaspCalcDb.from_db_file(db_file, admin=True) # dos gets inserted into GridFS dos = json.dumps(d["dos"], cls=MontyEncoder) fsid, compression = mmdb.insert_gridfs(dos, collection="dos_boltztrap_fs", compress=True) d["dos_boltztrap_fs_id"] = fsid del d["dos"] mmdb.db.boltztrap.insert(d)
def print_spg(src='POSCAR'): """ space group を return """ srcpos = Poscar.from_file(src) finder = SpacegroupAnalyzer(srcpos.structure, symprec=5e-2, angle_tolerance=8) spg = finder.get_space_group_symbol() spg_num = finder.get_space_group_number() return spg, spg_num
def debye_find(self): hit = [] phases = [] count = [] for i in self.items: mm = i['metadata'] if mm in hit: count[hit.index(mm)] += 1 else: hit.append(mm) count.append(1) structure = Structure.from_dict(i['structure']) formula_pretty = structure.composition.reduced_formula try: formula2composition(formula_pretty) except: formula_pretty = reduced_formula( structure.composition.alphabetical_formula) sa = SpacegroupAnalyzer(structure) phasename = formula_pretty+'_'\ + sa.get_space_group_symbol().replace('/','.')+'_'+str(sa.get_space_group_number()) if phasename in phases: for jj in range(10000): nphasename = phasename + "#" + str(jj) if nphasename in phases: continue phasename = nphasename break phases.append(phasename) print("\nfound complete calculations in the collection:", self.qhamode, "\n") all_static_calculations = list((self.vasp_db).db['tasks'].\ find({'$and':[{'metadata': { "$exists": True }}, {'adopted': True} ]},\ {'metadata':1, 'output':1, 'input':1, 'orig_inputs':1})) for i, m in enumerate(hit): if self.skipby(phases[i], m['tag']): continue static_calculations = [ f for f in all_static_calculations if f['metadata']['tag'] == m['tag'] ] for ii, calc in enumerate(static_calculations): potsoc = get_used_pot(calc) if self.qhamode == 'qha': potsoc += "_debye" pname = phases[i].split('#') if len(pname) > 1: phases[i] = pname[0] + potsoc + '#' + pname[1] else: phases[i] = pname[0] + potsoc break print(m, ":", phases[i]) self.tags.append({'tag': m['tag'], 'phasename': phases[i]})
def get_spacegroup(strt=""): """ Get spacegroup of a Structure pbject Args: strt: Structure object Returns: num: spacegroup number symb: spacegroup symbol """ finder = SpacegroupAnalyzer(strt) num = finder.get_space_group_number() symb = finder.get_space_group_symbol() return num, symb
def main(): # get args args = parse_arguments() # make output directory out_dir = args.out_dir out_dir_path = path.normpath(path.join(getcwd(), out_dir)) makedirs(out_dir_path, exist_ok=True) cell_dir_path = path.join(out_dir_path, 'cell_image') makedirs(cell_dir_path, exist_ok=True) # load raw dataset structure_path = path.normpath(path.join(getcwd(), args.structure_path)) csv_path = path.normpath(path.join(getcwd(), args.csv_path)) mp_ids_path = path.normpath(path.join(getcwd(), args.mp_ids)) structure_data = h5py.File(structure_path, "r") table_data = pd.read_csv(csv_path, index_col=False) mp_ids = np.load(mp_ids_path) table_data = table_data[table_data['material_id'].isin(mp_ids)] assert len(mp_ids) == len(table_data) cell_nbins = 32 length = len(table_data['material_id'].values) cell_csv = pd.DataFrame( [], columns=['mp_id', 'crystal_system', 'space_group', 'image_name'], index=range(length)) for i, mp_id in tqdm(enumerate(table_data['material_id'].values)): crystal = Structure.from_str(structure_data[mp_id].value, args.fmt) ase_atoms = AseAtomsAdaptor.get_atoms(crystal) cell_atoms = cell_translate(ase_atoms) cell_image, _ = ase_atoms_to_image(cell_atoms, cell_nbins, args.atom_list, args.jobs) # save cell image image_name = mp_id.replace('-', '_') cell_save_path = path.join(cell_dir_path, image_name) np.save('{}.npy'.format(cell_save_path), cell_image) # save basis image finder = SpacegroupAnalyzer(crystal) crystal_system = finder.get_crystal_system() space_group_num = finder.get_space_group_number() cell_csv.iloc[i] = [mp_id, crystal_system, space_group_num, image_name] # save cell_csv_save_path = path.join(out_dir_path, 'cell_image.csv') cell_csv.to_csv(cell_csv_save_path) return True
def print_spg(src='POSCAR'): """ 空間群を出力 """ srcpos = Poscar.from_file(src) # srcpos.structure | fnc.echo finder = SpacegroupAnalyzer(srcpos.structure, symprec=5e-2, angle_tolerance=8) # dir(finder) | fnc.echo # srcpos | fnc.echo # help(finder.get_space_group_symbol) # finder._space_group_data | fnc.echo spg = finder.get_space_group_symbol() spg_num = finder.get_space_group_number() print(spg) print(spg_num)
def analyze_symmetry(request): results = {} symprec = float(request.POST["symprec"]) angle_tolerance = float(request.POST["angle_tolerance"]) for name, f in request.FILES.items(): name, s = get_structure(f) a = SpacegroupAnalyzer(s, symprec=symprec, angle_tolerance=angle_tolerance) d = {} d["international"] = a.get_space_group_symbol() d["number"] = a.get_space_group_number() d["hall"] = a.get_hall() d["point_group"] = a.get_point_group() d["crystal_system"] = a.get_crystal_system() results[name] = d return results
def featurize(self, s): sga = SpacegroupAnalyzer(s) output = [] if "spacegroup_num" in self.features: output.append(sga.get_space_group_number()) if "crystal_system" in self.features: output.append(sga.get_crystal_system()) if "crystal_system_int" in self.features: output.append(GlobalSymmetryFeatures.crystal_idx[ sga.get_crystal_system()]) if "is_centrosymmetric" in self.features: output.append(sga.is_laue()) return output
def debye_find(self): hit = [] phases = [] count = [] for i in self.items: """ try: ii = len(i['debye']) mm = i['metadata'] except: continue if ii < 6: continue """ mm = i['metadata'] if mm in hit: count[hit.index(mm)] += 1 else: hit.append(mm) count.append(1) structure = Structure.from_dict(i['structure']) formula_pretty = structure.composition.reduced_formula try: formula2composition(formula_pretty) except: formula_pretty = reduced_formula( structure.composition.alphabetical_formula) sa = SpacegroupAnalyzer(structure) phasename = formula_pretty+'_'\ + sa.get_space_group_symbol().replace('/','.')+'_'+str(sa.get_space_group_number()) if phasename in phases: for jj in range(10000): nphasename = phasename + "#" + str(jj) if nphasename in phases: continue phasename = nphasename break phases.append(phasename) print("\nfound complete calculations in the collection:", self.qhamode, "\n") for i, m in enumerate(hit): if self.skipby(phases[i], m['tag']): continue print(m, ":", phases[i]) self.tags.append({'tag': m['tag'], 'phasename': phases[i]})
def get_raman_modes(self) -> List[int]: space_group_calculater = SpacegroupAnalyzer(self.structure) symmetrized_structure = space_group_calculater.get_symmetrized_structure() space_group = space_group_calculater.get_space_group_number() wyckoff = symmetrized_structure.wyckoff_symbols with open("utils/reformed_raman_modes.json") as f: raman_table = json.load(f) all_modes = raman_table["all_modes"] mode_check_table = raman_table["all_spgp"][space_group-1]["modes"] mode_check_table = DataFrame.from_dict(mode_check_table) keys = mode_check_table.keys() for i in range(len(all_modes)): mode = all_modes[i] all_modes[i] = 0 if mode in keys: modes_with_wyckoff = mode_check_table[mode] for wp in wyckoff: if modes_with_wyckoff[wp] != 0: all_modes[i] = 1 return all_modes
def test_single_specie(self): # print("test_h2o") struc = molecular_crystal(36, ["H2O"], [4], sites=[["8b"]]) struc.to_file() self.assertTrue(struc.valid) # test space group pmg_struc = struc.to_pymatgen() sga = SpacegroupAnalyzer(pmg_struc) # print(sga.get_space_group_symbol()) self.assertTrue(sga.get_space_group_number() >= 36) # print(pmg_struc.frac_coords[:3]) # test rotation ax = struc.mol_sites[0].orientation.axis struc.mol_sites[0].rotate(axis=[1, 0, 0], angle=90) pmg_struc = struc.to_pymatgen() sga = SpacegroupAnalyzer(pmg_struc) pmg_struc.to("cif", "1.cif") self.assertTrue(sga.get_space_group_symbol() == "Cmc2_1")
def redundancy_check(blank_coords, adsonly_positions, fp_dict, repeat_unit_cell, symmetry_tol): inv_ruc = np.linalg.inv(repeat_unit_cell) atoms = Atoms() for c in blank_coords: atoms.append(Atom(c[0], c[1])) formula = atoms.get_chemical_formula() atoms.set_cell(repeat_unit_cell.T) atoms.pbc = True struct = AseAtomsAdaptor.get_structure(atoms) sga = SpacegroupAnalyzer(struct, symprec=symmetry_tol) sgs = sga.get_space_group_symbol() sgn = sga.get_space_group_number() adsonly_positions = np.asarray(adsonly_positions) dists = [] for i in range(len(adsonly_positions)): icoord = np.dot(inv_ruc, adsonly_positions[i]) for j in range(i + 1, len(adsonly_positions)): jcoord = np.dot(inv_ruc, adsonly_positions[j]) fdist, sym = PBC3DF_sym(icoord, jcoord) dist = np.linalg.norm(np.dot(repeat_unit_cell, fdist)) dists.append(dist) dists.sort() index = 0 advance = True for ind in range(len(fp_dict[sgn])): fp = fp_dict[sgn][ind] if len(fp) == len(dists): if np.allclose(fp, dists): index = ind advance = False break index = str(index) return advance, index, sgs, sgn, dists, atoms, formula
def test_apply_transformation(self): trans = MagOrderingTransformation({"Fe": 5}) p = Poscar.from_file(os.path.join(test_dir, "POSCAR.LiFePO4"), check_for_POTCAR=False) s = p.structure alls = trans.apply_transformation(s, 10) self.assertEqual(len(alls), 3) f = SpacegroupAnalyzer(alls[0]["structure"], 0.1) self.assertEqual(f.get_space_group_number(), 31) model = IsingModel(5, 5) trans = MagOrderingTransformation({"Fe": 5}, energy_model=model) alls2 = trans.apply_transformation(s, 10) # Ising model with +J penalizes similar neighbor magmom. self.assertNotEqual(alls[0]["structure"], alls2[0]["structure"]) self.assertEqual(alls[0]["structure"], alls2[2]["structure"]) s = self.get_structure("Li2O") # Li2O doesn't have magnetism of course, but this is to test the # enumeration. trans = MagOrderingTransformation({"Li+": 1}, max_cell_size=3) alls = trans.apply_transformation(s, 100) self.assertEqual(len(alls), 10)
def add_cifs(doc): struc = Structure.from_dict(doc["structure"]) sym_finder = SpacegroupAnalyzer(struc, symprec=0.1) doc["cif"] = str(CifWriter(struc)) doc["cifs"] = {} if sym_finder.get_hall(): primitive = sym_finder.get_primitive_standard_structure() conventional = sym_finder.get_conventional_standard_structure() refined = sym_finder.get_refined_structure() doc["cifs"]["primitive"] = str(CifWriter(primitive)) doc["cifs"]["refined"] = str(CifWriter(refined)) doc["cifs"]["conventional_standard"] = str(CifWriter(conventional)) doc["cifs"]["computed"] = str(CifWriter(struc)) doc["spacegroup"]["symbol"] = sym_finder.get_space_group_symbol() doc["spacegroup"]["number"] = sym_finder.get_space_group_number() doc["spacegroup"]["point_group"] = sym_finder.get_point_group_symbol() doc["spacegroup"]["crystal_system"] = sym_finder.get_crystal_system() doc["spacegroup"]["hall"] = sym_finder.get_hall() else: doc["cifs"]["primitive"] = None doc["cifs"]["refined"] = None doc["cifs"]["conventional_standard"] = None
def prepare_spacegroup(spg: SpacegroupAnalyzer): """Given a spacegroup pypatgen object, return a dictionary to be sent to jinja. This includes the international number, and the name in Hermann-Mauguin notation nicely formatted in HTML (so, will need the `safe` filter).""" return { "international_number": spg.get_space_group_number(), "hm_name": spg.get_space_group_symbol().replace( "-1", '<span style="text-decoration:overline;">1</span>').replace( "-3", '<span style="text-decoration:overline;">3</span>').replace( "-4", '<span style="text-decoration:overline;">4</span>'). replace("-6", '<span style="text-decoration:overline;">6</span>').replace( "_1", "<sub>1</sub>").replace("_2", "<sub>2</sub>").replace( "_3", "<sub>3</sub>").replace("_4", "<sub>4</sub>").replace( "_5", "<sub>5</sub>"), }
def structure_symmetry(): structs, fnames = read_structures() multi_structs(structs, fnames) for struct, fname in zip(structs, fnames): if isinstance(struct, Structure): sa = SpacegroupAnalyzer(struct) print("file name: {}".format(fname)) print("{} : {}".format('Structure Type', 'periodicity')) print("{} : {}".format('Lattice Type', sa.get_lattice_type())) print("{} : {}".format('Space Group ID', sa.get_space_group_number())) print("{} : {}".format('International Symbol', sa.get_space_group_symbol())) print("{} : {}".format('Hall Symbol', sa.get_hall())) sepline() if isinstance(struct, Molecule): print("file name: {}".format(fname)) sa = PointGroupAnalyzer(struct) print("{} : {}".format('Structure Type', 'non-periodicity')) print("{} : {}".format('International Symbol', ast.get_pointgroup())) return True
def create(**kwargs): """ Generate deformed structures for calculating deformation potentials. """ from pymatgen.core.structure import Structure from pymatgen.core.tensors import symmetry_reduce from pymatgen.symmetry.analyzer import SpacegroupAnalyzer from pymatgen.util.string import unicodeify_spacegroup from amset.deformation.common import get_formatted_tensors from amset.deformation.generation import get_deformations, get_deformed_structures from amset.deformation.io import write_deformed_poscars symprec = _parse_symprec(kwargs["symprec"]) structure = Structure.from_file(kwargs["filename"]) click.echo("Generating deformations:") click.echo(" - Strain distance: {:g}".format(kwargs["distance"])) deformations = get_deformations(kwargs["distance"]) click.echo(" - # Total deformations: {}".format(len(deformations))) if symprec is not None: sga = SpacegroupAnalyzer(structure, symprec=symprec) spg_symbol = unicodeify_spacegroup(sga.get_space_group_symbol()) spg_number = sga.get_space_group_number() click.echo(" - Spacegroup: {} ({})".format(spg_symbol, spg_number)) deformations = list(symmetry_reduce(deformations, structure, symprec=symprec)) click.echo(" - # Inequivalent deformations: {}".format(len(deformations))) click.echo("\nDeformations:") click.echo(" - " + "\n - ".join(get_formatted_tensors(deformations))) deformed_structures = get_deformed_structures(structure, deformations) write_deformed_poscars(deformed_structures, directory=kwargs["directory"]) click.echo("\nDeformed structures have been created")
def set_output_data(self, d_calc, d): """ set the 'output' key """ d["output"] = { "structure": d_calc["output"]["structure"], "density": d_calc.pop("density"), "energy": d_calc["output"]["energy"], "energy_per_atom": d_calc["output"]["energy_per_atom"]} d["output"].update(self.get_basic_processed_data(d)) sg = SpacegroupAnalyzer(Structure.from_dict(d_calc["output"]["structure"]), 0.1) if not sg.get_symmetry_dataset(): sg = SpacegroupAnalyzer(Structure.from_dict(d_calc["output"]["structure"]), 1e-3, 1) d["output"]["spacegroup"] = { "source": "spglib", "symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall()} if d["input"]["parameters"].get("LEPSILON"): for k in ['epsilon_static', 'epsilon_static_wolfe', 'epsilon_ionic']: d["output"][k] = d_calc["output"][k]
class SpacegroupAnalyzerTest(PymatgenTest): def setUp(self): p = Poscar.from_file(os.path.join(test_dir, 'POSCAR')) self.structure = p.structure self.sg = SpacegroupAnalyzer(self.structure, 0.001) self.disordered_structure = self.get_structure('Li10GeP2S12') self.disordered_sg = SpacegroupAnalyzer(self.disordered_structure, 0.001) s = p.structure.copy() site = s[0] del s[0] s.append(site.species_and_occu, site.frac_coords) self.sg3 = SpacegroupAnalyzer(s, 0.001) graphite = self.get_structure('Graphite') graphite.add_site_property("magmom", [0.1] * len(graphite)) self.sg4 = SpacegroupAnalyzer(graphite, 0.001) self.structure4 = graphite def test_primitive(self): s = Structure.from_spacegroup("Fm-3m", np.eye(3) * 3, ["Cu"], [[0, 0, 0]]) a = SpacegroupAnalyzer(s) self.assertEqual(len(s), 4) self.assertEqual(len(a.find_primitive()), 1) def test_magnetic(self): lfp = PymatgenTest.get_structure("LiFePO4") sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_space_group_symbol(), "Pnma") magmoms = [0] * len(lfp) magmoms[4] = 1 magmoms[5] = -1 magmoms[6] = 1 magmoms[7] = -1 lfp.add_site_property("magmom", magmoms) sg = SpacegroupAnalyzer(lfp, 0.1) self.assertEqual(sg.get_space_group_symbol(), "Pnma") def test_get_space_symbol(self): self.assertEqual(self.sg.get_space_group_symbol(), "Pnma") self.assertEqual(self.disordered_sg.get_space_group_symbol(), "P4_2/nmc") self.assertEqual(self.sg3.get_space_group_symbol(), "Pnma") self.assertEqual(self.sg4.get_space_group_symbol(), "P6_3/mmc") def test_get_space_number(self): self.assertEqual(self.sg.get_space_group_number(), 62) self.assertEqual(self.disordered_sg.get_space_group_number(), 137) self.assertEqual(self.sg4.get_space_group_number(), 194) def test_get_hall(self): self.assertEqual(self.sg.get_hall(), '-P 2ac 2n') self.assertEqual(self.disordered_sg.get_hall(), 'P 4n 2n -1n') def test_get_pointgroup(self): self.assertEqual(self.sg.get_point_group_symbol(), 'mmm') self.assertEqual(self.disordered_sg.get_point_group_symbol(), '4/mmm') def test_get_symmetry_dataset(self): ds = self.sg.get_symmetry_dataset() self.assertEqual(ds['international'], 'Pnma') def test_get_crystal_system(self): crystal_system = self.sg.get_crystal_system() self.assertEqual('orthorhombic', crystal_system) self.assertEqual('tetragonal', self.disordered_sg.get_crystal_system()) def test_get_symmetry_operations(self): for sg, structure in [(self.sg, self.structure), (self.sg4, self.structure4)]: pgops = sg.get_point_group_operations() fracsymmops = sg.get_symmetry_operations() symmops = sg.get_symmetry_operations(True) latt = structure.lattice for fop, op, pgop in zip(fracsymmops, symmops, pgops): # translation vector values should all be 0 or 0.5 t = fop.translation_vector * 2 self.assertArrayAlmostEqual(t - np.round(t), 0) self.assertArrayAlmostEqual(fop.rotation_matrix, pgop.rotation_matrix) for site in structure: newfrac = fop.operate(site.frac_coords) newcart = op.operate(site.coords) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac)) found = False newsite = PeriodicSite(site.species_and_occu, newcart, latt, coords_are_cartesian=True) for testsite in structure: if newsite.is_periodic_image(testsite, 1e-3): found = True break self.assertTrue(found) # Make sure this works for any position, not just the atomic # ones. random_fcoord = np.random.uniform(size=(3)) random_ccoord = latt.get_cartesian_coords(random_fcoord) newfrac = fop.operate(random_fcoord) newcart = op.operate(random_ccoord) self.assertTrue(np.allclose(latt.get_fractional_coords(newcart), newfrac)) def test_get_refined_structure(self): for a in self.sg.get_refined_structure().lattice.angles: self.assertEqual(a, 90) refined = self.disordered_sg.get_refined_structure() for a in refined.lattice.angles: self.assertEqual(a, 90) self.assertEqual(refined.lattice.a, refined.lattice.b) s = self.get_structure('Li2O') sg = SpacegroupAnalyzer(s, 0.001) self.assertEqual(sg.get_refined_structure().num_sites, 4 * s.num_sites) def test_get_symmetrized_structure(self): symm_struct = self.sg.get_symmetrized_structure() for a in symm_struct.lattice.angles: self.assertEqual(a, 90) self.assertEqual(len(symm_struct.equivalent_sites), 5) symm_struct = self.disordered_sg.get_symmetrized_structure() self.assertEqual(len(symm_struct.equivalent_sites), 8) self.assertEqual([len(i) for i in symm_struct.equivalent_sites], [16,4,8,4,2,8,8,8]) s1 = symm_struct.equivalent_sites[1][1] s2 = symm_struct[symm_struct.equivalent_indices[1][1]] self.assertEqual(s1, s2) self.assertEqual(self.sg4.get_symmetrized_structure()[0].magmom, 0.1) self.assertEqual(symm_struct.wyckoff_symbols[0], '16h') # self.assertEqual(symm_struct[0].wyckoff, "16h") def test_find_primitive(self): """ F m -3 m Li2O testing of converting to primitive cell """ parser = CifParser(os.path.join(test_dir, 'Li2O.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure) primitive_structure = s.find_primitive() self.assertEqual(primitive_structure.formula, "Li2 O1") # This isn't what is expected. All the angles should be 60 self.assertAlmostEqual(primitive_structure.lattice.alpha, 60) self.assertAlmostEqual(primitive_structure.lattice.beta, 60) self.assertAlmostEqual(primitive_structure.lattice.gamma, 60) self.assertAlmostEqual(primitive_structure.lattice.volume, structure.lattice.volume / 4.0) def test_get_ir_reciprocal_mesh(self): grid = self.sg.get_ir_reciprocal_mesh() self.assertEqual(len(grid), 216) self.assertAlmostEqual(grid[1][0][0], 0.1) self.assertAlmostEqual(grid[1][0][1], 0.0) self.assertAlmostEqual(grid[1][0][2], 0.0) self.assertAlmostEqual(grid[1][1], 2) def test_get_conventional_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.b, 9.1980270633769461) self.assertAlmostEqual(conv.lattice.c, 9.1980270633769461) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.b, 5.0615106678044235) self.assertAlmostEqual(conv.lattice.c, 4.2327080177761687) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 2.9542233922299999) self.assertAlmostEqual(conv.lattice.b, 4.6330325651443296) self.assertAlmostEqual(conv.lattice.c, 5.373703587040775) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 4.1430033493799998) self.assertAlmostEqual(conv.lattice.b, 31.437979757624728) self.assertAlmostEqual(conv.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 117.53832420192903) self.assertAlmostEqual(conv.lattice.gamma, 90) self.assertAlmostEqual(conv.lattice.a, 14.033435583000625) self.assertAlmostEqual(conv.lattice.b, 3.96052850731) self.assertAlmostEqual(conv.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'hex_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) conv = s.get_conventional_standard_structure() self.assertAlmostEqual(conv.lattice.alpha, 90) self.assertAlmostEqual(conv.lattice.beta, 90) self.assertAlmostEqual(conv.lattice.gamma, 120) self.assertAlmostEqual(conv.lattice.a, 3.699919902005897) self.assertAlmostEqual(conv.lattice.b, 3.699919902005897) self.assertAlmostEqual(conv.lattice.c, 6.9779585500000003) def test_get_primitive_standard_structure(self): parser = CifParser(os.path.join(test_dir, 'bcc_1927.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 109.47122063400001) self.assertAlmostEqual(prim.lattice.beta, 109.47122063400001) self.assertAlmostEqual(prim.lattice.gamma, 109.47122063400001) self.assertAlmostEqual(prim.lattice.a, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.b, 7.9657251015812145) self.assertAlmostEqual(prim.lattice.c, 7.9657251015812145) parser = CifParser(os.path.join(test_dir, 'btet_1915.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 105.015053349) self.assertAlmostEqual(prim.lattice.beta, 105.015053349) self.assertAlmostEqual(prim.lattice.gamma, 118.80658411899999) self.assertAlmostEqual(prim.lattice.a, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.b, 4.1579321075608791) self.assertAlmostEqual(prim.lattice.c, 4.1579321075608791) parser = CifParser(os.path.join(test_dir, 'orci_1010.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 134.78923546600001) self.assertAlmostEqual(prim.lattice.beta, 105.856239333) self.assertAlmostEqual(prim.lattice.gamma, 91.276341676000001) self.assertAlmostEqual(prim.lattice.a, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.b, 3.8428217771014852) self.assertAlmostEqual(prim.lattice.c, 3.8428217771014852) parser = CifParser(os.path.join(test_dir, 'orcc_1003.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 164.985257335) self.assertAlmostEqual(prim.lattice.a, 15.854897098324196) self.assertAlmostEqual(prim.lattice.b, 15.854897098324196) self.assertAlmostEqual(prim.lattice.c, 3.99648651) parser = CifParser(os.path.join(test_dir, 'monoc_1028.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 63.579155761999999) self.assertAlmostEqual(prim.lattice.beta, 116.42084423747779) self.assertAlmostEqual(prim.lattice.gamma, 148.47965136208569) self.assertAlmostEqual(prim.lattice.a, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.b, 7.2908007159612325) self.assertAlmostEqual(prim.lattice.c, 6.8743926325200002) parser = CifParser(os.path.join(test_dir, 'hex_1170.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 90) self.assertAlmostEqual(prim.lattice.beta, 90) self.assertAlmostEqual(prim.lattice.gamma, 120) self.assertAlmostEqual(prim.lattice.a, 3.699919902005897) self.assertAlmostEqual(prim.lattice.b, 3.699919902005897) self.assertAlmostEqual(prim.lattice.c, 6.9779585500000003) parser = CifParser(os.path.join(test_dir, 'rhomb_3478_conv.cif')) structure = parser.get_structures(False)[0] s = SpacegroupAnalyzer(structure, symprec=1e-2) prim = s.get_primitive_standard_structure() self.assertAlmostEqual(prim.lattice.alpha, 28.049186140546812) self.assertAlmostEqual(prim.lattice.beta, 28.049186140546812) self.assertAlmostEqual(prim.lattice.gamma, 28.049186140546812) self.assertAlmostEqual(prim.lattice.a, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.b, 5.9352627428399982) self.assertAlmostEqual(prim.lattice.c, 5.9352627428399982)
def analyze(self): from aiida.orm.data.parameter import ParameterData import numpy as np x_material = self.get_parameter("x_material") a_sweep = self.get_attribute("a_sweep") aiidalogger.info("Retrieving a_sweep as {0}".format(a_sweep)) # Get calculations start_calcs = self.get_step_calculations(self.stress_tensor) # .get_calculations() # Calculate results #----------------------------------------- alat_steps = params['alat_steps'] s_calcs = np.linspace(-0.002, 0.002, alat_steps).tolist() e_calcs = [c.res.energy for c in start_calcs] v_calcs = [c.res.volume for c in start_calcs] e_calcs = zip(*sorted(zip(a_sweep, e_calcs)))[1] v_calcs = zip(*sorted(zip(a_sweep, v_calcs)))[1] s_calcs = zip(*sorted(zip(a_sweep, s_calcs)))[1] # Add to report #----------------------------------------- for i in range(len(a_sweep)): self.append_to_report(x_material + "Ti03 simulated with a=" + str(a_sweep[i]) + ", s=" + str(s_calcs[i]) + ", e=" + str(e_calcs[i])) s_pymatgen = s.get_pymatgen() import pymatgen as mg from pymatgen.symmetry.analyzer import SpacegroupAnalyzer finder = SpacegroupAnalyzer(s_pymatgen) SGN = finder.get_space_group_number() #%!%!%--- Classify the Space-Group Number ---%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%! if (1 <= SGN and SGN <= 2): # Triclinic LC = 'N' SCs= 6 elif(3 <= SGN and SGN <= 15): # Monoclinic LC = 'M' SCs= 4 elif(16 <= SGN and SGN <= 74): # Orthorhombic LC = 'O' SCs= 3 elif(75 <= SGN and SGN <= 88): # Tetragonal II LC = 'TII' SCs= 2 elif(89 <= SGN and SGN <= 142): # Tetragonal I LC = 'TI' SCs= 2 elif(143 <= SGN and SGN <= 148): # Rhombohedral II LC = 'RII' SCs= 2 elif(149 <= SGN and SGN <= 167): # Rhombohedral I LC = 'RI' SCs= 2 elif(168 <= SGN and SGN <= 176): # Hexagonal II LC = 'HII' SCs= 2 elif(177 <= SGN and SGN <= 194): # Hexagonal I LC = 'HI' SCs= 2 elif(195 <= SGN and SGN <= 206): # Cubic II LC = 'CII' SCs= 1 elif(207 <= SGN and SGN <= 230): # Cubic I LC = 'CI' SCs= 1 else: sys.exit('\n ... Oops ERROR: WRONG Space-Group Number !?!?!?\n') #%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%# #%!%!% ------------ Calculating the first derivative and Cross-Validation Error ------------ %!%!%# #%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%# A1 = [] mdri = 0.002 ordri = 1 strain = [] energy = [] strain = copy.copy(s_calcs) energy = copy.copy(e_calcs) coeffs = np.polyfit(strain, energy, ordri) A1.append(coeffs[ordri-1]) A1 = np.array(A1) if (len(A1) != SCs): sys.exit('\n ... Oops ERROR: The number of data is NOT equal to ' + \ str(SCs)+'\n') S = zeros((3,3)) #%!%!%--- Cubic structures ---%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!% if (LC == 'CI' or \ LC == 'CII'): S[0,0] = A1[0]/3. S[1,1] = S[0,0] S[2,2] = S[0,0] #-------------------------------------------------------------------------------------------------- #%!%!%--- Hexagonal, Rhombohedral, and Tetragonal structures ---%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!% if (LC == 'HI' or \ LC == 'HII'or \ LC == 'RI' or \ LC == 'RII'or \ LC == 'TI' or \ LC == 'TII'): S[0,0] = (A1[0] - 1.*A1[1])/3. S[1,1] = S[0,0] S[2,2] = (A1[0] + 2.*A1[1])/3. #-------------------------------------------------------------------------------------------------- #%!%!%--- Orthorhombic structures ---%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%! if (LC == 'O'): S[0,0] = (A1[0] - 2.*A1[1] - 2.*A1[2])/3. S[1,1] = (A1[0] + 2.*A1[1])/3. S[2,2] = (A1[0] + 2.*A1[2])/3. #-------------------------------------------------------------------------------------------------- #%!%!%--- Monoclinic structures ---%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%! if (LC == 'M'): S[0,0] = (A1[0] - 2.*A1[1] - 2.*A1[2])/3. S[1,1] = (A1[0] + 2.*A1[1])/3. S[2,2] = (A1[0] + 2.*A1[2])/3. if (unique_axis == 'a'): S[1,2] = A1[3]/2. if (unique_axis == 'b'): S[0,2] = A1[3]/2. if (unique_axis == 'c'): S[0,1] = A1[3]/2. #-------------------------------------------------------------------------------------------------- #%!%!%--- Triclinic structures ---%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!% if (LC == 'N'): S[0,0] = (A1[0] + 2.* A1[2])/3., S[1,1] = (A1[0] + 2.* A1[1])/3., S[2,2] = (A1[0] - 2.*(A1[1] + A1[2]))/3., S[1,2] = A1[3]/2., S[0,2] = A1[4]/2., S[0,1] = A1[5]/2. #-------------------------------------------------------------------------------------------------- #%!%!%--- Calculating the Pressure ---%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!%!% for i in range(2): for j in range(i+1, 3): S[j,i] = S[i,j] eV_over_ang3_toGPa = 160.21766208 v0i = int((alat_steps + 1) / 2) V0 = v_calcs [v0i] S = S / V0 * eV_over_ang3_toGPa P = (S[0,0]+S[1,1]+S[2,2])/-3.*eV_over_ang3_toGPa #-------------------------------------------------------------------------------------------------- self.append_to_report(x_material + "Ti03 simulated with a=" + str(a_sweep[v0i]) + ", e=" + str(e_calcs[v0i])) self.append_to_report("stress tensor matrix = " + str(S[0,0]) + str(S[0,1]) + str(S[0,2])) self.append_to_report("stress tensor matrix = " + str(S[1,0]) + str(S[1,1]) + str(S[1,2])) self.append_to_report("stress tensor matrix = " + str(S[2,0]) + str(S[2,1]) + str(S[2,2])) self.append_to_report("external pressure in GPa = " + str(P) ) self.next(self.exit)
def __init__(self, struct, symprec=None): format_str = "{:.8f}" block = OrderedDict() loops = [] spacegroup = ("P 1", 1) if symprec is not None: sf = SpacegroupAnalyzer(struct, symprec) spacegroup = (sf.get_space_group_symbol(), sf.get_space_group_number()) # Needs the refined struture when using symprec. This converts # primitive to conventional structures, the standard for CIF. struct = sf.get_refined_structure() latt = struct.lattice comp = struct.composition no_oxi_comp = comp.element_composition block["_symmetry_space_group_name_H-M"] = spacegroup[0] for cell_attr in ['a', 'b', 'c']: block["_cell_length_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) for cell_attr in ['alpha', 'beta', 'gamma']: block["_cell_angle_" + cell_attr] = format_str.format( getattr(latt, cell_attr)) block["_symmetry_Int_Tables_number"] = spacegroup[1] block["_chemical_formula_structural"] = no_oxi_comp.reduced_formula block["_chemical_formula_sum"] = no_oxi_comp.formula block["_cell_volume"] = latt.volume.__str__() reduced_comp, fu = no_oxi_comp.get_reduced_composition_and_factor() block["_cell_formula_units_Z"] = str(int(fu)) if symprec is None: block["_symmetry_equiv_pos_site_id"] = ["1"] block["_symmetry_equiv_pos_as_xyz"] = ["x, y, z"] else: sf = SpacegroupAnalyzer(struct, symprec) def round_symm_trans(i): for t in TRANSLATIONS.values(): if abs(i - t) < symprec: return t if abs(i - round(i)) < symprec: return 0 raise ValueError("Invalid translation!") symmops = [] for op in sf.get_symmetry_operations(): v = op.translation_vector v = [round_symm_trans(i) for i in v] symmops.append(SymmOp.from_rotation_and_translation( op.rotation_matrix, v)) ops = [op.as_xyz_string() for op in symmops] block["_symmetry_equiv_pos_site_id"] = \ ["%d" % i for i in range(1, len(ops) + 1)] block["_symmetry_equiv_pos_as_xyz"] = ops loops.append(["_symmetry_equiv_pos_site_id", "_symmetry_equiv_pos_as_xyz"]) contains_oxidation = True try: symbol_to_oxinum = OrderedDict([ (el.__str__(), float(el.oxi_state)) for el in sorted(comp.elements)]) except AttributeError: symbol_to_oxinum = OrderedDict([(el.symbol, 0) for el in sorted(comp.elements)]) contains_oxidation = False if contains_oxidation: block["_atom_type_symbol"] = symbol_to_oxinum.keys() block["_atom_type_oxidation_number"] = symbol_to_oxinum.values() loops.append(["_atom_type_symbol", "_atom_type_oxidation_number"]) atom_site_type_symbol = [] atom_site_symmetry_multiplicity = [] atom_site_fract_x = [] atom_site_fract_y = [] atom_site_fract_z = [] atom_site_label = [] atom_site_occupancy = [] count = 1 if symprec is None: for site in struct: for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("1") atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 else: # The following just presents a deterministic ordering. unique_sites = [ (sorted(sites, key=lambda s: tuple([abs(x) for x in s.frac_coords]))[0], len(sites)) for sites in sf.get_symmetrized_structure().equivalent_sites ] for site, mult in sorted( unique_sites, key=lambda t: (t[0].species_and_occu.average_electroneg, -t[1], t[0].a, t[0].b, t[0].c)): for sp, occu in site.species_and_occu.items(): atom_site_type_symbol.append(sp.__str__()) atom_site_symmetry_multiplicity.append("%d" % mult) atom_site_fract_x.append("{0:f}".format(site.a)) atom_site_fract_y.append("{0:f}".format(site.b)) atom_site_fract_z.append("{0:f}".format(site.c)) atom_site_label.append("{}{}".format(sp.symbol, count)) atom_site_occupancy.append(occu.__str__()) count += 1 block["_atom_site_type_symbol"] = atom_site_type_symbol block["_atom_site_label"] = atom_site_label block["_atom_site_symmetry_multiplicity"] = \ atom_site_symmetry_multiplicity block["_atom_site_fract_x"] = atom_site_fract_x block["_atom_site_fract_y"] = atom_site_fract_y block["_atom_site_fract_z"] = atom_site_fract_z block["_atom_site_occupancy"] = atom_site_occupancy loops.append(["_atom_site_type_symbol", "_atom_site_label", "_atom_site_symmetry_multiplicity", "_atom_site_fract_x", "_atom_site_fract_y", "_atom_site_fract_z", "_atom_site_occupancy"]) d = OrderedDict() d[comp.reduced_formula] = CifBlock(block, loops, comp.reduced_formula) self._cf = CifFile(d)
def get_energy(self, structure): f = SpacegroupAnalyzer(structure, symprec=self.symprec, angle_tolerance=self.angle_tolerance) return -f.get_space_group_number()
def get_sg(s): finder = SpacegroupAnalyzer(s, symprec=self.symprec) return finder.get_space_group_number()
def get_sg_info(ss): finder = SpacegroupAnalyzer(Structure.from_sites(ss), self.symm_prec) return finder.get_space_group_number()
def _gen_input_file(self): """ Generate the necessary struct_enum.in file for enumlib. See enumlib documentation for details. """ coord_format = "{:.6f} {:.6f} {:.6f}" # Using symmetry finder, get the symmetrically distinct sites. fitter = SpacegroupAnalyzer(self.structure, self.symm_prec) symmetrized_structure = fitter.get_symmetrized_structure() logger.debug("Spacegroup {} ({}) with {} distinct sites".format( fitter.get_space_group_symbol(), fitter.get_space_group_number(), len(symmetrized_structure.equivalent_sites)) ) """ Enumlib doesn"t work when the number of species get too large. To simplify matters, we generate the input file only with disordered sites and exclude the ordered sites from the enumeration. The fact that different disordered sites with the exact same species may belong to different equivalent sites is dealt with by having determined the spacegroup earlier and labelling the species differently. """ # index_species and index_amounts store mappings between the indices # used in the enum input file, and the actual species and amounts. index_species = [] index_amounts = [] # Stores the ordered sites, which are not enumerated. ordered_sites = [] disordered_sites = [] coord_str = [] for sites in symmetrized_structure.equivalent_sites: if sites[0].is_ordered: ordered_sites.append(sites) else: sp_label = [] species = {k: v for k, v in sites[0].species_and_occu.items()} if sum(species.values()) < 1 - EnumlibAdaptor.amount_tol: # Let us first make add a dummy element for every single # site whose total occupancies don't sum to 1. species[DummySpecie("X")] = 1 - sum(species.values()) for sp in species.keys(): if sp not in index_species: index_species.append(sp) sp_label.append(len(index_species) - 1) index_amounts.append(species[sp] * len(sites)) else: ind = index_species.index(sp) sp_label.append(ind) index_amounts[ind] += species[sp] * len(sites) sp_label = "/".join(["{}".format(i) for i in sorted(sp_label)]) for site in sites: coord_str.append("{} {}".format( coord_format.format(*site.coords), sp_label)) disordered_sites.append(sites) def get_sg_info(ss): finder = SpacegroupAnalyzer(Structure.from_sites(ss), self.symm_prec) return finder.get_space_group_number() curr_sites = list(itertools.chain.from_iterable(disordered_sites)) min_sgnum = get_sg_info(curr_sites) logger.debug("Disordered sites has sgnum %d" % ( min_sgnum)) # It could be that some of the ordered sites has a lower symmetry than # the disordered sites. So we consider the lowest symmetry sites as # disordered in our enumeration. self.ordered_sites = [] to_add = [] if self.check_ordered_symmetry: for sites in ordered_sites: temp_sites = list(curr_sites) + sites sgnum = get_sg_info(temp_sites) if sgnum < min_sgnum: logger.debug("Adding {} to sites to be ordered. " "New sgnum {}" .format(sites, sgnum)) to_add = sites min_sgnum = sgnum for sites in ordered_sites: if sites == to_add: index_species.append(sites[0].specie) index_amounts.append(len(sites)) sp_label = len(index_species) - 1 logger.debug("Lowest symmetry {} sites are included in enum." .format(sites[0].specie)) for site in sites: coord_str.append("{} {}".format( coord_format.format(*site.coords), sp_label)) disordered_sites.append(sites) else: self.ordered_sites.extend(sites) self.index_species = index_species lattice = self.structure.lattice output = [self.structure.formula, "bulk"] for vec in lattice.matrix: output.append(coord_format.format(*vec)) output.append("{}".format(len(index_species))) output.append("{}".format(len(coord_str))) output.extend(coord_str) output.append("{} {}".format(self.min_cell_size, self.max_cell_size)) output.append(str(self.enum_precision_parameter)) output.append("partial") ndisordered = sum([len(s) for s in disordered_sites]) base = int(ndisordered*reduce(lcm, [f.limit_denominator( ndisordered * self.max_cell_size).denominator for f in map(fractions.Fraction, index_amounts)])) # base = ndisordered #10 ** int(math.ceil(math.log10(ndisordered))) # To get a reasonable number of structures, we fix concentrations to the # range expected in the original structure. total_amounts = sum(index_amounts) for amt in index_amounts: conc = amt / total_amounts if abs(conc * base - round(conc * base)) < 1e-5: output.append("{} {} {}".format(int(round(conc * base)), int(round(conc * base)), base)) else: min_conc = int(math.floor(conc * base)) output.append("{} {} {}".format(min_conc - 1, min_conc + 1, base)) output.append("") logger.debug("Generated input file:\n{}".format("\n".join(output))) with open("struct_enum.in", "w") as f: f.write("\n".join(output))
def generate_doc(self, dir_name, vasprun_files): """ Process aflow style runs, where each run is actually a combination of two vasp runs. """ try: fullpath = os.path.abspath(dir_name) #Defensively copy the additional fields first. This is a MUST. #Otherwise, parallel updates will see the same object and inserts #will be overridden!! d = {k: v for k, v in self.additional_fields.items()} d["dir_name"] = fullpath d["schema_version"] = VaspToDbTaskDrone.__version__ d["calculations"] = [ self.process_vasprun(dir_name, taskname, filename) for taskname, filename in vasprun_files.items()] d1 = d["calculations"][0] d2 = d["calculations"][-1] #Now map some useful info to the root level. for root_key in ["completed_at", "nsites", "unit_cell_formula", "reduced_cell_formula", "pretty_formula", "elements", "nelements", "cif", "density", "is_hubbard", "hubbards", "run_type"]: d[root_key] = d2[root_key] d["chemsys"] = "-".join(sorted(d2["elements"])) #store any overrides to the exchange correlation functional xc = d2["input"]["incar"].get("GGA") if xc: xc = xc.upper() d["input"] = {"crystal": d1["input"]["crystal"], "is_lasph": d2["input"]["incar"].get("LASPH", False), "potcar_spec": d1["input"].get("potcar_spec"), "xc_override": xc} vals = sorted(d2["reduced_cell_formula"].values()) d["anonymous_formula"] = {string.ascii_uppercase[i]: float(vals[i]) for i in range(len(vals))} d["output"] = { "crystal": d2["output"]["crystal"], "final_energy": d2["output"]["final_energy"], "final_energy_per_atom": d2["output"]["final_energy_per_atom"]} d["name"] = "aflow" p = d2["input"]["potcar_type"][0].split("_") pot_type = p[0] functional = "lda" if len(pot_type) == 1 else "_".join(p[1:]) d["pseudo_potential"] = {"functional": functional.lower(), "pot_type": pot_type.lower(), "labels": d2["input"]["potcar"]} if len(d["calculations"]) == len(self.runs) or \ list(vasprun_files.keys())[0] != "relax1": d["state"] = "successful" if d2["has_vasp_completed"] \ else "unsuccessful" else: d["state"] = "stopped" d["analysis"] = get_basic_analysis_and_error_checks(d) sg = SpacegroupAnalyzer(Structure.from_dict(d["output"]["crystal"]), 0.1) d["spacegroup"] = {"symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "source": "spglib", "crystal_system": sg.get_crystal_system(), "hall": sg.get_hall()} d["last_updated"] = datetime.datetime.today() return d except Exception as ex: import traceback print(traceback.format_exc()) logger.error("Error in " + os.path.abspath(dir_name) + ".\n" + traceback.format_exc()) return None
def _gen_input_file(self): """ Generate the necessary struct_enum.in file for enumlib. See enumlib documentation for details. """ coord_format = "{:.6f} {:.6f} {:.6f}" # Using symmetry finder, get the symmetrically distinct sites. fitter = SpacegroupAnalyzer(self.structure, self.symm_prec) symmetrized_structure = fitter.get_symmetrized_structure() logger.debug("Spacegroup {} ({}) with {} distinct sites".format( fitter.get_space_group_symbol(), fitter.get_space_group_number(), len(symmetrized_structure.equivalent_sites)) ) """ Enumlib doesn"t work when the number of species get too large. To simplify matters, we generate the input file only with disordered sites and exclude the ordered sites from the enumeration. The fact that different disordered sites with the exact same species may belong to different equivalent sites is dealt with by having determined the spacegroup earlier and labelling the species differently. """ # index_species and index_amounts store mappings between the indices # used in the enum input file, and the actual species and amounts. index_species = [] index_amounts = [] # Stores the ordered sites, which are not enumerated. ordered_sites = [] disordered_sites = [] coord_str = [] for sites in symmetrized_structure.equivalent_sites: if sites[0].is_ordered: ordered_sites.append(sites) else: sp_label = [] species = {k: v for k, v in sites[0].species.items()} if sum(species.values()) < 1 - EnumlibAdaptor.amount_tol: # Let us first make add a dummy element for every single # site whose total occupancies don't sum to 1. species[DummySpecie("X")] = 1 - sum(species.values()) for sp in species.keys(): if sp not in index_species: index_species.append(sp) sp_label.append(len(index_species) - 1) index_amounts.append(species[sp] * len(sites)) else: ind = index_species.index(sp) sp_label.append(ind) index_amounts[ind] += species[sp] * len(sites) sp_label = "/".join(["{}".format(i) for i in sorted(sp_label)]) for site in sites: coord_str.append("{} {}".format( coord_format.format(*site.coords), sp_label)) disordered_sites.append(sites) def get_sg_info(ss): finder = SpacegroupAnalyzer(Structure.from_sites(ss), self.symm_prec) return finder.get_space_group_number() target_sgnum = get_sg_info(symmetrized_structure.sites) curr_sites = list(itertools.chain.from_iterable(disordered_sites)) sgnum = get_sg_info(curr_sites) ordered_sites = sorted(ordered_sites, key=lambda sites: len(sites)) logger.debug("Disordered sites has sg # %d" % (sgnum)) self.ordered_sites = [] # progressively add ordered sites to our disordered sites # until we match the symmetry of our input structure if self.check_ordered_symmetry: while sgnum != target_sgnum and len(ordered_sites) > 0: sites = ordered_sites.pop(0) temp_sites = list(curr_sites) + sites new_sgnum = get_sg_info(temp_sites) if sgnum != new_sgnum: logger.debug("Adding %s in enum. New sg # %d" % (sites[0].specie, new_sgnum)) index_species.append(sites[0].specie) index_amounts.append(len(sites)) sp_label = len(index_species) - 1 for site in sites: coord_str.append("{} {}".format( coord_format.format(*site.coords), sp_label)) disordered_sites.append(sites) curr_sites = temp_sites sgnum = new_sgnum else: self.ordered_sites.extend(sites) for sites in ordered_sites: self.ordered_sites.extend(sites) self.index_species = index_species lattice = self.structure.lattice output = [self.structure.formula, "bulk"] for vec in lattice.matrix: output.append(coord_format.format(*vec)) output.append("%d" % len(index_species)) output.append("%d" % len(coord_str)) output.extend(coord_str) output.append("{} {}".format(self.min_cell_size, self.max_cell_size)) output.append(str(self.enum_precision_parameter)) output.append("partial") ndisordered = sum([len(s) for s in disordered_sites]) base = int(ndisordered*lcm(*[f.limit_denominator(ndisordered * self.max_cell_size).denominator for f in map(fractions.Fraction, index_amounts)])) # This multiplicative factor of 10 is to prevent having too small bases # which can lead to rounding issues in the next step. # An old bug was that a base was set to 8, with a conc of 0.4:0.6. That # resulted in a range that overlaps and a conc of 0.5 satisfying this # enumeration. See Cu7Te5.cif test file. base *= 10 # base = ndisordered #10 ** int(math.ceil(math.log10(ndisordered))) # To get a reasonable number of structures, we fix concentrations to the # range expected in the original structure. total_amounts = sum(index_amounts) for amt in index_amounts: conc = amt / total_amounts if abs(conc * base - round(conc * base)) < 1e-5: output.append("{} {} {}".format(int(round(conc * base)), int(round(conc * base)), base)) else: min_conc = int(math.floor(conc * base)) output.append("{} {} {}".format(min_conc - 1, min_conc + 1, base)) output.append("") logger.debug("Generated input file:\n{}".format("\n".join(output))) with open("struct_enum.in", "w") as f: f.write("\n".join(output))