def run_task(self, fw_spec): user_incar_settings = self["user_incar_settings"] interpolation_type = self.get("interpolation_type", "IDPP") idpp_species = fw_spec.get("idpp_species") user_kpoints_settings = self.get("user_kpoints_settings") try: ep0 = Structure.from_dict(fw_spec["ep0"]) ep1 = Structure.from_dict(fw_spec["ep1"]) except: ep0 = fw_spec["ep0"] ep1 = fw_spec["ep1"] # Get number of images. nimages = user_incar_settings.get("IMAGES", self._get_nimages(ep0, ep1)) if interpolation_type == "IDPP": from pymatgen_diffusion.neb.pathfinder import IDPPSolver obj = IDPPSolver.from_endpoints([ep0, ep1], nimages=nimages) images = obj.run(species=idpp_species) images_dic_list = [image.as_dict() for image in images] elif interpolation_type == "linear": images = self._get_images_by_linear_interp(nimages, ep0, ep1) images_dic_list = [i.as_dict() for i in images] else: raise ValueError("The interpolation method must either be 'linear' or 'IDPP'!") write = WriteNEBFromImages(neb_label='1', user_incar_settings=user_incar_settings, user_kpoints_settings=user_kpoints_settings) fw_spec["neb"] = [images_dic_list] write.run_task(fw_spec=fw_spec)
def run_task(self, fw_spec): user_incar_settings = self["user_incar_settings"] interpolation_type = self.get("interpolation_type", "IDPP") idpp_species = fw_spec.get("idpp_species") user_kpoints_settings = self.get("user_kpoints_settings") try: ep0 = Structure.from_dict(fw_spec["ep0"]) ep1 = Structure.from_dict(fw_spec["ep1"]) except Exception: ep0 = fw_spec["ep0"] ep1 = fw_spec["ep1"] # Get number of images. nimages = user_incar_settings.get("IMAGES", self._get_nimages(ep0, ep1)) if interpolation_type == "IDPP": from pymatgen.analysis.diffusion.neb.pathfinder import IDPPSolver obj = IDPPSolver.from_endpoints([ep0, ep1], nimages=nimages) images = obj.run(species=idpp_species) images_dic_list = [image.as_dict() for image in images] elif interpolation_type == "linear": images = self._get_images_by_linear_interp(nimages, ep0, ep1) images_dic_list = [i.as_dict() for i in images] else: raise ValueError( "The interpolation method must either be 'linear' or 'IDPP'!") write = WriteNEBFromImages( neb_label="1", user_incar_settings=user_incar_settings, user_kpoints_settings=user_kpoints_settings, ) fw_spec["neb"] = [images_dic_list] write.run_task(fw_spec=fw_spec)
def match(self, snls, mat): """ Finds a material doc that matches with the given snl Args: snl ([dict]): the snls list mat (dict): a materials doc Returns: generator of materials doc keys """ m_strucs = [Structure.from_dict(mat["structure"])] + [ Structure.from_dict(init_struc) for init_struc in mat["initial_structures"] ] snl_strucs = [StructureNL.from_dict(snl) for snl in snls] groups = group_structures( m_strucs + snl_strucs, ltol=self.settings.LTOL, stol=self.settings.STOL, angle_tol=self.settings.ANGLE_TOL, ) matched_groups = [ group for group in groups if any( isinstance(struc, Structure) for struc in group) ] snls = [ struc for struc in group for group in matched_groups if isinstance(struc, StructureNL) ] self.logger.debug(f"Found {len(snls)} SNLs for {mat['material_id']}") return snls
def get_training_data(self, split=False): """returns the data used to train the model Parameters ---------- split : bool If True return the train/test split dataset used to train model. If False return list of input structure and target properties Returns ------- data_list: List If split==False, list of dictionary's with keys as 'structure' 'TARGET' 'structure' will return the structure as a dict that can be reconstructed as a pymatgen.structure train_in, test_in : List If split==True, list of pymatgen.Structure used to train/test model train_out, test_out : List If split==True, list of target values used to train/test model Examples -------- >>> with MLRester() as mlr: >>> model = mlr.get_model(['Al','Ni'],doi='1.2.5555') >>> data = model.get_training_data() >>> input = [] >>> target = [] >>> for data_point in data[0:3]: >>> input.append(Structure.from_dict(data_point['structure'])) >>> target.append(data_point['Formation_Energy']) >>> print(f'len(test_in) = {len(test_in)} element_type = {str(type(test_in[0]))[8:-2]}') >>> print(f'len(test_out) = {len(test_out)} element_type = {str(type(test_out[0]))[8:-2]}') len(test_in) = 3 element_type = pymatgen.core.structure.Structure len(test_out) = 3 element_type = float """ with urllib.request.urlopen(self.training_data_path) as url: data = json.loads(url.read().decode()) train = data["training"] test = data["testing"] if split: test_in = [] test_out = [] train_in = [] train_out = [] for ind in range(len(train)): if ind < len(test): data_point = test[str(ind)] test_in.append(Structure.from_dict( data_point['structure'])) test_out.append(data_point['Formation_Energy']) data_point = train[str(ind)] train_in.append(Structure.from_dict(data_point['structure'])) train_out.append(data_point['Formation_Energy']) return train_in, train_out, test_in, test_out else: data_list = [ data[k][key] for k in data.keys() for key in data[k].keys() ] return data_list
def process_item(self, item): """ Calculates substrate matches for all given substrates Args: item (dict): a dict with a material_id and a structure Returns: dict: a diffraction dict """ material = item["material"] elastic_tensor = item.get("elastic_tensor", None) substrates = item["substrates"] self.logger.debug("Calculating substrates for {}".format( get(self.materials.key, material))) film = Structure.from_dict(material["structure"]) all_matches = [] sa = SubstrateAnalyzer() for s in substrates: substrate = Structure.from_dict(s["structure"]) # Calculate all matches and group by substrate orientation matches_by_orient = groupby_itemkey( sa.calculate(film, substrate, elastic_tensor, lowest=True), "sub_miller") # Find the lowest area match for each substrate orientation lowest_matches = [ min(g, key=itemgetter("match_area")) for k, g in matches_by_orient ] for match in lowest_matches: db_entry = { "film_id": material[self.materials.key], "sub_id": s[self.materials.key], "orient": " ".join(map(str, match["sub_miller"])), "sub_form": substrate.composition.reduced_formula, "film_orient": " ".join(map(str, match["film_miller"])), "area": match["match_area"], } if "elastic_energy" in match: db_entry["energy"] = match["elastic_energy"] db_entry["strain"] = match["strain"] all_matches.append(db_entry) return all_matches
def _match_material(self, taskdoc, ltol=0.2, stol=0.3, angle_tol=5): """ Returns the material_id that has the same structure as this task as determined by the structure matcher. Returns None if no match. Args: taskdoc (dict): a JSON-like task document ltol (float): StructureMatcher tuning parameter stol (float): StructureMatcher tuning parameter angle_tol (float): StructureMatcher tuning parameter Returns: (int) matching material_id or None """ formula = taskdoc["formula_reduced_abc"] # handle the "parent structure" option, which is used to intentionally force slightly # different structures to contribute to the same "material", e.g. from an ordering scheme if "parent_structure" in taskdoc: t_struct = Structure.from_dict( taskdoc["parent_structure"]["structure"]) q = { "formula_reduced_abc": formula, "parent_structure.spacegroup.number": taskdoc["parent_structure"]["spacegroup"]["number"] } else: sgnum = taskdoc["output"]["spacegroup"]["number"] t_struct = Structure.from_dict(taskdoc["output"]["structure"]) q = {"formula_reduced_abc": formula, "sg_number": sgnum} for m in self._materials.find(q, { "parent_structure": 1, "structure": 1, "material_id": 1 }): s_dict = m["parent_structure"][ "structure"] if "parent_structure" in m else m["structure"] m_struct = Structure.from_dict(s_dict) sm = StructureMatcher(ltol=ltol, stol=stol, angle_tol=angle_tol, primitive_cell=True, scale=True, attempt_supercell=False, allow_subset=False, comparator=ElementComparator()) if sm.fit(m_struct, t_struct): return m["material_id"] return None
def test_local_extrema_append_sites_to_supercell_info2(local_extrema, simple_cubic): sites = { "H1": Site(element="H", wyckoff_letter="a", site_symmetry="mmm", equivalent_atoms=[0, 1, 2, 3, 4, 5, 6, 7]) } actual_cubic = Structure.from_dict(simple_cubic.as_dict()) supercell_info = SupercellInfo(actual_cubic * [2, 2, 2], "Pm-3m", [[2, 0, 0], [0, 2, 0], [0, 0, 2]], sites, []) actual_2 = local_extrema.append_sites_to_supercell_info(supercell_info, indices=[2]) interstitials = [ Interstitial(frac_coords=[0.05, 0.0, 0.0], site_symmetry="4mm", info="test #2") ] expected_2 = SupercellInfo(actual_cubic * [2, 2, 2], "Pm-3m", [[2, 0, 0], [0, 2, 0], [0, 0, 2]], sites, interstitials) assert actual_2 == expected_2
def write_cfgs(self, filename, cfg_pool): """ Write the formatted configuration file. Args: filename (str): The filename to be written. cfg_pool (list): The configuration pool contains structure and energy/forces properties. """ lines = [] elements = [] for dataset in cfg_pool: if isinstance(dataset['structure'], dict): structure = Structure.from_dict(dataset['structure']) else: structure = dataset['structure'] energy = dataset['outputs']['energy'] forces = dataset['outputs']['forces'] virial_stress = dataset['outputs']['virial_stress'] lines.append( self._line_up(structure, energy, forces, virial_stress)) elements.extend(structure.species) if self.elements is None: self.elements = [element.name for element in sorted(set(elements))] with open(filename, 'w') as f: f.write('\n'.join(lines)) return filename
def write_cfg(self, filename, cfg_pool): """ Write configurations to file Args: filename (str): filename cfg_pool (list): list of configurations Returns: """ if not self.elements: raise ValueError("No species given.") lines = [] for dataset in cfg_pool: if isinstance(dataset['structure'], dict): structure = Structure.from_dict(dataset['structure']) else: structure = dataset['structure'] energy = dataset['outputs']['energy'] forces = dataset['outputs']['forces'] virial_stress = dataset['outputs']['virial_stress'] virial_stress = [ virial_stress[self.vasp_stress_order.index(n)] for n in self.mtp_stress_order ] lines.append( self._line_up(structure, energy, forces, virial_stress)) with open(filename, 'w') as f: f.write('\n'.join(lines)) return filename
def from_dict(cls, d): structure = Structure.from_dict(d["structure"]) return cls(structure, np.array(d["displacements"]), specie=d["specie"], temperature=d["temperature"], time_step=d["time_step"], step_skip=d["step_skip"], min_obs=d["min_obs"], smoothed=d.get("smoothed", "max"), avg_nsteps=d.get("avg_nsteps", 1000))
def feff_task_to_spectrum(doc): energy = doc["spectrum"][0] # (eV) intensity = doc["spectrum"][3] # (mu) structure: Structure = Structure.from_dict(doc["structure"]) # Clean site properties for site_prop in structure.site_properties.keys(): structure.remove_site_property(site_prop) absorbing_index = doc["absorbing_atom"] absorbing_element = structure[absorbing_index].specie edge = doc["edge"] spectrum_type = doc["spectrum_type"] spectrum = XAS( x=energy, y=intensity, structure=structure, absorbing_element=absorbing_element, absorbing_index=absorbing_index, edge=edge, spectrum_type=spectrum_type, ) # Adding a attr is not a robust process # Figure out better solution later spectrum.last_updated = doc["last_updated"] spectrum.task_ids = [doc["xas_id"]] return spectrum
def test_no_duplicate_hops(self): test_structure_dict = { "@module": "pymatgen.core.structure", "@class": "Structure", "charge": None, "lattice": { "matrix": [[2.990355, -5.149042, 0.0], [2.990355, 5.149042, 0.0], [0.0, 0.0, 24.51998]] }, "sites": [ { "species": [{ "element": "Ba", "occu": 1 }], "abc": [0.005572, 0.994428, 0.151095], "properties": {} }, ], } test_structure = Structure.from_dict(test_structure_dict) nn = MinimumDistanceNN(cutoff=6, get_all_sites=True) sg = StructureGraph.with_local_env_strategy(test_structure, nn) self.assertEqual(sg.graph.number_of_edges(), 3)
def calcs_reversed_to_trajectory(calcs_reversed: List[dict]): """ Converts data from calc_reversed to pymatgen Trajectory objects that contain structure, energy, force and stress data for each ionic step. Args: calcs_reversed: List of dictionaries in calcs_reversed entry of a task document. """ trajectories = [] for calculation in calcs_reversed: for step in calculation["output"]["ionic_steps"]: structures = [] frame_props = defaultdict(list) # type: dict structures.append(Structure.from_dict(step["structure"])) frame_props["e_fr_energy"].append(step["e_fr_energy"]) frame_props["e_wo_entrp"].append(step["e_wo_entrp"]) frame_props["e_0_energy"].append(step["e_wo_entrp"]) frame_props["forces"].append(step["forces"]) frame_props["stresses"].append(step["stress"]) traj = Trajectory.from_structures(structures, frame_properties=frame_props, time_step=None).as_dict() trajectories.append(traj) return trajectories
def setUp(self): with open(os.path.join(test_dir, 'si_structure.json'), 'r') as sth: si_str = Structure.from_dict(json.load(sth)) with open(os.path.join(test_dir, 'si_bandstructure_line.json'), 'r') as bsh: si_bs_line = BandStructureSymmLine.from_dict(json.load(bsh)) si_bs_line.structure = si_str with open(os.path.join(test_dir, 'si_bandstructure_uniform.json'), 'r') as bsh: si_bs_uniform = BandStructure.from_dict(json.load(bsh)) si_bs_uniform.structure = si_str self.si_kpts = list(HighSymmKpath(si_str).kpath['kpoints'].values()) self.df = pd.DataFrame({ 'bs_line': [si_bs_line], 'bs_uniform': [si_bs_uniform] }) with open(os.path.join(test_dir, 'VBr2_971787_bandstructure.json'), 'r') as bsh: vbr2_uniform = BandStructure.from_dict(json.load(bsh)) self.vbr2kpts = [ k.frac_coords for k in vbr2_uniform.labels_dict.values() ] self.vbr2kpts = [ [0.0, 0.0, 0.0], # \\Gamma [0.2, 0.0, 0.0], # between \\Gamma and M [0.5, 0.0, 0.0], # M [0.5, 0.0, 0.5] ] # L self.df2 = pd.DataFrame({'bs_line': [vbr2_uniform]})
def get_eq_structure_by_metadata(metadata, db_file=None): ''' Get the equilibrium structure by metadata Parameters ---------- metadata: dict The metadata use for searching the database db_file: filepath-like The file path of db.json(the settings for mongodb file) if it is None or >>db_file<<, then using the db_file of fireworks configurations Returns ------- eq_structure: pymatgen.Strucutre object the equilibrium structure ''' if (db_file is None) or (db_file == '>>db_file<<'): db_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"] vasp_db = VaspCalcDb.from_db_file(db_file, admin=True) static_items = list(vasp_db.db['tasks'].find({ 'metadata.tag': metadata['tag'] }).sort('_id', 1)) structure_list = [itemi['output']['structure'] for itemi in static_items] if structure_list: #not empty eq_structure = Structure.from_dict(structure_list[0]) return eq_structure
def append_interstitial(supercell_info: SupercellInfo, unitcell_structure: Union[Structure, IStructure], frac_coords: List[Union[List[float], Coords]], infos: List[str]) -> SupercellInfo: """ inv_trans_mat must be multiplied with coords from the right as the trans_mat is multiplied to the unitcell lattice vector from the left. see __mul__ of IStructure in pymatgen. x_u, x_s means the frac coordinates in unitcell and supercell, while a, b, c are the unitcell lattice vector. (a_u, b_u, c_u) . (a, b, c) = (a_s, b_s, c_s) . trans_mat . (a, b, c) (a_u, b_u, c_u) = (a_s, b_s, c_s) . trans_mat so, (a_s, b_s, c_s) = (a_u, b_u, c_u) . inv_trans_ma """ if supercell_info.unitcell_structure and \ supercell_info.unitcell_structure != unitcell_structure: raise NotPrimitiveError if isinstance(frac_coords[0], float): frac_coords = [frac_coords] for fcoord, info in zip(frac_coords, infos): us = Structure.from_dict(unitcell_structure.as_dict()) us.append(species=Element.H, coords=fcoord) symmetrizer = StructureSymmetrizer(us) site_symm = symmetrizer.spglib_sym_data["site_symmetry_symbols"][-1] inv_matrix = inv(np.array(supercell_info.transformation_matrix)) new_coords = np.dot(fcoord, inv_matrix).tolist() supercell_info.interstitials.append( Interstitial(frac_coords=new_coords, site_symmetry=site_symm, info=info)) return supercell_info
def run(self): logger.info("MaterialsDescriptorBuilder starting...") self._build_indexes() q = {} if not self.update_all: q["descriptors.density"] = {"$exists": False} mats = [ m for m in self._materials.find(q, { "structure": 1, "material_id": 1 }) ] pbar = tqdm(mats) for m in pbar: pbar.set_description("Processing materials_id: {}".format( m['material_id'])) struct = Structure.from_dict(m["structure"]) d = {"descriptors": {}} d["descriptors"]["dimensionality"] = get_dimensionality(struct) d["descriptors"]["density"] = struct.density d["descriptors"]["nsites"] = len(struct) d["descriptors"]["volume"] = struct.volume self._materials.update_one({"material_id": m["material_id"]}, {"$set": d})
def get_images_list(self, structure_docs, scheme, fixed_index, fixed_specie): """ Returns a list of structure objects with selective dynamics applied according ot the specified scheme. Args: structure_docs (list): list of structure dictionaries scheme (str): "fix_two_atom" Returns: list of structure objects """ if isinstance(structure_docs, (list)) == False: raise TypeError("list input required for structure_docs") if scheme == "fix_two_atom": images = [] for doc in structure_docs: structure = Structure.from_dict(doc) image = self.add_fix_two_atom_selective_dynamics( structure, fixed_index, fixed_specie) images.append(image) # ToDo: add radius based selective dynamics scheme else: raise ValueError( "selective_dynamics_scheme does match any supported schemes, check input value" ) return images
def from_dict(cls, d): """ Args: d (dict): Dict representation Returns: GruneisenPhononBandStructure: Phonon band structure with Grueneisen parameters. """ lattice_rec = Lattice(d["lattice_rec"]["matrix"]) eigendisplacements = np.array( d["eigendisplacements"]["real"]) + np.array( d["eigendisplacements"]["imag"]) * 1j structure = Structure.from_dict( d["structure"]) if "structure" in d else None return cls( qpoints=d["qpoints"], frequencies=np.array(d["bands"]), gruneisenparameters=np.array(d["gruneisen"]), lattice=lattice_rec, eigendisplacements=eigendisplacements, labels_dict=d["labels_dict"], structure=structure, )
def iterate(self, nested_dict=None): """http://stackoverflow.com/questions/10756427/loop-through-all-nested-dictionary-values""" d = self if nested_dict is None else nested_dict if nested_dict is None: self.level = 0 for key in list(d.keys()): value = d[key] if isinstance(value, _Mapping): if value.get("@class") == "Structure": from pymatgen.core import Structure yield key, Structure.from_dict(value) continue yield (self.level, key), None if value.get("@class") == "Table": from mpcontribs.io.core.components.tdata import Table yield key, Table.from_dict(value) continue # if Quantity is not None and value.get('@class') == 'Quantity': # quantity = Quantity.from_dict(value) # yield key, quantity # continue if "display" in value and "value" in value: # 'unit' is optional yield (self.level, key), value["display"] continue self.level += 1 for inner_key, inner_value in self.iterate(nested_dict=value): yield inner_key, inner_value self.level -= 1 else: yield (self.level, key), value
def from_dict(cls, d): eigenvalues = {} # Programmatic access to enumeration members in Enum class. for s, v in d["eigenvalues"].items(): eigenvalues[Spin(int(s))] = np.array(v) final_structure = d["final_structure"] if isinstance(final_structure, dict): final_structure = Structure.from_dict(final_structure) band_edge_energies = str_key_to_spin(d["band_edge_energies"]) participation_ratio = str_key_to_spin(d["participation_ratio"]) orbital_character = str_key_to_spin(d["orbital_character"]) return cls( final_structure=final_structure, site_symmetry=d["site_symmetry"], total_energy=d["total_energy"], total_magnetization=d["total_magnetization"], eigenvalues=eigenvalues, kpoint_coords=d["kpoint_coords"], kpoint_weights=d["kpoint_weights"], electrostatic_potential=d["electrostatic_potential"], vbm=d["vbm"], cbm=d["cbm"], volume=d["volume"], fermi_level=d["fermi_level"], is_converged=d["is_converged"], defect_center=d["defect_center"], defect_coords=d["defect_coords"], displacements=d["displacements"], neighboring_sites_after_relax=d["neighboring_sites_after_relax"], band_edge_energies=band_edge_energies, participation_ratio=participation_ratio, orbital_character=orbital_character)
def test_analysis(self): # load example tasks (since workflow re-uses existing FW building # blocks for the actual calculations, the most important test is # the new analysis task) tasks = self.get_task_collection() with open(os.path.join(ref_dir, "ordering/sample_tasks.json"), "r") as f: sample_tasks = load(f) wf_uuid = sample_tasks[0]["wf_meta"]["wf_uuid"] parent_structure = Structure.from_dict( sample_tasks[0]["input"]["structure"]).get_primitive_structure() tasks.insert_many(sample_tasks) toDb = MagneticOrderingsToDb(db_file=os.path.join(DB_DIR, "db.json"), wf_uuid=wf_uuid, parent_structure=parent_structure, perform_bader=False, scan=False) toDb.run_task({}) mag_ordering_collection = self.get_task_database().magnetic_orderings from pprint import pprint stable_ordering = mag_ordering_collection.find_one({"stable": True}) self.assertEqual(stable_ordering['input']['index'], 2) self.assertAlmostEqual(stable_ordering['magmoms']['vasp'][0], -2.738)
def _create_inputs(basename, structures_dir, atom_featurizer, bond_featurizer, max_num_neighbors, cutoff): # load structure structure_json_basename = basename + ".json" structure_json_path = os.path.join(structures_dir, structure_json_basename) with open(structure_json_path, "r") as f: structure = Structure.from_dict(json.load(f)) initial_atom_features = atom_featurizer(structure) # Padding neighbors might cause artificial effect, see https://github.com/txie-93/cgcnn/pull/16 neighbors = structure.get_all_neighbors(r=cutoff) neighbors = [sorted(nn, key=lambda n: n.nn_distance) for nn in neighbors] # sort by distances bond_features, neighbor_indices = bond_featurizer(neighbors, max_num_neighbors) inputs = { "neighbor_indices": neighbor_indices, # (num_atoms, max_num_neighbors) "atom_features": initial_atom_features, # (num_atoms, num_atom_features) "bond_features": bond_features, # (num_atoms, max_num_neighbors, num_bond_features) } return inputs
def write_cfgs(self, filename, cfg_pool): """ Write the formatted configuration file. Args: filename (str): The filename to be written. cfg_pool (list): The configuration pool contains structure and energy/forces properties. """ if not filename.endswith('.xyz'): raise RuntimeError('The extended xyz file should end with ".xyz"') lines = [] for dataset in cfg_pool: if isinstance(dataset['structure'], dict): structure = Structure.from_dict(dataset['structure']) else: structure = dataset['structure'] energy = dataset['outputs']['energy'] forces = dataset['outputs']['forces'] virial_stress = dataset['outputs']['virial_stress'] lines.append( self._line_up(structure, energy, forces, virial_stress)) with open(filename, 'w') as f: f.write('\n'.join(lines)) return filename
def get_thermal_props(qha_result, phonon=True): """ Return a dictionary of thermal properties in J/mol-atom from a QHA analysis. Parameters ---------- qha_result : Dictionary of a QHA summary dict phonon : bool Whether to get the phonon data (True) or Debye data (False). Defaults to True. If the has_phonon key is False, it will fall back to Debye automatically. Returns ------- dict Dictionary of thermal properties. Dictionary keys are GM, HM, SM, CPM, and T. """ struct = Structure.from_dict(qha_result['structure']) if phonon and qha_result['has_phonon']: G = np.array( mget(qha_result, 'phonon.gibbs_free_energy' )) * eV_per_atom_to_J_per_mol / struct.composition.num_atoms T = np.array(mget(qha_result, 'phonon.temperatures')) else: G = np.array( mget(qha_result, 'debye.gibbs_free_energy' )) * eV_per_atom_to_J_per_mol / struct.composition.num_atoms T = np.array(mget(qha_result, 'debye.temperatures')) dT = T[1] - T[0] Cp = -T * np.gradient(np.gradient(G, dT), dT) S = -np.gradient(G, dT) H = G + T * S thermal_properties = {'GM': G, 'HM': H, 'SM': S, 'CPM': Cp, 'T': T} return thermal_properties
def from_dict(cls, d): structure = Structure.from_dict(d["structure"]) return cls(structure, np.array(d["displacements"]), specie=d["specie"], temperature=d["temperature"], time_step=d["time_step"], step_skip=d["step_skip"], min_obs=d["min_obs"], smoothed=d.get("smoothed", "max"), avg_nsteps=d.get("avg_nsteps", 1000))
def _check_run(self, d, mode): if mode not in [ "structure optimization", "bulk_modulus deformation 0", "bulk_modulus deformation 4", "fit equation of state", ]: raise ValueError("Invalid mode!") if mode not in ["fit equation of state"]: self.assertEqual(d["formula_pretty"], "Si") self.assertEqual(d["formula_anonymous"], "A") self.assertEqual(d["nelements"], 1) self.assertEqual(d["state"], "successful") if mode in ["structure optimization"]: self.assertAlmostEqual( d["calcs_reversed"][0]["output"]["structure"]["lattice"]["a"], 3.866, 3) self.assertAlmostEqual(d["output"]["energy_per_atom"], -5.432, 3) self.relaxed_struct_si = d["calcs_reversed"][0]["output"][ "structure"] elif mode in ["bulk_modulus deformation 0"]: for i, l in enumerate(["a", "b", "c"]): self.assertAlmostEqual( d["input"]["structure"]["lattice"][l], self.relaxed_struct_si["lattice"][l] * (self.deformations[0][i][i]), 2, ) stress = d["calcs_reversed"][0]["output"]["ionic_steps"][-1][ "stress"] np.testing.assert_allclose(stress, np.diag([189.19, 189.19, 189.19]), atol=1e-2) elif mode in ["bulk_modulus deformation 4"]: for i, l in enumerate(["a", "b", "c"]): self.assertAlmostEqual( d["input"]["structure"]["lattice"][l], self.relaxed_struct_si["lattice"][l] * (self.deformations[4][i][i]), 2, ) stress = d["calcs_reversed"][0]["output"]["ionic_steps"][-1][ "stress"] np.testing.assert_allclose(stress, np.diag([-65.56, -65.56, -65.56]), atol=1e-2) elif mode in ["fit equation of state"]: self.assertAlmostEqual(d["bulk_modulus"], 88.90, places=2) self.assertEqual(len(d["all_task_ids"]), 7) self.assertEqual(len(d["energies"]), self.ndeformations) self.assertEqual(len(d["volumes"]), self.ndeformations) s = SpacegroupAnalyzer(Structure.from_dict( d["structure"])).get_conventional_standard_structure() self.assertAlmostEqual(s.lattice.c, 5.468, places=3)
def _match_material(self, doc, ltol=0.2, stol=0.3, angle_tol=5): """ Returns the material_id that has the same structure as this doc as determined by the structure matcher. Returns None if no match. Args: doc (dict): a JSON-like document ltol (float): StructureMatcher tuning parameter stol (float): StructureMatcher tuning parameter angle_tol (float): StructureMatcher tuning parameter Returns: (int) matching material_id or None """ formula = doc["formula_reduced_abc"] sgnum = doc["spacegroup"]["number"] for m in self._materials.find( { "formula_reduced_abc": formula, "sg_number": sgnum }, { "structure": 1, "material_id": 1 }, ): m_struct = Structure.from_dict(m["structure"]) t_struct = Structure.from_dict(doc["structure"]) sm = StructureMatcher( ltol=ltol, stol=stol, angle_tol=angle_tol, primitive_cell=True, scale=True, attempt_supercell=False, allow_subset=False, comparator=ElementComparator(), ) if sm.fit(m_struct, t_struct): return m["material_id"] return None
def from_dict(cls, d): """ As in :Class: `pymatgen.core.Structure` except restoring graphs using `from_dict_of_dicts` from NetworkX to restore graph information. """ s = Structure.from_dict(d['structure']) return cls(s, d['graphs'])
def from_dict(cls, d): """ As in :Class: `pymatgen.core.Structure` except restoring graphs using `from_dict_of_dicts` from NetworkX to restore graph information. """ s = Structure.from_dict(d['structure']) return cls(s, d['graphs'])
def get_static_structure_by_metadata(metadata, db_file=None): ''' Get the static structure by metadata Parameters ---------- metadata: dict The metadata use for searching the database db_file: filepath-like The file path of db.json(the settings for mongodb file) if it is None or >>db_file<<, then using the db_file of fireworks configurations Returns ------- structure_list: list The list of different structures. The structures are sorted by volume ''' if (db_file is None) or (db_file == '>>db_file<<'): db_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"] vasp_db = VaspCalcDb.from_db_file(db_file, admin=True) static_items = list( vasp_db.collection.find( {'$and': [{ 'metadata.tag': metadata['tag'] }, { 'adopted': True }]})) #static_items = list(vasp_db.db['tasks'].find({'metadata.tag': metadata})) structure_list = [ Structure.from_dict(itemi['output']['structure']) for itemi in static_items ] volumes = [ itemi['output']['structure']['lattice']['volume'] for itemi in static_items ] energies = [itemi['output']['energy_per_atom'] for itemi in static_items] band_gap = [] static_settings = {} for itemi in static_items: if itemi['output']['is_gap_direct']: band_gap.append(itemi['output']['bandgap']) else: band_gap.append(itemi['output']['direct_gap']) if not static_settings: pot = itemi['input']['pseudo_potential']['functional'].upper() if pot == "": pot = itemi['orig_inputs']['potcar']['functional'].upper() if pot == 'Perdew-Zunger81'.upper(): pot = "LDA" static_settings['user_potcar_functional'] = pot static_settings['user_incar_settings'] = itemi['input']['incar'] structure_list = sort_x_by_y(structure_list, volumes) band_gap = sort_x_by_y(band_gap, volumes) energies = sort_x_by_y(energies, volumes) volumes = sorted(volumes) return (structure_list, energies, band_gap, static_settings, volumes)
def convert_cd_to_de( cd, b_cse): """ As of pymatgen v2.0, ComputedDefect objects were deprecated in favor of DefectEntry objects in pymatgen.analysis.defects.core This function takes a ComputedDefect (either as a dict or object) and converts it into a DefectEntry object in order to handle legacy PyCDT creation within the current paradigm of PyCDT. :param cd (dict or ComputedDefect object): ComputedDefect as an object or as a dictionary :params b_cse (dict or ComputedStructureEntry object): ComputedStructureEntry of bulk entry associated with the ComputedDefect. :return: de (DefectEntry): Resulting DefectEntry object """ if type(cd) != dict: cd = cd.as_dict() if type(b_cse) != dict: b_cse = b_cse.as_dict() bulk_sc_structure = Structure.from_dict( b_cse["structure"]) #modify defect_site as required for Defect object, confirming site exists in bulk structure site_cls = cd["site"] defect_site = PeriodicSite.from_dict( site_cls) def_nom = cd["name"].lower() if "sub_" in def_nom or "as_" in def_nom: #modify site object for substitution site of Defect object site_cls["species"][0]["element"] = cd["name"].split("_")[2] defect_site = PeriodicSite.from_dict( site_cls) poss_deflist = sorted( bulk_sc_structure.get_sites_in_sphere(defect_site.coords, 0.1, include_index=True), key=lambda x: x[1]) if len(poss_deflist) != 1: raise ValueError("ComputedDefect to DefectEntry conversion failed. " "Could not determine periodic site position in bulk supercell.") # create defect object if "vac_" in def_nom: defect_obj = Vacancy(bulk_sc_structure, defect_site, charge=cd["charge"]) elif "as_" in def_nom or "sub_" in def_nom: defect_obj = Substitution(bulk_sc_structure, defect_site, charge=cd["charge"]) elif "int_" in def_nom: defect_obj = Interstitial(bulk_sc_structure, defect_site, charge=cd["charge"]) else: raise ValueError("Could not recognize defect type for {}".format( cd["name"])) # assign proper energy and parameter metadata uncorrected_energy = cd["entry"]["energy"] - b_cse["energy"] def_path = os.path.split( cd["entry"]["data"]["locpot_path"])[0] bulk_path = os.path.split( b_cse["data"]["locpot_path"])[0] p = {"defect_path": def_path, "bulk_path": bulk_path, "encut": cd["entry"]["data"]["encut"]} de = DefectEntry( defect_obj, uncorrected_energy, parameters = p) return de
def from_dict(cls, d): structure = Structure.from_dict(d["structure"]) return cls(structure, np.array(d["displacements"]), specie=d["specie"], temperature=d["temperature"], time_step=d["time_step"], step_skip=d["step_skip"], min_obs=d["min_obs"], weighted=d["weighted"])
def run_task(self, fw_spec): user_incar_settings = self.get("user_incar_settings", {}) user_kpoints_settings = self.get("user_kpoints_settings", {}) neb_label = self.get("neb_label") assert neb_label.isdigit() and int(neb_label) >= 1 images = fw_spec["neb"][int(neb_label) - 1] try: images = [Structure.from_dict(i) for i in images] except: images = images vis = MVLCINEBSet(images, user_incar_settings=user_incar_settings, user_kpoints_settings=user_kpoints_settings) vis.write_input(".")
def setUp(self): with open(os.path.join(test_dir, 'si_structure.json'),'r') as sth: si_str = Structure.from_dict(json.load(sth)) with open(os.path.join(test_dir, 'si_bandstructure_line.json'),'r') as bsh: si_bs_line = BandStructureSymmLine.from_dict(json.load(bsh)) si_bs_line.structure = si_str with open(os.path.join(test_dir, 'si_bandstructure_uniform.json'),'r') as bsh: si_bs_uniform = BandStructure.from_dict(json.load(bsh)) si_bs_uniform.structure = si_str self.si_kpts = list(HighSymmKpath(si_str).kpath['kpoints'].values()) self.df = pd.DataFrame({'bs_line': [si_bs_line], 'bs_uniform': [si_bs_uniform]}) with open(os.path.join(test_dir, 'VBr2_971787_bandstructure.json'), 'r') as bsh: vbr2_uniform = BandStructure.from_dict(json.load(bsh)) self.vbr2kpts = [k.frac_coords for k in vbr2_uniform.labels_dict.values()] self.vbr2kpts = [[0.0, 0.0, 0.0], # \\Gamma [0.2, 0.0, 0.0], # between \\Gamma and M [0.5, 0.0, 0.0], # M [0.5, 0.0, 0.5]] # L self.df2 = pd.DataFrame({'bs_line': [vbr2_uniform]})
def process_entry(self, defect_entry, perform_corrections = True): """ Process a given DefectEntry with qualifiers given from initialization of class. Order of processing is: 1) perform all possible defect corrections with information given 2) consider delocalization analyses based on qualifier metrics given initialization of class. If delocalized, flag entry as delocalized 3) update corrections to defect entry and flag as delocalized Corrections are applied based on: i) if free charges are more than free_chg_cutoff then will not apply charge correction, because it no longer is applicable ii) use charge correction set by preferred_cc iii) only use BandFilling correction if use_bandfilling is set to True iv) only use BandEdgeShift correction if use_bandedgeshift is set to True """ for struct_key in ["bulk_sc_structure", "initial_defect_structure", "final_defect_structure"]: if struct_key in defect_entry.parameters.keys() and isinstance(defect_entry.parameters[struct_key], dict): defect_entry.parameters[struct_key] = Structure.from_dict(defect_entry.parameters[struct_key]) if perform_corrections: self.perform_all_corrections(defect_entry) self.delocalization_analysis(defect_entry) # apply corrections based on delocalization analysis corrections = {} skip_charge_corrections = False if "num_hole_vbm" in defect_entry.parameters.keys(): if (self.free_chg_cutoff < defect_entry.parameters["num_hole_vbm"]) or ( self.free_chg_cutoff < defect_entry.parameters["num_elec_cbm"]): logger.info('Will not use charge correction because too many free charges') skip_charge_corrections = True if skip_charge_corrections: corrections.update({'charge_correction': 0.}) else: if ('freysoldt' in self.preferred_cc.lower()) and ('freysoldt_meta' in defect_entry.parameters.keys()): frey_meta = defect_entry.parameters['freysoldt_meta'] frey_corr = frey_meta["freysoldt_electrostatic"] + frey_meta["freysoldt_potential_alignment_correction"] corrections.update({'charge_correction': frey_corr}) elif ('kumagai_meta' in defect_entry.parameters.keys()): kumagai_meta = defect_entry.parameters['kumagai_meta'] kumagai_corr = kumagai_meta["kumagai_electrostatic"] + \ kumagai_meta["kumagai_potential_alignment_correction"] corrections.update({'charge_correction': kumagai_corr}) else: logger.info('Could not use any charge correction because insufficient metadata was supplied.') if self.use_bandfilling: if "bandfilling_meta" in defect_entry.parameters.keys(): bfc_corr = defect_entry.parameters["bandfilling_meta"]["bandfilling_correction"] corrections.update({'bandfilling_correction': bfc_corr}) else: logger.info('Could not use band filling correction because insufficient metadata was supplied.') else: corrections.update({'bandfilling_correction': 0.}) if self.use_bandedgeshift and ("bandshift_meta" in defect_entry.parameters.keys()): corrections.update({'bandedgeshifting_correction': defect_entry.parameters["bandshift_meta"]["bandedgeshifting_correction"] }) # also want to update relevant data for phase diagram defect_entry.parameters.update({ 'phasediagram_meta': { 'vbm': defect_entry.parameters['hybrid_vbm'], 'gap': defect_entry.parameters['hybrid_cbm'] - defect_entry.parameters['hybrid_vbm'] } }) else: corrections.update({'bandedgeshifting_correction': 0.}) if (type(defect_entry.parameters['vbm']) == float) and (type(defect_entry.parameters['cbm']) == float): # still want to have vbm and gap ready for phase diagram defect_entry.parameters.update({ 'phasediagram_meta': { 'vbm': defect_entry.parameters['vbm'], 'gap': defect_entry.parameters['cbm'] - defect_entry.parameters['vbm'] } }) defect_entry.corrections.update(corrections) return defect_entry
def run_task(self, fw_spec): label = self["label"] assert label in ["parent", "ep0", "ep1"] or "neb" in label, "Unknown label!" d_img = float(self.get("d_img", 0.7)) # Angstrom wf_name = fw_spec["wf_name"] src_dir = os.path.abspath(".") dest_dir = os.path.join(fw_spec["_fw_env"]["run_dest_root"], wf_name, label) shutil.copytree(src_dir, dest_dir) # Update fw_spec based on the type of calculations. if "neb" in label: # Update all relaxed images. subs = glob.glob("[0-2][0-9]") nimages = len(subs) concar_list = ["{:02}/CONTCAR".format(i) for i in range(nimages)[1:-1]] images = [Structure.from_file(contcar) for contcar in concar_list] # Update the two ending "images". images.insert(0, Structure.from_file("00/POSCAR")) images.append(Structure.from_file("{:02}/POSCAR".format(nimages - 1))) images = [s.as_dict() for s in images] neb = fw_spec.get("neb") neb.append(images) update_spec = {"neb": neb, "_queueadapter": {"nnodes": str(len(images) - 2), "nodes": str(len(images) - 2)}} # Use neb walltime if it is in fw_spec if fw_spec["neb_walltime"] is not None: update_spec["_queueadapter"].update({"walltime": fw_spec.get("neb_walltime")}) elif label in ["ep0", "ep1"]: # Update relaxed endpoint structures. file = glob.glob("CONTCAR*")[0] ep = Structure.from_file(file, False) # One endpoint if fw_spec.get("incar_images"): # "incar_images": pre-defined image number. update_spec = {label: ep.as_dict(), "_queueadapter": {"nnodes": fw_spec["incar_images"], "nodes": fw_spec["incar_images"]}} else: # Calculate number of images if "IMAGES" tag is not provided. index = int(label[-1]) ep_1_dict = fw_spec.get("ep{}".format(1 - index)) # Another endpoint try: ep_1 = Structure.from_dict(ep_1_dict) except: ep_1 = ep_1_dict max_dist = max(get_endpoint_dist(ep, ep_1)) nimages = round(max_dist / d_img) or 1 update_spec = {label: ep, "_queueadapter": {"nnodes": int(nimages), "nodes": int(nimages)}} # Use neb walltime if it is in fw_spec if fw_spec["neb_walltime"] is not None: update_spec["_queueadapter"].update({"walltime": fw_spec.get("neb_walltime")}) else: # label == "parent" f = glob.glob("CONTCAR*")[0] s = Structure.from_file(f, False) ep0, ep1 = get_endpoints_from_index(s, fw_spec["site_indices"]) update_spec = {"parent": s.as_dict(), "ep0": ep0.as_dict(), "ep1": ep1.as_dict()} # Clear current directory. for d in os.listdir(src_dir): try: os.remove(os.path.join(src_dir, d)) except: shutil.rmtree(os.path.join(src_dir, d)) return FWAction(update_spec=update_spec)
def from_dict(cls, d): structure = Structure.from_dict(d["structure"]) return cls(structure, np.array(d["displacements"]), specie=d["specie"], temperature=d["temperature"], time_step=d["time_step"], step_skip=d["step_skip"], min_obs=d["min_obs"], weighted=d["weighted"])