Skip to content

Commit 4be9392

Browse files
committed
add initial draft of resubmission approach
1 parent 51b7fb7 commit 4be9392

File tree

2 files changed

+164
-48
lines changed

2 files changed

+164
-48
lines changed

atomate/vasp/firetasks/defects.py

Lines changed: 68 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,6 @@ def run_task(self, fw_spec):
235235
charges = [v.charge for v in SCG]
236236

237237
def_structs.append({'charges': charges, 'defect': vac.copy()})
238-
239238
else:
240239
#only create vacancies of interest...
241240
for elt_type in vacancies:
@@ -345,55 +344,80 @@ def get_charges_from_inter( inter_elt):
345344
charges = get_charges_from_inter( elt_val)
346345
def_structs.append({'charges': charges, 'defect': elt_val.copy()})
347346

348-
stdrd_defect_incar_settings = {"EDIFF": 0.0001, "EDIFFG": 0.001, "IBRION":2, "ISMEAR":0, "SIGMA":0.05,
349-
"ISPIN":2, "ISYM":2, "LVHAR":True, "LVTOT":True, "NSW": 100,
350-
"NELM": 60, "ISIF": 2, "LAECHG":False, "LWAVE": True}
351-
stdrd_defect_incar_settings.update( user_incar_settings)
352347

353348
# now that def_structs is assembled, set up Transformation FW for all defect + charge combinations
354349
for defcalc in def_structs:
355-
#get defect supercell and defect site for parsing purposes
356-
defect = defcalc['defect'].copy()
357-
defect_sc = defect.generate_defect_structure( supercell = supercell_size)
358-
struct_for_defect_site = Structure(defect.bulk_structure.copy().lattice,
359-
[defect.site.specie],
360-
[defect.site.frac_coords],
361-
to_unit_cell=True, coords_are_cartesian=False)
362-
struct_for_defect_site.make_supercell(supercell_size)
363-
defect_site = struct_for_defect_site[0]
364-
365350
#iterate over all charges to be run
366351
for charge in defcalc['charges']:
367-
chgdstruct = defect_sc.copy()
368-
chgdstruct.set_charge(charge) #NOTE that the charge will be reflected in NELECT of INCAR because use_structure_charge=True
369-
370-
reciprocal_density = 100
371-
kpoints_settings = user_kpoints_settings if user_kpoints_settings else {"reciprocal_density": reciprocal_density}
372-
defect_input_set = MPRelaxSet( chgdstruct,
373-
user_incar_settings=stdrd_defect_incar_settings.copy(),
374-
user_kpoints_settings=kpoints_settings,
375-
use_structure_charge=True)
376-
377-
defect_for_trans_param = defect.copy()
378-
defect_for_trans_param.set_charge(charge)
379-
chgdef_trans = ["DefectTransformation"]
380-
chgdef_trans_params = [{"scaling_matrix": supercell_size,
381-
"defect": defect_for_trans_param}]
382-
if structure != defect_for_trans_param.bulk_structure:
383-
raise ValueError("Defect bulk_structure is not the same as input structure.")
384-
385-
def_tag = "{}:{}_{}_{}atoms".format(structure.composition.reduced_formula,
386-
defect.name, charge, num_atoms)
387-
fw = TransmuterFW( name = def_tag, structure=structure,
388-
transformations=chgdef_trans,
389-
transformation_params=chgdef_trans_params,
390-
vasp_input_set=defect_input_set,
391-
vasp_cmd=self.get("vasp_cmd", ">>vasp_cmd<<"),
392-
copy_vasp_outputs=False,
393-
db_file=self.get("db_file", ">>db_file<<"),
394-
bandstructure_mode="auto",
395-
defect_wf_parsing=defect_site)
352+
defect = defcalc['defect'].copy()
353+
defect.set_charge(charge)
354+
355+
fw = get_fw_from_defect( defect, supercell_size,
356+
user_kpoints_settings = user_kpoints_settings,
357+
user_incar_settings = user_incar_settings
358+
)
396359

397360
fws.append(fw)
398361

