def setUp(self): self.voigt_1 = [[59.33, 28.08, 28.08, 0, 0, 0], [28.08, 59.31, 28.07, 0, 0, 0], [28.08, 28.07, 59.32, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]] mat = np.random.randn(6, 6) mat = mat + np.transpose(mat) self.rand_elastic_tensor = ElasticTensor.from_voigt(mat) self.ft = np.array([[[[59.33, 0, 0], [0, 28.08, 0], [0, 0, 28.08]], [[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]]], [[[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[28.08, 0, 0], [0, 59.31, 0], [0, 0, 28.07]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]]], [[[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]], [[28.08, 0, 0], [0, 28.07, 0], [0, 0, 59.32]]]]) self.elastic_tensor_1 = ElasticTensor(self.ft) filepath = os.path.join(test_dir, 'Sn_def_stress.json') with open(filepath) as f: self.def_stress_dict = json.load(f) with open(os.path.join(test_dir, 'test_toec_data.json')) as f: self.toec_dict = json.load(f) self.structure = self.get_structure("Sn") warnings.simplefilter("always")
def test_new(self): self.assertArrayAlmostEqual(self.elastic_tensor_1, ElasticTensor(self.ft)) nonsymm = self.ft nonsymm[0, 1, 2, 2] += 1.0 with warnings.catch_warnings(record=True) as w: ElasticTensor(nonsymm) self.assertEqual(len(w), 1) badtensor1 = np.zeros((3, 3, 3)) badtensor2 = np.zeros((3, 3, 3, 2)) self.assertRaises(ValueError, ElasticTensor, badtensor1) self.assertRaises(ValueError, ElasticTensor, badtensor2)
def test_new(self): with self.assertRaises(ValueError): ElasticTensor([[59.33, 28.08, 28.08, 0], [28.08, 59.31, 28.07, 0], [28.08, 28.07, 59.32, 0, 0], [0, 0, 0, 26.35, 0], [0, 0, 0, 0, 26.35]]) with warnings.catch_warnings(record=True) as w: ElasticTensor([[59.33, 28.08, 28.08, 0, 0, 0], [0.0, 59.31, 28.07, 0, 0, 0], [28.08, 28.07, 59.32, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]]) self.assertEqual(len(w), 1)
def test_from_voigt(self): with self.assertRaises(ValueError): ElasticTensor.from_voigt([[59.33, 28.08, 28.08, 0], [28.08, 59.31, 28.07, 0], [28.08, 28.07, 59.32, 0, 0], [0, 0, 0, 26.35, 0], [0, 0, 0, 0, 26.35]]) with warnings.catch_warnings(record=True) as w: ElasticTensor.from_voigt([[59.33, 28.08, 28.08, 0, 0, 0], [0.0, 59.31, 28.07, 0, 0, 0], [28.08, 28.07, 59.32, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]]) self.assertEqual(len(w), 1)
def _fit_elastic_tensor(stresses, strains, strain_magnitudes, equilibrium_structure, equilibrium_stress, symmetric_strains_only=True): symm_eql_stresses = copy.deepcopy(stresses) symm_eql_strains = copy.deepcopy(strains) if symmetric_strains_only: all_deformations = _get_deformed_structures(equilibrium_structure, strain_magnitudes, symmetric_strains_only=False)[0] symmetry_operations_dict = symmetry_reduce(all_deformations, equilibrium_structure) deformations = [deformation for deformation in symmetry_operations_dict] for i in range(len(deformations)): deformation = deformations[i] symmetry_operations = [x for x in symmetry_operations_dict[deformation]] for symm_op in symmetry_operations: symm_eql_strains.append(strains[i].transform(symm_op)) symm_eql_stresses.append(stresses[i].transform(symm_op)) # Fit the elastic constants compliance_tensor = ElasticTensor.from_independent_strains( stresses=symm_eql_stresses, strains=symm_eql_strains, eq_stress=equilibrium_stress ) compliance_tensor = -1.0 * compliance_tensor # pymatgen has opposite sign convention return symm_eql_stresses, symm_eql_strains, compliance_tensor
def test_energy_density(self): film_elac = ElasticTensor.from_voigt( [[324.32, 187.3, 170.92, 0., 0., 0.], [187.3, 324.32, 170.92, 0., 0., 0.], [170.92, 170.92, 408.41, 0., 0., 0.], [0., 0., 0., 150.73, 0., 0.], [0., 0., 0., 0., 150.73, 0.], [0., 0., 0., 0., 0., 238.74]]) dfm = Deformation([[-9.86004855e-01, 2.27539582e-01, -4.64426035e-17], [-2.47802121e-01, -9.91208483e-01, -7.58675185e-17], [-6.12323400e-17, -6.12323400e-17, 1.00000000e+00]]) self.assertAlmostEqual( film_elac.energy_density(dfm.green_lagrange_strain), 0.00125664672793) film_elac.energy_density( Strain.from_deformation([[0.99774738, 0.11520994, -0.], [-0.11520994, 0.99774738, 0.], [ -0., -0., 1., ]]))
def cmpt_vasp(jdata, conf_dir): fp_params = jdata['vasp_params'] kspacing = fp_params['kspacing'] kgamma = fp_params['kgamma'] conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') task_path = re.sub('confs', global_task_name, conf_path) if 'relax_incar' in jdata.keys(): vasp_str = 'vasp-relax_incar' else: vasp_str = 'vasp-k%.2f' % kspacing task_path = os.path.join(task_path, vasp_str) equi_stress = Stress(np.loadtxt(os.path.join(task_path, 'equi.stress.out'))) lst_dfm_path = glob.glob(os.path.join(task_path, 'dfm-*')) lst_strain = [] lst_stress = [] for ii in lst_dfm_path: strain = np.loadtxt(os.path.join(ii, 'strain.out')) stress = vasp.get_stress(os.path.join(ii, 'OUTCAR')) # convert from pressure in kB to stress stress *= -1000 lst_strain.append(Strain(strain)) lst_stress.append(Stress(stress)) et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress=equi_stress, vasp=False) # et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress = None) # bar to GPa # et = -et / 1e4 print_et(et)
def test_init(self): # Film VO2 film = SpacegroupAnalyzer(self.get_structure("VO2"), symprec=0.1).get_conventional_standard_structure() # Substrate TiO2 substrate = SpacegroupAnalyzer(self.get_structure("TiO2"), symprec=0.1).get_conventional_standard_structure() film_elac = ElasticTensor.from_voigt( [ [324.32, 187.3, 170.92, 0.0, 0.0, 0.0], [187.3, 324.32, 170.92, 0.0, 0.0, 0.0], [170.92, 170.92, 408.41, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 150.73, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 150.73, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0, 238.74], ] ) s = SubstrateAnalyzer() matches = list(s.calculate(film, substrate, film_elac)) self.assertEqual(len(matches), 192) for match in matches: assert match is not None assert isinstance(match.match_area, float)
def cmpt_deepmd_lammps(jdata, conf_dir, task_name): deepmd_model_dir = jdata['deepmd_model_dir'] deepmd_type_map = jdata['deepmd_type_map'] ntypes = len(deepmd_type_map) conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') task_path = re.sub('confs', global_task_name, conf_path) task_path = os.path.join(task_path, task_name) equi_stress = Stress(np.loadtxt(os.path.join(task_path, 'equi.stress.out'))) lst_dfm_path = glob.glob(os.path.join(task_path, 'dfm-*')) lst_strain = [] lst_stress = [] for ii in lst_dfm_path: strain = np.loadtxt(os.path.join(ii, 'strain.out')) stress = lammps.get_stress(os.path.join(ii, 'log.lammps')) # convert from pressure to stress stress = -stress lst_strain.append(Strain(strain)) lst_stress.append(Stress(stress)) et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress=equi_stress, vasp=False) # et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress = None) # bar to GPa # et = -et / 1e4 print_et(et)
def plug_in(symbol_values): tensor = ElasticTensor.from_voigt(symbol_values["C_ij"]) structure = symbol_values["structure"] to_return = tensor.clarke_thermalcond(structure) if not isinstance(to_return, float): to_return = float(to_return) return {'t': to_return}
def cmpt_deepmd_lammps(jdata, conf_dir, task_name) : conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') task_path = re.sub('confs', global_task_name, conf_path) task_path = os.path.join(task_path, task_name) equi_stress = Stress(np.loadtxt(os.path.join(task_path, 'equi.stress.out'))) lst_dfm_path = glob.glob(os.path.join(task_path, 'dfm-*')) lst_strain = [] lst_stress = [] for ii in lst_dfm_path : strain = np.loadtxt(os.path.join(ii, 'strain.out')) stress = lammps.get_stress(os.path.join(ii, 'log.lammps')) # convert from pressure to stress stress = -stress lst_strain.append(Strain(strain)) lst_stress.append(Stress(stress)) et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress = equi_stress, vasp = False) # et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress = None) # bar to GPa # et = -et / 1e4 print_et(et) result = os.path.join(task_path,'result') result_et(et,conf_dir,result) if 'upload_username' in jdata.keys() and task_name=='deepmd': upload_username=jdata['upload_username'] util.insert_data('elastic','deepmd',upload_username,result)
def test_energy(self): film_elac = ElasticTensor([ [324.32, 187.3, 170.92, 0., 0., 0.], [187.3, 324.32, 170.92, 0., 0., 0.], [170.92, 170.92, 408.41, 0., 0., 0.], [0., 0., 0., 150.73, 0., 0.], [0., 0., 0., 0., 150.73, 0.], [0., 0., 0., 0., 0., 238.74]]) dfm = Deformation([[ -9.86004855e-01,2.27539582e-01,-4.64426035e-17], [ -2.47802121e-01,-9.91208483e-01,-7.58675185e-17], [ -6.12323400e-17,-6.12323400e-17,1.00000000e+00]]) self.assertAlmostEqual(film_elac.energy_density(dfm.green_lagrange_strain), 0.000125664672793)
def setUp(self): with open(os.path.join(test_dir, 'test_toec_data.json')) as f: self.data_dict = json.load(f) self.strains = [Strain(sm) for sm in self.data_dict['strains']] self.pk_stresses = [Stress(d) for d in self.data_dict['pk_stresses']] self.c2 = self.data_dict["C2_raw"] self.c3 = self.data_dict["C3_raw"] self.exp = ElasticTensorExpansion.from_voigt([self.c2, self.c3]) self.cu = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3.623), ["Cu"], [[0] * 3]) indices = [(0, 0), (0, 1), (3, 3)] values = [167.8, 113.5, 74.5] cu_c2 = ElasticTensor.from_values_indices(values, indices, structure=self.cu, populate=True) indices = [(0, 0, 0), (0, 0, 1), (0, 1, 2), (0, 3, 3), (0, 5, 5), (3, 4, 5)] values = [-1507., -965., -71., -7., -901., 45.] cu_c3 = Tensor.from_values_indices(values, indices, structure=self.cu, populate=True) self.exp_cu = ElasticTensorExpansion([cu_c2, cu_c3]) cu_c4 = Tensor.from_voigt(self.data_dict["Cu_fourth_order"]) self.exp_cu_4 = ElasticTensorExpansion([cu_c2, cu_c3, cu_c4]) warnings.simplefilter("ignore")
def test_from_independent_strains(self): strains = self.toec_dict["strains"] stresses = self.toec_dict["stresses"] with warnings.catch_warnings(record=True) as w: et = ElasticTensor.from_independent_strains(strains, stresses) self.assertArrayAlmostEqual(et.voigt, self.toec_dict["C2_raw"], decimal=-1)
def _evaluate(self, symbol_values): tensor = ElasticTensor.from_voigt(symbol_values["C_ij"]) structure = symbol_values["_structure"] return { 't': tensor.clarke_thermalcond(structure) }
def test_from_stress_dict(self): stress_dict = dict(list(zip([IndependentStrain(def_matrix) for def_matrix in self.def_stress_dict['deformations']], [Stress(stress_matrix) for stress_matrix in self.def_stress_dict['stresses']]))) et_from_sd = ElasticTensor.from_stress_dict(stress_dict) self.assertArrayAlmostEqual(et_from_sd.round(2), self.elastic_tensor_1)
def test_from_stress_dict(self): stress_dict = dict(list(zip([IndependentStrain(def_matrix) for def_matrix in self.def_stress_dict['deformations']], [Stress(stress_matrix) for stress_matrix in self.def_stress_dict['stresses']]))) with warnings.catch_warnings(record = True): et_from_sd = ElasticTensor.from_stress_dict(stress_dict) self.assertArrayAlmostEqual(et_from_sd.voigt_symmetrized.round(2), self.elastic_tensor_1)
def setUp(self): # Empty aggregated collection self.test_elasticity_agg = MongoStore("test_emmet", "elasticity_agg") self.test_elasticity_agg.connect() # Generate test materials collection self.test_materials = MongoStore("test_emmet", "materials") self.test_materials.connect() mat_docs = [] for n, formula in enumerate(['Si', 'BaNiO3', 'Li2O2', 'TiO2']): structure = PymatgenTest.get_structure(formula) structure.add_site_property("magmoms", [0.0] * len(structure)) mat_docs.append({ "task_id": "mp-{}".format(n), "structure": structure.as_dict(), "pretty_formula": formula }) self.test_materials.update(mat_docs, update_lu=False) # Create elasticity collection and add docs self.test_elasticity = MongoStore("test_emmet", "elasticity", key="optimization_task_id") self.test_elasticity.connect() si = PymatgenTest.get_structure("Si") si.add_site_property("magmoms", [0.0] * len(si)) et = ElasticTensor.from_voigt([[50, 25, 25, 0, 0, 0], [25, 50, 25, 0, 0, 0], [25, 25, 50, 0, 0, 0], [0, 0, 0, 75, 0, 0], [0, 0, 0, 0, 75, 0], [0, 0, 0, 0, 0, 75]]) doc = { "input_structure": si.copy().as_dict(), "order": 2, "magnetic_type": "non-magnetic", "optimization_task_id": "mp-1", "last_updated": datetime.utcnow(), "completed_at": datetime.utcnow(), "optimized_structure": si.copy().as_dict(), "pretty_formula": "Si", "state": "successful" } doc['elastic_tensor'] = et.voigt doc.update(et.property_dict) self.test_elasticity.update([doc]) # Insert second doc with diff params si.perturb(0.005) doc.update({ "optimized_structure": si.copy().as_dict(), "updated_at": datetime.utcnow(), "optimization_task_id": "mp-5" }) self.test_elasticity.update([doc]) self.builder = self.get_a_new_builder()
def get_et(elast_str=""): cij = np.empty((6, 6), dtype=float) elast = np.array(elast_str.split(","), dtype="float") count = 0 for ii in range(6): for jj in range(6): cij[ii][jj] = elast[count] count = count + 1 et = ElasticTensor.from_voigt(cij) return et
def _compute_lower(self, output_file, all_tasks, all_res): output_file = os.path.abspath(output_file) res_data = {} ptr_data = output_file + '\n' equi_stress = Stress( np.loadtxt( os.path.join(os.path.dirname(output_file), 'equi.stress.out'))) lst_strain = [] lst_stress = [] for ii in all_tasks: with open(os.path.join(ii, 'inter.json')) as fp: idata = json.load(fp) inter_type = idata['type'] strain = np.loadtxt(os.path.join(ii, 'strain.out')) if inter_type == 'vasp': stress = vasp.get_stress(os.path.join(ii, 'OUTCAR')) # convert from pressure in kB to stress stress *= -1000 lst_strain.append(Strain(strain)) lst_stress.append(Stress(stress)) elif inter_type in ['deepmd', 'meam', 'eam_fs', 'eam_alloy']: stress = lammps.get_stress(os.path.join(ii, 'log.lammps')) # convert from pressure to stress stress = -stress lst_strain.append(Strain(strain)) lst_stress.append(Stress(stress)) et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress=equi_stress, vasp=False) res_data['elastic_tensor'] = [] for ii in range(6): for jj in range(6): res_data['elastic_tensor'].append(et.voigt[ii][jj] / 1e4) ptr_data += "%7.2f " % (et.voigt[ii][jj] / 1e4) ptr_data += '\n' BV = et.k_voigt / 1e4 GV = et.g_voigt / 1e4 EV = 9 * BV * GV / (3 * BV + GV) uV = 0.5 * (3 * BV - 2 * GV) / (3 * BV + GV) res_data['BV'] = BV res_data['GV'] = GV res_data['EV'] = EV res_data['uV'] = uV ptr_data += "# Bulk Modulus BV = %.2f GPa\n" % BV ptr_data += "# Shear Modulus GV = %.2f GPa\n" % GV ptr_data += "# Youngs Modulus EV = %.2f GPa\n" % EV ptr_data += "# Poission Ratio uV = %.2f " % uV with open(output_file, 'w') as fp: json.dump(res_data, fp, indent=4) return res_data, ptr_data
def run_task(self, fw_spec): # Get optimized structure # TODO: will this find the correct path if the workflow is rerun from the start? optimize_loc = fw_spec["calc_locs"][0]["path"] logger.info("PARSING INITIAL OPTIMIZATION DIRECTORY: {}".format(optimize_loc)) drone = VaspDrone() optimize_doc = drone.assimilate(optimize_loc) opt_struct = Structure.from_dict(optimize_doc["calcs_reversed"][0]["output"]["structure"]) d = {"analysis": {}, "deformation_tasks": fw_spec["deformation_tasks"], "initial_structure": self['structure'].as_dict(), "optimized_structure": opt_struct.as_dict()} if fw_spec.get("tags",None): d["tags"] = fw_spec["tags"] dtypes = fw_spec["deformation_tasks"].keys() defos = [fw_spec["deformation_tasks"][dtype]["deformation_matrix"] for dtype in dtypes] stresses = [fw_spec["deformation_tasks"][dtype]["stress"] for dtype in dtypes] stress_dict = {IndependentStrain(defo) : Stress(stress) for defo, stress in zip(defos, stresses)} logger.info("ANALYZING STRESS/STRAIN DATA") # DETERMINE IF WE HAVE 6 "UNIQUE" deformations if len(set([de[:3] for de in dtypes])) == 6: # Perform Elastic tensor fitting and analysis result = ElasticTensor.from_stress_dict(stress_dict) d["elastic_tensor"] = result.voigt.tolist() kg_average = result.kg_average d.update({"K_Voigt": kg_average[0], "G_Voigt": kg_average[1], "K_Reuss": kg_average[2], "G_Reuss": kg_average[3], "K_Voigt_Reuss_Hill": kg_average[4], "G_Voigt_Reuss_Hill": kg_average[5]}) d["universal_anisotropy"] = result.universal_anisotropy d["homogeneous_poisson"] = result.homogeneous_poisson else: raise ValueError("Fewer than 6 unique deformations") d["state"] = "successful" # Save analysis results in json or db db_file = env_chk(self.get('db_file'), fw_spec) if not db_file: with open("elasticity.json", "w") as f: f.write(json.dumps(d, default=DATETIME_HANDLER)) else: db = MMVaspDb.from_db_file(db_file, admin=True) db.collection = db.db["elasticity"] db.collection.insert_one(d) logger.info("ELASTIC ANALYSIS COMPLETE") return FWAction()
def get_et(elast_str=''): if elast_str == 'na': return 'na' else: cij = np.empty((6, 6), dtype=float) elast = np.array(elast_str.split(','), dtype='float') count = 0 for ii in range(6): for jj in range(6): cij[ii][jj] = elast[count] count = count + 1 et = ElasticTensor.from_voigt(cij) return et
def test_from_strain_stress_list(self): strain_list = [Strain.from_deformation(def_matrix) for def_matrix in self.def_stress_dict['deformations']] stress_list = [stress for stress in self.def_stress_dict['stresses']] with warnings.catch_warnings(record = True): et_fl = -0.1*ElasticTensor.from_strain_stress_list(strain_list, stress_list) self.assertArrayAlmostEqual(et_fl.round(2), [[59.29, 24.36, 22.46, 0, 0, 0], [28.06, 56.91, 22.46, 0, 0, 0], [28.06, 25.98, 54.67, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]])
def test_from_stress_dict(self): stress_dict = dict( list( zip([ IndependentStrain(def_matrix) for def_matrix in self.def_stress_dict['deformations'] ], [ Stress(stress_matrix) for stress_matrix in self.def_stress_dict['stresses'] ]))) minimal_sd = { k: v for k, v in stress_dict.items() if (abs(k[k.independent_deformation] - 0.015) < 1e-10 or abs(k[k.independent_deformation] - 0.01005) < 1e-10) } with warnings.catch_warnings(record=True): et_from_sd = ElasticTensor.from_stress_dict(stress_dict) et_from_minimal_sd = ElasticTensor.from_stress_dict(minimal_sd) self.assertArrayAlmostEqual(et_from_sd.voigt_symmetrized.round(2), self.elastic_tensor_1) self.assertAlmostEqual(50.63394169, et_from_minimal_sd[0, 0, 0, 0])
def process_item(self, item): """ Process the tasks and materials into an elasticity collection Args: item: a dictionary of documents keyed by materials id Returns: an elasticity document """ all_docs = [] tasks, material_dict = item if not tasks: return all_docs grouped = group_by_task_id(material_dict, tasks) for mp_id, task_sets in grouped.items(): elastic_docs = [] for opt_task, defo_tasks in task_sets: elastic_doc = get_elastic_analysis(opt_task, defo_tasks) if elastic_doc: elastic_docs.append(elastic_doc) if not elastic_docs: logger.warning("No elastic doc for mp_id {}".format(mp_id)) continue # For now just do the most recent one that's not failed sorted(elastic_docs, key=lambda x: (x['state'], x['completed_at'])) final_doc = elastic_docs[-1] c_ijkl = ElasticTensor.from_voigt(final_doc['elastic_tensor']) structure = final_doc['optimized_structure'] formula = structure.composition.reduced_formula elements = [s.symbol for s in structure.composition.elements] chemsys = '-'.join(elements) final_doc.update(c_ijkl.property_dict) final_doc.update(c_ijkl.get_structure_property_dict(structure)) elastic_summary = { 'task_id': mp_id, 'all_elastic_fits': elastic_docs, 'elasticity': final_doc, 'pretty_formula': formula, 'chemsys': chemsys, 'elements': elements, 'last_updated': self.elasticity.lu_field } all_docs.append(elastic_summary) # elastic_summary.update(final_doc) return all_docs
def legacy_fit(strains, stresses): """ Legacy fitting method for mpworks documents, intended to be temporary Args: strains: strains stresses: stresses Returns: elastic tensor fit using the legacy functionality """ strains = [s.zeroed(0.002) for s in strains] return ElasticTensor.from_independent_strains(strains, stresses)
def test_from_strain_stress_list(self): strain_list = [Strain.from_deformation(def_matrix) for def_matrix in self.def_stress_dict['deformations']] stress_list = [stress for stress in self.def_stress_dict['stresses']] with warnings.catch_warnings(record=True): et_fl = -0.1*ElasticTensor.from_strain_stress_list(strain_list, stress_list).voigt self.assertArrayAlmostEqual(et_fl.round(2), [[59.29, 24.36, 22.46, 0, 0, 0], [28.06, 56.91, 22.46, 0, 0, 0], [28.06, 25.98, 54.67, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]])
def setUp(self): self.elastic_tensor_1 = ElasticTensor([[59.33, 28.08, 28.08, 0, 0, 0], [28.08, 59.31, 28.07, 0, 0, 0], [28.08, 28.07, 59.32, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]]) mat = np.random.randn(6, 6) mat = mat + np.transpose(mat) self.rand_elastic_tensor = ElasticTensor(mat) self.ft = np.array([[[[59.33, 0, 0], [0, 28.08, 0], [0, 0, 28.08]], [[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]]], [[[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[28.08, 0, 0], [0, 59.31, 0], [0, 0, 28.07]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]]], [[[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]], [[28.08, 0, 0], [0, 28.07, 0], [0, 0, 59.32]]]]) filepath = os.path.join(test_dir, 'Sn_def_stress.json') with open(filepath) as f: self.def_stress_dict = json.load(f) warnings.simplefilter("always")
def _compute_lower(self, output_file, all_tasks, all_res): output_file = os.path.abspath(output_file) res_data = {} ptr_data = os.path.dirname(output_file) + '\n' equi_stress = Stress( loadfn( os.path.join(os.path.dirname(output_file), 'equi.stress.json'))) lst_strain = [] lst_stress = [] for ii in all_tasks: strain = loadfn(os.path.join(ii, 'strain.json')) # stress, deal with unsupported stress in dpdata #with open(os.path.join(ii, 'result_task.json')) as fin: # task_result = json.load(fin) #stress = np.array(task_result['stress']['data'])[-1] stress = loadfn(os.path.join(ii, 'result_task.json'))['stress'][-1] lst_strain.append(strain) lst_stress.append(Stress(stress * -1000)) et = ElasticTensor.from_independent_strains(lst_strain, lst_stress, eq_stress=equi_stress, vasp=False) res_data['elastic_tensor'] = [] for ii in range(6): for jj in range(6): res_data['elastic_tensor'].append(et.voigt[ii][jj] / 1e4) ptr_data += "%7.2f " % (et.voigt[ii][jj] / 1e4) ptr_data += '\n' BV = et.k_voigt / 1e4 GV = et.g_voigt / 1e4 EV = 9 * BV * GV / (3 * BV + GV) uV = 0.5 * (3 * BV - 2 * GV) / (3 * BV + GV) res_data['BV'] = BV res_data['GV'] = GV res_data['EV'] = EV res_data['uV'] = uV ptr_data += "# Bulk Modulus BV = %.2f GPa\n" % BV ptr_data += "# Shear Modulus GV = %.2f GPa\n" % GV ptr_data += "# Youngs Modulus EV = %.2f GPa\n" % EV ptr_data += "# Poission Ratio uV = %.2f\n " % uV dumpfn(res_data, output_file, indent=4) return res_data, ptr_data
def runTest(self): # Film VO2 film = SpacegroupAnalyzer(self.get_structure("VO2"), symprec=0.1).get_conventional_standard_structure() # Substrate TiO2 substrate = SpacegroupAnalyzer(self.get_structure("TiO2"), symprec=0.1).get_conventional_standard_structure() film_elac = ElasticTensor.from_voigt([ [324.32, 187.3, 170.92, 0., 0., 0.], [187.3, 324.32, 170.92, 0., 0., 0.], [170.92, 170.92, 408.41, 0., 0., 0.], [0., 0., 0., 150.73, 0., 0.], [0., 0., 0., 0., 150.73, 0.], [0., 0., 0., 0., 0., 238.74]]) s = SubstrateAnalyzer() matches = list(s.calculate(film,substrate,film_elac)) self.assertEqual(len(matches), 82)
def runTest(self): # Film VO2 film = SpacegroupAnalyzer(self.get_structure("VO2"), symprec=0.1).get_conventional_standard_structure() # Substrate TiO2 substrate = SpacegroupAnalyzer(self.get_structure("TiO2"), symprec=0.1).get_conventional_standard_structure() film_elac = ElasticTensor([ [324.32, 187.3, 170.92, 0., 0., 0.], [187.3, 324.32, 170.92, 0., 0., 0.], [170.92, 170.92, 408.41, 0., 0., 0.], [0., 0., 0., 150.73, 0., 0.], [0., 0., 0., 0., 150.73, 0.], [0., 0., 0., 0., 0., 238.74]]) s = SubstrateAnalyzer() matches = list(s.calculate(film,substrate,film_elac)) self.assertEqual(len(matches), 82)
def setUp(self): with open(os.path.join(test_dir, 'test_toec_data.json')) as f: self.data_dict = json.load(f) self.strains = [Strain(sm) for sm in self.data_dict['strains']] self.pk_stresses = [Stress(d) for d in self.data_dict['pk_stresses']] self.c2 = self.data_dict["C2_raw"] self.c3 = self.data_dict["C3_raw"] self.exp = ElasticTensorExpansion.from_voigt([self.c2, self.c3]) self.cu = Structure.from_spacegroup("Fm-3m", Lattice.cubic(3.623), ["Cu"], [[0]*3]) indices = [(0, 0), (0, 1), (3, 3)] values = [167.8, 113.5, 74.5] cu_c2 = ElasticTensor.from_values_indices(values, indices, structure=self.cu, populate=True) indices = [(0, 0, 0), (0, 0, 1), (0, 1, 2), (0, 3, 3), (0, 5, 5), (3, 4, 5)] values = [-1507., -965., -71., -7., -901., 45.] cu_c3 = Tensor.from_values_indices(values, indices, structure=self.cu, populate=True) self.exp_cu = ElasticTensorExpansion([cu_c2, cu_c3]) cu_c4 = Tensor.from_voigt(self.data_dict["Cu_fourth_order"]) self.exp_cu_4 = ElasticTensorExpansion([cu_c2, cu_c3, cu_c4]) warnings.simplefilter("ignore")
def runSimulation(self): if self.args["pymatgen"] == True: starting_struct = singleFromFile(self.args) info = runCalc("all_relax", ["structures","stresses"], [starting_struct], self.args) relaxed_struct = info["structures"][0] relaxed_stress = info["stresses"][0] strains = [] deformed_set = DeformedStructureSet(relaxed_struct, symmetry=True) deformed_structs = deformed_set.deformed_structures symmetry_dict = deformed_set.sym_dict deformations = deformed_set.deformations stresses = runCalc("atom_relax", ["stresses"], deformed_structs, self.args)["stresses"] for i in range(len(deformations)): strains.append(Strain.from_deformation(deformations[i])) for i in range(len(deformations)): for symm in symmetry_dict[deformations[i]]: strains.append(strains[i].transform(symm)) stresses.append(stresses[i].transform(symm)) self.elastic_tensor = ElasticTensor.from_independent_strains(strains,stresses,eq_stress=relaxed_stress,vasp=True).zeroed().voigt
def run_task(self, fw_spec): db_dir = os.environ['DB_LOC'] db_path = os.path.join(db_dir, 'tasks_db.json') i = fw_spec['original_task_id'] with open(db_path) as f: db_creds = json.load(f) connection = MongoClient(db_creds['host'], db_creds['port']) tdb = connection[db_creds['database']] tdb.authenticate(db_creds['admin_user'], db_creds['admin_password']) tasks = tdb[db_creds['collection']] elasticity = tdb['elasticity'] ndocs = tasks.find({"original_task_id": i, "state":"successful"}).count() existing_doc = elasticity.find_one({"relaxation_task_id" : i}) if existing_doc: print "Updating: " + i else: print "New material: " + i d = {"analysis": {}, "error": [], "warning": []} d["ndocs"] = ndocs o = tasks.find_one({"task_id" : i}, {"pretty_formula" : 1, "spacegroup" : 1, "snl" : 1, "snl_final" : 1, "run_tags" : 1}) if not o: raise ValueError("Cannot find original task id") # Get stress from deformed structure d["deformation_tasks"] = {} ss_dict = {} for k in tasks.find({"original_task_id": i}, {"deformation_matrix":1, "calculations.output":1, "state":1, "task_id":1}): defo = k['deformation_matrix'] d_ind = np.nonzero(defo - np.eye(3)) delta = Decimal((defo - np.eye(3))[d_ind][0]) # Normal deformation if d_ind[0] == d_ind[1]: dtype = "_".join(["d", str(d_ind[0][0]), "{:.0e}".format(delta)]) # Shear deformation else: dtype = "_".join(["s", str(d_ind[0] + d_ind[1]), "{:.0e}".format(delta)]) sm = IndependentStrain(defo) if dtype in d["deformation_tasks"].keys(): print "old_task: {}".format(d["deformation_tasks"][dtype]["task_id"]) print "new_task: {}".format(k["task_id"]) raise ValueError("Duplicate deformation task in database.") d["deformation_tasks"][dtype] = {"state" : k["state"], "deformation_matrix" : defo, "strain" : sm.tolist(), "task_id": k["task_id"]} if k["state"] == "successful": st = Stress(k["calculations"][-1]["output"] \ ["ionic_steps"][-1]["stress"]) ss_dict[sm] = st d["snl"] = o["snl"] if "run_tags" in o.keys(): d["run_tags"] = o["run_tags"] for tag in o["run_tags"]: if isinstance(tag, dict): if "input_id" in tag.keys(): d["input_mp_id"] = tag["input_id"] d["snl_final"] = o["snl_final"] d["pretty_formula"] = o["pretty_formula"] # Old input mp-id style if o["snl"]["about"].get("_mp_id"): d["material_id"] = o["snl"]["about"]["_mp_id"] # New style elif "input_mp_id" in d: d["material_id"] = d["input_mp_id"] else: d["material_id"] = None d["relaxation_task_id"] = i calc_struct = Structure.from_dict(o["snl_final"]) # TODO: # JHM: This test is unnecessary at the moment, but should be redone """ conventional = is_conventional(calc_struct) if conventional: d["analysis"]["is_conventional"] = True else: d["analysis"]["is_conventional"] = False """ d["spacegroup"]=o.get("spacegroup", "Unknown") if ndocs >= 20: # Perform Elastic tensor fitting and analysis result = ElasticTensor.from_stress_dict(ss_dict) d["elastic_tensor"] = result.voigt.tolist() kg_average = result.kg_average d.update({"K_Voigt":kg_average[0], "G_Voigt":kg_average[1], "K_Reuss":kg_average[2], "G_Reuss":kg_average[3], "K_Voigt_Reuss_Hill":kg_average[4], "G_Voigt_Reuss_Hill":kg_average[5]}) d["universal_anisotropy"] = result.universal_anisotropy d["homogeneous_poisson"] = result.homogeneous_poisson if ndocs < 24: d["warning"].append("less than 24 tasks completed") # Perform filter checks symm_t = result.voigt_symmetrized d["symmetrized_tensor"] = symm_t.voigt.tolist() d["analysis"]["not_rare_earth"] = True for s in calc_struct.species: if s.is_rare_earth_metal: d["analysis"]["not_rare_earth"] = False eigvals = np.linalg.eigvals(symm_t.voigt) eig_positive = np.all((eigvals > 0) & np.isreal(eigvals)) d["analysis"]["eigval_positive"] = bool(eig_positive) c11 = symm_t.voigt[0][0] c12 = symm_t.voigt[0][1] c13 = symm_t.voigt[0][2] c23 = symm_t.voigt[1][2] d["analysis"]["c11_c12"]= not (abs((c11-c12)/c11) < 0.05 or c11 < c12) d["analysis"]["c11_c13"]= not (abs((c11-c13)/c11) < 0.05 or c11 < c13) d["analysis"]["c11_c23"]= not (abs((c11-c23)/c11) < 0.1 or c11 < c23) d["analysis"]["K_R"] = not (d["K_Reuss"] < 2) d["analysis"]["G_R"] = not (d["G_Reuss"] < 2) d["analysis"]["K_V"] = not (d["K_Voigt"] < 2) d["analysis"]["G_V"] = not (d["G_Voigt"] < 2) filter_state = np.all(d["analysis"].values()) d["analysis"]["filter_pass"] = bool(filter_state) d["analysis"]["eigval"] = list(eigvals) # TODO: # JHM: eventually we can reintroduce the IEEE conversion # but as of now it's not being used, and it should # be in pymatgen """ # IEEE Conversion try: ieee_tensor = IEEE_conversion.get_ieee_tensor(struct_final, result) d["elastic_tensor_IEEE"] = ieee_tensor[0].tolist() d["analysis"]["IEEE"] = True except Exception as e: d["elastic_tensor_IEEE"] = None d["analysis"]["IEEE"] = False d["error"].append("Unable to get IEEE tensor: {}".format(e)) """ # Add thermal properties nsites = calc_struct.num_sites volume = calc_struct.volume natoms = calc_struct.composition.num_atoms weight = calc_struct.composition.weight num_density = 1e30 * nsites / volume mass_density = 1.6605e3 * nsites * volume * weight / \ (natoms * volume) tot_mass = sum([e.atomic_mass for e in calc_struct.species]) avg_mass = 1.6605e-27 * tot_mass / natoms y_mod = 9e9 * result.k_vrh * result.g_vrh / \ (3. * result.k_vrh * result.g_vrh) trans_v = 1e9 * result.k_vrh / mass_density**0.5 long_v = 1e9 * result.k_vrh + \ 4./3. * result.g_vrh / mass_density**0.5 clarke = 0.87 * 1.3806e-23 * avg_mass**(-2./3.) * \ mass_density**(1./6.) * y_mod**0.5 cahill = 1.3806e-23 / 2.48 * num_density**(2./3.) * long_v + \ 2 * trans_v snyder_ac = 0.38483 * avg_mass * \ (long_v + 2./3.*trans_v)**3. / \ (300. * num_density**(-2./3.) * nsites**(1./3.)) snyder_opt = 1.66914e-23 * (long_v + 2./3.*trans_v) / \ num_density**(-2./3.) * \ (1 - nsites**(-1./3.)) snyder_total = snyder_ac + snyder_opt debye = 2.489e-11 * avg_mass**(-1./3.) * \ mass_density**(-1./6.) * y_mod**0.5 d["thermal"]={"num_density" : num_density, "mass_density" : mass_density, "avg_mass" : avg_mass, "num_atom_per_unit_formula" : natoms, "youngs_modulus" : y_mod, "trans_velocity" : trans_v, "long_velocity" : long_v, "clarke" : clarke, "cahill" : cahill, "snyder_acou_300K" : snyder_ac, "snyder_opt" : snyder_opt, "snyder_total" : snyder_total, "debye": debye } else: d['state'] = "Fewer than 20 successful tasks completed" return FWAction() if o["snl"]["about"].get("_kpoint_density"): d["kpoint_density"]= o["snl"]["about"].get("_kpoint_density") if d["error"]: raise ValueError("Elastic analysis failed: {}".format(d["error"])) elif d["analysis"]["filter_pass"]: d["state"] = "successful" else: d["state"] = "filter_failed" elasticity.update({"relaxation_task_id": d["relaxation_task_id"]}, d, upsert=True) return FWAction()
class ElasticTensorTest(PymatgenTest): def setUp(self): self.voigt_1 = [[59.33, 28.08, 28.08, 0, 0, 0], [28.08, 59.31, 28.07, 0, 0, 0], [28.08, 28.07, 59.32, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]] mat = np.random.randn(6, 6) mat = mat + np.transpose(mat) self.rand_elastic_tensor = ElasticTensor.from_voigt(mat) self.ft = np.array([[[[59.33, 0, 0], [0, 28.08, 0], [0, 0, 28.08]], [[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]]], [[[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[28.08, 0, 0], [0, 59.31, 0], [0, 0, 28.07]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]]], [[[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]], [[28.08, 0, 0], [0, 28.07, 0], [0, 0, 59.32]]]]) self.elastic_tensor_1 = ElasticTensor(self.ft) filepath = os.path.join(test_dir, 'Sn_def_stress.json') with open(filepath) as f: self.def_stress_dict = json.load(f) with open(os.path.join(test_dir, 'test_toec_data.json')) as f: self.toec_dict = json.load(f) self.structure = self.get_structure("Sn") warnings.simplefilter("always") def test_properties(self): # compliance tensor ct = ComplianceTensor.from_voigt( np.linalg.inv(self.elastic_tensor_1.voigt)) self.assertArrayAlmostEqual(ct, self.elastic_tensor_1.compliance_tensor) # KG average properties self.assertAlmostEqual(38.49111111111, self.elastic_tensor_1.k_voigt) self.assertAlmostEqual(22.05866666666, self.elastic_tensor_1.g_voigt) self.assertAlmostEqual(38.49110945133, self.elastic_tensor_1.k_reuss) self.assertAlmostEqual(20.67146635306, self.elastic_tensor_1.g_reuss) self.assertAlmostEqual(38.49111028122, self.elastic_tensor_1.k_vrh) self.assertAlmostEqual(21.36506650986, self.elastic_tensor_1.g_vrh) # universal anisotropy self.assertAlmostEqual(0.33553509658699, self.elastic_tensor_1.universal_anisotropy) # homogeneous poisson self.assertAlmostEqual(0.26579965576472, self.elastic_tensor_1.homogeneous_poisson) # voigt notation tensor self.assertArrayAlmostEqual(self.elastic_tensor_1.voigt, self.voigt_1) # young's modulus self.assertAlmostEqual(54087787667.160583, self.elastic_tensor_1.y_mod) # prop dict prop_dict = self.elastic_tensor_1.property_dict self.assertAlmostEqual(prop_dict["homogeneous_poisson"], 0.26579965576) for k, v in prop_dict.items(): self.assertAlmostEqual(getattr(self.elastic_tensor_1, k), v) def test_directional_elastic_mod(self): self.assertAlmostEqual( self.elastic_tensor_1.directional_elastic_mod([1, 0, 0]), self.elastic_tensor_1.voigt[0, 0]) self.assertAlmostEqual( self.elastic_tensor_1.directional_elastic_mod([1, 1, 1]), 73.624444444) def test_compliance_tensor(self): stress = self.elastic_tensor_1.calculate_stress([0.01] + [0] * 5) comp = self.elastic_tensor_1.compliance_tensor strain = Strain(comp.einsum_sequence([stress])) self.assertArrayAlmostEqual(strain.voigt, [0.01] + [0] * 5) def test_directional_poisson_ratio(self): v_12 = self.elastic_tensor_1.directional_poisson_ratio([1, 0, 0], [0, 1, 0]) self.assertAlmostEqual(v_12, 0.321, places=3) def test_structure_based_methods(self): # trans_velocity self.assertAlmostEqual(1996.35019877, self.elastic_tensor_1.trans_v(self.structure)) # long_velocity self.assertAlmostEqual(3534.68123832, self.elastic_tensor_1.long_v(self.structure)) # Snyder properties self.assertAlmostEqual(18.06127074, self.elastic_tensor_1.snyder_ac(self.structure)) self.assertAlmostEqual( 0.18937465, self.elastic_tensor_1.snyder_opt(self.structure)) self.assertAlmostEqual( 18.25064540, self.elastic_tensor_1.snyder_total(self.structure)) # Clarke self.assertAlmostEqual( 0.3450307, self.elastic_tensor_1.clarke_thermalcond(self.structure)) # Cahill self.assertAlmostEqual( 0.37896275, self.elastic_tensor_1.cahill_thermalcond(self.structure)) # Debye self.assertAlmostEqual( 198.8037985019, self.elastic_tensor_1.debye_temperature(self.structure)) # structure-property dict sprop_dict = self.elastic_tensor_1.get_structure_property_dict( self.structure) self.assertAlmostEqual(sprop_dict["long_v"], 3534.68123832) for val in sprop_dict.values(): self.assertFalse(isinstance(val, FloatWithUnit)) for k, v in sprop_dict.items(): if k == "structure": self.assertEqual(v, self.structure) else: f = getattr(self.elastic_tensor_1, k) if callable(f): self.assertAlmostEqual( getattr(self.elastic_tensor_1, k)(self.structure), v) else: self.assertAlmostEqual(getattr(self.elastic_tensor_1, k), v) # Test other sprop dict modes sprop_dict = self.elastic_tensor_1.get_structure_property_dict( self.structure, include_base_props=False) self.assertFalse("k_vrh" in sprop_dict) # Test ValueError being raised for structure properties test_et = deepcopy(self.elastic_tensor_1) test_et[0][0][0][0] = -100000 prop_dict = test_et.property_dict for attr_name in sprop_dict: if not attr_name in (list(prop_dict.keys()) + ['structure']): self.assertRaises(ValueError, getattr(test_et, attr_name), self.structure) self.assertRaises(ValueError, test_et.get_structure_property_dict, self.structure) noval_sprop_dict = test_et.get_structure_property_dict( self.structure, ignore_errors=True) self.assertIsNone(noval_sprop_dict['snyder_ac']) def test_new(self): self.assertArrayAlmostEqual(self.elastic_tensor_1, ElasticTensor(self.ft)) nonsymm = self.ft nonsymm[0, 1, 2, 2] += 1.0 with warnings.catch_warnings(record=True) as w: ElasticTensor(nonsymm) self.assertEqual(len(w), 1) badtensor1 = np.zeros((3, 3, 3)) badtensor2 = np.zeros((3, 3, 3, 2)) self.assertRaises(ValueError, ElasticTensor, badtensor1) self.assertRaises(ValueError, ElasticTensor, badtensor2) def test_from_pseudoinverse(self): strain_list = [ Strain.from_deformation(def_matrix) for def_matrix in self.def_stress_dict['deformations'] ] stress_list = [stress for stress in self.def_stress_dict['stresses']] with warnings.catch_warnings(record=True): et_fl = -0.1 * ElasticTensor.from_pseudoinverse( strain_list, stress_list).voigt self.assertArrayAlmostEqual( et_fl.round(2), [[59.29, 24.36, 22.46, 0, 0, 0], [ 28.06, 56.91, 22.46, 0, 0, 0 ], [28.06, 25.98, 54.67, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]]) def test_from_independent_strains(self): strains = self.toec_dict["strains"] stresses = self.toec_dict["stresses"] with warnings.catch_warnings(record=True) as w: et = ElasticTensor.from_independent_strains(strains, stresses) self.assertArrayAlmostEqual(et.voigt, self.toec_dict["C2_raw"], decimal=-1) def test_energy_density(self): film_elac = ElasticTensor.from_voigt( [[324.32, 187.3, 170.92, 0., 0., 0.], [187.3, 324.32, 170.92, 0., 0., 0.], [170.92, 170.92, 408.41, 0., 0., 0.], [0., 0., 0., 150.73, 0., 0.], [0., 0., 0., 0., 150.73, 0.], [0., 0., 0., 0., 0., 238.74]]) dfm = Deformation([[-9.86004855e-01, 2.27539582e-01, -4.64426035e-17], [-2.47802121e-01, -9.91208483e-01, -7.58675185e-17], [-6.12323400e-17, -6.12323400e-17, 1.00000000e+00]]) self.assertAlmostEqual( film_elac.energy_density(dfm.green_lagrange_strain), 0.00125664672793) film_elac.energy_density( Strain.from_deformation([[0.99774738, 0.11520994, -0.], [-0.11520994, 0.99774738, 0.], [ -0., -0., 1., ]]))
def run_task(self, fw_spec): # Get optimized structure optimize_loc = fw_spec["calc_locs"][0]["path"] logger.info("PARSING INITIAL OPTIMIZATION DIRECTORY: {}".format(optimize_loc)) drone = VaspDrone() optimize_doc = drone.assimilate(optimize_loc) opt_struct = Structure.from_dict( optimize_doc["calcs_reversed"][0]["output"]["structure"]) deformations = fw_spec['deformations'] d = {"analysis": {}, "deformation_tasks": {}, "initial_structure": self['structure'].as_dict(), "optimized_structure": opt_struct.as_dict()} stress_dict = {} dtypes = [] for deformation in deformations: defo = deformation['deformation'] d_ind = np.nonzero(defo - np.eye(3)) delta = Decimal((defo - np.eye(3))[d_ind][0]) # Shorthand is d_X_V, X is voigt index, V is value dtype = "_".join(["d", str(reverse_voigt_map[d_ind][0]), "{:.0e}".format(delta)]) strain = IndependentStrain(defo) stress = Stress(deformation['stress']) d["deformation_tasks"][dtype] = {'deformation_matrix': defo, 'strain': strain.tolist(), 'stress': deformation['stress']} dtypes.append(dtype) stress_dict[strain] = stress logger.info("ANALYZING STRESS/STRAIN DATA") # DETERMINE IF WE HAVE 6 "UNIQUE" deformations if len(set([de[:3] for de in dtypes])) == 6: # Perform Elastic tensor fitting and analysis result = ElasticTensor.from_stress_dict(stress_dict) d["elastic_tensor"] = result.voigt.tolist() kg_average = result.kg_average d.update({"K_Voigt": kg_average[0], "G_Voigt": kg_average[1], "K_Reuss": kg_average[2], "G_Reuss": kg_average[3], "K_Voigt_Reuss_Hill": kg_average[4], "G_Voigt_Reuss_Hill": kg_average[5]}) d["universal_anisotropy"] = result.universal_anisotropy d["homogeneous_poisson"] = result.homogeneous_poisson else: raise ValueError("Fewer than 6 unique deformations") d["state"] = "successful" # Save analysis results in json or db db_file = env_chk(self.get('db_file'), fw_spec) if not db_file: with open("elasticity.json", "w") as f: f.write(json.dumps(d, default=DATETIME_HANDLER)) else: db = MMDb.from_db_file(db_file, admin=True) db.collection = db.db["elasticity"] db.collection.insert_one(d) logger.info("ELASTIC ANALYSIS COMPLETE") return FWAction()
def test_from_full_tensor(self): self.assertArrayAlmostEqual(self.elastic_tensor_1, ElasticTensor.from_full_tensor(self.ft))
def run_task(self, fw_spec): ref_struct = self['structure'] d = {"analysis": {}, "initial_structure": self['structure'].as_dict()} # Get optimized structure calc_locs_opt = [ cl for cl in fw_spec.get('calc_locs', []) if 'optimiz' in cl['name'] ] if calc_locs_opt: optimize_loc = calc_locs_opt[-1]['path'] logger.info("Parsing initial optimization directory: {}".format( optimize_loc)) drone = VaspDrone() optimize_doc = drone.assimilate(optimize_loc) opt_struct = Structure.from_dict( optimize_doc["calcs_reversed"][0]["output"]["structure"]) d.update({"optimized_structure": opt_struct.as_dict()}) ref_struct = opt_struct eq_stress = -0.1 * Stress(optimize_doc["calcs_reversed"][0] ["output"]["ionic_steps"][-1]["stress"]) else: eq_stress = None if self.get("fw_spec_field"): d.update({ self.get("fw_spec_field"): fw_spec.get(self.get("fw_spec_field")) }) # Get the stresses, strains, deformations from deformation tasks defo_dicts = fw_spec["deformation_tasks"].values() stresses, strains, deformations = [], [], [] for defo_dict in defo_dicts: stresses.append(Stress(defo_dict["stress"])) strains.append(Strain(defo_dict["strain"])) deformations.append(Deformation(defo_dict["deformation_matrix"])) # Add derived stresses and strains if symmops is present for symmop in defo_dict.get("symmops", []): stresses.append(Stress(defo_dict["stress"]).transform(symmop)) strains.append(Strain(defo_dict["strain"]).transform(symmop)) deformations.append( Deformation( defo_dict["deformation_matrix"]).transform(symmop)) stresses = [-0.1 * s for s in stresses] pk_stresses = [ stress.piola_kirchoff_2(deformation) for stress, deformation in zip(stresses, deformations) ] d['fitting_data'] = { 'cauchy_stresses': stresses, 'eq_stress': eq_stress, 'strains': strains, 'pk_stresses': pk_stresses, 'deformations': deformations } logger.info("Analyzing stress/strain data") # TODO: @montoyjh: what if it's a cubic system? don't need 6. -computron # TODO: Can add population method but want to think about how it should # be done. -montoyjh order = self.get('order', 2) if order > 2: method = 'finite_difference' else: method = self.get('fitting_method', 'finite_difference') if method == 'finite_difference': result = ElasticTensorExpansion.from_diff_fit(strains, pk_stresses, eq_stress=eq_stress, order=order) if order == 2: result = ElasticTensor(result[0]) elif method == 'pseudoinverse': result = ElasticTensor.from_pseudoinverse(strains, pk_stresses) elif method == 'independent': result = ElasticTensor.from_independent_strains( strains, pk_stresses, eq_stress=eq_stress) else: raise ValueError( "Unsupported method, method must be finite_difference, " "pseudoinverse, or independent") ieee = result.convert_to_ieee(ref_struct) d.update({ "elastic_tensor": { "raw": result.voigt, "ieee_format": ieee.voigt } }) if order == 2: d.update({ "derived_properties": ieee.get_structure_property_dict(ref_struct) }) else: soec = ElasticTensor(ieee[0]) d.update({ "derived_properties": soec.get_structure_property_dict(ref_struct) }) d["formula_pretty"] = ref_struct.composition.reduced_formula d["fitting_method"] = method d["order"] = order d = jsanitize(d) # Save analysis results in json or db db_file = env_chk(self.get('db_file'), fw_spec) if not db_file: with open("elasticity.json", "w") as f: f.write(json.dumps(d, default=DATETIME_HANDLER)) else: db = VaspCalcDb.from_db_file(db_file, admin=True) db.collection = db.db["elasticity"] db.collection.insert_one(d) logger.info("Elastic analysis complete.") return FWAction()
class ElasticTensorTest(PymatgenTest): def setUp(self): self.voigt_1 = [[59.33, 28.08, 28.08, 0, 0, 0], [28.08, 59.31, 28.07, 0, 0, 0], [28.08, 28.07, 59.32, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]] mat = np.random.randn(6, 6) mat = mat + np.transpose(mat) self.rand_elastic_tensor = ElasticTensor.from_voigt(mat) self.ft = np.array([[[[59.33, 0, 0], [0, 28.08, 0], [0, 0, 28.08]], [[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]]], [[[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[28.08, 0, 0], [0, 59.31, 0], [0, 0, 28.07]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]]], [[[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]], [[28.08, 0, 0], [0, 28.07, 0], [0, 0, 59.32]]]]) self.elastic_tensor_1 = ElasticTensor(self.ft) filepath = os.path.join(test_dir, 'Sn_def_stress.json') with open(filepath) as f: self.def_stress_dict = json.load(f) with open(os.path.join(test_dir, 'test_toec_data.json')) as f: self.toec_dict = json.load(f) self.structure = self.get_structure("Sn") warnings.simplefilter("always") def test_properties(self): # compliance tensor ct = ComplianceTensor.from_voigt(np.linalg.inv(self.elastic_tensor_1.voigt)) self.assertArrayAlmostEqual(ct, self.elastic_tensor_1.compliance_tensor) # KG average properties self.assertAlmostEqual(38.49111111111, self.elastic_tensor_1.k_voigt) self.assertAlmostEqual(22.05866666666, self.elastic_tensor_1.g_voigt) self.assertAlmostEqual(38.49110945133, self.elastic_tensor_1.k_reuss) self.assertAlmostEqual(20.67146635306, self.elastic_tensor_1.g_reuss) self.assertAlmostEqual(38.49111028122, self.elastic_tensor_1.k_vrh) self.assertAlmostEqual(21.36506650986, self.elastic_tensor_1.g_vrh) # universal anisotropy self.assertAlmostEqual(0.33553509658699, self.elastic_tensor_1.universal_anisotropy) # homogeneous poisson self.assertAlmostEqual(0.26579965576472, self.elastic_tensor_1.homogeneous_poisson) # voigt notation tensor self.assertArrayAlmostEqual(self.elastic_tensor_1.voigt, self.voigt_1) # young's modulus self.assertAlmostEqual(54087787667.160583, self.elastic_tensor_1.y_mod) # prop dict prop_dict = self.elastic_tensor_1.property_dict self.assertAlmostEqual(prop_dict["homogeneous_poisson"], 0.26579965576) for k, v in prop_dict.items(): self.assertAlmostEqual(getattr(self.elastic_tensor_1, k), v) def test_directional_elastic_mod(self): self.assertAlmostEqual(self.elastic_tensor_1.directional_elastic_mod([1, 0, 0]), self.elastic_tensor_1.voigt[0, 0]) self.assertAlmostEqual(self.elastic_tensor_1.directional_elastic_mod([1, 1, 1]), 73.624444444) def test_compliance_tensor(self): stress = self.elastic_tensor_1.calculate_stress([0.01] + [0]*5) comp = self.elastic_tensor_1.compliance_tensor strain = Strain(comp.einsum_sequence([stress])) self.assertArrayAlmostEqual(strain.voigt, [0.01] + [0]*5) def test_directional_poisson_ratio(self): v_12 = self.elastic_tensor_1.directional_poisson_ratio([1, 0, 0], [0, 1, 0]) self.assertAlmostEqual(v_12, 0.321, places=3) def test_structure_based_methods(self): # trans_velocity self.assertAlmostEqual(1996.35019877, self.elastic_tensor_1.trans_v(self.structure)) # long_velocity self.assertAlmostEqual(3534.68123832, self.elastic_tensor_1.long_v(self.structure)) # Snyder properties self.assertAlmostEqual(18.06127074, self.elastic_tensor_1.snyder_ac(self.structure)) self.assertAlmostEqual(0.18937465, self.elastic_tensor_1.snyder_opt(self.structure)) self.assertAlmostEqual(18.25064540, self.elastic_tensor_1.snyder_total(self.structure)) # Clarke self.assertAlmostEqual(0.3450307, self.elastic_tensor_1.clarke_thermalcond(self.structure)) # Cahill self.assertAlmostEqual(0.37896275, self.elastic_tensor_1.cahill_thermalcond(self.structure)) # Debye self.assertAlmostEqual(198.8037985019, self.elastic_tensor_1.debye_temperature(self.structure)) # structure-property dict sprop_dict = self.elastic_tensor_1.get_structure_property_dict(self.structure) self.assertAlmostEqual(sprop_dict["long_v"], 3534.68123832) for val in sprop_dict.values(): self.assertFalse(isinstance(val, FloatWithUnit)) for k, v in sprop_dict.items(): if k=="structure": self.assertEqual(v, self.structure) else: f = getattr(self.elastic_tensor_1, k) if callable(f): self.assertAlmostEqual(getattr(self.elastic_tensor_1, k)(self.structure), v) else: self.assertAlmostEqual(getattr(self.elastic_tensor_1, k), v) # Test other sprop dict modes sprop_dict = self.elastic_tensor_1.get_structure_property_dict( self.structure, include_base_props=False) self.assertFalse("k_vrh" in sprop_dict) # Test ValueError being raised for structure properties test_et = deepcopy(self.elastic_tensor_1) test_et[0][0][0][0] = -100000 prop_dict = test_et.property_dict for attr_name in sprop_dict: if not attr_name in (list(prop_dict.keys()) + ['structure']): self.assertRaises(ValueError, getattr(test_et, attr_name), self.structure) self.assertRaises(ValueError, test_et.get_structure_property_dict, self.structure) noval_sprop_dict = test_et.get_structure_property_dict(self.structure, ignore_errors=True) self.assertIsNone(noval_sprop_dict['snyder_ac']) def test_new(self): self.assertArrayAlmostEqual(self.elastic_tensor_1, ElasticTensor(self.ft)) nonsymm = self.ft nonsymm[0, 1, 2, 2] += 1.0 with warnings.catch_warnings(record=True) as w: ElasticTensor(nonsymm) self.assertEqual(len(w), 1) badtensor1 = np.zeros((3, 3, 3)) badtensor2 = np.zeros((3, 3, 3, 2)) self.assertRaises(ValueError, ElasticTensor, badtensor1) self.assertRaises(ValueError, ElasticTensor, badtensor2) def test_from_pseudoinverse(self): strain_list = [Strain.from_deformation(def_matrix) for def_matrix in self.def_stress_dict['deformations']] stress_list = [stress for stress in self.def_stress_dict['stresses']] with warnings.catch_warnings(record=True): et_fl = -0.1*ElasticTensor.from_pseudoinverse(strain_list, stress_list).voigt self.assertArrayAlmostEqual(et_fl.round(2), [[59.29, 24.36, 22.46, 0, 0, 0], [28.06, 56.91, 22.46, 0, 0, 0], [28.06, 25.98, 54.67, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]]) def test_from_independent_strains(self): strains = self.toec_dict["strains"] stresses = self.toec_dict["stresses"] with warnings.catch_warnings(record=True) as w: et = ElasticTensor.from_independent_strains(strains, stresses) self.assertArrayAlmostEqual(et.voigt, self.toec_dict["C2_raw"], decimal=-1) def test_energy_density(self): film_elac = ElasticTensor.from_voigt([ [324.32, 187.3, 170.92, 0., 0., 0.], [187.3, 324.32, 170.92, 0., 0., 0.], [170.92, 170.92, 408.41, 0., 0., 0.], [0., 0., 0., 150.73, 0., 0.], [0., 0., 0., 0., 150.73, 0.], [0., 0., 0., 0., 0., 238.74]]) dfm = Deformation([[ -9.86004855e-01,2.27539582e-01,-4.64426035e-17], [ -2.47802121e-01,-9.91208483e-01,-7.58675185e-17], [ -6.12323400e-17,-6.12323400e-17,1.00000000e+00]]) self.assertAlmostEqual(film_elac.energy_density(dfm.green_lagrange_strain), 0.00125664672793) film_elac.energy_density(Strain.from_deformation([[ 0.99774738, 0.11520994, -0. ], [-0.11520994, 0.99774738, 0. ], [-0., -0., 1., ]]))
class ElasticTensorTest(PymatgenTest): def setUp(self): self.voigt_1 = [[59.33, 28.08, 28.08, 0, 0, 0], [28.08, 59.31, 28.07, 0, 0, 0], [28.08, 28.07, 59.32, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]] mat = np.random.randn(6, 6) mat = mat + np.transpose(mat) self.rand_elastic_tensor = ElasticTensor.from_voigt(mat) self.ft = np.array([[[[59.33, 0, 0], [0, 28.08, 0], [0, 0, 28.08]], [[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]]], [[[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[28.08, 0, 0], [0, 59.31, 0], [0, 0, 28.07]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]]], [[[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]], [[28.08, 0, 0], [0, 28.07, 0], [0, 0, 59.32]]]]) self.elastic_tensor_1 = ElasticTensor(self.ft) filepath = os.path.join(test_dir, 'Sn_def_stress.json') with open(filepath) as f: self.def_stress_dict = json.load(f) self.structure = self.get_structure("Sn") warnings.simplefilter("always") def test_properties(self): # compliance tensor self.assertArrayAlmostEqual(np.linalg.inv(self.elastic_tensor_1.voigt), self.elastic_tensor_1.compliance_tensor) # KG average properties self.assertAlmostEqual(38.49111111111, self.elastic_tensor_1.k_voigt) self.assertAlmostEqual(22.05866666666, self.elastic_tensor_1.g_voigt) self.assertAlmostEqual(38.49110945133, self.elastic_tensor_1.k_reuss) self.assertAlmostEqual(20.67146635306, self.elastic_tensor_1.g_reuss) self.assertAlmostEqual(38.49111028122, self.elastic_tensor_1.k_vrh) self.assertAlmostEqual(21.36506650986, self.elastic_tensor_1.g_vrh) self.assertArrayAlmostEqual(self.elastic_tensor_1.kg_average, [ 38.49111111111, 22.05866666666, 38.49110945133, 20.67146635306, 38.49111028122, 21.36506650986 ]) # universal anisotropy self.assertAlmostEqual(0.33553509658699, self.elastic_tensor_1.universal_anisotropy) # homogeneous poisson self.assertAlmostEqual(0.26579965576472, self.elastic_tensor_1.homogeneous_poisson) # voigt notation tensor self.assertArrayAlmostEqual(self.elastic_tensor_1.voigt, self.voigt_1) # young's modulus self.assertAlmostEqual(54087787667.160583, self.elastic_tensor_1.y_mod) def test_structure_based_methods(self): # trans_velocity self.assertAlmostEqual(1996.35019877, self.elastic_tensor_1.trans_v(self.structure)) # long_velocity self.assertAlmostEqual(3534.68123832, self.elastic_tensor_1.long_v(self.structure)) # Snyder properties self.assertAlmostEqual(18.06127074, self.elastic_tensor_1.snyder_ac(self.structure)) self.assertAlmostEqual( 0.18937465, self.elastic_tensor_1.snyder_opt(self.structure)) self.assertAlmostEqual( 18.25064540, self.elastic_tensor_1.snyder_total(self.structure)) # Clarke self.assertAlmostEqual( 0.3450307, self.elastic_tensor_1.clarke_thermalcond(self.structure)) # Cahill self.assertAlmostEqual( 0.37896275, self.elastic_tensor_1.cahill_thermalcond(self.structure)) # Debye self.assertAlmostEqual( 247.3058931, self.elastic_tensor_1.debye_temperature(self.structure)) self.assertAlmostEqual( 189.05670205, self.elastic_tensor_1.debye_temperature_gibbs(self.structure)) def test_new(self): self.assertArrayAlmostEqual(self.elastic_tensor_1, ElasticTensor(self.ft)) nonsymm = self.ft nonsymm[0, 1, 2, 2] += 1.0 with warnings.catch_warnings(record=True) as w: ElasticTensor(nonsymm) self.assertEqual(len(w), 1) badtensor1 = np.zeros((3, 3, 3)) badtensor2 = np.zeros((3, 3, 3, 2)) self.assertRaises(ValueError, ElasticTensor, badtensor1) self.assertRaises(ValueError, ElasticTensor, badtensor2) def test_from_strain_stress_list(self): strain_list = [ Strain.from_deformation(def_matrix) for def_matrix in self.def_stress_dict['deformations'] ] stress_list = [stress for stress in self.def_stress_dict['stresses']] with warnings.catch_warnings(record=True): et_fl = -0.1 * ElasticTensor.from_strain_stress_list( strain_list, stress_list).voigt self.assertArrayAlmostEqual( et_fl.round(2), [[59.29, 24.36, 22.46, 0, 0, 0], [ 28.06, 56.91, 22.46, 0, 0, 0 ], [28.06, 25.98, 54.67, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]]) def test_from_stress_dict(self): stress_dict = dict( list( zip([ IndependentStrain(def_matrix) for def_matrix in self.def_stress_dict['deformations'] ], [ Stress(stress_matrix) for stress_matrix in self.def_stress_dict['stresses'] ]))) minimal_sd = { k: v for k, v in stress_dict.items() if (abs(k[k.independent_deformation] - 0.015) < 1e-10 or abs(k[k.independent_deformation] - 0.01005) < 1e-10) } with warnings.catch_warnings(record=True): et_from_sd = ElasticTensor.from_stress_dict(stress_dict) et_from_minimal_sd = ElasticTensor.from_stress_dict(minimal_sd) self.assertArrayAlmostEqual(et_from_sd.voigt_symmetrized.round(2), self.elastic_tensor_1) self.assertAlmostEqual(50.63394169, et_from_minimal_sd[0, 0, 0, 0]) def test_energy_density(self): film_elac = ElasticTensor.from_voigt( [[324.32, 187.3, 170.92, 0., 0., 0.], [187.3, 324.32, 170.92, 0., 0., 0.], [170.92, 170.92, 408.41, 0., 0., 0.], [0., 0., 0., 150.73, 0., 0.], [0., 0., 0., 0., 150.73, 0.], [0., 0., 0., 0., 0., 238.74]]) dfm = Deformation([[-9.86004855e-01, 2.27539582e-01, -4.64426035e-17], [-2.47802121e-01, -9.91208483e-01, -7.58675185e-17], [-6.12323400e-17, -6.12323400e-17, 1.00000000e+00]]) self.assertAlmostEqual( film_elac.energy_density(dfm.green_lagrange_strain), 0.000125664672793) film_elac.energy_density( Strain.from_deformation([[0.99774738, 0.11520994, -0.], [-0.11520994, 0.99774738, 0.], [ -0., -0., 1., ]])) @unittest.skipIf(not sympy, "sympy not present, skipping toec_fit test") def test_toec_fit(self): with open(os.path.join(test_dir, 'test_toec_data.json')) as f: toec_dict = json.load(f) strains = [Strain(sm) for sm in toec_dict['strains']] pk_stresses = [Stress(d) for d in toec_dict['pk_stresses']] reduced = [(strain, pks) for strain, pks in zip(strains, pk_stresses) if not (abs(abs(strain) - 0.05) < 1e-10).any()] with warnings.catch_warnings(record=True) as w: c2, c3 = toec_fit(strains, pk_stresses, eq_stress=toec_dict["eq_stress"]) self.assertArrayAlmostEqual(c2.voigt, toec_dict["C2_raw"]) self.assertArrayAlmostEqual(c3.voigt, toec_dict["C3_raw"]) # Try with reduced data set r_strains, r_pk_stresses = zip(*reduced) c2_red, c3_red = toec_fit(r_strains, r_pk_stresses, eq_stress=toec_dict["eq_stress"]) self.assertArrayAlmostEqual(c2, c2_red, decimal=0) self.assertArrayAlmostEqual(c3, c3_red, decimal=-1)
def run_task(self, fw_spec): ref_struct = self['structure'] d = { "analysis": {}, "initial_structure": self['structure'].as_dict() } # Get optimized structure calc_locs_opt = [cl for cl in fw_spec.get('calc_locs', []) if 'optimiz' in cl['name']] if calc_locs_opt: optimize_loc = calc_locs_opt[-1]['path'] logger.info("Parsing initial optimization directory: {}".format(optimize_loc)) drone = VaspDrone() optimize_doc = drone.assimilate(optimize_loc) opt_struct = Structure.from_dict(optimize_doc["calcs_reversed"][0]["output"]["structure"]) d.update({"optimized_structure": opt_struct.as_dict()}) ref_struct = opt_struct eq_stress = -0.1*Stress(optimize_doc["calcs_reversed"][0]["output"]["ionic_steps"][-1]["stress"]) else: eq_stress = None if self.get("fw_spec_field"): d.update({self.get("fw_spec_field"): fw_spec.get(self.get("fw_spec_field"))}) # Get the stresses, strains, deformations from deformation tasks defo_dicts = fw_spec["deformation_tasks"].values() stresses, strains, deformations = [], [], [] for defo_dict in defo_dicts: stresses.append(Stress(defo_dict["stress"])) strains.append(Strain(defo_dict["strain"])) deformations.append(Deformation(defo_dict["deformation_matrix"])) # Add derived stresses and strains if symmops is present for symmop in defo_dict.get("symmops", []): stresses.append(Stress(defo_dict["stress"]).transform(symmop)) strains.append(Strain(defo_dict["strain"]).transform(symmop)) deformations.append(Deformation(defo_dict["deformation_matrix"]).transform(symmop)) stresses = [-0.1*s for s in stresses] pk_stresses = [stress.piola_kirchoff_2(deformation) for stress, deformation in zip(stresses, deformations)] d['fitting_data'] = {'cauchy_stresses': stresses, 'eq_stress': eq_stress, 'strains': strains, 'pk_stresses': pk_stresses, 'deformations': deformations } logger.info("Analyzing stress/strain data") # TODO: @montoyjh: what if it's a cubic system? don't need 6. -computron # TODO: Can add population method but want to think about how it should # be done. -montoyjh order = self.get('order', 2) if order > 2: method = 'finite_difference' else: method = self.get('fitting_method', 'finite_difference') if method == 'finite_difference': result = ElasticTensorExpansion.from_diff_fit( strains, pk_stresses, eq_stress=eq_stress, order=order) if order == 2: result = ElasticTensor(result[0]) elif method == 'pseudoinverse': result = ElasticTensor.from_pseudoinverse(strains, pk_stresses) elif method == 'independent': result = ElasticTensor.from_independent_strains(strains, pk_stresses, eq_stress=eq_stress) else: raise ValueError("Unsupported method, method must be finite_difference, " "pseudoinverse, or independent") ieee = result.convert_to_ieee(ref_struct) d.update({ "elastic_tensor": { "raw": result.voigt, "ieee_format": ieee.voigt } }) if order == 2: d.update({"derived_properties": ieee.get_structure_property_dict(ref_struct)}) else: soec = ElasticTensor(ieee[0]) d.update({"derived_properties": soec.get_structure_property_dict(ref_struct)}) d["formula_pretty"] = ref_struct.composition.reduced_formula d["fitting_method"] = method d["order"] = order d = jsanitize(d) # Save analysis results in json or db db_file = env_chk(self.get('db_file'), fw_spec) if not db_file: with open("elasticity.json", "w") as f: f.write(json.dumps(d, default=DATETIME_HANDLER)) else: db = VaspCalcDb.from_db_file(db_file, admin=True) db.collection = db.db["elasticity"] db.collection.insert_one(d) logger.info("Elastic analysis complete.") return FWAction()
class ElasticTensorTest(PymatgenTest): def setUp(self): self.voigt_1 = [[59.33, 28.08, 28.08, 0, 0, 0], [28.08, 59.31, 28.07, 0, 0, 0], [28.08, 28.07, 59.32, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]] mat = np.random.randn(6, 6) mat = mat + np.transpose(mat) self.rand_elastic_tensor = ElasticTensor.from_voigt(mat) self.ft = np.array([[[[59.33, 0, 0], [0, 28.08, 0], [0, 0, 28.08]], [[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]]], [[[0, 26.35, 0], [26.35, 0, 0], [0, 0, 0]], [[28.08, 0, 0], [0, 59.31, 0], [0, 0, 28.07]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]]], [[[0, 0, 26.35], [0, 0, 0], [26.35, 0, 0]], [[0, 0, 0], [0, 0, 26.35], [0, 26.35, 0]], [[28.08, 0, 0], [0, 28.07, 0], [0, 0, 59.32]]]]) self.elastic_tensor_1 = ElasticTensor(self.ft) filepath = os.path.join(test_dir, 'Sn_def_stress.json') with open(filepath) as f: self.def_stress_dict = json.load(f) self.structure = self.get_structure("Sn") warnings.simplefilter("always") def test_properties(self): # compliance tensor self.assertArrayAlmostEqual(np.linalg.inv(self.elastic_tensor_1.voigt), self.elastic_tensor_1.compliance_tensor) # KG average properties self.assertAlmostEqual(38.49111111111, self.elastic_tensor_1.k_voigt) self.assertAlmostEqual(22.05866666666, self.elastic_tensor_1.g_voigt) self.assertAlmostEqual(38.49110945133, self.elastic_tensor_1.k_reuss) self.assertAlmostEqual(20.67146635306, self.elastic_tensor_1.g_reuss) self.assertAlmostEqual(38.49111028122, self.elastic_tensor_1.k_vrh) self.assertAlmostEqual(21.36506650986, self.elastic_tensor_1.g_vrh) self.assertArrayAlmostEqual(self.elastic_tensor_1.kg_average, [38.49111111111, 22.05866666666, 38.49110945133, 20.67146635306, 38.49111028122, 21.36506650986]) # universal anisotropy self.assertAlmostEqual(0.33553509658699, self.elastic_tensor_1.universal_anisotropy) # homogeneous poisson self.assertAlmostEqual(0.26579965576472, self.elastic_tensor_1.homogeneous_poisson) # voigt notation tensor self.assertArrayAlmostEqual(self.elastic_tensor_1.voigt, self.voigt_1) # young's modulus self.assertAlmostEqual(54087787667.160583, self.elastic_tensor_1.y_mod) def test_structure_based_methods(self): # trans_velocity self.assertAlmostEqual(1996.35019877, self.elastic_tensor_1.trans_v(self.structure)) # long_velocity self.assertAlmostEqual(3534.68123832, self.elastic_tensor_1.long_v(self.structure)) # Snyder properties self.assertAlmostEqual(18.06127074, self.elastic_tensor_1.snyder_ac(self.structure)) self.assertAlmostEqual(0.18937465, self.elastic_tensor_1.snyder_opt(self.structure)) self.assertAlmostEqual(18.25064540, self.elastic_tensor_1.snyder_total(self.structure)) # Clarke self.assertAlmostEqual(0.3450307, self.elastic_tensor_1.clarke_thermalcond(self.structure)) # Cahill self.assertAlmostEqual(0.37896275, self.elastic_tensor_1.cahill_thermalcond(self.structure)) # Debye self.assertAlmostEqual(247.3058931, self.elastic_tensor_1.debye_temperature(self.structure)) self.assertAlmostEqual(189.05670205, self.elastic_tensor_1.debye_temperature_gibbs(self.structure)) def test_new(self): self.assertArrayAlmostEqual(self.elastic_tensor_1, ElasticTensor(self.ft)) nonsymm = self.ft nonsymm[0, 1, 2, 2] += 1.0 with warnings.catch_warnings(record=True) as w: ElasticTensor(nonsymm) self.assertEqual(len(w), 1) badtensor1 = np.zeros((3, 3, 3)) badtensor2 = np.zeros((3, 3, 3, 2)) self.assertRaises(ValueError, ElasticTensor, badtensor1) self.assertRaises(ValueError, ElasticTensor, badtensor2) def test_from_strain_stress_list(self): strain_list = [Strain.from_deformation(def_matrix) for def_matrix in self.def_stress_dict['deformations']] stress_list = [stress for stress in self.def_stress_dict['stresses']] with warnings.catch_warnings(record=True): et_fl = -0.1*ElasticTensor.from_strain_stress_list(strain_list, stress_list).voigt self.assertArrayAlmostEqual(et_fl.round(2), [[59.29, 24.36, 22.46, 0, 0, 0], [28.06, 56.91, 22.46, 0, 0, 0], [28.06, 25.98, 54.67, 0, 0, 0], [0, 0, 0, 26.35, 0, 0], [0, 0, 0, 0, 26.35, 0], [0, 0, 0, 0, 0, 26.35]]) def test_from_stress_dict(self): stress_dict = dict(list(zip([IndependentStrain(def_matrix) for def_matrix in self.def_stress_dict['deformations']], [Stress(stress_matrix) for stress_matrix in self.def_stress_dict['stresses']]))) with warnings.catch_warnings(record = True): et_from_sd = ElasticTensor.from_stress_dict(stress_dict) self.assertArrayAlmostEqual(et_from_sd.voigt_symmetrized.round(2), self.elastic_tensor_1) def test_energy_density(self): film_elac = ElasticTensor.from_voigt([ [324.32, 187.3, 170.92, 0., 0., 0.], [187.3, 324.32, 170.92, 0., 0., 0.], [170.92, 170.92, 408.41, 0., 0., 0.], [0., 0., 0., 150.73, 0., 0.], [0., 0., 0., 0., 150.73, 0.], [0., 0., 0., 0., 0., 238.74]]) dfm = Deformation([[ -9.86004855e-01,2.27539582e-01,-4.64426035e-17], [ -2.47802121e-01,-9.91208483e-01,-7.58675185e-17], [ -6.12323400e-17,-6.12323400e-17,1.00000000e+00]]) self.assertAlmostEqual(film_elac.energy_density(dfm.green_lagrange_strain), 0.000125664672793)