Пример #1
0
    def run_task(self, fw_spec):
        v = Vasprun('vasprun.xml.gz')
        stress = v.ionic_steps[-1]['stress']
        defo = self['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)
        defo_dict = {'deformation_matrix': defo,
                     'strain': strain.tolist(),
                     'stress': stress}

        return FWAction(mod_spec=[{'_set': {
            'deformation_tasks->{}'.format(dtype): defo_dict}}])
Пример #2
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)
Пример #3
0
 def test_as_strain_dict(self):
     strain_dict = self.default_dss.as_strain_dict()
     for i, def_struct in enumerate(self.default_dss):
         test_strain = IndependentStrain(self.default_dss.deformations[i])
         strain_keys = [
             strain for strain in list(strain_dict.keys())
             if (strain == test_strain).all()
         ]
         self.assertEqual(len(strain_keys), 1)
         self.assertEqual(self.default_dss.def_structs[i],
                          strain_dict[strain_keys[0]])
Пример #4
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.ij] - 0.015) < 1e-10 or abs(k[k.ij] - 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])
Пример #5
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()
Пример #6
0
 def test_new(self):
     with self.assertRaises(ValueError):
         IndependentStrain([[0.1, 0.1, 0], [0, 0, 0], [0, 0, 0]])
Пример #7
0
 def setUp(self):
     self.ind_strain = IndependentStrain([[1, 0.1, 0], [0, 1, 0], [0, 0,
                                                                   1]])
Пример #8
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()
Пример #9
0
    def run_task(self, fw_spec):
        d = {
            "analysis": {},
            "deformation_tasks": fw_spec["deformation_tasks"],
            "initial_structure": self['structure'].as_dict()
        }

        # Get optimized structure
        calc_locs_opt = [
            cl for cl in fw_spec['calc_locs'] if 'optimize' 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()})

        # TODO: @montoyjh: does the below have anything to do with elastic tensor? If not, try
        # the more general fw_spec_field approach in the VaspToDb rather than hard-coding the
        # tags insertion here. -computron
        if fw_spec.get("tags", None):
            d["tags"] = fw_spec["tags"]

        results = fw_spec["deformation_tasks"].values()
        defos = [r["deformation_matrix"] for r in results]
        stresses = [r["stress"] for r in results]
        strains = np.array([Strain(r["strain"]).voigt for r in results])
        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
        # TODO: @montoyjh: what if it's a cubic system? don't need 6. -computron
        if np.linalg.matrix_rank(strains) == 6:
            # Perform Elastic tensor fitting and analysis
            result = ElasticTensor.from_stress_dict(stress_dict)
            d["elastic_tensor"] = result.voigt.tolist()
            d.update(result.property_dict)

        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 = 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()
Пример #10
0
    def process_item(self, item):
        """
        Process the tasks and materials into a dielectrics collection

        Args:
            item dict: a dict of material_id, structure, and tasks

        Returns:
            dict: a dieletrics dictionary  
        """
        root_mats = [
            mat for mat in item["mats"]
            if mat.get("inputs", {}).get("structure optimization", None)
        ]
        deform_mats = [mat for mat in item["mats"] if mat not in root_mats]
        docs = []

        # TODO: What structure matcher parameters to use?
        # TODO: Should SM parameters be configurable?
        sm = StructureMatcher(primitive_cell=True,
                              scale=True,
                              attempt_supercell=False,
                              allow_subset=False,
                              comparator=ElementComparator())

        for r_mat in root_mats:

            # Enumerate over all deformations
            r_struc = Structure.from_dict(r_mat['initial_structure'])

            defos = []
            stresses = []
            strains = []
            m_ids = []

            for d_mat in deform_mats:
                # Find deformation matrix
                d_struc = Structure.from_dict(d_mat["initial_structure"])
                transform_matrix = np.transpose(
                    np.linalg.solve(r_struc.lattice.matrix,
                                    d_struc.lattice.matrix))
                # apply deformation matrix to root_mat and check if the two structures match
                dfm = Deformation(transform_matrix)
                dfm_struc = dfm.apply_to_structure(r_struc)

                # if match store stress and strain matrix
                if sm.fit(dfm_struc, d_struc):
                    # This is a deformtion of the root struc
                    defos.append(dfm)
                    stresses.append(d_mat['stress'])
                    strains.append(dfm.green_lagrange_strain)
                    m_ids.append(d_mat['material_id'])

            stress_dict = {
                IndependentStrain(defo): Stress(stress)
                for defo, stress in zip(defos, stresses)
            }

            self.__logger.info("Analyzing stress/strain data")

            # Determine if we have 6 unique deformations
            if np.linalg.matrix_rank(strains) == 6:
                # Perform Elastic tensor fitting and analysis
                result = ElasticTensor.from_stress_dict(stress_dict)

                d = {
                    "material_id": r_mat["material_id"],
                    "elasticity": {
                        "elastic_tensor": result.voigt.tolist(),
                        "material_ids": m_ids
                    }
                }

                d["elasticity"].update(result.property_dict)

                docs.append(d)
            else:
                self.__logger.warn(
                    "Fewer than 6 unique deformations for {}".format(
                        r_mat["material_id"]))

        return docs
Пример #11
0
    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()