399362
return FWAction(detours=fws)
363+
364+
365+
366+
def get_fw_from_defect( defect, supercell_size, user_kpoints_settings = {},
367+
user_incar_settings = {},
368+
db_file='>>db_file<<', vasp_cmd='>>vasp_cmd<<'):
369+
"""
370+
Simple function for grabbing fireworks for a defect, given a supercell_size
371+
:param defect:
372+
:param supercell_size:
373+
:param user_kpoints_settings:
374+
:param db_file:
375+
:param vasp_cmd:
376+
:return:
377+
"""
378+
chgd_sc_struct = defect.generate_defect_structure(supercell=supercell_size)
379+
380+
reciprocal_density = 100
381+
382+
kpoints_settings = user_kpoints_settings if user_kpoints_settings else {"reciprocal_density": reciprocal_density}
383+
384+
# NOTE that the charge will be reflected in NELECT of INCAR because use_structure_charge=True
385+
stdrd_defect_incar_settings = {"EDIFF": 0.0001, "EDIFFG": 0.001, "IBRION": 2, "ISMEAR": 0, "SIGMA": 0.05,
386+
"ISPIN": 2, "ISYM": 2, "LVHAR": True, "LVTOT": True, "NSW": 100,
387+
"NELM": 60, "ISIF": 2, "LAECHG": False, "LWAVE": True}
388+
stdrd_defect_incar_settings.update(user_incar_settings)
389+
defect_input_set = MPRelaxSet(chgd_sc_struct,
390+
user_incar_settings=stdrd_defect_incar_settings.copy(),
391+
user_kpoints_settings=kpoints_settings,
392+
use_structure_charge=True)
393+
394+
# get defect site for parsing purposes
395+
struct_for_defect_site = Structure(defect.bulk_structure.copy().lattice,
396+
[defect.site.specie],
397+
[defect.site.frac_coords],
398+
to_unit_cell=True, coords_are_cartesian=False)
399+
struct_for_defect_site.make_supercell(supercell_size)
400+
defect_site = struct_for_defect_site[0]
401+
402+
bulk_sc = defect.bulk_structure.copy()
403+
bulk_sc.make_supercell( supercell_size)
404+
num_atoms = len(bulk_sc)
405+
406+
chgdef_trans = ["DefectTransformation"]
407+
chgdef_trans_params = [{"scaling_matrix": supercell_size,
408+
"defect": defect.copy()}]
409+
410+
def_tag = "{}:{}_{}_{}atoms".format(defect.bulk_structure.composition.reduced_formula,
411+
defect.name, defect.charge, num_atoms)
412+
fw = TransmuterFW(name=def_tag, structure=defect.bulk_structure,
413+
transformations=chgdef_trans,
414+
transformation_params=chgdef_trans_params,
415+
vasp_input_set=defect_input_set,
416+
vasp_cmd=vasp_cmd,
417+
copy_vasp_outputs=False,
418+
db_file=db_file,
419+
bandstructure_mode="auto",
420+
defect_wf_parsing=defect_site)
421+
422+
return fw
423+

atomate/vasp/workflows/base/defects.py

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@
2020
from atomate.vasp.fireworks.core import OptimizeFW, StaticFW, HSEBSFW, DFPTFW
2121
from atomate.vasp.firetasks.glue_tasks import CopyVaspOutputs
2222

23-
from atomate.vasp.firetasks.defects import DefectSetupFiretask
23+
from atomate.vasp.firetasks.defects import DefectSetupFiretask, get_fw_from_defect
2424

2525
logger = get_logger(__name__)
2626

2727

