Example #1
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")
Example #2
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)
Example #3
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)
Example #4
0
 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)
Example #5
0
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
Example #6
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.00125664672793)

        film_elac.energy_density(
            Strain.from_deformation([[0.99774738, 0.11520994, -0.],
                                     [-0.11520994, 0.99774738, 0.],
                                     [
                                         -0.,
                                         -0.,
                                         1.,
                                     ]]))
Example #7
0
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)
Example #8
0
    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)
Example #9
0
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}
Example #11
0
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)
Example #12
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)
Example #13
0
 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")
Example #14
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")
Example #15
0
 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)
       }
Example #17
0
 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)
Example #18
0
 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)
Example #19
0
    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()
Example #20
0
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
Example #21
0
    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()
Example #23
0
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
Example #24
0
 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]])
Example #25
0
 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])
Example #26
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
Example #27
0
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)
Example #28
0
 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]])
Example #29
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")
Example #30
0
    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)
Example #33
0
 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")
Example #34
0
    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
Example #35
0
    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()
Example #36
0
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.,
                                     ]]))
Example #37
0
    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()
Example #38
0
 def test_from_full_tensor(self):
     self.assertArrayAlmostEqual(self.elastic_tensor_1,
                                 ElasticTensor.from_full_tensor(self.ft))
Example #39
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()
Example #40
0
 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)
Example #41
0
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.,        ]]))
Example #42
0
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)
Example #43
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()
Example #44
0
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)