def test_check_freysoldt_delocalized(self):
        de = DefectEntry(self.vac,
                         0.0,
                         corrections={},
                         parameters=self.frey_params,
                         entry_id=None)
        de.parameters.update(
            {"is_compatible":
             True})  # needs to be initialized with this here for unittest
        dc = DefectCompatibility(plnr_avg_var_tol=0.1, plnr_avg_minmax_tol=0.5)
        dentry = dc.perform_freysoldt(de)

        # check case which fits under compatibility constraints
        dentry = dc.check_freysoldt_delocalized(dentry)
        frey_delocal = dentry.parameters["delocalization_meta"]["plnr_avg"]
        self.assertTrue(frey_delocal["is_compatible"])
        ans_var = [0.00038993, 0.02119532, 0.02119532]
        ans_window = [0.048331509, 0.36797169, 0.36797169]
        for ax in range(3):
            ax_metadata = frey_delocal["metadata"][ax]
            self.assertTrue(ax_metadata["frey_variance_compatible"])
            self.assertAlmostEqual(ax_metadata["frey_variance"], ans_var[ax])
            self.assertTrue(ax_metadata["frey_minmax_compatible"])
            self.assertAlmostEqual(ax_metadata["frey_minmax_window"],
                                   ans_window[ax])

        self.assertTrue(dentry.parameters["is_compatible"])

        # check planar delocalization on 2nd and 3rd axes
        dc = DefectCompatibility(plnr_avg_var_tol=0.1, plnr_avg_minmax_tol=0.2)
        dentry.parameters.update({"is_compatible": True})
        dentry = dc.check_freysoldt_delocalized(dentry)
        frey_delocal = dentry.parameters["delocalization_meta"]["plnr_avg"]
        self.assertFalse(frey_delocal["is_compatible"])
        ax_metadata = frey_delocal["metadata"][0]
        self.assertTrue(ax_metadata["frey_variance_compatible"])
        self.assertTrue(ax_metadata["frey_minmax_compatible"])
        for ax in [1, 2]:
            ax_metadata = frey_delocal["metadata"][ax]
            self.assertTrue(ax_metadata["frey_variance_compatible"])
            self.assertFalse(ax_metadata["frey_minmax_compatible"])

        self.assertFalse(dentry.parameters["is_compatible"])

        # check variance based delocalization on 2nd and 3rd axes
        dc = DefectCompatibility(plnr_avg_var_tol=0.01,
                                 plnr_avg_minmax_tol=0.5)
        dentry.parameters.update({"is_compatible": True})
        dentry = dc.check_freysoldt_delocalized(dentry)
        frey_delocal = dentry.parameters["delocalization_meta"]["plnr_avg"]
        self.assertFalse(frey_delocal["is_compatible"])
        ax_metadata = frey_delocal["metadata"][0]
        self.assertTrue(ax_metadata["frey_variance_compatible"])
        self.assertTrue(ax_metadata["frey_minmax_compatible"])
        for ax in [1, 2]:
            ax_metadata = frey_delocal["metadata"][ax]
            self.assertFalse(ax_metadata["frey_variance_compatible"])
            self.assertTrue(ax_metadata["frey_minmax_compatible"])

        self.assertFalse(dentry.parameters["is_compatible"])
    def test_bandfilling_SOC_calc(self):
        v = Vasprun(os.path.join(PymatgenTest.TEST_FILES_DIR, "vasprun.xml.int_Te_SOC.gz"))
        struc = v.structures[0]
        interstitial = Interstitial(struc, struc.sites[-1], charge=-2)
        eigenvalues = v.eigenvalues.copy()
        kptweights = v.actual_kpoints_weights
        potalign = -0.1
        defect_incar = v.incar

        bandfill_params = {
            "eigenvalues": eigenvalues,
            "kpoint_weights": kptweights,
            "potalign": potalign,
            "vbm": 1.6465,  # bulk VBM
            "cbm": 3.1451,  # bulk CBM
            "run_metadata": {"defect_incar": defect_incar},
        }

        soc_dentry = DefectEntry(
            interstitial,
            0.0,
            corrections={},
            parameters=bandfill_params,
            entry_id=None,
        )
        dc = DefectCompatibility()
        soc_dentry = dc.process_entry(soc_dentry)

        self.assertAlmostEqual(soc_dentry.corrections["bandfilling_correction"], -1.9628402187500003)
    def test_perform_all_corrections(self):

        # return entry even if insufficent values are provided
        # for freysoldt, kumagai, bandfilling, or band edge shifting
        de = DefectEntry(self.vac, 0.0, corrections={}, parameters={}, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.perform_all_corrections(de)
        self.assertIsNotNone(dentry)
 def test_delocalization_analysis(self):
     #return entry even if insufficent values are provided
     # for delocalization analysis with freysoldt, kumagai,
     # bandfilling, or band edge shifting
     de = DefectEntry(self.vac, 0., corrections={}, parameters={}, entry_id=None)
     dc = DefectCompatibility()
     dentry = dc.delocalization_analysis( de)
     self.assertIsNotNone( dentry)
    def test_perform_all_corrections(self):

        #return entry even if insufficent values are provided
        # for freysoldt, kumagai, bandfilling, or band edge shifting
        de = DefectEntry(self.vac, 0., corrections={}, parameters={}, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.perform_all_corrections( de)
        self.assertIsNotNone( dentry)
 def test_delocalization_analysis(self):
     # return entry even if insufficent values are provided
     # for delocalization analysis with freysoldt, kumagai,
     # bandfilling, or band edge shifting
     de = DefectEntry(self.vac, 0.0, corrections={}, parameters={}, entry_id=None)
     dc = DefectCompatibility()
     dentry = dc.delocalization_analysis(de)
     self.assertIsNotNone(dentry)
    def test_run_band_edge_shifting(self):
        de = DefectEntry(self.vac, 0., corrections={}, parameters=self.band_edge_params, entry_id=None)

        dc = DefectCompatibility()
        dentry = dc.perform_band_edge_shifting( de)
        val = dentry.parameters['bandshift_meta']
        self.assertEqual(val['vbmshift'], -0.5)
        self.assertEqual(val['cbmshift'], 0.4)
        self.assertEqual(val['bandedgeshifting_correction'], 1.5)
    def test_run_bandfilling(self):
        de = DefectEntry(self.vac, 0., corrections={}, parameters=self.bandfill_params, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.perform_bandfilling( de)

        val = dentry.parameters['bandfilling_meta']
        self.assertAlmostEqual(val['num_hole_vbm'], 0.)
        self.assertAlmostEqual(val['num_elec_cbm'], 0.)
        self.assertAlmostEqual(val['bandfilling_correction'], 0.)
    def test_perform_freysoldt(self):
        de = DefectEntry(self.vac, 0.0, corrections={}, parameters=self.frey_params, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.perform_freysoldt(de)

        val = dentry.parameters["freysoldt_meta"]
        self.assertAlmostEqual(val["freysoldt_electrostatic"], 0.975893)
        self.assertAlmostEqual(val["freysoldt_potential_alignment_correction"], 4.4700574)
        self.assertAlmostEqual(val["freysoldt_potalign"], 1.4900191)
        self.assertTrue("pot_corr_uncertainty_md" in val.keys())
        self.assertTrue("pot_plot_data" in val.keys())
    def test_perform_kumagai(self):
        de = DefectEntry( self.kumagai_vac, 0., parameters=self.kumagai_params)
        dc = DefectCompatibility()
        dentry = dc.perform_kumagai( de)

        val = dentry.parameters['kumagai_meta']
        self.assertAlmostEqual(val['kumagai_electrostatic'], 0.88236299)
        self.assertAlmostEqual(val['kumagai_potential_alignment_correction'], 2.09704862)
        self.assertAlmostEqual(val['kumagai_potalign'], 0.69901620)
        self.assertTrue('pot_corr_uncertainty_md' in val.keys())
        self.assertTrue('pot_plot_data' in val.keys())
    def test_perform_freysoldt(self):
        de = DefectEntry(self.vac, 0., corrections={}, parameters=self.frey_params, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.perform_freysoldt( de)

        val = dentry.parameters['freysoldt_meta']
        self.assertAlmostEqual(val['freysoldt_electrostatic'], 0.975893)
        self.assertAlmostEqual(val['freysoldt_potential_alignment_correction'], 4.4700574)
        self.assertAlmostEqual(val['freysoldt_potalign'], 1.4900191)
        self.assertTrue('pot_corr_uncertainty_md' in val.keys())
        self.assertTrue('pot_plot_data' in val.keys())
    def test_perform_kumagai(self):
        de = DefectEntry(self.kumagai_vac, 0.0, parameters=self.kumagai_params)
        dc = DefectCompatibility()
        dentry = dc.perform_kumagai(de)

        val = dentry.parameters["kumagai_meta"]
        self.assertAlmostEqual(val["kumagai_electrostatic"], 0.88236299)
        self.assertAlmostEqual(val["kumagai_potential_alignment_correction"], 2.09704862)
        self.assertAlmostEqual(val["kumagai_potalign"], 0.69901620)
        self.assertTrue("pot_corr_uncertainty_md" in val.keys())
        self.assertTrue("pot_plot_data" in val.keys())
Exemple #13
0
    def test_run_band_edge_shifting(self):
        de = DefectEntry(self.vac,
                         0.,
                         corrections={},
                         parameters=self.band_edge_params,
                         entry_id=None)

        dc = DefectCompatibility()
        dentry = dc.perform_band_edge_shifting(de)
        val = dentry.parameters['bandshift_meta']
        self.assertEqual(val['vbmshift'], -0.5)
        self.assertEqual(val['cbmshift'], 0.4)
        self.assertEqual(val['bandedgeshifting_correction'], 1.5)
Exemple #14
0
    def test_run_bandfilling(self):
        de = DefectEntry(self.vac,
                         0.,
                         corrections={},
                         parameters=self.bandfill_params,
                         entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.perform_bandfilling(de)

        val = dentry.parameters['bandfilling_meta']
        self.assertAlmostEqual(val['num_hole_vbm'], 0.)
        self.assertAlmostEqual(val['num_elec_cbm'], 0.)
        self.assertAlmostEqual(val['bandfilling_correction'], 0.)
    def test_run_bandfilling(self):
        de = DefectEntry(self.vac, 0., corrections={}, parameters=self.bandfill_params, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.perform_bandfilling( de)

        val = dentry.parameters['bandfilling_meta']
        self.assertAlmostEqual(val['num_hole_vbm'], 0.)
        self.assertAlmostEqual(val['num_elec_cbm'], 0.)
        self.assertAlmostEqual(val['bandfilling_correction'], 0.)
        occu = [[1.457, 0.1666667], [1.5204, 0.1666667], [1.53465, 0.1666667], [1.5498, 0.0833333]]
        self.assertArrayAlmostEqual(
            list(sorted(val['occupied_def_levels'], key=lambda x: x[0])), list(
                sorted(occu, key=lambda x: x[0])))
        self.assertAlmostEqual(val['total_occupation_defect_levels'], 0.58333338)
        self.assertFalse(val['unoccupied_def_levels'])
    def test_check_kumagai_delocalized(self):
        de = DefectEntry( self.kumagai_vac, 0., parameters=self.kumagai_params)
        de.parameters.update( {'is_compatible': True}) #needs to be initialized with this here for unittest
        dc = DefectCompatibility( atomic_site_var_tol=13.3, atomic_site_minmax_tol=20.95)
        dentry = dc.perform_kumagai( de)

        # check case which fits under compatibility constraints
        dentry = dc.check_kumagai_delocalized( dentry)
        kumagai_delocal = dentry.parameters['delocalization_meta']['atomic_site']
        self.assertTrue( kumagai_delocal['is_compatible'])
        kumagai_md = kumagai_delocal['metadata']
        true_variance = 13.262304401193997
        true_minmax = 20.9435
        self.assertTrue(kumagai_md['kumagai_variance_compatible'])
        self.assertAlmostEqual(kumagai_md['kumagai_variance'], true_variance)
        self.assertTrue(kumagai_md['kumagai_minmax_compatible'])
        self.assertAlmostEqual(kumagai_md['kumagai_minmax_window'], true_minmax)

        self.assertTrue( dentry.parameters['is_compatible'])

        # break variable compatibility
        dc = DefectCompatibility( atomic_site_var_tol=0.1, atomic_site_minmax_tol=20.95)
        de.parameters.update( {'is_compatible': True})
        dentry = dc.perform_kumagai( de)
        dentry = dc.check_kumagai_delocalized( dentry)
        kumagai_delocal = dentry.parameters['delocalization_meta']['atomic_site']
        self.assertFalse( kumagai_delocal['is_compatible'])
        kumagai_md = kumagai_delocal['metadata']
        self.assertFalse(kumagai_md['kumagai_variance_compatible'])
        self.assertAlmostEqual(kumagai_md['kumagai_variance'], true_variance)
        self.assertTrue(kumagai_md['kumagai_minmax_compatible'])
        self.assertAlmostEqual(kumagai_md['kumagai_minmax_window'], true_minmax)

        self.assertFalse( dentry.parameters['is_compatible'])

        # break maxmin compatibility
        dc = DefectCompatibility(atomic_site_var_tol=13.3, atomic_site_minmax_tol=0.5)
        de.parameters.update({'is_compatible': True})
        dentry = dc.perform_kumagai(de)
        dentry = dc.check_kumagai_delocalized(dentry)
        kumagai_delocal = dentry.parameters['delocalization_meta']['atomic_site']
        self.assertFalse(kumagai_delocal['is_compatible'])
        kumagai_md = kumagai_delocal['metadata']
        self.assertTrue(kumagai_md['kumagai_variance_compatible'])
        self.assertAlmostEqual(kumagai_md['kumagai_variance'], true_variance)
        self.assertFalse(kumagai_md['kumagai_minmax_compatible'])
        self.assertAlmostEqual(kumagai_md['kumagai_minmax_window'], true_minmax)

        self.assertFalse(dentry.parameters['is_compatible'])
    def test_run_bandfilling(self):
        de = DefectEntry(self.vac,
                         0.,
                         corrections={},
                         parameters=self.bandfill_params,
                         entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.perform_bandfilling(de)

        val = dentry.parameters['bandfilling_meta']
        self.assertAlmostEqual(val['num_hole_vbm'], 0.)
        self.assertAlmostEqual(val['num_elec_cbm'], 0.)
        self.assertAlmostEqual(val['bandfilling_correction'], 0.)
        occu = [[1.457, 0.0833333], [1.5204, 0.0833333], [1.53465, 0.0833333],
                [1.5498, 0.0416667]]
        self.assertArrayAlmostEqual(
            list(sorted(val['occupied_def_levels'], key=lambda x: x[0])),
            list(sorted(occu, key=lambda x: x[0])))
        self.assertAlmostEqual(val['total_occupation_defect_levels'],
                               0.29166669)
        self.assertFalse(val['unoccupied_def_levels'])
    def test_process_entry(self):

        # basic process with no corrections
        dentry = DefectEntry(self.vac, 0., corrections={}, parameters={'vbm': 0., 'cbm': 0.}, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.process_entry( dentry)
        self.assertIsNotNone( dentry)

        # process with corrections from parameters used in other unit tests
        params = self.frey_params.copy()
        params.update(self.bandfill_params)
        params.update({'hybrid_cbm': params['cbm'] + .2, 'hybrid_vbm': params['vbm'] - .4, })
        dentry = DefectEntry(self.vac, 0., corrections={}, parameters=params, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.process_entry( dentry)
        self.assertAlmostEqual( dentry.corrections['bandedgeshifting_correction'], 1.2)
        self.assertAlmostEqual( dentry.corrections['bandfilling_correction'], 0.0)
        self.assertAlmostEqual( dentry.corrections['charge_correction'], 5.44595036)

        #TODO: add correction analysis with Kumagai correction

        # test over delocalized free carriers which forces skipping charge correction
        # modify the eigenvalue list to have free holes
        hole_eigenvalues = {}
        for spinkey, spinset in params['eigenvalues'].items():
            hole_eigenvalues[spinkey] = []
            for kptset in spinset:
                hole_eigenvalues[spinkey].append([])
                for eig in kptset:
                    if (eig[0] < params['vbm']) and (eig[0] > params['vbm'] - .8):
                        hole_eigenvalues[spinkey][-1].append([eig[0], 0.5])
                    else:
                        hole_eigenvalues[spinkey][-1].append(eig)

        params.update( {'eigenvalues': hole_eigenvalues})
        dentry = DefectEntry(self.vac, 0., corrections={}, parameters=params, entry_id=None)
        dc = DefectCompatibility( free_chg_cutoff=1.)
        dentry = dc.process_entry( dentry)
        self.assertAlmostEqual( dentry.corrections['bandedgeshifting_correction'], 1.85000005)
        self.assertAlmostEqual( dentry.corrections['bandfilling_correction'], -3.244048)
        self.assertAlmostEqual( dentry.corrections['charge_correction'], 0.)

        # turn off band filling and band edge shifting
        dc = DefectCompatibility( free_chg_cutoff=1., use_bandfilling=False, use_bandedgeshift=False)
        dentry = dc.process_entry( dentry)
        self.assertAlmostEqual( dentry.corrections['bandedgeshifting_correction'], 0.)
        self.assertAlmostEqual( dentry.corrections['bandfilling_correction'], 0.)
        self.assertAlmostEqual( dentry.corrections['charge_correction'], 0.)
    def test_check_freysoldt_delocalized(self):
        de = DefectEntry(self.vac, 0., corrections={}, parameters=self.frey_params, entry_id=None)
        de.parameters.update( {'is_compatible': True}) #needs to be initialized with this here for unittest
        dc = DefectCompatibility( plnr_avg_var_tol=0.1, plnr_avg_minmax_tol=0.5)
        dentry = dc.perform_freysoldt( de)

        # check case which fits under compatibility constraints
        dentry = dc.check_freysoldt_delocalized( dentry)
        frey_delocal = dentry.parameters['delocalization_meta']['plnr_avg']
        self.assertTrue( frey_delocal['is_compatible'])
        ans_var = [0.00038993, 0.02119532, 0.02119532]
        ans_window = [0.048331509, 0.36797169, 0.36797169]
        for ax in range(3):
            ax_metadata = frey_delocal['metadata'][ax]
            self.assertTrue( ax_metadata['frey_variance_compatible'])
            self.assertAlmostEqual( ax_metadata['frey_variance'], ans_var[ax])
            self.assertTrue( ax_metadata['frey_minmax_compatible'])
            self.assertAlmostEqual( ax_metadata['frey_minmax_window'], ans_window[ax])

        self.assertTrue( dentry.parameters['is_compatible'])

        # check planar delocalization on 2nd and 3rd axes
        dc = DefectCompatibility( plnr_avg_var_tol=0.1, plnr_avg_minmax_tol=0.2)
        dentry.parameters.update( {'is_compatible': True})
        dentry = dc.check_freysoldt_delocalized( dentry)
        frey_delocal = dentry.parameters['delocalization_meta']['plnr_avg']
        self.assertFalse( frey_delocal['is_compatible'])
        ax_metadata = frey_delocal['metadata'][0]
        self.assertTrue( ax_metadata['frey_variance_compatible'])
        self.assertTrue( ax_metadata['frey_minmax_compatible'])
        for ax in [1,2]:
            ax_metadata = frey_delocal['metadata'][ax]
            self.assertTrue( ax_metadata['frey_variance_compatible'])
            self.assertFalse( ax_metadata['frey_minmax_compatible'])

        self.assertFalse( dentry.parameters['is_compatible'])

        # check variance based delocalization on 2nd and 3rd axes
        dc = DefectCompatibility( plnr_avg_var_tol=0.01, plnr_avg_minmax_tol=0.5)
        dentry.parameters.update( {'is_compatible': True})
        dentry = dc.check_freysoldt_delocalized( dentry)
        frey_delocal = dentry.parameters['delocalization_meta']['plnr_avg']
        self.assertFalse( frey_delocal['is_compatible'])
        ax_metadata = frey_delocal['metadata'][0]
        self.assertTrue( ax_metadata['frey_variance_compatible'])
        self.assertTrue( ax_metadata['frey_minmax_compatible'])
        for ax in [1,2]:
            ax_metadata = frey_delocal['metadata'][ax]
            self.assertFalse( ax_metadata['frey_variance_compatible'])
            self.assertTrue( ax_metadata['frey_minmax_compatible'])

        self.assertFalse( dentry.parameters['is_compatible'])
    def __init__(self, defect_entry, compatibility=DefectCompatibility(),
                 defect_vr = None, bulk_vr = None):
        """
        Parse a defect object using features that resemble that of a standard
        DefectBuilder object (emmet), but without the requirement of atomate.
        Also allows for use of DefectCompatibility object within pymatgen

        :param defect_entry (DefectEntry): DefectEntry of interest (using the bulk supercell as bulk_structure)
            NOTE: to make use of methods within the class, bulk_path and and defect_path
            must exist within the defect_entry parameters class.
        :param compatibility (DefectCompatibility): Compatibility class instance for
            performing compatibility analysis on defect entry.
        :param defect_vr (Vasprun):
        :param bulk_vr (Vasprun):

        """
        self.defect_entry = defect_entry
        self.compatibility = compatibility
        self.defect_vr = defect_vr
        self.bulk_vr = bulk_vr
    def test_check_kumagai_delocalized(self):
        de = DefectEntry(self.kumagai_vac, 0.0, parameters=self.kumagai_params)
        de.parameters.update({"is_compatible": True})  # needs to be initialized with this here for unittest
        dc = DefectCompatibility(atomic_site_var_tol=13.3, atomic_site_minmax_tol=20.95)
        dentry = dc.perform_kumagai(de)

        # check case which fits under compatibility constraints
        dentry = dc.check_kumagai_delocalized(dentry)
        kumagai_delocal = dentry.parameters["delocalization_meta"]["atomic_site"]
        self.assertTrue(kumagai_delocal["is_compatible"])
        kumagai_md = kumagai_delocal["metadata"]
        true_variance = 13.262304401193997
        true_minmax = 20.9435
        self.assertTrue(kumagai_md["kumagai_variance_compatible"])
        self.assertAlmostEqual(kumagai_md["kumagai_variance"], true_variance)
        self.assertTrue(kumagai_md["kumagai_minmax_compatible"])
        self.assertAlmostEqual(kumagai_md["kumagai_minmax_window"], true_minmax)

        self.assertTrue(dentry.parameters["is_compatible"])

        # break variable compatibility
        dc = DefectCompatibility(atomic_site_var_tol=0.1, atomic_site_minmax_tol=20.95)
        de.parameters.update({"is_compatible": True})
        dentry = dc.perform_kumagai(de)
        dentry = dc.check_kumagai_delocalized(dentry)
        kumagai_delocal = dentry.parameters["delocalization_meta"]["atomic_site"]
        self.assertFalse(kumagai_delocal["is_compatible"])
        kumagai_md = kumagai_delocal["metadata"]
        self.assertFalse(kumagai_md["kumagai_variance_compatible"])
        self.assertAlmostEqual(kumagai_md["kumagai_variance"], true_variance)
        self.assertTrue(kumagai_md["kumagai_minmax_compatible"])
        self.assertAlmostEqual(kumagai_md["kumagai_minmax_window"], true_minmax)

        self.assertFalse(dentry.parameters["is_compatible"])

        # break maxmin compatibility
        dc = DefectCompatibility(atomic_site_var_tol=13.3, atomic_site_minmax_tol=0.5)
        de.parameters.update({"is_compatible": True})
        dentry = dc.perform_kumagai(de)
        dentry = dc.check_kumagai_delocalized(dentry)
        kumagai_delocal = dentry.parameters["delocalization_meta"]["atomic_site"]
        self.assertFalse(kumagai_delocal["is_compatible"])
        kumagai_md = kumagai_delocal["metadata"]
        self.assertTrue(kumagai_md["kumagai_variance_compatible"])
        self.assertAlmostEqual(kumagai_md["kumagai_variance"], true_variance)
        self.assertFalse(kumagai_md["kumagai_minmax_compatible"])
        self.assertAlmostEqual(kumagai_md["kumagai_minmax_window"], true_minmax)

        self.assertFalse(dentry.parameters["is_compatible"])
    def test_is_final_relaxed_structure_delocalized(self):
        # test structure delocalization analysis
        # first test no movement in atoms
        initial_defect_structure = self.vac.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        sampling_radius = 4.55

        params = {
            'initial_defect_structure': initial_defect_structure,
            'final_defect_structure': final_defect_structure,
            'sampling_radius': sampling_radius,
            'is_compatible': True
        }
        dentry = DefectEntry(self.vac,
                             0.,
                             corrections={},
                             parameters=params,
                             entry_id=None)

        dc = DefectCompatibility(tot_relax_tol=0.1,
                                 perc_relax_tol=0.1,
                                 defect_tot_relax_tol=0.1)
        dentry = dc.is_final_relaxed_structure_delocalized(dentry)

        struc_delocal = dentry.parameters['delocalization_meta'][
            'structure_relax']
        self.assertTrue(dentry.parameters['is_compatible'])
        self.assertTrue(struc_delocal['is_compatible'])
        self.assertTrue(
            struc_delocal['metadata']['structure_tot_relax_compatible'])
        self.assertEqual(struc_delocal['metadata']['tot_relax_outside_rad'],
                         0.)
        self.assertTrue(
            struc_delocal['metadata']['structure_perc_relax_compatible'])
        self.assertEqual(struc_delocal['metadata']['perc_relax_outside_rad'],
                         0.)
        self.assertEqual(
            len(struc_delocal['metadata']['full_structure_relax_data']),
            len(initial_defect_structure))
        self.assertIsNone(struc_delocal['metadata']['defect_index'])

        defect_delocal = dentry.parameters['delocalization_meta'][
            'defectsite_relax']
        self.assertTrue(defect_delocal['is_compatible'])
        self.assertIsNone(defect_delocal['metadata']['relax_amount'])

        # next test for when structure has delocalized outside of radius from defect
        pert_struct_fin_struct = initial_defect_structure.copy()
        pert_struct_fin_struct.perturb(0.1)
        dentry.parameters.update(
            {'final_defect_structure': pert_struct_fin_struct})
        dentry = dc.is_final_relaxed_structure_delocalized(dentry)

        struc_delocal = dentry.parameters['delocalization_meta'][
            'structure_relax']
        self.assertFalse(dentry.parameters['is_compatible'])
        self.assertFalse(struc_delocal['is_compatible'])
        self.assertFalse(
            struc_delocal['metadata']['structure_tot_relax_compatible'])
        self.assertAlmostEqual(
            struc_delocal['metadata']['tot_relax_outside_rad'], 12.5)
        self.assertFalse(
            struc_delocal['metadata']['structure_perc_relax_compatible'])
        self.assertAlmostEqual(
            struc_delocal['metadata']['perc_relax_outside_rad'], 77.63975155)

        # now test for when an interstitial defect has migrated too much
        inter_def_site = PeriodicSite('H',
                                      [7.58857304, 11.70848069, 12.97817518],
                                      self.vac.bulk_structure.lattice,
                                      to_unit_cell=True,
                                      coords_are_cartesian=True)
        inter = Interstitial(self.vac.bulk_structure, inter_def_site, charge=0)

        initial_defect_structure = inter.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        poss_deflist = sorted(final_defect_structure.get_sites_in_sphere(
            inter.site.coords, 2, include_index=True),
                              key=lambda x: x[1])
        def_index = poss_deflist[0][2]
        final_defect_structure.translate_sites(
            indices=[def_index],
            vector=[0., 0., 0.008])  #fractional coords translation

        params = {
            'initial_defect_structure': initial_defect_structure,
            'final_defect_structure': final_defect_structure,
            'sampling_radius': sampling_radius,
            'is_compatible': True
        }
        dentry = DefectEntry(inter,
                             0.,
                             corrections={},
                             parameters=params,
                             entry_id=None)

        dentry = dc.is_final_relaxed_structure_delocalized(dentry)

        defect_delocal = dentry.parameters['delocalization_meta'][
            'defectsite_relax']
        self.assertFalse(defect_delocal['is_compatible'])
        self.assertAlmostEqual(defect_delocal['metadata']['relax_amount'],
                               0.10836054)
Exemple #23
0
    def test_process_entry(self):

        # basic process with no corrections
        dentry = DefectEntry(self.vac,
                             0.,
                             corrections={},
                             parameters={
                                 'vbm': 0.,
                                 'cbm': 0.
                             },
                             entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.process_entry(dentry)
        self.assertIsNotNone(dentry)

        # process with corrections from parameters used in other unit tests
        params = self.frey_params.copy()
        params.update(self.bandfill_params)
        params.update({
            'hybrid_cbm': params['cbm'] + .2,
            'hybrid_vbm': params['vbm'] - .4,
        })
        dentry = DefectEntry(self.vac,
                             0.,
                             corrections={},
                             parameters=params,
                             entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.process_entry(dentry)
        self.assertAlmostEqual(
            dentry.corrections['bandedgeshifting_correction'], 1.2)
        self.assertAlmostEqual(dentry.corrections['bandfilling_correction'],
                               0.0)
        self.assertAlmostEqual(dentry.corrections['charge_correction'],
                               5.44595036)

        # test over delocalized free carriers which forces skipping charge correction
        # modify the eigenvalue list to have free holes
        hole_eigenvalues = {}
        for spinkey, spinset in params['eigenvalues'].items():
            hole_eigenvalues[spinkey] = []
            for kptset in spinset:
                hole_eigenvalues[spinkey].append([])
                for eig in kptset:
                    if (eig[0] < params['vbm']) and (eig[0] >
                                                     params['vbm'] - .8):
                        hole_eigenvalues[spinkey][-1].append([eig[0], 0.5])
                    else:
                        hole_eigenvalues[spinkey][-1].append(eig)

        params.update({'eigenvalues': hole_eigenvalues})
        dentry = DefectEntry(self.vac,
                             0.,
                             corrections={},
                             parameters=params,
                             entry_id=None)
        dc = DefectCompatibility(free_chg_cutoff=0.8)
        dentry = dc.process_entry(dentry)
        self.assertAlmostEqual(
            dentry.corrections['bandedgeshifting_correction'], 1.19999999)
        self.assertAlmostEqual(dentry.corrections['bandfilling_correction'],
                               -1.62202400)
        self.assertAlmostEqual(dentry.corrections['charge_correction'], 0.)

        # turn off band filling and band edge shifting
        dc = DefectCompatibility(free_chg_cutoff=0.8,
                                 use_bandfilling=False,
                                 use_bandedgeshift=False)
        dentry = dc.process_entry(dentry)
        self.assertAlmostEqual(
            dentry.corrections['bandedgeshifting_correction'], 0.)
        self.assertAlmostEqual(dentry.corrections['bandfilling_correction'],
                               0.)
        self.assertAlmostEqual(dentry.corrections['charge_correction'], 0.)
    def test_check_final_relaxed_structure_delocalized(self):
        # test structure delocalization analysis
        # first test no movement in atoms
        initial_defect_structure = self.vac.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        sampling_radius = 4.55
        defect_frac_sc_coords = self.vac.site.frac_coords[:]

        params = {
            "initial_defect_structure": initial_defect_structure,
            "final_defect_structure": final_defect_structure,
            "sampling_radius": sampling_radius,
            "defect_frac_sc_coords": defect_frac_sc_coords,
            "is_compatible": True,
        }
        dentry = DefectEntry(self.vac, 0.0, corrections={}, parameters=params, entry_id=None)

        dc = DefectCompatibility(tot_relax_tol=0.1, perc_relax_tol=0.1, defect_tot_relax_tol=0.1)
        dentry = dc.check_final_relaxed_structure_delocalized(dentry)

        struc_delocal = dentry.parameters["delocalization_meta"]["structure_relax"]
        self.assertTrue(dentry.parameters["is_compatible"])
        self.assertTrue(struc_delocal["is_compatible"])
        self.assertTrue(struc_delocal["metadata"]["structure_tot_relax_compatible"])
        self.assertEqual(struc_delocal["metadata"]["tot_relax_outside_rad"], 0.0)
        self.assertTrue(struc_delocal["metadata"]["structure_perc_relax_compatible"])
        self.assertEqual(struc_delocal["metadata"]["perc_relax_outside_rad"], 0.0)
        self.assertEqual(
            len(struc_delocal["metadata"]["full_structure_relax_data"]),
            len(initial_defect_structure),
        )
        self.assertIsNone(struc_delocal["metadata"]["defect_index"])

        defect_delocal = dentry.parameters["delocalization_meta"]["defectsite_relax"]
        self.assertTrue(defect_delocal["is_compatible"])
        self.assertIsNone(defect_delocal["metadata"]["relax_amount"])

        # next test for when structure has delocalized outside of radius from defect
        pert_struct_fin_struct = initial_defect_structure.copy()
        pert_struct_fin_struct.perturb(0.1)
        dentry.parameters.update({"final_defect_structure": pert_struct_fin_struct})
        dentry = dc.check_final_relaxed_structure_delocalized(dentry)

        struc_delocal = dentry.parameters["delocalization_meta"]["structure_relax"]
        self.assertFalse(dentry.parameters["is_compatible"])
        self.assertFalse(struc_delocal["is_compatible"])
        self.assertFalse(struc_delocal["metadata"]["structure_tot_relax_compatible"])
        self.assertAlmostEqual(struc_delocal["metadata"]["tot_relax_outside_rad"], 12.5)
        self.assertFalse(struc_delocal["metadata"]["structure_perc_relax_compatible"])
        self.assertAlmostEqual(struc_delocal["metadata"]["perc_relax_outside_rad"], 77.63975155)

        # now test for when an interstitial defect has migrated too much
        inter_def_site = PeriodicSite(
            "H",
            [7.58857304, 11.70848069, 12.97817518],
            self.vac.bulk_structure.lattice,
            to_unit_cell=True,
            coords_are_cartesian=True,
        )
        inter = Interstitial(self.vac.bulk_structure, inter_def_site, charge=0)

        initial_defect_structure = inter.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        poss_deflist = sorted(
            final_defect_structure.get_sites_in_sphere(inter.site.coords, 2, include_index=True),
            key=lambda x: x[1],
        )
        def_index = poss_deflist[0][2]
        final_defect_structure.translate_sites(
            indices=[def_index], vector=[0.0, 0.0, 0.008]
        )  # fractional coords translation
        defect_frac_sc_coords = inter_def_site.frac_coords[:]

        params = {
            "initial_defect_structure": initial_defect_structure,
            "final_defect_structure": final_defect_structure,
            "sampling_radius": sampling_radius,
            "defect_frac_sc_coords": defect_frac_sc_coords,
            "is_compatible": True,
        }
        dentry = DefectEntry(inter, 0.0, corrections={}, parameters=params, entry_id=None)

        dentry = dc.check_final_relaxed_structure_delocalized(dentry)

        defect_delocal = dentry.parameters["delocalization_meta"]["defectsite_relax"]
        self.assertFalse(defect_delocal["is_compatible"])
        self.assertAlmostEqual(defect_delocal["metadata"]["relax_amount"], 0.10836054)
    def test_check_final_relaxed_structure_delocalized(self):
        # test structure delocalization analysis
        # first test no movement in atoms
        initial_defect_structure = self.vac.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        sampling_radius = 4.55
        defect_frac_sc_coords = self.vac.site.frac_coords[:]

        params = {'initial_defect_structure': initial_defect_structure,
                  'final_defect_structure': final_defect_structure,
                  'sampling_radius': sampling_radius,
                  'defect_frac_sc_coords': defect_frac_sc_coords,
                  'is_compatible': True}
        dentry = DefectEntry(self.vac, 0., corrections={}, parameters=params, entry_id=None)

        dc = DefectCompatibility( tot_relax_tol=0.1, perc_relax_tol=0.1, defect_tot_relax_tol=0.1)
        dentry = dc.check_final_relaxed_structure_delocalized( dentry)

        struc_delocal = dentry.parameters['delocalization_meta']['structure_relax']
        self.assertTrue( dentry.parameters['is_compatible'])
        self.assertTrue( struc_delocal['is_compatible'])
        self.assertTrue( struc_delocal['metadata']['structure_tot_relax_compatible'])
        self.assertEqual( struc_delocal['metadata']['tot_relax_outside_rad'], 0.)
        self.assertTrue( struc_delocal['metadata']['structure_perc_relax_compatible'])
        self.assertEqual( struc_delocal['metadata']['perc_relax_outside_rad'], 0.)
        self.assertEqual( len(struc_delocal['metadata']['full_structure_relax_data']), len(initial_defect_structure))
        self.assertIsNone( struc_delocal['metadata']['defect_index'])

        defect_delocal = dentry.parameters['delocalization_meta']['defectsite_relax']
        self.assertTrue( defect_delocal['is_compatible'])
        self.assertIsNone( defect_delocal['metadata']['relax_amount'])


        # next test for when structure has delocalized outside of radius from defect
        pert_struct_fin_struct = initial_defect_structure.copy()
        pert_struct_fin_struct.perturb( 0.1)
        dentry.parameters.update( {'final_defect_structure': pert_struct_fin_struct})
        dentry = dc.check_final_relaxed_structure_delocalized( dentry)

        struc_delocal = dentry.parameters['delocalization_meta']['structure_relax']
        self.assertFalse( dentry.parameters['is_compatible'])
        self.assertFalse( struc_delocal['is_compatible'])
        self.assertFalse( struc_delocal['metadata']['structure_tot_relax_compatible'])
        self.assertAlmostEqual( struc_delocal['metadata']['tot_relax_outside_rad'], 12.5)
        self.assertFalse( struc_delocal['metadata']['structure_perc_relax_compatible'])
        self.assertAlmostEqual( struc_delocal['metadata']['perc_relax_outside_rad'], 77.63975155)


        # now test for when an interstitial defect has migrated too much
        inter_def_site = PeriodicSite('H',  [7.58857304, 11.70848069, 12.97817518],
                                self.vac.bulk_structure.lattice, to_unit_cell=True,
                                coords_are_cartesian=True)
        inter = Interstitial(self.vac.bulk_structure, inter_def_site, charge=0)

        initial_defect_structure = inter.generate_defect_structure()
        final_defect_structure = initial_defect_structure.copy()
        poss_deflist = sorted(
            final_defect_structure.get_sites_in_sphere(inter.site.coords,
                                                       2, include_index=True), key=lambda x: x[1])
        def_index = poss_deflist[0][2]
        final_defect_structure.translate_sites(indices=[def_index],
                                               vector=[0., 0., 0.008]) #fractional coords translation
        defect_frac_sc_coords = inter_def_site.frac_coords[:]

        params = {'initial_defect_structure': initial_defect_structure,
                  'final_defect_structure': final_defect_structure,
                  'sampling_radius': sampling_radius,
                  'defect_frac_sc_coords': defect_frac_sc_coords,
                  'is_compatible': True}
        dentry = DefectEntry(inter, 0., corrections={}, parameters=params, entry_id=None)

        dentry = dc.check_final_relaxed_structure_delocalized( dentry)

        defect_delocal = dentry.parameters['delocalization_meta']['defectsite_relax']
        self.assertFalse( defect_delocal['is_compatible'])
        self.assertAlmostEqual( defect_delocal['metadata']['relax_amount'], 0.10836054)
    def test_process_entry(self):

        # basic process with no corrections
        dentry = DefectEntry(
            self.vac,
            0.0,
            corrections={},
            parameters={"vbm": 0.0, "cbm": 0.0},
            entry_id=None,
        )
        dc = DefectCompatibility()
        dentry = dc.process_entry(dentry)
        self.assertIsNotNone(dentry)

        # process with corrections from parameters used in other unit tests
        params = self.frey_params.copy()
        params.update(self.bandfill_params)
        params.update(
            {
                "hybrid_cbm": params["cbm"] + 0.2,
                "hybrid_vbm": params["vbm"] - 0.4,
            }
        )
        dentry = DefectEntry(self.vac, 0.0, corrections={}, parameters=params, entry_id=None)
        dc = DefectCompatibility()
        dentry = dc.process_entry(dentry)
        self.assertAlmostEqual(dentry.corrections["bandedgeshifting_correction"], 1.2)
        self.assertAlmostEqual(dentry.corrections["bandfilling_correction"], 0.0)
        self.assertAlmostEqual(dentry.corrections["charge_correction"], 5.44595036)

        # test over delocalized free carriers which forces skipping charge correction
        params = self.bandfill_params.copy()  # No Freysoldt metadata
        params.update(
            {
                "hybrid_cbm": params["cbm"] + 0.2,
                "hybrid_vbm": params["vbm"] - 0.4,
            }
        )
        # modify the eigenvalue list to have free holes
        hole_eigenvalues = {}
        for spinkey, spinset in params["eigenvalues"].items():
            hole_eigenvalues[spinkey] = []
            for kptset in spinset:
                hole_eigenvalues[spinkey].append([])
                for eig in kptset:
                    if (eig[0] < params["vbm"]) and (eig[0] > params["vbm"] - 0.8):
                        hole_eigenvalues[spinkey][-1].append([eig[0], 0.5])
                    else:
                        hole_eigenvalues[spinkey][-1].append(eig)

        params.update({"eigenvalues": hole_eigenvalues})
        dentry = DefectEntry(self.vac, 0.0, corrections={}, parameters=params, entry_id=None)
        dc = DefectCompatibility(free_chg_cutoff=0.8)
        dentry = dc.process_entry(dentry)
        self.assertAlmostEqual(dentry.corrections["bandedgeshifting_correction"], 1.19999999)
        self.assertAlmostEqual(dentry.corrections["bandfilling_correction"], -0.492633372744)
        self.assertAlmostEqual(dentry.corrections["charge_correction"], 0.0)

        # turn off band filling and band edge shifting
        dc = DefectCompatibility(free_chg_cutoff=0.8, use_bandfilling=False, use_bandedgeshift=False)
        dentry = dc.process_entry(dentry)
        self.assertAlmostEqual(dentry.corrections["bandedgeshifting_correction"], 0.0)
        self.assertAlmostEqual(dentry.corrections["bandfilling_correction"], 0.0)
        self.assertAlmostEqual(dentry.corrections["charge_correction"], 0.0)
    def from_paths( path_to_defect, path_to_bulk, dielectric, defect_charge, mpid = None,
                    compatibility=DefectCompatibility(), initial_defect_structure = None):
        """
        Identify defect object based on file paths. Minimal parsing performing for
        instantiating the SingleDefectParser class.

        :param path_to_defect (str): path to defect file of interest
        :param path_to_bulk (str): path to bulk file of interest
        :param dielectric (float or 3x3 matrix): ionic + static contributions to dielectric constant
        :param defect_charge (int):
        :param mpid (str):
        :param compatibility (DefectCompatibility): Compatibility class instance for
            performing compatibility analysis on defect entry.

        Return:
            Instance of the SingleDefectParser class.
        """
        parameters = {"bulk_path": path_to_bulk, "defect_path": path_to_defect,
                      "dielectric": dielectric, "mpid": mpid}

        # add bulk simple properties
        bulk_vr = Vasprun( os.path.join(path_to_bulk, "vasprun.xml"))
        bulk_energy = bulk_vr.final_energy
        bulk_sc_structure = bulk_vr.initial_structure.copy()

        # add defect simple properties
        defect_vr = Vasprun( os.path.join(path_to_defect, "vasprun.xml"))
        defect_energy = defect_vr.final_energy
        # Can specify initial defect structure (to help PyCDT find the defect site if
        # multiple relaxations were required, else use from defect relaxation OUTCAR:
        if initial_defect_structure:
            initial_defect_structure = Poscar.from_file(initial_defect_structure).structure.copy()
        else:
            initial_defect_structure = defect_vr.initial_structure.copy()

        # identify defect site, structural information, and create defect object
        num_ids = len(initial_defect_structure)
        num_bulk = len(bulk_sc_structure)
        if num_ids == num_bulk - 1:
            defect_type = "Vacancy"
        elif num_ids == num_bulk + 1:
            defect_type = "Interstitial"
        elif num_ids == num_bulk:
            defect_type = "Substitution"
        else:
            raise ValueError("Could not identify defect type just from number of sites in structure: "
                             "{} in bulk vs. {} in defect?".format( num_ids, num_bulk ))

        defect_index_sc_coords = None
        transformation_path = os.path.join( path_to_defect, "transformation.json")
        if os.path.exists( transformation_path):
            tf = loadfn( transformation_path)
            site = tf["defect_supercell_site"]
            if defect_type == "Vacancy":
                poss_deflist = sorted(
                    bulk_sc_structure.get_sites_in_sphere(site.coords, 0.1, include_index=True), key=lambda x: x[1])
            else:
                poss_deflist = sorted(
                    initial_defect_structure.get_sites_in_sphere(site.coords, 0.1, include_index=True), key=lambda x: x[1])
            if not len(poss_deflist):
                raise ValueError("{} specified defect site {}, but could not find it in bulk_supercell."
                                 " Abandoning parsing".format( transformation_path, site))
            else:
                defect_index_sc_coords = poss_deflist[0][2]
        else:
            print("No transformation file exists at {}.\nCalculating defect index manually"
                  " (proceed with caution)".format( transformation_path))

        # IF not transformation file exists, the defect_index_sc_coords will not be identified in previous routine,
        # proceed by identifying the defect site through a comparison of bulk sites and initial defect structure sites.
        # WARNING: this can cause issues if intial_defect_structure is slightly different than
        # bulk_sc_structure (as a result of multiple relaxation steps, for example)
        if defect_index_sc_coords is None:
            bulksites = [site.frac_coords for site in bulk_sc_structure]
            initsites = [site.frac_coords for site in initial_defect_structure]
            distmatrix = initial_defect_structure.lattice.get_all_distances(bulksites,
                                                                            initsites)
            min_dist_with_index = [[min(distmatrix[bulk_index]), int(bulk_index),
                                    int(distmatrix[bulk_index].argmin())] for bulk_index in
                                   range(len(distmatrix))]  # list of [min dist, bulk ind, defect ind]

            site_matching_indices = []
            poss_defect = []
            if defect_type in ["Vacancy", "Interstitial"]:
                for mindist, bulk_index, defect_index in min_dist_with_index:
                    if mindist < 0.1:
                        site_matching_indices.append([bulk_index, defect_index])
                    elif defect_type == "Vacancy":
                        poss_defect.append([bulk_index, bulksites[bulk_index][:]])

                if defect_type == "Interstitial":
                    poss_defect = [[ind, fc[:]] for ind, fc in enumerate(initsites) \
                                   if ind not in np.array(site_matching_indices)[:, 1]]

            elif defect_type == "Substitution":
                for mindist, bulk_index, defect_index in min_dist_with_index:
                    species_match = bulk_sc_structure[bulk_index].specie == \
                                    initial_defect_structure[defect_index].specie
                    if mindist < 0.1 and species_match:
                        site_matching_indices.append([bulk_index, defect_index])

                    elif not species_match:
                        poss_defect.append([defect_index, initsites[defect_index][:]])

            if len(poss_defect) == 1:
                defect_index_sc_coords = poss_defect[0][0]
            else:
                raise ValueError("Found {} possible defect sites when matching bulk and "
                                 "defect structure".format(len(poss_defect)))

            if len(set(np.array(site_matching_indices)[:, 0])) != len(set(np.array(site_matching_indices)[:, 1])):
                raise ValueError("Error occured in site_matching routine. Double counting of site matching "
                                  "occured:{}\nAbandoning structure parsing.".format(site_matching_indices))

        if defect_type == "Vacancy":
            defect_site = bulk_sc_structure[ defect_index_sc_coords]
        else:
            defect_site = initial_defect_structure[ defect_index_sc_coords]


        for_monty_defect = {"@module": "pymatgen.analysis.defects.core",
                            "@class": defect_type,
                            "charge": defect_charge,
                            "structure": bulk_sc_structure,
                            "defect_site": defect_site}
        defect = MontyDecoder().process_decoded(for_monty_defect)
        test_defect_structure = defect.generate_defect_structure()
        if not StructureMatcher(stol=0.5, primitive_cell=False, scale=False, attempt_supercell=False,
                                allow_subset=False).fit(test_defect_structure,
                                                        defect_vr.initial_structure):
            # NOTE: this does not insure that cartesian coordinates or indexing are identical
            # Note: I've changed stol to 0.5 to fix matching for defects that move the f**k about yo
            raise ValueError("Error in defect object matching!")


        defect_entry = DefectEntry(defect, defect_energy - bulk_energy,
                                   corrections={}, parameters=parameters)

        return SingleDefectParser( defect_entry, compatibility=compatibility,
                                   defect_vr=defect_vr, bulk_vr=bulk_vr)