Exemple #1
0
 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)
Exemple #2
0
 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)
Exemple #3
0
    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")
Exemple #4
0
    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")
Exemple #5
0
    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 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)
Exemple #7
0
    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()
Exemple #8
0
def get_elastic_analysis(opt_task, defo_tasks):
    """
    Performs the analysis of opt_tasks and defo_tasks necessary for
    an elastic analysis

    Args:
        opt_task: task doc corresponding to optimization
        defo_tasks: task_doc corresponding to deformations

    Returns:
        elastic document with fitted elastic tensor and analysis

    """
    elastic_doc = {"warnings": []}
    opt_struct = Structure.from_dict(opt_task['output']['structure'])
    input_struct = Structure.from_dict(opt_task['input']['structure'])
    # For now, discern order (i.e. TOEC) using parameters from optimization
    # TODO: figure this out more intelligently
    diff = get(opt_task, "input.incar.EDIFFG", 0)
    order = 3 if np.isclose(diff, -0.001) else 2
    explicit, derived = process_elastic_calcs(opt_task, defo_tasks)
    all_calcs = explicit + derived
    stresses = [c.get("cauchy_stress") for c in all_calcs]
    pk_stresses = [c.get("pk_stress") for c in all_calcs]
    strains = [c.get("strain") for c in all_calcs]
    elastic_doc['calculations'] = all_calcs
    vstrains = [s.zeroed(0.002).voigt for s in strains]
    if np.linalg.matrix_rank(vstrains) == 6:
        if order == 2:
            et_fit = legacy_fit(strains, stresses)
        elif order == 3:
            # Test for TOEC
            if len(strains) < 70:
                logger.info("insufficient valid strains for {} TOEC".format(
                    opt_task['formula_pretty']))
                return None
            eq_stress = -0.1 * Stress(opt_task['output']['stress'])
            # strains = [s.zeroed(0.0001) for s in strains]
            # et_expansion = pdb_function(ElasticTensorExpansion.from_diff_fit,
            #     strains, pk_stresses, eq_stress=eq_stress, tol=1e-5)
            et_exp_raw = ElasticTensorExpansion.from_diff_fit(
                strains, pk_stresses, eq_stress=eq_stress, tol=1e-6)
            et_exp = et_exp_raw.voigt_symmetrized.convert_to_ieee(opt_struct)
            et_exp = et_exp.round(1)
            et_fit = ElasticTensor(et_exp[0])
            # Update elastic doc with TOEC stuff
            tec = et_exp.thermal_expansion_coeff(opt_struct, 300)
            elastic_doc.update({
                "elastic_tensor_expansion":
                elastic_sanitize(et_exp),
                "elastic_tensor_expansion_original":
                elastic_sanitize(et_exp_raw),
                "thermal_expansion_tensor":
                tec,
                "average_linear_thermal_expansion":
                np.trace(tec) / 3
            })
        et = et_fit.voigt_symmetrized.convert_to_ieee(opt_struct)
        vasp_input = opt_task['input']
        if 'structure' in vasp_input:
            vasp_input.pop('structure')
        completed_at = max([d['completed_at'] for d in defo_tasks])
        elastic_doc.update({
            "optimization_task_id":
            opt_task['task_id'],
            "optimization_dir_name":
            opt_task['dir_name'],
            "cauchy_stresses":
            stresses,
            "strains":
            strains,
            "elastic_tensor":
            elastic_sanitize(et.zeroed(0.01).round(0)),
            # Convert compliance to 10^-12 Pa
            "compliance_tensor":
            elastic_sanitize(et.compliance_tensor * 1000),
            "elastic_tensor_original":
            elastic_sanitize(et_fit),
            "optimized_structure":
            opt_struct,
            "spacegroup":
            input_struct.get_space_group_info()[0],
            "input_structure":
            input_struct,
            "completed_at":
            completed_at,
            "optimization_input":
            vasp_input,
            "order":
            order,
            "pretty_formula":
            opt_struct.composition.reduced_formula
        })
        # Add magnetic type
        mag = CollinearMagneticStructureAnalyzer(opt_struct).ordering.value
        elastic_doc['magnetic_type'] = mag_types[mag]
        try:
            prop_dict = et.get_structure_property_dict(opt_struct)
            prop_dict.pop('structure')
        except ValueError:
            logger.debug("Negative K or G found, structure property "
                         "dict not computed")
            prop_dict = et.property_dict
        for k, v in prop_dict.items():
            if k in ['homogeneous_poisson', 'universal_anisotropy']:
                prop_dict[k] = np.round(v, 2)
            else:
                prop_dict[k] = np.round(v, 0)
        elastic_doc.update(prop_dict)
        # Update with state and warnings
        state, warnings = get_state_and_warnings(elastic_doc)
        elastic_doc.update({"state": state, "warnings": warnings})
        # TODO: add kpoints params?
        return elastic_doc
    else:
        logger.info("insufficient valid strains for {}".format(
            opt_task['formula_pretty']))
        return None
                        - np.identity(3)) / 2.0, h)))
eps_voigt = np.empty([6, eps_mat.shape[0]], "d")
eps_voigt[0] = eps_mat[:, 0, 0]
eps_voigt[1] = eps_mat[:, 1, 1]
eps_voigt[2] = eps_mat[:, 2, 2]
eps_voigt[3] = eps_mat[:, 2, 1]
eps_voigt[4] = eps_mat[:, 2, 0]
eps_voigt[5] = eps_mat[:, 1, 0]
eps_voigt_mean = np.mean(eps_voigt, axis=1)
Smat = np.zeros([6, 6], "d")
for i in range(6):
    for j in range(i, 6):
        Smat[i,
             j] = np.mean(eps_voigt[i] *
                          eps_voigt[j]) - eps_voigt_mean[i] * eps_voigt_mean[j]
        if i != j: Smat[j, i] = Smat[i, j]
T = 300
V = np.linalg.det(h0)
Cmat = np.linalg.inv(Smat) * ((1.3806488E-23 * T) / (V * 1E-30)) * 1E-9
Cmat = np.around(Cmat, decimals=2)
print(Cmat)
Cmat_eig = np.linalg.eigvals(Cmat)
mechanical_eig_max.append(max(Cmat_eig))
mechanical_eig_min.append(min(Cmat_eig))
print(mechanical_eig_max)
print(mechanical_eig_min)

mat = Tensor.from_voigt(Cmat)
elastic = ElasticTensor(mat)
print(elastic.k_vrh)
#np.savetxt("pcu_1.cij", Cmat)
Exemple #10
0
 def test_new(self):
     self.assertArrayAlmostEqual(self.elastic_tensor_1,
                                 ElasticTensor(self.ft))