28-
def get_wf_chg_defects(structure, mpid=None, name="chg_defect_wf", user_incar_settings={},
28+
def get_wf_chg_defects(structure, name="chg_defect_wf", user_incar_settings={},
2929
vasp_cmd=">>vasp_cmd<<", db_file=">>db_file<<",
3030
conventional=True, diel_flag=True, n_max=128,
3131
vacancies=[], substitutions={}, interstitials={},
3232
initial_charges={}, rerelax_flag=False, hybrid_run_for_gap_corr=True,
33-
run_analysis=False, user_kpoints_settings={}):
33+
user_kpoints_settings={}):
3434
"""
3535
Returns a charged defect workflow
3636
@@ -45,7 +45,6 @@ def get_wf_chg_defects(structure, mpid=None, name="chg_defect_wf", user_incar_se
4545
4646
Args:
4747
structure (Structure): input structure to have defects run on
48-
mpid (str): Materials Project id number to be used (for storage in metadata).
4948
name (str): some appropriate name for the workflow.
5049
user_incar_settings (dict):
5150
a dictionary of incar settings specified by user for both bulk and defect supercells
@@ -176,3 +175,96 @@ def get_wf_chg_defects(structure, mpid=None, name="chg_defect_wf", user_incar_se
176175

177176
return final_wf
178177

178+
179+
def run_defect_resubmissions( dpd, name="chg_defect_wf", consider_charges=True,
180+
consider_supercells=False, user_incar_settings={},
181+
vasp_cmd=">>vasp_cmd<<", db_file=">>db_file<<",
182+
n_max=400, hybrid_run_for_gap_corr=False,
183+
user_kpoints_settings={}):
184+
"""
185+
This takes a DefectPhaseDiagram object and resubmits additional Defect calculations as needed.
186+
Also useful for resubmitting a hybrid calculation and band edge considerations.
187+
188+
It can do this in two ways:
189+
(a) Extra Charge submissions: run any charges suggested for followup by DefectPhaseDiagram
190+
(b) Larger supercell submissions: run larger supercells for certain charges as suggested by DefectPhaseDiagram
191+
192+
Args:
193+
dpd (DefectPhaseDiagram): phase diagram to consider for analysis of resubmission jobs
194+
name (str): some appropriate name for the workflow.
195+
consider_charges (bool): Whether to consider rerunning additional charge states
196+
Defaults to True (fireworks generated for additional charge states)
197+
consider_supercells (bool): Whether to consider submitting additional supercell sizes
198+
Note that when this is True, if there is no bulk_supercell that matches the supercell sizes
199+
being submitted, a bulk supercell calculation is also submitted.
200+
Defaults to False (will not generate fireworks for additional supercell sizes)
201+
user_incar_settings (dict):
202+
a dictionary of incar settings specified by user for both bulk and defect supercells
203+
vasp_cmd (str): Command to run vasp.
204+
db_file (str): path to file containing the database credentials.
205+
n_max (int): maximum supercell size to consider for consider_supercells supercell routine
206+
hybrid_run_for_gap_corr (bool):
207+
Flag to run a single small hybrid bulk structure for band edge shifting correction.
208+
Useful if you forgot to run the hybrid in your first
209+
Default is False (Hybrid will be calculated)
210+
user_kpoints_settings (dict or Kpoints pmg object):
211+
a dictionary of kpoint settings specific by user OR an Actual Kpoint set to be used for the
212+
supercell calculations
213+
214+
Returns:
215+
Workflow
216+
:return:
217+
"""
218+
if not consider_charges and not consider_supercells and not hybrid_run_for_gap_corr:
219+
raise ValueError("Ony makes since to run get_defect_resubmissions for resubmissions of "
220+
"charges, supercells or hybrids.")
221+
222+
fws = []
223+
224+
if consider_charges:
225+
rec_dict = dpd.suggest_charges()
226+
for defname, charge_list in rec_dict.items():
227+
defect_template = dpd.finished_charges[ defname][0].defect.copy()
228+
if "scaling_matrix" in dpd.finished_charges[defname][0].parameters:
229+
supercell_size = dpd.finished_charges[defname][0].parameters['scaling_matrix']
230+
else:
231+
raise ValueError("No scaling_matrix available in {} defect entry! "
232+
"Cannot submit additional charged defects.".format( defname))
233+
234+
for charge in charge_list:
235+
defect = defect_template.copy()
236+
defect.set_charge( charge)
237+
238+
fw = get_fw_from_defect( defect, supercell_size,
239+
user_kpoints_settings = user_kpoints_settings,
240+
user_incar_settings = user_incar_settings,
241+
db_file=db_file, vasp_cmd=vasp_cmd)
242+
fws.append( fw)
243+
244+
if consider_supercells:
245+
rec_dict = dpd.suggest_larger_supercells()
246+
for defname, charge_list in rec_dict.items():
247+
defect_template = dpd.finished_charges[ defname][0].defect.copy()
248+
249+
#TODO -> consider next sized supercell size..
250+
supercell_size = ?
251+
252+
for charge in charge_list:
253+
defect = defect_template.copy()
254+
defect.set_charge( charge)
255+
256+
fw = get_fw_from_defect( defect, supercell_size,
257+
user_kpoints_settings = user_kpoints_settings,
258+
user_incar_settings = user_incar_settings,
259+
db_file=db_file, vasp_cmd=vasp_cmd)
260+
fws.append( fw)
261+
262+
if not len(fws):
263+
print("No fireworks generated from defect resubmission scheme")
264+
return None
265+
else:
266+
bs_struct = dpd.entries[0].defect.bulk_structure.copy()
267+
wfname = "{}:{}".format(bs_struct.composition.reduced_formula, name)
268+
final_wf = Workflow(fws, name=wfname)
269+
270+
return final_wf

0 commit comments

Comments
 (0)