diff --git a/dfttk/EVcheck_QHA.py b/dfttk/EVcheck_QHA.py index 578b3fa5..860dc3e9 100644 --- a/dfttk/EVcheck_QHA.py +++ b/dfttk/EVcheck_QHA.py @@ -81,8 +81,8 @@ def check_deformations_in_volumes(deformations, volumes, orig_vol=None): if orig_vol is None: orig_vol = (max(volumes) + min(volumes))/2. result = [] - min_vol = min(volumes) / orig_vol - max_vol = max(volumes) / orig_vol + min_vol = min(volumes) / orig_vol*(1.0-1.0e-6) + max_vol = max(volumes) / orig_vol*(1.0+1.0e-6) for deformation in deformations: if deformation < min_vol or deformation > max_vol: result.append(deformation) @@ -203,7 +203,7 @@ class EVcheck_QHA(FiretaskBase): 'del_limited', 'vol_spacing', 't_min', 't_max', 't_step', 'phonon', 'phonon_supercell_matrix', 'verbose', 'modify_incar_params', 'run_num','modify_kpoints_params', 'site_properties', 'override_symmetry_tolerances', 'override_default_vasp_params', 'db_file', 'vasp_cmd', - 'force_phonon', 'stable_tor', 'store_volumetric_data','test'] + 'force_phonon', 'stable_tor', 'store_volumetric_data', 'a_kwargs', 'test'] def run_task(self, fw_spec): ''' @@ -237,11 +237,14 @@ def run_task(self, fw_spec): site_properties = self.get('site_properties', None) modify_incar_params = self.get('modify_incar_params', {}) - powerups_options=modify_incar_params.get('powerups', None) + #powerups_options=modify_incar_params.get('powerups', None) override_default_vasp_params = self.get('override_default_vasp_params', {}) - user_incar_settings = override_default_vasp_params.get('user_incar_settings',{}) - powerups_options=user_incar_settings.get('powerups', powerups_options) + #user_incar_settings = override_default_vasp_params.get('user_incar_settings',{}) + #powerups_options=user_incar_settings.get('powerups', powerups_options) + a_kwargs = self.get('a_kwargs', {}) + settings = a_kwargs.get('settings', None) + override_symmetry_tolerances = self.get('override_symmetry_tolerances', {}) store_volumetric_data = self.get('store_volumetric_data', False) @@ -334,7 +337,7 @@ def run_task(self, fw_spec): name="relax_Vol{:.3f}".format(vol_add), vasp_input_set=None, job_type="normal", override_symmetry_tolerances=override_symmetry_tolerances, prev_calc_loc=True, parents=relax_parents_fw, db_insert=False, force_gamma=True, - modify_incar={}, **vasp_kwargs, **common_kwargs) + modify_incar={}, **vasp_kwargs, a_kwargs=a_kwargs, **common_kwargs) relax_parents_fw = deepcopy(relax_fw) fws.append(relax_fw) calcs.append(relax_fw) @@ -342,7 +345,7 @@ def run_task(self, fw_spec): static_fw = StaticFW(struct, isif=relax_scheme[-1], name='static_Vol{:.3f}'.format(vol_add), vasp_input_set=None, prev_calc_loc=True, parents=relax_parents_fw, store_volumetric_data=store_volumetric_data, - **common_kwargs) + a_kwargs=a_kwargs, **common_kwargs) fws.append(static_fw) calcs.append(static_fw) @@ -350,12 +353,13 @@ def run_task(self, fw_spec): #visphonon = ForceConstantsSet(struct) phonon_fw = PhononFW(struct, phonon_supercell_matrix, vasp_input_set=None, stable_tor=stable_tor, name='structure_{:.3f}-phonon'.format(vol_add), prev_calc_loc=True, - parents=static_fw, **t_kwargs, **common_kwargs) + parents=static_fw, **t_kwargs, a_kwargs=a_kwargs, **common_kwargs) fws.append(phonon_fw) calcs.append(phonon_fw) check_result = Firework(EVcheck_QHA(structure=relax_structure, relax_scheme=relax_scheme, store_volumetric_data=store_volumetric_data, run_num=run_num, verbose=verbose, site_properties=site_properties, stable_tor=stable_tor, phonon=phonon, phonon_supercell_matrix=phonon_supercell_matrix, force_phonon=force_phonon, + a_kwargs = a_kwargs, **eos_kwargs, **vasp_kwargs, **t_kwargs, **common_kwargs), parents=calcs, name='{}-EVcheck_QHA'.format(structure.composition.reduced_formula)) fws.append(check_result) @@ -368,7 +372,7 @@ def run_task(self, fw_spec): if modify_kpoints_params != {}: from dfttk.utils import add_modify_kpoints_by_FWname add_modify_kpoints_by_FWname(wfs, modify_kpoints_params = modify_kpoints_params) - wfs=Customizing_Workflows(wfs,powerups_options = powerups_options) + wfs=Customizing_Workflows(wfs,powerups_options = settings.get('powerups',None)) if not test: lpad.add_wf(wfs) else: too_many_run_error() @@ -391,7 +395,7 @@ def run_task(self, fw_spec): ''' strname = "{}:{}".format(structure.composition.reduced_formula, 'QHA') wfs = Workflow(fws, name = strname, metadata=metadata) - wfs=Customizing_Workflows(wfs,powerups_options = powerups_options) + wfs=Customizing_Workflows(wfs,powerups_options = settings.get('powerups',None)) if not test: lpad.add_wf(wfs) else: # failure to meet the tolerance if len(volumes) == 0: #self.error == 1e10: # Bad initial running set @@ -573,6 +577,7 @@ def check_vol_coverage(self, volume, vol_spacing, vol_orig, run_num, energy, str vol_spacing = volumer[-1] - volumer[-2] for i in range(idx+1+nV_addR-nV): result.append(volumer[-1] + (i+1)*vol_spacing) + #raise ValueError('************* {}'.format(results)) return(np.array(result)) def check_fit(self, volumes, energies): @@ -580,6 +585,163 @@ def check_fit(self, volumes, energies): self.eos_fit = eos.fit(volumes, energies) +@explicit_serialize +class Crosscom_EVcheck_QHA(FiretaskBase): + ''' + If EVcheck(Energies versus Volumes) meets the tolerance, it will launch QHA; + otherwise it will append more volumes to VASP calculation and take EVcheck again. + The maximum appending VASP running times set by run_num; + + Important Properties: + correct: whether result satisfies the tolerance + points: the selected data index + error: actual fitting error + eos_fit: eos fitting + + required_params + None - but you must specify structure or ensure the structure exists in fw_spec(e.g. run the CheckRelaxScheme) + optional_paramms + structure + ''' + _fw_name = 'EVcheck' + required_params = [] + optional_params = ['tag', 'metadata', 'deformations', 'eos_tolerance', 'threshold', + 'del_limited', 'vol_spacing', 't_min', 't_max', 't_step', + 'verbose', 'modify_incar_params', 'run_num','modify_kpoints_params', + 'override_default_vasp_params', 'db_file', 'vasp_cmd', 'site_properties', + 'stable_tor', 'store_volumetric_data', 'a_kwargs', 'test'] + + def run_task(self, fw_spec): + ''' + run_num: maximum number of appending VASP running; this limitation is to avoid always running due to bad settings; + only for internal usage; + + Important args: + eos_tolerance: acceptable value for average RMS, recommend >= 0.005; + threshold: total point number above the value should be reduced, recommend < 16 or much time to run; + del_limited: maximum deletion ration for large results; + vol_spacing: the maximum ratio step between two volumes, larger step will be inserted points to calculate; + ''' + # Get the parameters from the object + max_run = 16 + test = self.get('test', False) + if test: + db_file = self.get('db_file', DB_FILE) + vasp_cmd = self.get('vasp_cmd', VASP_CMD) + else: + db_file = env_chk(self.get('db_file', DB_FILE), fw_spec) #always concrete db_fiel + vasp_cmd = env_chk(self.get('vasp_cmd', VASP_CMD), fw_spec) #chould change for user to provide the change + + deformations = self.get('deformations', []) + run_num = self.get('run_num', 0) + eos_tolerance = self.get('eos_tolerance', 0.005) + threshold = self.get('threshold', 14) + del_limited = self.get('del_limited', 0.3) + vol_spacing = self.get('vol_spacing', 0.05) + t_min = self.get('t_min', 5) + t_max = self.get('t_max', 2000) + t_step = self.get('t_step', 5) + a_kwargs = self.get('a_kwargs', {}) + phonon = a_kwargs.get('phonon', False) + phonon_supercell_matrix = a_kwargs.get('phonon_supercell_matrix', None) + settings = a_kwargs.get('settings', None) + structure = a_kwargs.get('structure', None) + site_properties = structure.site_properties + + modify_kpoints_params = self.get('modify_kpoints_params', {}) + verbose = self.get('verbose', False) + """ + modify_incar_params = self.get('modify_incar_params', {}) + powerups_options=modify_incar_params.get('powerups', None) + """ + + override_default_vasp_params = self.get('override_default_vasp_params', {}) + #user_incar_settings = override_default_vasp_params.get('user_incar_settings',{}) + #powerups_options=user_incar_settings.get('powerups', powerups_options) + + store_volumetric_data = self.get('store_volumetric_data', False) + stable_tor = self.get('stable_tor', 0.01) + + metadata = self.get('metadata', {}) + tag = self.get('tag', metadata.get('tag', None)) + if tag is None: + tag = str(uuid4()) + metadata['tag'] = tag + + run_num += 1 + + #Some initial checks + #TODO: add phonon after RobustOptimizeFW + if phonon: + #To check if the consistent of phonon and optimize + if not consistent_check_db(db_file, tag): + print('Please check DB, DFTTK running ended!') + return + + if site_properties: + for pkey in site_properties: + structure.add_site_property(pkey, site_properties[pkey]) + # get original EV curve + volumes, energies, dos_objs = self.get_orig_EV(db_file, tag) + vol_orig = structure.volume + vol_adds = self.check_vol_coverage(volumes, energies, vol_orig) + # Marked as adopted in db + mark_adopted(tag, db_file, volumes, phonon=phonon) + + lpad = LaunchPad.auto_load() + if len(vol_adds) > 0: # VASP calculations need to append + if run_num < max_run: + # Do VASP and check again + print('Appending the volumes of : %s to calculate in VASP!' %(vol_adds).tolist()) + from dfttk.wflows import get_wf_crosscom + wfs = get_wf_crosscom(structure, run_num = run_num, + new_deformation_fraction = vol_adds, + metadata=metadata, settings=settings) + wfs=Customizing_Workflows(wfs,powerups_options = settings.get('powerups', None)) + if not test: lpad.add_wf(wfs) + else: # No need to do more VASP calculation, QHA could be running + print('Success in Volumes-Energies checking, enter QHA ...') + debye_fw = Firework(QHAAnalysis(phonon=phonon, t_min=t_min, t_max=t_max, t_step=t_step, db_file=self.get('db_file', DB_FILE), tag=tag, metadata=metadata), + name="{}-qha_analysis".format(structure.composition.reduced_formula)) + fws=[debye_fw] + + strname = "{}:{}".format(structure.composition.reduced_formula, 'QHA') + wfs = Workflow(fws, name = strname, metadata=metadata) + wfs=Customizing_Workflows(wfs,powerups_options = settings.get('powerups', None)) + if not test: lpad.add_wf(wfs) + + + def get_orig_EV(self, db_file, tag): + vasp_db = VaspCalcDb.from_db_file(db_file=db_file, admin = True) + volumes, energies, dos_objs, _ \ + = get_static_calculations(vasp_db, tag) + print('%s Volumes = %s' %(len(volumes), volumes)) + print('%s Energies = %s' %(len(energies), energies)) + return(list(volumes), list(energies), dos_objs) + + + def check_vol_coverage(self, volume, energy, vol_orig, ): + result = [] + volumer = volume.copy() + # Check minimum spacing + volumer = [vol_i / vol_orig for vol_i in volumer] + print('Finished volumes of : %s to calculate in VASP!' % volumer) + + val, idx = min((val, idx) for (idx, val) in enumerate(energy)) + nV = len(energy) + nV_addL = 3 + if nV_addL - idx > 0: + vol_spacing = volumer[1] - volumer[0] + for i in range(nV_addL-idx): + result.append(volumer[0] - (nV_addL-idx-i)*vol_spacing) + nV_addR = 4 + if idx+1+nV_addR - nV > 0: + vol_spacing = volumer[-1] - volumer[-2] + for i in range(idx+1+nV_addR-nV): + result.append(volumer[-1] + (i+1)*vol_spacing) + return(np.array(result)) + + @explicit_serialize class PreEV_check(FiretaskBase): ''' @@ -599,7 +761,7 @@ class PreEV_check(FiretaskBase): optional_params = ['deformations', 'relax_path', 'run_num', 'tolerance', 'threshold', 'del_limited', 'vol_spacing', 't_min', 't_max', 't_step', 'phonon', 'phonon_supercell_matrix', 'verbose', 'modify_incar_params', 'structure', 'modify_kpoints_params', 'symmetry_tolerance', 'run_isif2', 'pass_isif4', 'site_properties', - 'store_volumetric_data'] + 'store_volumetric_data', 'a_kwargs'] def run_task(self, fw_spec): ''' @@ -633,12 +795,13 @@ def run_task(self, fw_spec): verbose = self.get('verbose') or False modify_incar_params = self.get('modify_incar_params') or {} modify_kpoints_params = self.get('modify_kpoints_params') or {} - powerups_options=modify_incar_params.get('powerups', None) symmetry_tolerance = self.get('symmetry_tolerance') or None run_isif2 = self.get('run_isif2') or None pass_isif4 = self.get('pass_isif4') or False site_properties = self.get('site_properties') or None store_volumetric_data = self.get('store_volumetric_data', False) + a_kwargs = self.get('a_kwargs', {}) + settings = a_kwargs.get('settings', None) run_num += 1 volumes, energies = self.get_orig_EV_structure(db_file, tag) @@ -675,7 +838,7 @@ def run_task(self, fw_spec): for vol_add in vol_adds: prestatic = StaticFW(structure=structure, job_type='normal', name='VR_%.3f-PreStatic' %vol_add, prev_calc_loc=False, vasp_input_set=vis_prestatic, vasp_cmd=">>vasp_cmd<<", db_file=self.get('db_file', DB_FILE), - metadata=metadata, Prestatic=True) + metadata=metadata, a_kwargs=a_kwargs, Prestatic=True) fws.append(prestatic) prestatic_calcs.append(prestatic) @@ -683,7 +846,8 @@ def run_task(self, fw_spec): tolerance = tolerance, threshold = 14, vol_spacing = vol_spacing, vasp_cmd = ">>vasp_cmd<<", pass_isif4=pass_isif4, metadata = metadata, t_min=t_min, t_max=t_max, t_step=t_step, phonon = phonon, symmetry_tolerance = symmetry_tolerance, phonon_supercell_matrix = phonon_supercell_matrix, verbose = verbose, site_properties=site_properties, - modify_incar_params=modify_incar_params, modify_kpoints_params = modify_kpoints_params), + modify_incar_params=modify_incar_params, modify_kpoints_params = modify_kpoints_params, + a_kwargs=a_kwargs), parents=prestatic_calcs, name='%s-PreEV_check%s' %(structure.composition.reduced_formula, run_num)) fws.append(check_result) strname = "{}:{}".format(structure.composition.reduced_formula, 'PreEV_check') @@ -694,7 +858,7 @@ def run_task(self, fw_spec): if modify_kpoints_params != {}: from dfttk.utils import add_modify_kpoints_by_FWname add_modify_kpoints_by_FWname(wfs, modify_kpoints_params = modify_kpoints_params) - wfs=Customizing_Workflows(wfs,powerups_options = powerups_options) + wfs=Customizing_Workflows(wfs,powerups_options = settings.get('powerups', None)) lpad.add_wf(wfs) else: too_many_run_error() @@ -707,6 +871,7 @@ def run_task(self, fw_spec): prev_calc_loc=False, vasp_input_set=vis_relax, vasp_cmd=">>vasp_cmd<<", db_file=self.get('db_file', DB_FILE), metadata=metadata, record_path = True, modify_incar = {'ISIF': 2}, run_isif2=run_isif2, pass_isif4=pass_isif4, modify_incar_params=modify_incar_params, modify_kpoints_params = modify_kpoints_params, + a_kwargs=a_kwargs, spec={'_preserve_fworker': True}, store_volumetric_data=store_volumetric_data) fws.append(ps2_relax_fw) else: @@ -717,6 +882,7 @@ def run_task(self, fw_spec): metadata = metadata, t_min = t_min, t_max = t_max, t_step = t_step, phonon = phonon, deformations =deformations, phonon_supercell_matrix = phonon_supercell_matrix, symmetry_tolerance = symmetry_tolerance, modify_incar_params = modify_incar_params, verbose = verbose, pass_isif4=pass_isif4, + a_kwargs=a_kwargs, modify_kpoints_params = modify_kpoints_params, site_properties=site_properties), parents = ps2_relax_fw, name='%s-EVcheck_QHA' %structure.composition.reduced_formula, store_volumetric_data=store_volumetric_data) fws.append(check_result) @@ -728,7 +894,7 @@ def run_task(self, fw_spec): if modify_kpoints_params != {}: from dfttk.utils import add_modify_kpoints_by_FWname add_modify_kpoints_by_FWname(wfs, modify_kpoints_params = modify_kpoints_params) - wfs=Customizing_Workflows(wfs,powerups_options = powerups_options) + wfs=Customizing_Workflows(wfs,powerups_options = settings.get('powerups', None)) lpad.add_wf(wfs) else: # failure to meet the tolerance if len(volumes) == 0: #self.error == 1e10: # Bad initial running set diff --git a/dfttk/analysis/debye.py b/dfttk/analysis/debye.py index d865cbca..518ef989 100644 --- a/dfttk/analysis/debye.py +++ b/dfttk/analysis/debye.py @@ -202,8 +202,10 @@ def debye_temperature(self, volume): # Low temperature limit: 1 # take 0 K E-V curve properties dBdP = self.ev_eos_fit.b1 # bulk modulus/pressure derivative + debye = s*A * (self.ev_eos_fit.v0*1.e-30/self.natoms) ** (1. / 6.) * np.sqrt(self.bulk_modulus*1e9/self.avg_mass) gamma = (1+dBdP)/2 - self.bp2gru # 0K equilibrium Gruneisen parameter - return debye * (self.ev_eos_fit.v0 / volume) ** (gamma) + debye = debye*(self.ev_eos_fit.v0 / volume) ** (gamma) + return debye else: return debye diff --git a/dfttk/analysis/phonon.py b/dfttk/analysis/phonon.py index 3ed9e5f7..9e2d62d3 100644 --- a/dfttk/analysis/phonon.py +++ b/dfttk/analysis/phonon.py @@ -42,7 +42,7 @@ def get_f_vib_phonopy(structure, supercell_matrix, vasprun_path, # get codename and version from vasprun.xml file code_name, code_version = get_code_version(xml=vasprun_path) force_constant_factor = 1.0 - if code_version[0:1] >= '6': + if code_version[0:3] >= '6.2': force_constant_factor = 0.004091649655126895 # get the force constants from a vasprun.xml file diff --git a/dfttk/analysis/ywplot.py b/dfttk/analysis/ywplot.py index accfb047..2e3a4463 100644 --- a/dfttk/analysis/ywplot.py +++ b/dfttk/analysis/ywplot.py @@ -617,7 +617,7 @@ def __init__(self, folder,thermodynamicproperty,x,y,reflin=None, yzero=None,fitt elif self.thermodynamicproperty.lower()!="heat capacities (J/mol-atom/K)".lower(): self.plot_default() else: self.plot_Heat_Capacity() - if self.plottitle!=None: plt.title(self.plottitle) + #if self.plottitle!=None: plt.title(self.plottitle) plt.xlabel(self._xlabel) plt.ylabel(self._ylabel) self.ax.legend(loc=0, prop={'size': 24}) @@ -642,10 +642,11 @@ def plot_EV(self): self.ax.plot(self.x, self.y, fillstyle='none', marker='o', markersize=12, color='k', linestyle='None', label=self._label) xnew = np.linspace(min(self.x)*0.95,max(self.x)*1.05, 300) - from dfttk.pythelec import BMvol4, BMvol, alt_curve_fit - f2, pcov = alt_curve_fit(BMvol4, self.x, self.y) - ynew = BMvol(xnew, f2) - self.ax.plot(xnew,ynew,'-',linewidth=1,color='b', label="BMvol4") + if len(self.x)>=4: + from dfttk.pythelec import BMvol4, BMvol, alt_curve_fit + f2, pcov = alt_curve_fit(BMvol4, self.x, self.y) + ynew = BMvol(xnew, f2) + self.ax.plot(xnew,ynew,'-',linewidth=1,color='b', label="BMvol4") def plot_Helmholtz_energy_v0(self): @@ -1432,7 +1433,7 @@ def mkDict(line): idx = 1 while True: if not os.path.exists(dir0): break - recordfile = dir0,"record.json" + recordfile = os.path.join(dir0,"record.json") newdir = False try: if os.path.exists(recordfile): @@ -1743,7 +1744,6 @@ def Phonon298(dir0, pvdos=False): copyfile(os.path.join(plotdatabase,dfile),os.path.join(phdir298,dfile)) cwd = os.getcwd() os.chdir( phdir298 ) - import platform if platform.system()=="Linux": cmd = 'timeout 6 pos2s Symmetry.pos -THR 3.e-4 >&symmetry.out' output = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, @@ -2366,19 +2366,29 @@ def Plot298(folder, V298, volumes, debug=False, plottitle=None, local=None): ydir = os.path.join(folder,'..') vdict = {} + emin = 1.0e36 for root, dirs, files in os.walk(ydir): for dir in dirs: poscar = os.path.join(ydir,dir,'POSCAR') + if os.path.exists(poscar): structure = Structure.from_file(poscar) vol = 'V{:010.6f}'.format(structure.volume) vdict[vol]=dir - try: - natom = len(structure.sites) - sa = SpacegroupAnalyzer(structure) - ngroup = sa.get_space_group_number() - except: - return + oszicar = os.path.join(ydir,dir, 'OSZICAR') + if not os.path.exists(poscar): continue + with open(oszicar,"r") as fp: + lines = fp.readlines() + for line in lines: + dat = [s for s in line.split() if s!=""] + if len(dat) < 5: continue + if dat[1]!="F=" or dat[3]!="E0=": continue + e = float(dat[4]) + if e < emin: + emin = e + natom = len(structure.sites) + sa = SpacegroupAnalyzer(structure) + ngroup = sa.get_space_group_number() #print(natom,ngroup) i1 = 0 @@ -2435,7 +2445,6 @@ def Plot298(folder, V298, volumes, debug=False, plottitle=None, local=None): move("vdos.png", os.path.join(cwd,folder,'vdos298.15.png')) if not os.path.exists('symmetry.mode'): - import platform if platform.system()=="Linux": cmd = "pos2s Symmetry.pos -THR 0.001" output = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, diff --git a/dfttk/analysis/ywutils.py b/dfttk/analysis/ywutils.py index 1eb236b9..6cad8845 100644 --- a/dfttk/analysis/ywutils.py +++ b/dfttk/analysis/ywutils.py @@ -227,10 +227,19 @@ def get_Magnetic_State(calc): magmoms = [k for k in magmoms] magmoms = np.array(magmoms) fmax = max(magmoms) + sdw = magmoms[magmoms>0.1] + if len(sdw)>0: + smin = min(sdw) + smax = max(sdw) + else: + smin = 0.0 + smax = 0.0 + fmax = max(magmoms) fmin = min(magmoms) fsum = sum(magmoms) if fmax>0.1 and fmin<=-0.1: if abs(fsum) > 0.1: return "_FIM" + elif smax-smin > 0.1: return "_SDW" else: return "_AFM" elif fmax>0.1 or fmin<=-0.1: return "_FM" else: return "" @@ -262,7 +271,7 @@ def get_rec_from_metatag(vasp_db,m, test=False): for calc in static_calculations: vol = calc['output']['structure']['lattice']['volume'] if kpoints is None: kpoints = calc['orig_inputs']['kpoints']['kpoints'] - if vol_within(vol, volumes): continue + if vol_within(vol, volumes, thr=1.e-6): continue natoms = len(calc['output']['structure']['sites']) try: sites = calc['output']['structure']['sites'] @@ -288,8 +297,8 @@ def get_rec_from_metatag(vasp_db,m, test=False): else: pressures.append(None) if not gapfound: gapfound = float(gap) > 0.0 tvolumes = np.array(sorted(volumes)) - if len(tvolumes)>1: - dvolumes = tvolumes[1:-1] - tvolumes[0:-2] + if len(tvolumes)>=3: + dvolumes = tvolumes[1:] - tvolumes[0:-1] dvolumes = sorted(dvolumes) if abs(dvolumes[-1]-dvolumes[-2]) > 0.01*dvolumes[-1]: all_static_calculations = vasp_db.collection.\ @@ -297,7 +306,7 @@ def get_rec_from_metatag(vasp_db,m, test=False): for calc in all_static_calculations: if len(calc['metadata'])<=1:continue # only check constrained calculation vol = calc['output']['structure']['lattice']['volume'] - if vol_within(vol, volumes): continue + if vol_within(vol, volumes, thr=1.e-6): continue natoms = len(calc['output']['structure']['sites']) try: sites = calc['output']['structure']['sites'] diff --git a/dfttk/elasticity/parse_outputs.py b/dfttk/elasticity/parse_outputs.py index 9883ccf1..ec0fdfdc 100644 --- a/dfttk/elasticity/parse_outputs.py +++ b/dfttk/elasticity/parse_outputs.py @@ -305,9 +305,14 @@ def run_task(self, fw_spec): } vasp_input_set = env_chk(self.get('vasp_input_set'), False) if vasp_input_set: + from pymatgen.io.vasp.inputs import Kpoints d['vasp_input_set_all'] = vasp_input_set.config - d['vasp_input_set'] = {'INCAR':vasp_input_set.config['INCAR'], \ - 'KPOINTS':vasp_input_set.config['KPOINTS'].as_dict()} + if isinstance(vasp_input_set.config['KPOINTS'], Kpoints): + d['vasp_input_set'] = {'INCAR':vasp_input_set.config['INCAR'], \ + 'KPOINTS':vasp_input_set.config['KPOINTS'].as_dict()} + else: + d['vasp_input_set'] = {'INCAR':vasp_input_set.config['INCAR'], \ + 'KPOINTS':vasp_input_set.config['KPOINTS']} # Get optimized structure calc_locs_opt = [cl for cl in fw_spec.get('calc_locs', []) if 'optimiz' in cl['name']] diff --git a/dfttk/ftasks.py b/dfttk/ftasks.py index 8550ee44..edb024e4 100644 --- a/dfttk/ftasks.py +++ b/dfttk/ftasks.py @@ -32,8 +32,8 @@ from atomate import __version__ as atomate_ver from dfttk import __version__ as dfttk_ver from pymatgen.core import __version__ as pymatgen_ver -from dfttk.pythelec import get_static_calculations -from dfttk.scripts.assign_fworker_name import Customizing_Workflows, get_powerups_options +from dfttk.pythelec import get_static_calculations, vol_within +from dfttk.scripts.assign_fworker_name import Customizing_Workflows def extend_calc_locs(name, fw_spec): """ @@ -340,9 +340,13 @@ def run_task(self, fw_spec): #always perform phonon calculations when when enough phonon calculations found #to perform a quasiharmonic phonon calculations, one needs at least phonon results five volumes #phonon_calculations= list(vasp_db.db['phonon'].find({'$and':[ {'metadata.tag': tag}, {'adopted': True} ]})) - phonon_calculations= list(vasp_db.db['phonon'].find({'$and':[ {'metadata': {'tag':tag}}, {'adopted': True} ]})) + phonon_calculations= list(vasp_db.db['phonon'].find({'$and':[ {'metadata': {'tag':tag}}, {'adopted': True}, {'S_vib': {'$exists': True}} ]})) num_phonon_finished = len(phonon_calculations) qha_result['has_phonon'] = num_phonon_finished >= 5 + if not qha_result['has_phonon']: + phonon_calculations= list(vasp_db.db['phonon'].find({'$and':[ {'metadata': {'tag':tag}}, {'S_vib': {'$exists': True}} ]})) + num_phonon_finished = len(phonon_calculations) + qha_result['has_phonon'] = num_phonon_finished >= 5 #if self['phonon']: if qha_result['has_phonon']: # get the vibrational properties from the FW spec @@ -355,12 +359,15 @@ def run_task(self, fw_spec): vol_s_vib = [] vol_c_vib = [] for calc in phonon_calculations: - if calc['volume'] in vol_vol: continue - if calc['volume'] not in volumes: continue - vol_vol.append(calc['volume']) + #if calc['volume'] in vol_vol: continue + #if calc['volume'] not in volumes: continue + if vol_within(calc['volume'], vol_vol, thr=1.e-6): continue + if not vol_within(calc['volume'],volumes, thr=1.e-6): continue vol_f_vib.append(calc['F_vib'][::everyT]) vol_s_vib.append(calc['S_vib']) vol_c_vib.append(calc['CV_vib']) + vol_vol.append(calc['volume']) + # sort them order of the unit cell volumes vol_f_vib = sort_x_by_y(vol_f_vib, vol_vol) vol_s_vib = sort_x_by_y(vol_s_vib, vol_vol) @@ -371,7 +378,8 @@ def run_task(self, fw_spec): _energies = [] _dos_objs = [] for iv,vol in enumerate(volumes): - if vol not in vol_vol: continue + #if vol not in vol_vol: continue + if not vol_within(vol,vol_vol, thr=1.e-6): continue _volumes.append(vol) _energies.append(energies[iv]) _dos_objs.append(dos_objs[iv]) @@ -740,6 +748,88 @@ def run_task(self, fw_spec): kpoint.write_file('KPOINTS') +@explicit_serialize +class Crosscom_Calculation(FiretaskBase): + """Continue Static/Phonon calculations + """ + + required_params = [] + optional_params = ['db_file', 'vasp_cmd', 'a_kwargs', + 'db_insert', 'tag', 'metadata', 'name', 'vasp_input_set', + 't_min', 't_max', 't_step', + 'verbose', 'modify_incar_params', 'modify_kpoints_params', + 'override_default_vasp_params', + 'store_volumetric_data', 'static', 'defo'] + + def run_task(self, fw_spec): + db_file = self.get('db_file') or DB_FILE + vasp_cmd = self.get('vasp_cmd') or VASP_CMD + db_insert = self.get('db_insert', None) + tag = self.get('tag') + metadata = self.get('metadata') + name = self.get('name', "Crosscom_Calculation") + t_min = self.get('t_min', None) + t_max = self.get('t_max', None) + t_step = self.get('t_step', None) + modify_incar_params = self.get('modify_incar_params', {}) + modify_kpoints_params = self.get('modify_kpoints_params', {}) + override_default_vasp_params = self.get('override_default_vasp_params', {}) + store_volumetric_data = self.get('store_volumetric_data', False) + + return FWAction(detours=self.get_detour_workflow( + db_file, vasp_cmd, db_insert, tag, metadata, name, + t_min, t_max, t_step, + modify_incar_params, modify_kpoints_params, + override_default_vasp_params, + store_volumetric_data) + ) + + def get_detour_workflow(self, + db_file, vasp_cmd, db_insert, tag, metadata, name, + t_min, t_max, t_step, + modify_incar_params, modify_kpoints_params, + override_default_vasp_params, + store_volumetric_data): + from fireworks import Workflow + from .fworks import PhononFW, StaticFW + a_kwargs = self.get('a_kwargs',{}) + settings = a_kwargs.get('settings', {}) + stable_tor = settings.get('stable_tor', 0.01) + + phonon = settings.get('phonon', False) + phonon_supercell_matrix = a_kwargs.get('phonon_supercell_matrix', None) + structure=a_kwargs.get('structure', None) + site_properties = structure.site_properties + + detour_fws = [] + inp_structure = Structure.from_file('CONTCAR') + if len(site_properties)>0: + for prop, vals in site_properties.items(): + inp_structure.add_site_property(prop, vals) + + detour_fws.append(StaticFW(inp_structure, name="crosscom-static"+'-defo={:5.3f}'.format(self.get('defo',1.0)), + vasp_cmd=vasp_cmd, metadata=metadata, prev_calc_loc=False, modify_incar=modify_incar_params, + db_file=db_file, tag=tag, + a_kwargs=a_kwargs, + override_default_vasp_params=override_default_vasp_params, + store_volumetric_data=store_volumetric_data)) + + if phonon: + t_kwargs = {'t_min': t_min, 't_max': t_max, 't_step': t_step} + common_kwargs = {'vasp_cmd': vasp_cmd, 'db_file': db_file, "metadata": metadata, "tag": tag, + 'override_default_vasp_params': override_default_vasp_params} + detour_fws.append(PhononFW(inp_structure, phonon_supercell_matrix, + name='crosscom-phonon'+'-defo={:5.3f}'.format(self.get('defo',1.0)), + prev_calc_loc=False, stable_tor=stable_tor, + a_kwargs=a_kwargs, + **t_kwargs, **common_kwargs)) + """ + override_default_vasp_params = override_default_vasp_params or {} + user_incar_settings = override_default_vasp_params.get('user_incar_settings',{}) + """ + return Customizing_Workflows(detour_fws, powerups_options=settings.get('powerups', None)) + + @explicit_serialize class CheckRelaxation(FiretaskBase): """Run VASP calculations to get symmetry conserved and symmetry broken structures. @@ -806,7 +896,8 @@ class CheckRelaxation(FiretaskBase): required_params = ["db_file", "tag", "common_kwargs"] optional_params = ["metadata", "tol_energy", "tol_strain", "tol_bond", 'level', 'isif4', "energy_with_isif", - "static_kwargs", "relax_kwargs", 'store_volumetric_data', 'site_properties'] + "static_kwargs", "relax_kwargs", 'store_volumetric_data', + 'a_kwargs', 'site_properties'] def run_task(self, fw_spec): self.db_file = env_chk(self.get("db_file"), fw_spec) @@ -930,6 +1021,8 @@ def get_detour_workflow(self, next_steps, final_energy, energy_with_isif={}): symmetry_options = self.symmetry_options static_kwargs = self.get('static_kwargs', {}) + a_kwargs = self.get('a_kwargs', {}) + settings = a_kwargs.get('settings', {}) # Assume the data for the current step is already in the database db = VaspCalcDb.from_db_file(self.db_file, admin=True).db['relaxations'] @@ -949,17 +1042,21 @@ def _get_input_structure_for_step(step): md['symmetry_type'] = step["symmetry_type"] common_copy["metadata"] = md detour_fws.append(StaticFW(inp_structure, isif=step['isif'], store_volumetric_data=self.store_volumetric_data, - **static_kwargs, **common_copy)) + a_kwargs=a_kwargs, + **static_kwargs, **common_copy)) elif job_type == "relax": detour_fws.append(RobustOptimizeFW(inp_structure, isif=step["isif"], energy_with_isif=energy_with_isif, - override_symmetry_tolerances=symmetry_options, store_volumetric_data=self.store_volumetric_data, **self["common_kwargs"])) + override_symmetry_tolerances=symmetry_options, store_volumetric_data=self.store_volumetric_data, + a_kwargs=a_kwargs, **self["common_kwargs"])) else: raise ValueError(f"Unknown job_type {job_type} for step {step}.") + """ common_kwargs = self.get('common_kwargs',{}) override_default_vasp_params = common_kwargs.get('override_default_vasp_params',{}) user_incar_settings = override_default_vasp_params.get('user_incar_settings',{}) #user_incar_settings = common_kwargs.get('modify_incar_params',{}) - return Customizing_Workflows(detour_fws, powerups_options=user_incar_settings.get('powerups', None)) + """ + return Customizing_Workflows(detour_fws, powerups_options=settings.get('powerups', None)) @explicit_serialize diff --git a/dfttk/fworks.py b/dfttk/fworks.py index d77ea9d9..0552c00d 100644 --- a/dfttk/fworks.py +++ b/dfttk/fworks.py @@ -13,7 +13,8 @@ from dfttk.input_sets import RelaxSet, StaticSet, ForceConstantsSet, ATATIDSet, BornChargeSet from dfttk.ftasks import WriteVaspFromIOSetPrevStructure, SupercellTransformation, CalculatePhononThermalProperties, \ CheckSymmetry, CheckRelaxation, ScaleVolumeTransformation, TransmuteStructureFile, WriteATATFromIOSet, RunATATCustodian, RunVaspCustodianNoValidate, \ - Record_relax_running_path, Record_PreStatic_result, CheckSymmetryToDb, PhononStable, BornChargeToDb + Record_relax_running_path, Record_PreStatic_result, CheckSymmetryToDb, PhononStable, BornChargeToDb, \ + Crosscom_Calculation from atomate import __version__ as atomate_ver from dfttk import __version__ as dfttk_ver from dfttk.run_task_ext import run_task_ext @@ -48,7 +49,8 @@ def __init__(self, structure, scale_lattice=None, isif=4, override_symmetry_tole metadata=None, override_default_vasp_params=None, db_file=None, record_path=False, prev_calc_loc=True, parents=None, db_insert=False, tag=None, run_isif2=False, pass_isif4=False, force_gamma=True, store_volumetric_data=False, - modify_incar=None, modify_incar_params={}, modify_kpoints_params={}, **kwargs): + modify_incar=None, modify_incar_params={}, modify_kpoints_params={}, + t_kwargs=None, a_kwargs={}, defo=1.0, **kwargs): metadata = metadata or {} tag = tag or metadata.get('tag') # generate a tag with a warning @@ -68,9 +70,15 @@ def __init__(self, structure, scale_lattice=None, isif=4, override_symmetry_tole raise ValueError('The store_volumetric_data should be list or bool') override_default_vasp_params = override_default_vasp_params or {} + """ + if len (override_default_vasp_params)==0: + override_default_vasp_params = a_kwargs.get("override_default_vasp_params", {}) + """ + override_symmetry_tolerances = override_symmetry_tolerances or {} + vasp_input_set = vasp_input_set or RelaxSet(structure, isif=isif, force_gamma=force_gamma, - **override_default_vasp_params) + a_kwargs=a_kwargs, **override_default_vasp_params) site_properties = deepcopy(structure).site_properties t = [] @@ -97,6 +105,15 @@ def __init__(self, structure, scale_lattice=None, isif=4, override_symmetry_tole if db_insert: t.append(VaspToDb(db_file=">>db_file<<", additional_fields={"task_label": name, "metadata": metadata}, store_volumetric_data=store_volumetric_data)) t.append(CheckSymmetryToDb(db_file=">>db_file<<", tag=tag, override_symmetry_tolerances=override_symmetry_tolerances, site_properties=site_properties)) + if a_kwargs.get("static", False): + t.append(Crosscom_Calculation( + name="Crosscom_Calculation", vasp_input_set=None, vasp_cmd=vasp_cmd, db_file=db_file, defo=defo, + metadata=metadata, + db_insert=db_insert, tag=tag, + store_volumetric_data=store_volumetric_data, + override_default_vasp_params=override_default_vasp_params, + modify_incar_params=modify_incar_params, modify_kpoints_params=modify_kpoints_params, **t_kwargs, + a_kwargs=a_kwargs, **kwargs)) super(OptimizeFW, self).__init__(t, parents=parents, name="{}-{}".format(structure.composition.reduced_formula, name), **kwargs) @@ -127,7 +144,8 @@ def __init__(self, structure, isif=7, name="structure optimization", isif4=False override_symmetry_tolerances=None, job_type="normal", vasp_input_set=None, vasp_cmd="vasp", metadata=None, override_default_vasp_params=None, db_file=None, prev_calc_loc=True, parents=None, db_insert=False, tag=None, modify_incar_params={}, - modify_kpoints_params={}, energy_with_isif={}, store_volumetric_data=False, + modify_kpoints_params={}, energy_with_isif={}, store_volumetric_data=False, + a_kwargs={}, **kwargs): metadata = metadata or {} tag = tag or metadata.get('tag') @@ -154,7 +172,7 @@ def __init__(self, structure, isif=7, name="structure optimization", isif4=False tmp['user_incar_settings'].pop('EDIFFG') override_symmetry_tolerances = override_symmetry_tolerances or {} - vasp_input_set = vasp_input_set or RelaxSet(structure, isif=isif, **tmp) + vasp_input_set = vasp_input_set or RelaxSet(structure, isif=isif, a_kwargs=a_kwargs, **tmp) site_properties = deepcopy(structure).site_properties t = [] @@ -178,6 +196,7 @@ def __init__(self, structure, isif=7, name="structure optimization", isif4=False t.append(CheckRelaxation(db_file=">>db_file<<", metadata=metadata, tag=tag, isif4=isif4, level=level, energy_with_isif=energy_with_isif, common_kwargs=common_kwargs, relax_kwargs=relax_kwargs, static_kwargs=static_kwargs, site_properties=site_properties, store_volumetric_data=store_volumetric_data, + a_kwargs=a_kwargs, **override_symmetry_tolerances)) super().__init__(t, parents=parents, name="{}-{}".format(structure.composition.reduced_formula, name), **kwargs) @@ -212,7 +231,8 @@ class StaticFW(Firework): def __init__(self, structure, isif=2, scale_lattice=None, name="static", vasp_input_set=None, vasp_cmd="vasp", metadata=None, prev_calc_loc=True, Prestatic=False, modify_incar=None, db_file=None, parents=None, tag=None, override_default_vasp_params=None, - store_volumetric_data=False, **kwargs): + store_volumetric_data=False, + a_kwargs={}, **kwargs): # TODO: @computron - I really don't like how you need to set the structure even for # prev_calc_loc jobs. Sometimes it makes appending new FWs to an existing workflow @@ -236,7 +256,7 @@ def __init__(self, structure, isif=2, scale_lattice=None, name="static", vasp_in override_default_vasp_params = override_default_vasp_params or {} self.override_default_vasp_params = override_default_vasp_params - vasp_input_set = vasp_input_set or StaticSet(structure, isif=isif, **override_default_vasp_params) + vasp_input_set = vasp_input_set or StaticSet(structure, isif=isif, a_kwargs=a_kwargs, **override_default_vasp_params) self.vasp_input_set = vasp_input_set site_properties = deepcopy(structure).site_properties # Avoids delivery (prev_calc_loc == '' (instead by True)) @@ -305,7 +325,9 @@ class InflectionDetectionFW(Firework): """ def __init__(self, structure, name="infdet", input_set=None, metadata=None, prev_calc_loc=True, - db_file=None, parents=None, continuation=False, run_isif2=False, pass_isif4=False, **kwargs): + db_file=None, parents=None, continuation=False, run_isif2=False, pass_isif4=False, + a_kwargs={}, + **kwargs): metadata = metadata or {} input_set = input_set or ATATIDSet(structure) @@ -379,6 +401,7 @@ def __init__(self, structure, supercell_matrix, t_min=5, t_max=2000, t_step=5, name="phonon", vasp_input_set=None, override_default_vasp_params=None, vasp_cmd="vasp", metadata=None, tag=None, qpoint_mesh=(50, 50, 50), prev_calc_loc=True, db_file=None, parents=None, stable_tor=0.01, + a_kwargs={}, **kwargs): metadata = metadata or {} @@ -412,7 +435,7 @@ def __init__(self, structure, supercell_matrix, t_min=5, t_max=2000, t_step=5, supercell_structure = deepcopy(structure) supercell_structure.make_supercell(supercell_matrix) supercell_site_properties = deepcopy(supercell_structure.site_properties) - vasp_input_set = vasp_input_set or ForceConstantsSet(supercell_structure, **tmp) + vasp_input_set = vasp_input_set or ForceConstantsSet(supercell_structure, a_kwargs=a_kwargs, **tmp) t = [] @@ -424,7 +447,7 @@ def __init__(self, structure, supercell_matrix, t_min=5, t_max=2000, t_step=5, else: # write the input set first, just to get the POSCAR file in the directory # the other inputs will get overridden by WriteVaspFromIOSetPrevStructure - t.append(WriteVaspFromIOSetPrevStructure(structure=structure, vasp_input_set=vasp_input_set, site_properties=site_properties)) + t.append(WriteVaspFromIOSetPrevStructure(structure=structure, vasp_input_set=vasp_input_set, site_properties=structure.site_properties)) t.append(SupercellTransformation(supercell_matrix=supercell_matrix)) t.append(WriteVaspFromIOSetPrevStructure(vasp_input_set=vasp_input_set, site_properties=supercell_site_properties)) @@ -469,7 +492,8 @@ class BornChargeFW(Firework): """ def __init__(self, structure, isif=2, scale_lattice=None, name="born charge", vasp_input_set=None, vasp_cmd="vasp", metadata=None, override_default_vasp_params=None, tag=None, - prev_calc_loc=True, modify_incar=None, db_file=None, parents=None, **kwargs): + prev_calc_loc=True, modify_incar=None, db_file=None, parents=None, + a_kwargs={}, **kwargs): metadata = metadata or {} tag = tag or metadata.get('tag') @@ -480,7 +504,7 @@ def __init__(self, structure, isif=2, scale_lattice=None, name="born charge", va override_default_vasp_params = override_default_vasp_params or {} - vasp_input_set = vasp_input_set or BornChargeSet(structure, isif=isif, **override_default_vasp_params) + vasp_input_set = vasp_input_set or BornChargeSet(structure, isif=isif, a_kwargs=a_kwargs, **override_default_vasp_params) site_properties = deepcopy(structure).site_properties # Avoids delivery (prev_calc_loc == '' (instead by True)) diff --git a/dfttk/input_sets.py b/dfttk/input_sets.py index 4c2b1a40..6c8d59a5 100644 --- a/dfttk/input_sets.py +++ b/dfttk/input_sets.py @@ -98,18 +98,35 @@ class RelaxSet(DictSet): CONFIG['POTCAR_FUNCTIONAL'] = 'PBE' CONFIG['POTCAR'].update(POTCAR_UPDATES) - def __init__(self, structure, volume_relax=False, isif=None, **kwargs): + def __init__(self, structure, volume_relax=False, isif=None, a_kwargs={}, **kwargs): """If volume relax is True, will do volume only, ISIF 7""" self.kwargs = copy.deepcopy(kwargs) self.volume_relax = volume_relax self.isif = isif - uis = copy.deepcopy(self.kwargs.get('user_incar_settings', {})) - new_config = copy.deepcopy(RelaxSet.CONFIG) + self.a_kwargs = copy.deepcopy(a_kwargs) + if self.volume_relax and self.isif is not None: raise ValueError("isif cannot have a value while volume_relax is True.") + + no_position_relax = self.isif is None or self.isif>4 + if self.volume_relax or no_position_relax: + if 'user_incar_settings' in self.kwargs: + if 'EDIFFG' in self.kwargs['user_incar_settings']: + self.kwargs['user_incar_settings'].pop('EDIFFG') + + if 'settings' in self.a_kwargs: + try: + for _key in self.a_kwargs['settings']: + if 'EDIFFG' in self.a_kwargs['settings'][_key]: + self.a_kwargs['settings'][_key].pop('EDIFFG') + except: + pass + + uis = copy.deepcopy(self.kwargs.get('user_incar_settings', {})) + new_config = copy.deepcopy(RelaxSet.CONFIG) + if self.volume_relax: uis.update({'ISIF': 7}) - #uis['ISIF'] = 7 if self.isif is not None: uis.update({'ISIF': self.isif}) @@ -126,21 +143,21 @@ def __init__(self, structure, volume_relax=False, isif=None, **kwargs): if 'MAGMON' in uis.keys(): uis.pop['MAGMOM'] if 'MAGMON' in new_config['INCAR']: new_config['INCAR'].pop['MAGMOM'] - if 'Relax_settings' in uis: - relax = uis['Relax_settings'] - for ff in relax: + settings = self.a_kwargs.get('settings', {}) + new_vasp_settings = settings.get('Relax_settings', None) or uis.get('Relax_settings', None) + if new_vasp_settings: + for ff in new_vasp_settings: if ff.lower()=='prec': if 'ENCUT' in new_config['INCAR']: new_config['INCAR'].pop('ENCUT') - new_config['INCAR'].update({ff:relax.get(ff)}) - elif ff=='KPAR': - new_config['INCAR'].update({ff:relax.get(ff)}) + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) elif ff=='grid_density': - new_config['KPOINTS'].update({ff:relax.get(ff)}) + new_config['KPOINTS'].update({ff:new_vasp_settings.get(ff)}) elif ff=='k_mesh': - kpoints = Kpoints(kpts=relax.get(ff)) + kpoints = Kpoints(kpts=new_vasp_settings.get(ff)) new_config['KPOINTS'] = kpoints - #print (new_config) + else: + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) new_config['INCAR'].update(uis) pot = self.kwargs.get('user_potcar_functional', None) @@ -180,7 +197,7 @@ class PreStaticSet(DictSet): CONFIG['POTCAR_FUNCTIONAL'] = 'PBE' CONFIG['POTCAR'].update(POTCAR_UPDATES) - def __init__(self, structure, **kwargs): + def __init__(self, structure, a_kwargs={}, **kwargs): # pop the old kwargs, backwards compatibility from the complex StaticSet old_kwargs = ['prev_incar', 'prev_kpoints', 'grid_density', 'lepsilon', 'lcalcpol'] for k in old_kwargs: @@ -249,8 +266,10 @@ class ForceConstantsSet(DictSet): CONFIG['POTCAR_FUNCTIONAL'] = 'PBE' CONFIG['POTCAR'].update(POTCAR_UPDATES) - def __init__(self, structure, **kwargs): + def __init__(self, structure, a_kwargs={}, **kwargs): self.kwargs = copy.deepcopy(kwargs) + self.a_kwargs = a_kwargs + uis = copy.deepcopy(self.kwargs.get('user_incar_settings', {})) new_config = copy.deepcopy(ForceConstantsSet.CONFIG) if 'ISPIN' not in uis: @@ -268,6 +287,7 @@ def __init__(self, structure, **kwargs): new_config['INCAR'].update(uis) from pymatgen.io.vasp.inputs import Kpoints + """ user_kpoints_settings = kwargs.get('user_kpoints_settings', {}) grid_density = user_kpoints_settings.get('grid_density') or None if grid_density is not None: @@ -275,14 +295,30 @@ def __init__(self, structure, **kwargs): new_config['INCAR'].update({'PREC': 'High'}) kpoints = Kpoints.automatic_gamma_density(structure, grid_density) new_config['KPOINTS'] = kpoints + """ + settings = self.a_kwargs.get('settings', {}) + new_vasp_settings = settings.get('Forceconstant_settings', None) or uis.get('Forceconstant_settings', None) + if new_vasp_settings: + for ff in new_vasp_settings: + if ff.lower()=='prec': + if 'ENCUT' in new_config['INCAR']: + new_config['INCAR'].pop('ENCUT') + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) + elif ff=='grid_density': + new_config['KPOINTS'].update({ff:new_vasp_settings.get(ff)}) + elif ff=='k_mesh': + kpoints = Kpoints(kpts=new_vasp_settings.get(ff)) + new_config['KPOINTS'] = kpoints + else: + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) else: kpoints = Kpoints(kpts=[[3,3,3],]) new_config['KPOINTS'] = kpoints pot = self.kwargs.get('user_potcar_functional', None) - if pot: + if pot: new_config['POTCAR_FUNCTIONAL'] = pot super(ForceConstantsSet, self).__init__( - structure, new_config, sort_structure=False, **self.kwargs) + structure, new_config, sort_structure=False, force_gamma=True, **self.kwargs) class StaticSet(DictSet): @@ -316,10 +352,11 @@ class StaticSet(DictSet): CONFIG['POTCAR_FUNCTIONAL'] = 'PBE' CONFIG['POTCAR'].update(POTCAR_UPDATES) - def __init__(self, structure, isif=2, **kwargs): + def __init__(self, structure, isif=2, a_kwargs={}, **kwargs): # pop the old kwargs, backwards compatibility from the complex StaticSet self.isif = isif - + self.a_kwargs = a_kwargs + old_kwargs = ['prev_incar', 'prev_kpoints', 'grid_density', 'lepsilon', 'lcalcpol'] for k in old_kwargs: try: @@ -344,6 +381,22 @@ def __init__(self, structure, isif=2, **kwargs): if 'MAGMON' in uis.keys(): uis.pop['MAGMOM'] if 'MAGMON' in new_config['INCAR']: new_config['INCAR'].pop['MAGMOM'] + settings = self.a_kwargs.get('settings', {}) + new_vasp_settings = settings.get('Static_settings', None) or uis.get('Static_settings', None) + if new_vasp_settings: + for ff in new_vasp_settings: + if ff.lower()=='prec': + if 'ENCUT' in new_config['INCAR']: + new_config['INCAR'].pop('ENCUT') + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) + elif ff=='grid_density': + new_config['KPOINTS'].update({ff:new_vasp_settings.get(ff)}) + elif ff=='k_mesh': + kpoints = Kpoints(kpts=new_vasp_settings.get(ff)) + new_config['KPOINTS'] = kpoints + else: + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) + new_config['INCAR'].update(uis) pot = self.kwargs.get('user_potcar_functional', None) if pot: @@ -420,7 +473,7 @@ class ForcesSet(DictSet): CONFIG['POTCAR_FUNCTIONAL'] = 'PBE' CONFIG['POTCAR'].update(POTCAR_UPDATES) - def __init__(self, structure, **kwargs): + def __init__(self, structure, a_kwargs={}, **kwargs): # pop the old kwargs, backwards compatibility from the complex StaticSet old_kwargs = ['prev_incar', 'prev_kpoints', 'grid_density', 'lepsilon', 'lcalcpol'] for k in old_kwargs: @@ -451,7 +504,7 @@ class BornChargeSet(DictSet): #"LCALCEPS": True, #For Born Effective Charge "LRPA": False, 'EDIFF_PER_ATOM': 1e-6, - 'ENCUT': 520, # MP compatibility + #'ENCUT': 520, # MP compatibility 'ISMEAR': 0, "NSW": 0, "LORBIT": 11, @@ -462,13 +515,15 @@ class BornChargeSet(DictSet): "LCHARG": False, "LWAVE": False, "ICHARG": 2, + "PREC": "High" }) CONFIG['POTCAR_FUNCTIONAL'] = 'PBE' CONFIG['POTCAR'].update(POTCAR_UPDATES) - def __init__(self, structure, isif=2, **kwargs): + def __init__(self, structure, isif=2, a_kwargs={}, **kwargs): # pop the old kwargs, backwards compatibility from the complex StaticSet + self.a_kwargs = a_kwargs self.isif = isif uis = copy.deepcopy(kwargs.get('user_incar_settings', {})) @@ -503,6 +558,7 @@ def __init__(self, structure, isif=2, **kwargs): if 'MAGMON' in new_config['INCAR']: new_config['INCAR'].pop['MAGMOM'] for key in uis.keys(): + if key == 'ENCUT': continue if key not in new_config['INCAR']: if key in {'NELM', 'EDIFF', 'NEDOS', 'KPOINT_BSE'} : continue new_config['INCAR'][key] = uis[key] @@ -516,6 +572,24 @@ def __init__(self, structure, isif=2, **kwargs): if 'SIGMA' in new_config['INCAR'] and 'ISMEAR' in new_config['INCAR'] : if new_config['INCAR']['ISMEAR'] == -5: new_config['INCAR'].pop('SIGMA') + + from pymatgen.io.vasp.inputs import Kpoints + settings = self.a_kwargs.get('settings', {}) + new_vasp_settings = settings.get('Born_settings', None) or uis.get('Born_settings', None) + if new_vasp_settings: + for ff in new_vasp_settings: + if ff.lower()=='prec': + if 'ENCUT' in new_config['INCAR']: + new_config['INCAR'].pop('ENCUT') + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) + elif ff=='grid_density': + new_config['KPOINTS'].update({ff:new_vasp_settings.get(ff)}) + elif ff=='k_mesh': + kpoints = Kpoints(kpts=new_vasp_settings.get(ff)) + new_config['KPOINTS'] = kpoints + else: + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) + pot = self.kwargs.get('user_potcar_functional', None) if pot: new_config['POTCAR_FUNCTIONAL'] = pot @@ -528,10 +602,16 @@ class ElasticSet(DictSet): Kpoints have a 6000 reciprocal density default. """ CONFIG = _load_yaml_config("MPRelaxSet") + + CONFIG['KPOINTS'].update({ + 'grid_density': 8000, + }) + CONFIG['KPOINTS'].pop('reciprocal_density') # to be explicit + # 'EDIFF_PER_ATOM': 1e-6, CONFIG['INCAR'] = { 'EDIFF': 1e-6, - 'ENCUT': 520, # MP compatibility + #'ENCUT': 520, # MP compatibility 'ISMEAR': -5, "IBRION": 2, 'LREAL': False, @@ -553,19 +633,17 @@ class ElasticSet(DictSet): CONFIG['POTCAR_FUNCTIONAL'] = 'PBE' CONFIG['POTCAR'].update(POTCAR_UPDATES) - def __init__(self, structure, **kwargs): + def __init__(self, structure, a_kwargs={}, **kwargs): # pop the old kwargs, backwards compatibility from the complex StaticSet - + self.a_kwargs = a_kwargs + uis = copy.deepcopy(kwargs.get('user_incar_settings', {})) new_config = copy.deepcopy(ElasticSet.CONFIG) if metal_check(structure): grid_density = 15625 else: grid_density = 8000 user_kpoints_settings = kwargs.get('user_kpoints_settings', {}) grid_density = user_kpoints_settings.get('grid_density') or grid_density - """ - old_kwargs = ['prev_incar', 'prev_kpoints', 'grid_density', 'lepsilon', 'lcalcpol', \ - 'user_potcar_functional', 'user_incar_settings'] - """ + old_kwargs = ['prev_incar', 'prev_kpoints', 'grid_density', 'lepsilon', 'lcalcpol', \ 'user_incar_settings', 'user_kpoints_settings'] @@ -590,6 +668,7 @@ def __init__(self, structure, **kwargs): if 'MAGMON' in new_config['INCAR']: new_config['INCAR'].pop['MAGMOM'] for key in uis.keys(): + if key == 'ENCUT': continue if key not in new_config['INCAR']: if key in {'NELM', 'EDIFF', 'NEDOS', 'KPOINT_BSE'} : continue new_config['INCAR'][key] = uis[key] @@ -599,43 +678,44 @@ def __init__(self, structure, **kwargs): new_config['INCAR'][key] = uis[key] elif key == 'SIGMA': new_config['INCAR'][key] = uis[key] - elif key == 'ENCUT': - new_config['INCAR'][key] = uis[key] + #avoid conflict betwwen HIHG and ENCUT + """ for key in uis.keys(): if key == 'PREC': new_config['INCAR'][key] = uis[key] if 'ENCUT' in new_config['INCAR'] : new_config['INCAR'].pop('ENCUT') + """ if 'SIGMA' in new_config['INCAR'] and 'ISMEAR' in new_config['INCAR'] : if new_config['INCAR']['ISMEAR'] == -5: new_config['INCAR'].pop('SIGMA') - + from pymatgen.io.vasp.inputs import Kpoints - kpoints = Kpoints(kpts=[[31,31,31],]) - new_config['KPOINTS'] = kpoints + settings = self.a_kwargs.get('settings', {}) + new_vasp_settings = settings.get('Elastic_settings', None) or uis.get('Elastic_settings', None) + + if 'grid_density' not in new_vasp_settings: + kpoints = Kpoints(kpts=[[31,31,31],]) + new_config['KPOINTS'] = kpoints - if 'Relax_settings' in uis: - relax = uis['Relax_settings'] - for ff in relax: + if new_vasp_settings: + for ff in new_vasp_settings: if ff.lower()=='prec': if 'ENCUT' in new_config['INCAR']: new_config['INCAR'].pop('ENCUT') - new_config['INCAR'].update({ff:relax.get(ff)}) - elif ff=='KPAR': - new_config['INCAR'].update({ff:relax.get(ff)}) + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) elif ff=='grid_density': - new_config['KPOINTS'].update({ff:relax.get(ff)}) - #kpoints = Kpoints.automatic_gamma_density(structure, grid_density) + new_config['KPOINTS'].update({ff:new_vasp_settings.get(ff)}) elif ff=='k_mesh': - kpoints = Kpoints(kpts=relax.get(ff)) + kpoints = Kpoints(kpts=new_vasp_settings.get(ff)) new_config['KPOINTS'] = kpoints - from pymatgen.io.vasp.inputs import Kpoints + else: + new_config['INCAR'].update({ff:new_vasp_settings.get(ff)}) pot = self.kwargs.get('user_potcar_functional', None) if pot: new_config['POTCAR_FUNCTIONAL'] = pot super(ElasticSet, self).__init__(structure, new_config, sort_structure=False, **self.kwargs) self.config = new_config - diff --git a/dfttk/pyEVfind.py b/dfttk/pyEVfind.py index 38312f6f..96198589 100644 --- a/dfttk/pyEVfind.py +++ b/dfttk/pyEVfind.py @@ -187,10 +187,12 @@ def EV_find(self): else: phases[i] = pname[0]+potname[i]+EV['MagState'] if EV['natoms'] < self.natoms: continue - sys.stdout.write('{}, static: {:>2}, natoms: {:>3}, {}\n'.format(metadata, count[i], EV['natoms'], phases[i])) - folder = os.path.join(evdirhome,phases[i]) if not os.path.exists(folder): os.mkdir(folder) + self.num_Born = 0 + self.get_data(folder, EV, mm) + sys.stdout.write('{}, static: {:>2}, natoms: {:>3}, phonon: {:>2}, Born: {}, {}\n'.format(metadata, \ + count[i], EV['natoms'], self.num_phonon, self.num_Born, phases[i])) with open (os.path.join(folder,'POSCAR'), 'w') as fp: fp.write(POSCAR) readme = {} @@ -250,3 +252,139 @@ def EV_find(self): for j in range(len(i_volumes)): print(i_volumes[j], i_energies[j], file=fp_ev) thermoplot(folder,"0 K total energies (eV/atom)", i_volumes, i_energies) + + def get_data(self, phasename, EV, tag): + phdir = os.path.join(phasename,'Yphon') + if not os.path.exists(phdir): + os.mkdir(phdir) + + self.num_Born = self.get_dielecfij(phdir, tag) + vasp_version = list(self.vasp_db.db['tasks'].find({'$and':[ {'metadata.tag': tag}, { 'calcs_reversed': { '$exists': True } }]})) + self.static_vasp_version = None + for i in vasp_version: + v = i['calcs_reversed'][0]['vasp_version'] + #print ("xxxxxxxx", v) + if self.static_vasp_version is None: self.static_vasp_version = v + """ + elif v[0:3]!=self.static_vasp_version[0:3]: + print("\n***********FETAL messing up calculation! please remove:", tag, "\n") + """ + """ + if self.static_vasp_version is not None: + print("\nvasp version for the static calculation is:", self.static_vasp_version, " for ", tag, "\n") + """ + + self.num_phonon = 0 + for i in (self.vasp_db).db['phonon'].find({'metadata.tag': tag}): + try: + self.force_constant_factor = i['force_constant_factor'] + except: + if self.static_vasp_version[0:1] >= '6': + self.force_constant_factor = 0.004091649655126895 + else: + self.force_constant_factor = 1.0 + + if i['volume'] not in EV['volumes']: continue + self.num_phonon += 1 + voldir = self.get_superfij(i, phdir, EV['volumes'], EV['energies']) + + + + def get_superfij(self,i, phdir, volumes, energies): + try: + structure = Structure.from_dict(i['unitcell']) + except: + print("\nit seems phonon for", i['volume'],"is not finished yet and so it is discared\n") + return None + vol = 'V{:010.6f}'.format(float(i['volume'])) + voldir = os.path.join(phdir,vol) + if not os.path.exists(voldir): + os.mkdir(voldir) + elif os.path.exists(os.path.join(voldir,'superfij.out')): return voldir + + poscar = structure.to(fmt="poscar") + unitcell_l = str(poscar).split('\n') + natom = len(structure.sites) + + supercell_matrix = i['supercell_matrix'] + supercell_structure = copy.deepcopy(structure) + supercell_structure.make_supercell(supercell_matrix) + + sa = SpacegroupAnalyzer(supercell_structure) + #reduced_structure = supercell_structure.get_reduced_structure(reduction_algo='niggli') + #print ('niggli reduced structure', reduced_structure) + #poscar = reduced_structure.to(fmt="poscar") + primitive_unitcell_structure = sa.find_primitive() + poscar = primitive_unitcell_structure.to(fmt="poscar") + punitcell_l = str(poscar).split('\n') + + natoms = len(supercell_structure.sites) + ##print(supercell_structure.sites) + poscar = supercell_structure.to(fmt="poscar") + supercell_l = str(poscar).split('\n') + structure.to(filename=os.path.join(voldir,'POSCAR')) + + with open (os.path.join(voldir,'OSZICAR'),'w') as out: + out.write(' 1 F= xx E0= {}\n'.format(energies[(list(volumes)).index(i['volume'])])) + with open (os.path.join(voldir,'superfij.out'),'w') as out: + for line in range (2,5): + out.write('{}\n'.format(unitcell_l[line])) + for line in range (2,5): + out.write('{}\n'.format(supercell_l[line])) + out.write('{} {}\n'.format(natoms, natoms//natom)) + for line in range (7,natoms+8): + out.write('{}\n'.format(supercell_l[line])) + force_constant_matrix = np.array(i['force_constants']) + hessian_matrix = np.empty((natoms*3, natoms*3), dtype=float) + + for ii in range(natoms): + for jj in range(natoms): + for x in range(3): + for y in range(3): + hessian_matrix[ii*3+x, jj*3+y] = -force_constant_matrix[ii,jj,x,y] + + hessian_matrix *= self.force_constant_factor + if self.force_constant_factor!=1.0: + print ("\n force constant matrix has been rescaled by :", self.force_constant_factor) + + for xx in range(natoms*3): + for yy in range(natoms*3-1): + out.write('{} '.format(hessian_matrix[xx,yy])) + out.write('{}\n'.format(hessian_matrix[xx,natoms*3-1])) + return voldir + + def get_dielecfij(self, phdir, tag): + + volumes_b = (self.vasp_db).db['borncharge'].find({'metadata.tag': tag}, {'_id':0, 'volume':1}) + volumes_b = [i['volume'] for i in volumes_b] + num_Born = len(volumes_b) + if num_Born>0: + for i in (self.vasp_db).db['borncharge'].find({'metadata.tag': tag}): + vol = 'V{:010.6f}'.format(float(i['volume'])) + voldir = phdir+'/'+vol + if not os.path.exists(voldir): + os.mkdir(voldir) + + structure = Structure.from_dict(i['structure']) + poscar = structure.to(fmt="poscar") + poscar = str(poscar).split('\n') + natom = len(structure.sites) + with open (voldir+'/dielecfij.out','w') as out: + for line in range (2,5): + out.write('{}\n'.format(poscar[line])) + for line in range (8,natom+8): + out.write('{}\n'.format(poscar[line])) + dielectric_tensor = np.array(i['dielectric_tensor']) + for x in range(3): + for y in range(3): + out.write('{} '.format(dielectric_tensor[x,y])) + out.write('\n') + born_charge = np.array(i['born_charge']) + for ii in range(natom): + out.write(' ion {}\n'.format(ii+1)) + for x in range(3): + out.write(' {} '.format(x+1)) + for y in range(3): + out.write('{} '.format(born_charge[ii,x,y])) + out.write('\n') + return num_Born diff --git a/dfttk/pyphon.py b/dfttk/pyphon.py index 00bc2c76..670865df 100644 --- a/dfttk/pyphon.py +++ b/dfttk/pyphon.py @@ -292,15 +292,15 @@ def vibrational_contributions(T, dos_input=sys.stdin, _dmu=0.0, energyunit='J'): sys.stderr.write ("\nThe phonon quality= {:08.6f}\n\n".format(quality)) - for i in range(T.size): + for i in range(1, T.size): tmp0 = 0.0 tmp1 = 0.0 if N_ph[i]!=0.: tmp0 = C_ph_mu[i]/N_ph[i] tmp1 = C_ph_n[i]/N_ph[i] - sys.stdout.write('{:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g} \ - {:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g}\n'.format(\ - T[i], F_ph[i]*unit, U_ph[i]*unit, S_ph[i]*unit, C_ph_mu[i]*unit, C_ph_n[i], \ + sys.stdout.write('{:10.7g} {:10.2f} {:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g} \ + {:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g} {:10.7g} \n'.format(\ + T[i], debyeT[i], F_ph[i]*unit, U_ph[i]*unit, S_ph[i]*unit, C_ph_mu[i]*unit, C_ph_n[i], \ tmp0, tmp1, Sound_ph[i], Sound_nn[i], \ N_ph[i], NN_ph[i], debyeT[i])) diff --git a/dfttk/pythelec.py b/dfttk/pythelec.py index ae7fc461..0d578f2e 100644 --- a/dfttk/pythelec.py +++ b/dfttk/pythelec.py @@ -893,6 +893,12 @@ def vol_within(vol, volumes, thr=0.001): return False +def vol_within_index(vol, volumes, thr=0.001): + for i,v in enumerate(volumes): + if (abs(vol-v) < thr): return i + return -1 + + def vol_closest(vol, volumes, thr=1.e-6): for i,v in enumerate(volumes): if (abs(vol-v) < thr*vol): return i @@ -931,8 +937,8 @@ def get_static_calculations(vasp_db, tag): _dos_objs.append(vasp_db.get_dos(calc['task_id'])) tvolumes = np.array(sorted(volumes)) - if len(tvolumes)>1: - dvolumes = tvolumes[1:-1] - tvolumes[0:-2] + if len(tvolumes)>=3: + dvolumes = tvolumes[1:] - tvolumes[0:-1] dvolumes = sorted(dvolumes) if abs(dvolumes[-1]-dvolumes[-2]) > 0.01*dvolumes[-1]: #adding useful contraint calculations if not calculated statically @@ -1068,7 +1074,7 @@ def __init__(self, t0, t1, td, xdn, xup, dope, ndosmx, gaussian, natfactor, outf def get_superfij(self,i, phdir): - if vol_within(float(i['volume']), self.Vlat): + if vol_within(float(i['volume']), self.Vlat, thr=1.e-6): print("\nit seems a repeated phonon calculation for", i['volume'],"so it is discared\n") return None try: @@ -1105,10 +1111,13 @@ def get_superfij(self,i, phdir): structure.to(filename=os.path.join(voldir,'POSCAR')) with open (os.path.join(voldir,'metadata.json'),'w') as out: - mm = i['metadata'] - mm['volume'] = i['volume'] - mm['energy'] = self.energies[(list(self.volumes)).index(i['volume'])] - out.write('{}\n'.format(mm)) + idx = vol_within_index(i['volume'],self.volumes, thr=1.e-6) + #print("iiiiiiiiii idx=", idx, i['volume'],self.volumes) + if idx >=0: + mm = i['metadata'] + mm['volume'] = i['volume'] + mm['energy'] = self.energies[idx] + out.write('{}\n'.format(mm)) if len(self.xmlvol)!=0: @@ -1121,7 +1130,8 @@ def get_superfij(self,i, phdir): with open (os.path.join(voldir,'OSZICAR'),'w') as out: - out.write(' 1 F= xx E0= {}\n'.format(self.energies[(list(self.volumes)).index(i['volume'])])) + idx = vol_within_index(i['volume'],self.volumes, thr=1.e-6) + if idx >0: out.write(' 1 F= xx E0= {}\n'.format(self.energies[idx])) with open (os.path.join(voldir,'superfij.out'),'w') as out: for line in range (2,5): out.write('{}\n'.format(unitcell_l[line])) @@ -1433,11 +1443,19 @@ def toYphon(self, _T=None, for_plot=False): for i in (self.vasp_db).db['phonon'].find({'metadata.tag': self.tag}): try: self.force_constant_factor = i['force_constant_factor'] + if self.static_vasp_version[0:1] >= '6' and self.static_vasp_version[0:3] < '6.2': + if self.force_constant_factor == 1.0: + self.force_constant_factor /= 0.004091649655126895 except: - if self.static_vasp_version[0:1] >= '6': + if self.static_vasp_version[0:3] >= '6.2': self.force_constant_factor = 0.004091649655126895 + else: + self.force_constant_factor = 1.0 - if i['volume'] not in self.volumes: continue + #if i['volume'] not in self.volumes: + if not vol_within(i['volume'], self.volumes, thr=1.e-6): + print (i['volume'], "is not within", self.volumes) + continue voldir = self.get_superfij(i, phdir) if voldir is None: continue @@ -1460,7 +1478,7 @@ def toYphon(self, _T=None, for_plot=False): if self.debug: _nqwave = "-nqwave "+ str(1.e4) #md = "Yphon -tranI 2 -DebCut 0.5 " +_nqwave+ " = '6': - print("\n**************FETAL ERROR! force constant not compatible for :", self.tag, "by default phonopy with vasp6\n") + print("\n**************Warning! force constant may not compatible for :", self.tag, "by default phonopy with vasp6\n") try: @@ -2019,12 +2044,12 @@ def find_vibrational(self): #print("xxxx=",self.T_vib) except: try: - self.qha_items = self.vasp_db.db['qha_phonon'].find({'metadata': self.tag}) + self.qha_items = self.vasp_db.db['qha_phonon'].find({'$and':[ {'metadata.tag': self.tag}, {'S_vib': {'$exists': True}} ]}) self.T_vib = self.qha_items[0][self.qhamode]['temperatures'][::self.everyT] except: try: self.qhamode = 'phonon' - self.qha_items = self.vasp_db.db[self.qhamode].find({'metadata.tag': self.tag}) + self.qha_items = self.vasp_db.db[self.qhamode].find({'$and':[ {'metadata.tag': self.tag}, {'S_vib': {'$exists': True}} ]}) self.T_vib = self.qha_items[0]['temperatures'][::self.everyT] self.from_phonon_collection = True except: @@ -2041,10 +2066,11 @@ def get_qha(self): _Flat = [] for i in self.qha_items: - _Vlat.append(i['volume']) _Slat.append(i['S_vib'][::self.everyT]) _Clat.append(i['CV_vib'][::self.everyT]) _Flat.append(i['F_vib'][::self.everyT]) + _Vlat.append(i['volume']) + self.volT = np.zeros(len(self.T_vib)) self.GibT = np.zeros(len(self.T_vib)) _Dlat = np.full((len(_Vlat)), 400.) @@ -2070,9 +2096,10 @@ def get_qha(self): Flat = [] Dlat = [] for i, vol in enumerate(_Vlat): - if vol_within(vol, Vlat): continue + if vol_within(vol, Vlat, thr=1.e-6): continue #if vol in Vlat: continue - if vol not in self.volumes: continue + if not vol_within(vol, self.volumes, thr=1.e-6): continue + #if vol not in self.volumes: continue Vlat.append(vol) Slat.append(_Slat[i]) Clat.append(_Clat[i]) @@ -2337,6 +2364,7 @@ def calc_thermodynamics(self): def datasm(self, fname): data = np.loadtxt(fname, comments="#", dtype=float) + data_orig = copy.deepcopy(data) nT = data.shape[0] nF = data.shape[1] nSmooth = 11 @@ -2346,7 +2374,8 @@ def datasm(self, fname): for i in range(1,nF): #data[:,i]=np.convolve(data[:,i], box, mode='same') data[:,i]=savgol_filter(data[:,i], nSmooth, 3) - with open(fname+'_sm', 'w') as fout: + + with open(fname+'_sm.csv', 'w') as fout: with open(fname, 'r') as fin: lines = fin.readlines() for line in lines: @@ -2355,9 +2384,19 @@ def datasm(self, fname): for i in range(0,nT): for j in range(0,nF): if j==nF-1: fout.write('{}\n'.format(data[i,j])) - else: fout.write('{} '.format(data[i,j])) + else: fout.write('{}, '.format(data[i,j])) + + with open(fname+'.csv', 'w') as fout: + with open(fname, 'r') as fin: + lines = fin.readlines() + for line in lines: + if line.startswith('#'): print(line.strip(),file=fout) + for i in range(0,nT): + for j in range(0,nF): + if j==nF-1: fout.write('{}\n'.format(data_orig[i,j])) + else: fout.write('{}, '.format(data_orig[i,j])) def add_comput_inf(self): if self.vasp_db!=None: @@ -2757,7 +2796,10 @@ def calc_Cij_S(self): def run_console(self): - finished_tags = finished_calc() + try: + finished_tags = finished_calc() + except: + finished_tags = {} if not self.renew: if self.tag is not None: if self.tag in finished_tags: diff --git a/dfttk/scripts/QHAAnalysis_renew.py b/dfttk/scripts/QHAAnalysis_renew.py index 9feef576..89ad7a07 100644 --- a/dfttk/scripts/QHAAnalysis_renew.py +++ b/dfttk/scripts/QHAAnalysis_renew.py @@ -41,7 +41,7 @@ from fireworks import Firework from atomate.vasp.config import VASP_CMD, DB_FILE import os -from dfttk.pythelec import get_static_calculations +from dfttk.pythelec import get_static_calculations, vol_within head,tail = os.path.split(__file__) db_file = os.path.join(head,"db.json") @@ -131,8 +131,10 @@ def run_task(self): vol_s_vib = [] vol_c_vib = [] for calc in phonon_calculations: - if calc['volume'] in vol_vol: continue - if calc['volume'] not in volumes: continue + #if calc['volume'] in vol_vol: continue + #if calc['volume'] not in volumes: continue + if vol_within(calc['volume'], vol_vol, thr=1.e-6): continue + if not vol_within(calc['volume'],volumes, the=1.e-6): continue vol_vol.append(calc['volume']) vol_f_vib.append(calc['F_vib']) vol_s_vib.append(calc['S_vib']) @@ -149,7 +151,8 @@ def run_task(self): _energies = [] _dos_objs = [] for iv,vol in enumerate(volumes): - if vol not in vol_vol: continue + #if vol not in vol_vol: continue + if not vol_within(vol, vol_vol, thr=1.e-6): continue _volumes.append(vol) _energies.append(energies[iv]) _dos_objs.append(dos_objs[iv]) diff --git a/dfttk/scripts/assign_fworker_name.py b/dfttk/scripts/assign_fworker_name.py index 2c9cdf42..64022a99 100644 --- a/dfttk/scripts/assign_fworker_name.py +++ b/dfttk/scripts/assign_fworker_name.py @@ -278,6 +278,8 @@ def get_powerups_options(override_default_vasp_params): def Customizing_Workflows(wfs, powerups_options=None): if powerups_options is None: powerups_options = get_powerups(wfs) + if not powerups_options: return wfs + if isinstance(wfs, list) : _wfs = [] diff --git a/dfttk/scripts/config_dfttk.py b/dfttk/scripts/config_dfttk.py index b6ca21a5..5a22537b 100644 --- a/dfttk/scripts/config_dfttk.py +++ b/dfttk/scripts/config_dfttk.py @@ -75,7 +75,8 @@ def get_machines(nodes=1, ppn=16, user_machines=None): "_fw_template_file": os.path.join(".", "config", "PBS_template_custom.txt"), "vasp_cmd": "mpirun vasp_std"} } - dumpfn(machines, "machines.yaml", default_flow_style=False, indent=4) + #dumpfn(machines, "machines.yaml", default_flow_style=False, indent=4) + dumpfn(machines, "machines.yaml") return machines def replace_file(filename, old_str, new_str): @@ -600,7 +601,8 @@ def config_pymatgen(psp_dir=None, def_fun="PBE", mapi=None, path_to_store_psp="p shutil.copyfile(pmg_config_file, pmg_config_file + ".dfttk.bak") for key in keys_required: params[key] = keys_dict[key] - dumpfn(params, pmg_config_file, default_flow_style=False) + #dumpfn(params, pmg_config_file, default_flow_style=False) + dumpfn(params, pmg_config_file) if "PMG_MAPI_KEY" in keys_required and (not mapi): warnings.warn("'PMG_MAPI_KEY' is empty, some function will not work. " + "Please add your own Materials Project's API. " + @@ -637,9 +639,10 @@ def update_configfile(filename, base_file): ori_file[item] = base_file[item] """ if filename.endswith(".json"): - dumpfn(ori_file, filename, indent=4) + dumpfn(ori_file, filename) elif filename.endswith(".yaml"): - dumpfn(ori_file, filename, default_flow_style=False, indent=4) + #dumpfn(ori_file, filename, default_flow_style=False, indent=4) + dumpfn(ori_file, filename) def config_atomate(path_to_store_config=".", config_folder="config", queue_script="vaspjob.pbs", queue_type="pbs", vasp_cmd_flag="vasp_std", machine="aci", machines=None, @@ -724,10 +727,11 @@ def write_file(self): with open(filename, 'w') as f: if filename.endswith(".json"): from json import dump - dump(self.DATA, f, indent=4) + dump(self.DATA, f) elif filename.endswith(".yaml"): from yaml import dump - dump(self.DATA, f, default_flow_style=False, sort_keys=False, indent=4) + #dump(self.DATA, f, default_flow_style=False, sort_keys=False, indent=4) + dump(self.DATA, f, sort_keys=False) class ConfigDb(ConfigTemplate): """docstring for ConfigDb""" diff --git a/dfttk/scripts/run_dfttk.py b/dfttk/scripts/run_dfttk.py index af504302..c82a48d5 100644 --- a/dfttk/scripts/run_dfttk.py +++ b/dfttk/scripts/run_dfttk.py @@ -3,7 +3,8 @@ import argparse from pymatgen.ext.matproj import MPRester, Structure from pymatgen.io.vasp.inputs import Potcar, Incar -from dfttk.wflows import get_wf_gibbs, get_wf_EV_bjb, get_wf_gibbs_robust, get_wf_borncharge, get_wf_elastic +from dfttk.wflows import get_wf_gibbs, get_wf_EV_bjb, get_wf_singleV, get_wf_crosscom, \ + get_wf_gibbs_robust, get_wf_borncharge, get_wf_elastic from dfttk.utils import recursive_glob from dfttk.structure_builders.parse_anrl_prototype import multi_replace from dfttk.scripts.querydb import get_eq_structure_by_metadata @@ -237,11 +238,13 @@ def get_wf_single(structure, WORKFLOW="get_wf_gibbs", settings={}, db_file=None) #check if fworker_name is assigned powerups = settings.get('powerups', {}) + """ if len(powerups)>0: if 'user_incar_settings' not in override_default_vasp_params: override_default_vasp_params.update({'user_incar_settings':{}}) override_default_vasp_params['user_incar_settings'].update({'powerups':powerups}) modify_incar_params.update({'powerups':powerups}) + """ #dict, dict of class ModifyKpoints with keywords in Workflow name, similar with modify_incar_params modify_kpoints_params = settings.get('modify_kpoints_params', {}) @@ -307,7 +310,12 @@ def get_wf_single(structure, WORKFLOW="get_wf_gibbs", settings={}, db_file=None) """ if WORKFLOW == "eos": wf = get_wf_EV_bjb(structure, deformation_fraction=deformation_fraction, store_volumetric_data=store_volumetric_data, - num_deformations=num_deformations, override_symmetry_tolerances=override_default_vasp_params, metadata=metadata) + num_deformations=num_deformations, settings=settings, override_symmetry_tolerances=override_default_vasp_params, metadata=metadata) + elif WORKFLOW == "singleV": + wf = get_wf_singleV(structure, store_volumetric_data=store_volumetric_data, metadata=metadata, + override_default_vasp_params=override_default_vasp_params, settings=settings) + elif WORKFLOW == "crosscom": + wf = get_wf_crosscom(structure, metadata=metadata, settings=settings) elif WORKFLOW == "robust" or WORKFLOW == "get_wf_gibbs": wf = get_wf_gibbs_robust(structure, num_deformations=num_deformations, deformation_fraction=deformation_fraction, phonon=phonon, phonon_supercell_matrix=phonon_supercell_matrix, t_min=t_min, t_max=t_max, t_step=t_step, @@ -316,14 +324,17 @@ def get_wf_single(structure, WORKFLOW="get_wf_gibbs", settings={}, db_file=None) override_default_vasp_params=override_default_vasp_params, modify_incar_params=modify_incar_params, modify_kpoints_params=modify_kpoints_params, verbose=verbose, phonon_supercell_matrix_min=phonon_supercell_matrix_min, phonon_supercell_matrix_max=phonon_supercell_matrix_max, optimize_sc=optimize_sc, level=level, - force_phonon=force_phonon, stable_tor=stable_tor, store_volumetric_data=store_volumetric_data) + force_phonon=force_phonon, stable_tor=stable_tor, store_volumetric_data=store_volumetric_data, + settings=settings) elif WORKFLOW == "born": wf = get_wf_borncharge(structure=structure, metadata=metadata, db_file=db_file, isif=2, name="born charge", vasp_cmd=">>vasp_cmd<<", override_default_vasp_params=override_default_vasp_params, - modify_incar=modify_incar_params) + modify_incar=modify_incar_params, settings=settings) elif WORKFLOW == 'elastic': wf = get_wf_elastic(structure=structure, metadata=metadata, vasp_cmd=">>vasp_cmd<<", db_file=">>db_file<<", name="elastic", - override_default_vasp_params=override_default_vasp_params, strain_states=strain_states, + override_default_vasp_params=override_default_vasp_params, + settings=settings, + strain_states=strain_states, stencils=stencils, analysis=analysis, sym_reduce=sym_reduce, order=order, conventional=conventional) else: raise ValueError("Currently, only the gibbs energy workflow is supported.") @@ -448,7 +459,7 @@ def run(args): user_settings.update({"phonon_supercell_matrix": "atoms"}) wf = get_wf_single(structure, WORKFLOW=WORKFLOW, settings=user_settings) - wf = Customizing_Workflows(wf) + wf = Customizing_Workflows(wf,powerups_options=user_settings.get('powerups', None)) metadatas[STR_FILE] = wf.as_dict()["metadata"] wfs.append(wf) diff --git a/dfttk/utils.py b/dfttk/utils.py index 9910b1bc..0afa8cb3 100644 --- a/dfttk/utils.py +++ b/dfttk/utils.py @@ -519,9 +519,9 @@ def mark_adopted_TF(tag, db_file, adpoted, phonon=False): t_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"] vasp_db = VaspCalcDb.from_db_file(t_file, admin=True) if vasp_db: - vasp_db.collection.update({'metadata.tag': tag}, {'$set': {'adopted': adpoted}}, upsert = True, multi = True) + vasp_db.collection.update_many({'metadata.tag': tag}, {'$set': {'adopted': adpoted}}, upsert = True) if phonon: - vasp_db.db['phonon'].update({'metadata.tag': tag}, {'$set': {'adopted': adpoted}}, upsert = True, multi = True) + vasp_db.db['phonon'].update_many({'metadata.tag': tag}, {'$set': {'adopted': adpoted}}, upsert = True) def mark_adopted(tag, db_file, volumes, phonon=False): @@ -533,11 +533,11 @@ def mark_adopted(tag, db_file, volumes, phonon=False): t_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"] vasp_db = VaspCalcDb.from_db_file(t_file, admin=True) for volume in volumes: - vasp_db.collection.update({'$and':[ {'metadata.tag': tag}, {'output.structure.lattice.volume': volume} ]}, - {'$set': {'adopted': True}}, upsert = True, multi = False) # Mark only one + vasp_db.collection.update_one({'$and':[ {'metadata.tag': tag}, {'output.structure.lattice.volume': volume} ]}, + {'$set': {'adopted': True}}, upsert = True) # Mark only one if phonon: - vasp_db.db['phonon'].update({'$and':[ {'metadata.tag': tag}, {'volume': volume} ]}, - {'$set': {'adopted': True}}, upsert = True, multi = False) + vasp_db.db['phonon'].update_one({'$and':[ {'metadata.tag': tag}, {'volume': volume} ]}, + {'$set': {'adopted': True}}, upsert = True) def consistent_check_db(db_file, tag): diff --git a/dfttk/wflows.py b/dfttk/wflows.py index a7089e65..a237bafd 100644 --- a/dfttk/wflows.py +++ b/dfttk/wflows.py @@ -8,6 +8,7 @@ os.environ["HOME"] = str(Path.home()) import numpy as np +import copy from uuid import uuid4 from copy import deepcopy from fireworks import Workflow, Firework @@ -15,7 +16,7 @@ from dfttk.fworks import OptimizeFW, StaticFW, PhononFW, RobustOptimizeFW, BornChargeFW from dfttk.ftasks import CheckRelaxScheme from dfttk.input_sets import PreStaticSet, RelaxSet, ForceConstantsSet, ElasticSet -from dfttk.EVcheck_QHA import EVcheck_QHA, PreEV_check +from dfttk.EVcheck_QHA import EVcheck_QHA, Crosscom_EVcheck_QHA, PreEV_check from dfttk.utils import check_relax_path, add_modify_incar_by_FWname, add_modify_kpoints_by_FWname, supercell_scaling_by_atom_lat_vol from dfttk.scripts.querydb import is_property_exist_in_db, get_eq_structure_by_metadata #from atomate.vasp.workflows.base.elastic import get_wf_elastic_constant @@ -24,6 +25,29 @@ import sys +from pymatgen.core import Structure +from pymatgen.symmetry.analyzer import SpacegroupAnalyzer + + +def scale_lattice_vector(structure, factor: float, axisa=False, axisb=False, axisc=True,): + """ + Performs a scaling of the lattice vectors so that angles are preserved + axisx(x=a,b,c) = True: + x lattice scale. + Args: + factor (float): scaling factor. + """ + struct = copy.deepcopy(structure).as_dict() + matrix = np.array(struct['lattice']['matrix']) + if axisa: + matrix[0] *= factor + if axisb: + matrix[1] *= factor + if axisc: + matrix[2] *= factor + struct['lattice']['matrix']=list(matrix) + return Structure.from_dict(struct) + def _get_deformations(def_frac, num_def): if isinstance(def_frac, (list, tuple)): return np.linspace(1 + def_frac[0], 1 + def_frac[1], num_def) @@ -32,6 +56,7 @@ def _get_deformations(def_frac, num_def): def get_wf_EV_bjb(structure, deformation_fraction=(-0.08, 0.12), store_volumetric_data=False, + settings={}, num_deformations=11, override_symmetry_tolerances=None, metadata=None): """ Perform an E-V curve, robustly relaxating all structures on the curve. @@ -58,13 +83,14 @@ def get_wf_EV_bjb(structure, deformation_fraction=(-0.08, 0.12), store_volumetri """ deformations = _get_deformations(deformation_fraction, num_deformations)*structure.volume + a_kwargs = {"settings":settings} fws = [] for defo in deformations: struct = deepcopy(structure) struct.scale_lattice(defo) full_relax_fw = RobustOptimizeFW(struct, isif=5, vasp_cmd=VASP_CMD, db_file=DB_FILE, - store_volumetric_data=store_volumetric_data) + a_kwargs = a_kwargs, store_volumetric_data=store_volumetric_data) fws.append(full_relax_fw) if metadata is not None and all(x in metadata for x in ('phase_name', 'sublattice_configuration')): # create a nicer name for the workflow @@ -76,6 +102,229 @@ def get_wf_EV_bjb(structure, deformation_fraction=(-0.08, 0.12), store_volumetri return wf +def get_constrain(deformation_scheme, new_deformation_fraction): + if deformation_scheme=='volume': + ppp = 1./3. + axisa=True + axisb=True + axisc=True + elif deformation_scheme=='a': + ppp = 1. + axisa=True + axisb=False + axisc=False + elif deformation_scheme=='b': + ppp = 1. + axisa=False + axisb=True + axisc=False + elif deformation_scheme=='c': + ppp = 1. + axisa=False + axisb=False + axisc=True + elif deformation_scheme=='bc' or deformation_scheme=='cb': + ppp = 0.5 + axisa=False + axisb=True + axisc=True + elif deformation_scheme=='ca' or deformation_scheme=='ac': + ppp = 0.5 + axisa=True + axisb=False + axisc=True + elif deformation_scheme=='ab' or deformation_scheme=='ba': + ppp = 0.5 + axisa=True + axisb=True + axisc=False + return axisa, axisb, axisc, pow(np.array(new_deformation_fraction),ppp) + + +def get_wf_singleV(structure, store_volumetric_data=False, metadata=None, override_default_vasp_params=None, settings={}): + """ + Perform single volume relaxation calculation. + + Parameters + ---------- + structure : pymatgen.Structure + """ + metadata = metadata or {} + tag = metadata.get('tag', '{}'.format(str(uuid4()))) + metadata.update({'tag': tag}) + common_kwargs = {"metadata": metadata, "tag":tag, + 'override_default_vasp_params': override_default_vasp_params} + + num_deformations = settings.get('num_deformations', 1) + #list/tuple(min, max) or float(-max, max), the maximum amplitude of deformation, e.g. (-0.15, 0.15) means (0.95, 1.1) in volume + deformation_fraction = settings.get('deformation_fraction', (-0.0, +0.0)) + deformation_scheme = settings.get('deformation_scheme', 'volume') + new_deformation_fraction = _get_deformations(deformation_fraction, num_deformations) + + isif = settings.get('run_isif', None) + if not isif: + isif=3 + if num_deformations>1: + if deformation_scheme=='volume': isif = 4 + else: isif = 2 + + axisa, axisb, axisc, new_deformations = get_constrain(deformation_scheme, new_deformation_fraction) + a_kwargs = {"settings":settings} + fws = [] + for defo in new_deformations: + struct = scale_lattice_vector(structure, defo, axisa=axisa, axisb=axisb, axisc=axisc) + full_relax_fw = OptimizeFW(struct, isif=isif, vasp_cmd=VASP_CMD, db_file=DB_FILE, + name='Relax_with_ISIF='+str(isif)+'_and_defo={:5.3f}'.format(defo), + a_kwargs = a_kwargs, + store_volumetric_data=store_volumetric_data, **common_kwargs) + fws.append(full_relax_fw) + static_fw = StaticFW(struct, isif=2, vasp_cmd=VASP_CMD, db_file=DB_FILE, + name='Staitc', a_kwargs = a_kwargs, + vasp_input_set=None, prev_calc_loc=True, parents=full_relax_fw, + store_volumetric_data=store_volumetric_data, **common_kwargs) + fws.append(static_fw) + wfname = "{}:{}".format(structure.composition.reduced_formula, 'singleV') + wf = Workflow(fws, name=wfname, metadata=metadata) + return wf + + +def get_wf_crosscom(structure, metadata=None, settings={}, run_num = 0, + new_deformation_fraction=None): + """ + Perform cross computer QHA calculation without computer dependent. + + Parameters + ---------- + structure : pymatgen.Structure + """ + ################ PARAMETERS FOR WF ############################# + #str, the absolute path of db.json file, e.g. /storage/home/mjl6505/atomate/config/db.json + # If None, it will use the configuration in fireworks + db_file = settings.get('db_file', DB_FILE) + #str, the vasp command, if None then find in the FWorker configuration + vasp_cmd = settings.get('vasp_cmd', VASP_CMD) + #dict, metadata to be included, this parameter is useful for filter the data, e.g. metadata={"phase": "BCC_A2", "tag": "AFM"} + metadata = metadata or {} + tag = metadata.get('tag', '{}'.format(str(uuid4()))) + metadata.update({'tag': tag}) + + #list/tuple(min, max) or float(-max, max), the maximum amplitude of deformation, e.g. (-0.15, 0.15) means (0.95, 1.1) in volume + deformation_fraction = settings.get('deformation_fraction', (-0.15, 0.20)) + #int, the number of initial deformations, e.g. 7 + num_deformations = settings.get('num_deformations', 8) + if num_deformations==1: + deformation_fraction[1] = deformation_fraction[0] + #bool, run phonon(True) or not(False) + phonon = settings.get('phonon', False) + #list(3x3), the supercell matrix for phonon, e.g. [[2.0, 0, 0], [0, 2.0, 0], [0, 0, 2.0]] + phonon_supercell_matrix = settings.get('phonon_supercell_matrix', None) + phonon_supercell_matrix_min = settings.get('phonon_supercell_matrix_min', None) + phonon_supercell_matrix_max = settings.get('phonon_supercell_matrix_max', None) + optimize_sc = settings.get('optimize_sc', False) + #run phonon always, no matter ISIF=4 passed or not + force_phonon = settings.get('force_phonon', False) + #The tolerance for phonon stable + stable_tor = settings.get('stable_tor', 0.01) + #float, the mimimum of temperature in QHA process, e.g. 5 + t_min = settings.get('t_min', 5) + #float, the maximum of temperature in QHA process, e.g. 2000 + t_max = settings.get('t_max', 2000) + #float, the step of temperature in QHA process, e.g. 5 + t_step = settings.get('t_step', 5) + #float, acceptable value for average RMS, recommend >= 0.005 + eos_tolerance = settings.get('eos_tolerance', 0.01) + + #Global settings for all vasp job, e.g. + #override_default_vasp_params = {'user_incar_settings': {}, 'user_kpoints_settings': {}, 'user_potcar_functional': str} + #If some value in 'user_incar_settings' is set to None, it will use vasp's default value + override_default_vasp_params = settings.get('override_default_vasp_params', {}) + + #dict, dict of class ModifyIncar with keywords in Workflow name. e.g. + modify_incar_params = settings.get('modify_incar_params', {}) + + """ + #check if fworker_name is assigned + powerups = settings.get('powerups', {}) + if len(powerups)>0: + if 'user_incar_settings' not in override_default_vasp_params: + override_default_vasp_params.update({'user_incar_settings':{}}) + override_default_vasp_params['user_incar_settings'].update({'powerups':powerups}) + modify_incar_params.update({'powerups':powerups}) + """ + + #dict, dict of class ModifyKpoints with keywords in Workflow name, similar with modify_incar_params + modify_kpoints_params = settings.get('modify_kpoints_params', {}) + #bool, print(True) or not(False) some informations, used for debug + verbose = settings.get('verbose', False) + #Save the volume data or not ("chgcar", "aeccar0", "aeccar2", "elfcar", "locpot") + store_volumetric_data = settings.get('store_volumetric_data', False) + + + if phonon: + if isinstance(phonon_supercell_matrix, str): + if phonon_supercell_matrix=='Yphon': + phonon_supercell_matrix = supercell_scaling_by_Yphon(structure, + supercellsize=phonon_supercell_matrix_max) + else: + phonon_supercell_matrix = supercell_scaling_by_atom_lat_vol(structure, min_obj=phonon_supercell_matrix_min, + max_obj=phonon_supercell_matrix_max, scale_object=phonon_supercell_matrix, + target_shape='sc', lower_search_limit=-2, upper_search_limit=2, + verbose=verbose, sc_tolerance=1e-5, optimize_sc=optimize_sc) + + deformations = _get_deformations(deformation_fraction, num_deformations) + if num_deformations > 1: vol_spacing = deformations[1]-deformations[0] + else: vol_spacing=0.05 + + if new_deformation_fraction is None: + new_deformation_fraction = copy.deepcopy(deformations) + + deformation_scheme = settings.get('deformation_scheme', 'volume') + single_volume = settings.get('single_volume', False) + + + isif = settings.get('run_isif', None) + if not isif: + isif=3 + if num_deformations>1: + if deformation_scheme=='volume': isif = 4 + else: isif = 2 + + t_kwargs = {'t_min': t_min, 't_max': t_max, 't_step': t_step} + common_kwargs = {'vasp_cmd': vasp_cmd, 'db_file': db_file, "metadata": metadata, "tag": tag, + 'override_default_vasp_params': override_default_vasp_params} + vasp_kwargs = {'modify_incar_params': modify_incar_params, 'modify_kpoints_params': modify_kpoints_params} + eos_kwargs = {'deformations': deformations, 'vol_spacing': vol_spacing, 'eos_tolerance': eos_tolerance, 'threshold': 14} + a_kwargs = {"structure":structure, "settings":settings, "eos_kwargs":eos_kwargs, + "static": True, "phonon":phonon, "phonon_supercell_matrix":phonon_supercell_matrix} + + + axisa, axisb, axisc, new_deformations = get_constrain(deformation_scheme, new_deformation_fraction) + + fws = [] + parents_com = [] + for defo in new_deformations: + struct = scale_lattice_vector(structure, defo, axisa=axisa, axisb=axisb, axisc=axisc) + full_relax_fw = OptimizeFW(struct, isif=isif, + name='Relax_with_ISIF='+str(isif)+'_and_defo={:5.3f}'.format(defo), + store_volumetric_data=store_volumetric_data, + t_kwargs=t_kwargs, a_kwargs=a_kwargs, **common_kwargs, defo=defo) + fws.append(full_relax_fw) + parents_com.append(full_relax_fw) + + if not single_volume: + check_qha_fw = Firework(Crosscom_EVcheck_QHA(verbose=verbose, stable_tor=stable_tor, + run_num = run_num, + store_volumetric_data=store_volumetric_data, a_kwargs=a_kwargs, + **eos_kwargs, **vasp_kwargs, **t_kwargs, **common_kwargs), + parents=parents_com, name='{}-Crosscom_EVcheck_QHA'.format(structure.composition.reduced_formula)) + fws.append(check_qha_fw) + + wfname = "{}:{}".format(structure.composition.reduced_formula, 'EV_QHA_crosscom') + wf = Workflow(fws, name=wfname, metadata=metadata) + add_modify_incar_by_FWname(wf, modify_incar_params = modify_incar_params) + add_modify_kpoints_by_FWname(wf, modify_kpoints_params = modify_kpoints_params) + return wf + def vol_in_volumes(vol, volumes): for v in volumes: @@ -86,7 +335,8 @@ def vol_in_volumes(vol, volumes): def get_wf_elastic(structure=None, metadata=None, tag=None, vasp_cmd=None, db_file=None, name="elastic", vasp_input_set=None, override_default_vasp_params=None, strain_states=None, stencils=None, - analysis=True, sym_reduce=False, order=2, conventional=False, **kwargs): + analysis=True, sym_reduce=False, order=2, conventional=False, + settings={}, **kwargs): ''' Parameter --------- @@ -118,6 +368,7 @@ def get_wf_elastic(structure=None, metadata=None, tag=None, vasp_cmd=None, db_fi db_file = db_file or DB_FILE override_default_vasp_params = override_default_vasp_params or {} + a_kwargs={'settings':settings} metadata = metadata or {} tag = metadata.get('tag', '{}'.format(str(uuid4()))) @@ -176,7 +427,7 @@ def get_wf_elastic(structure=None, metadata=None, tag=None, vasp_cmd=None, db_fi override_default_vasp_params['user_incar_settings'].update({'SIGMA': 0.05}) print(vasp_input_set.CONFIG['INCAR']) """ - vasp_input_set = vasp_input_set or ElasticSet(structure=_struct, **override_default_vasp_params) + vasp_input_set = vasp_input_set or ElasticSet(structure=_struct, a_kwargs=a_kwargs, **override_default_vasp_params) wf_elastic = get_wf_elastic_constant(struct, metadata, strain_states=strain_states, stencils=stencils, db_file=db_file, conventional=conventional, order=order, vasp_input_set=vasp_input_set, @@ -197,7 +448,8 @@ def get_wf_elastic(structure=None, metadata=None, tag=None, vasp_cmd=None, db_fi def get_wf_borncharge(structure=None, metadata=None, db_file=None, isif=2, name="born charge", vasp_input_set=None,vasp_cmd=None, override_default_vasp_params=None, - tag=None, modify_incar=None, **kwargs): + tag=None, modify_incar=None, + settings={}, **kwargs): ''' The born charge work flow @@ -258,7 +510,7 @@ def get_wf_borncharge(structure=None, metadata=None, db_file=None, isif=2, name= struct_energy_bandgap[0][0].composition.reduced_formula, " with tag:", tag, "\n") else: bandgap=False - + a_kwargs={'settings':settings} fws = [] if bandgap: if override_default_vasp_params is None: override_default_vasp_params = {} @@ -277,7 +529,7 @@ def get_wf_borncharge(structure=None, metadata=None, db_file=None, isif=2, name= fw = BornChargeFW(structure, isif=isif, name="{}-{:.3f}".format(name, structure.volume), vasp_cmd=vasp_cmd, metadata=metadata, modify_incar=modify_incar, override_default_vasp_params=override_default_vasp_params, tag=tag, - prev_calc_loc=False, db_file=db_file, **kwargs) + prev_calc_loc=False, db_file=db_file, a_kwargs=a_kwargs, **kwargs) fws.append(fw) else: if structure is None: @@ -286,7 +538,7 @@ def get_wf_borncharge(structure=None, metadata=None, db_file=None, isif=2, name= fw = BornChargeFW(structure, isif=isif, name="{}-{:.3f}".format(name, structure.volume), vasp_cmd=vasp_cmd, metadata=metadata, modify_incar=modify_incar, override_default_vasp_params=override_default_vasp_params, tag=tag, - prev_calc_loc=False, db_file=db_file, **kwargs) + prev_calc_loc=False, db_file=db_file, a_kwargs=a_kwargs, **kwargs) fws.append(fw) if not fws: raise ValueError('The system is metal or no static result under given metadata in the mongodb') @@ -315,6 +567,7 @@ def get_wf_gibbs_robust(structure, num_deformations=7, deformation_fraction=(-0. metadata=None, name='EV_QHA', override_default_vasp_params=None, modify_incar_params={}, modify_kpoints_params={}, verbose=False, level=1, phonon_supercell_matrix_min=60, phonon_supercell_matrix_max=120, optimize_sc=False, force_phonon=False, stable_tor=0.01, + settings={}, store_volumetric_data=False): """ E - V @@ -393,11 +646,12 @@ def get_wf_gibbs_robust(structure, num_deformations=7, deformation_fraction=(-0. vasp_kwargs = {'modify_incar_params': modify_incar_params, 'modify_kpoints_params': modify_kpoints_params} t_kwargs = {'t_min': t_min, 't_max': t_max, 't_step': t_step} eos_kwargs = {'deformations': deformations, 'vol_spacing': vol_spacing, 'eos_tolerance': eos_tolerance, 'threshold': 14} + a_kwargs = {'settings':settings} fws = [] robust_opt_fw = RobustOptimizeFW(structure, prev_calc_loc=False, name='Full relax', store_volumetric_data=store_volumetric_data, - **robust_opt_kwargs, **vasp_kwargs, **common_kwargs) + a_kwargs=a_kwargs, **robust_opt_kwargs, **vasp_kwargs, **common_kwargs) fws.append(robust_opt_fw) check_qha_parent = [] @@ -416,7 +670,7 @@ def get_wf_gibbs_robust(structure, num_deformations=7, deformation_fraction=(-0. raise ValueError('Current phonon_supercell_matrix({}) is not correct.'.format(phonon_supercell_matrix)) phonon_wf = PhononFW(structure, phonon_supercell_matrix, parents=robust_opt_fw, prev_calc_loc='static', name='structure_{:.3f}-phonon'.format(structure.volume), stable_tor=stable_tor, - **t_kwargs, **common_kwargs) + a_kwargs=a_kwargs, **t_kwargs, **common_kwargs) fws.append(phonon_wf) check_qha_parent.append(phonon_wf) @@ -427,7 +681,7 @@ def get_wf_gibbs_robust(structure, num_deformations=7, deformation_fraction=(-0. check_qha_fw = Firework(EVcheck_QHA(site_properties=site_properties,verbose=verbose, stable_tor=stable_tor, phonon=phonon, phonon_supercell_matrix=phonon_supercell_matrix, force_phonon=force_phonon, override_symmetry_tolerances=override_symmetry_tolerances, store_volumetric_data=store_volumetric_data, - **eos_kwargs, **vasp_kwargs, **t_kwargs, **common_kwargs), + a_kwargs=a_kwargs, **eos_kwargs, **vasp_kwargs, **t_kwargs, **common_kwargs), parents=check_qha_parent, name='{}-EVcheck_QHA'.format(structure.composition.reduced_formula)) fws.append(check_qha_fw) @@ -444,6 +698,7 @@ def get_wf_gibbs(structure, num_deformations=7, deformation_fraction=(-0.1, 0.1) t_min=5, t_max=2000, t_step=5, tolerance = 0.01, volume_spacing_min = 0.03, vasp_cmd=None, db_file=None, metadata=None, name='EV_QHA', symmetry_tolerance = 0.05, passinitrun=False, relax_path='', modify_incar_params={}, + settings={}, modify_kpoints_params={}, verbose=False, store_volumetric_data=False): """ E - V @@ -564,6 +819,7 @@ def get_wf_gibbs_SQS(structure, num_deformations=7, deformation_fraction=(-0.1, t_min=5, t_max=2000, t_step=5, tolerance = 0.01, volume_spacing_min = 0.03, vasp_cmd=None, db_file=None, metadata=None, name='EV_QHA', symmetry_tolerance = 0.05, passinitrun=False, relax_path='', modify_incar_params={}, + settings={}, modify_kpoints_params={}, verbose=False, store_volumetric_data=False): """ E - V @@ -644,6 +900,7 @@ def get_wf_gibbs_SQS(structure, num_deformations=7, deformation_fraction=(-0.1, vis_PreStatic = PreStaticSet(structure1) prestatic = StaticFW(structure=structure1, scale_lattice=deformation, name='VR_%.3f-PreStatic' %deformation, prev_calc_loc=False, vasp_input_set=vis_PreStatic, vasp_cmd=vasp_cmd, db_file=db_file, + a_kwargs={'settings':settings}, metadata=metadata, Prestatic=True, store_volumetric_data=store_volumetric_data) fws.append(prestatic) @@ -653,6 +910,7 @@ def get_wf_gibbs_SQS(structure, num_deformations=7, deformation_fraction=(-0.1, tolerance = tolerance, threshold = 14, vol_spacing = vol_spacing, vasp_cmd = vasp_cmd, run_isif2=run_isif2, metadata = metadata, t_min=t_min, t_max=t_max, t_step=t_step, phonon = phonon, symmetry_tolerance = symmetry_tolerance, phonon_supercell_matrix = phonon_supercell_matrix, verbose = verbose, pass_isif4=pass_isif4, + a_kwargs={'settings':settings}, modify_incar_params=modify_incar_params, modify_kpoints_params = modify_kpoints_params), parents=prestatic_calcs, name='%s-PreEV_check' %structure.composition.reduced_formula) fws.append(check_result) diff --git a/docs/source/Installation.rst b/docs/source/Installation.rst index 20012bd6..13a44c03 100644 --- a/docs/source/Installation.rst +++ b/docs/source/Installation.rst @@ -7,7 +7,7 @@ It is recommended to install DFTTK under the `anaconda `_. + +:: + + @article{Wang2021DFTTK, + archivePrefix = {arXiv}, + arxivId = {2107.03966}, + author = {Yi Wang, Mingqing Liao, Brandon J. Bocklund, Peng Gao, Shun-Li Shang, Hojong Kim, Allison M. Beese, Long-Qing Chen, Zi-Kui Liu}, + doi = {10.1016/j.calphad.2021.102355}, + eprint = {2107.03966}, + issn = {0364-5916}, + journal = {CALPHAD}, + month = {december}, + pages = {102355}, + title = {{DFTTK: Density functional theory toolkit for high-throughput lattice dynamics calculations}}, + year = {2019} + } + High-throughput calculations ---------------------------- @@ -140,10 +164,19 @@ The solution is to make the best use of `ISIF `_ +.. [Bocklund2019] Bocklund *et al.*, MRS Communications 9(2) (2019) 1–10. doi:`10.1557/mrc.2019.59 `_ +.. [Dinsdale1991] Dinsdale, Calphad 15(4) (1991) 317-425, doi:`10.1016/0364-5916(91)90030-N `_ +.. [Otis2016] Otis, Ph.D. Dissertation, The Pennsylvania State University (2016). https://etda.libraries.psu.edu/catalog/s1784k73d +.. [Otis2017] Otis *et al.*, JOM 69 (2017) doi:`10.1007/s11837-017-2318-6 `_ +.. [Shang2010] Shang, Wang, and Liu, Magnes. Technol. 2010 617-622 (2010). diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst index fbd8869a..ef2e5edc 100644 --- a/docs/source/troubleshooting.rst +++ b/docs/source/troubleshooting.rst @@ -29,23 +29,21 @@ or equivalently in the ``.cshrc`` file setenv FW_CONFIG_FILE /storage/work/y/yuw3/dfttk/config/FW_config.yaml 5. git push issue for contributors, see https://docs.github.com/en/github/authenticating-to-github/adding-a-new-ssh-key-to-your-github-account -6. for batch run of the postprocessing modules, make sure compatibilities of non-ascii character by: + +6. For batch run of the postprocessing modules, make sure compatibilities of non-ascii character by: .. code-block:: bash export LC_ALL='en_US.utf8' #for bsh; setenv LC_ALL en_US.utf8 #for csh -7. For phonon calculations, due to certain reasons (such as temperature range too high), one may not see results in the ``qha_phonon`` or ``qha`` MongoDB collections. In this case, the subcommand ``dfttk thfind`` will try to find results from the ``phonon`` collection and process the data by calling ``Yphon`` +7. For phonon calculations, due to certain reasons (such as temperature range too high), one may not see results in the ``qha_phonon`` or ``qha`` MongoDB collections. In this case, the subcommand ``dfttk thfind`` will try to find results from the ``phonon`` collection and process the data by calling ``Yphon``: 8. When you are interesting in revising the code, if have job running in the system before your changes, the codes in the batch system might not be updated and the results might be not as you assumed. It takes me two days to figure out this problem. The solution is to kill all the dfttk running job and resubmit them. -Following are the steps of adding API key number on DFTTK. -9. How to solve the install warning of 'PMG_MAPI_KEY' is empty. +9. How to solve the install warning of 'PMG_MAPI_KEY' is empty. Following are the steps of adding API key number on DFTTK. - 1. Go to the materials project website, - https://materialsproject.org/, under the API section, you will - easily find you API Keys number. + 1. Go to the materials project website, https://materialsproject.org/, under the API section, you will easily find you API Keys number. 2. Go to the .pmgrc.yaml file @@ -59,18 +57,76 @@ Following are the steps of adding API key number on DFTTK. PMG_MAPI_KEY: ######(your API key number) -10. How to find the reason for FIZZLED job. +10. How to find the reason for FIZZLED job. - .. code-block:: bash - lpad get_fws -i fw_id -d more +.. code-block:: bash + + lpad get_fws -i fw_id -d more -11. VasprunXMLValidator found from the command "lpad get_fws -i fw_id -d more" +11. VasprunXMLValidator found from the command "lpad get_fws -i fw_id -d more" If you get an error from the VasprunXMLValidator, that means that the vasprun.xml failed to be parsed and/or validated. Usually that means the VASP job did not run or failed for a reason that was not caught and handled by Custodian. Check the output files in the launch directory and see if there are any errors in the VASP output or stdout/stderr. +12. During the installation or running dfttk, it could report this or that packakge missing/VersionConflict errors. You may have many of them, esspecially when you have good years' experience using python and many of your packages are obselete. DO NOT blame me, ``it is due to pymatgen`` + + You can try to sovle them by + + .. code-block:: bash + + pip install -U #where should be the name of missed package + + Sometimes, one may meet issue with ruamel_yaml due to ``conda`` bug on namespace of ruamel_yaml vs ruamel.yaml. One may Manually delete the files from site-packages. What I learnt was to delete ruamel.yaml ``rm -rf your-path-to-anaconda3/lib/python-your-version/site-packages/ruamel*``. Then install ruamel.yaml by + + .. code-block:: bash + + pip install ruamel.yaml + +13. During the installation in Windows system, the latest fireworks package may give you some troubles + + See troubleshooting 6. If the problem persists, do the following: + + I solved the problem by installing the development version + + .. code-block:: bash + + git clone https://github.com/materialsproject/fireworks + cd fireworks + + The trouble is due to the line containing "```" in README.md. You can delete/replace them followed by installing fireworks it as + + .. code-block:: bash + + pip install -e . + + 14. Sometimes, some VASP jobs may crash (showing as "F" or "FIZZLED" when you use the command ``lpad get_wflows`` to check your job status) due to various reasons (Ram leakage, job time limitations etc) or even no reasons. + + These problems can mostly be resoleed by rerunning the wflows using: + + .. code-block:: bash + + lapd detect_lostruns --rerun + lapd rerun_fws -s FIZZLED #you may need ``qlaunch`` your VASP batch jobs if no jobs in queue + +atomate issue (This issue has been resolved by atomate 1.0.3) +============================================================= + + if you use old version of atomate such as 0.9.7, atomate may not be compatible with pymongo >=4.0, you can sovle it by:: + + pip uninstall pymongo + + pip install pymongo==3.11.3 + + pip uninstall maggma + + pip install maggma==0.26.0 + +fireworks issue +=============== + + fireworks>=1.9.5 requires UTF-8 for for Windows, you should turn it on Windows setting (system locale) pymatgen 2021 issue =================== diff --git a/pytest.ini b/pytest.ini index e49973f3..3ef4c603 100644 --- a/pytest.ini +++ b/pytest.ini @@ -17,5 +17,6 @@ markers = check_symmetry_magmom: check_points_1: check_points_2: + check_points_3: EVcheck_QHA_2: get_static_calculations diff --git a/setup.py b/setup.py index 6df8657e..31532708 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ def readme(): package_data = {'dfttk.structure_builders' : ["prototype_anrl.all", "aflow_prototype_db.json"]}, description='Density functional theory workflows for finite temperature thermodynamics based on atomate workflows. Created by the Phases Research Lab', long_description=readme(), - install_requires=['atomate>=0.9.4', 'tinydb', 'phonopy', 'ase', 'pymatgen', 'numpy>=1.20.1'], + install_requires=['atomate==1.0.3', 'maggma==0.49.9', 'pymongo==4.3.3','phonopy==2.9.1', 'fireworks==2.0.3', 'tinydb', 'ase', 'pymatgen==2022.11.1', 'numpy>=1.20.1'], extras_require={ 'dev': [ 'sphinx', diff --git a/tests/test_QHAAnalysis.py b/tests/test_QHAAnalysis.py index 2ca856bc..e6dd60b8 100644 --- a/tests/test_QHAAnalysis.py +++ b/tests/test_QHAAnalysis.py @@ -35,6 +35,7 @@ from dfttk import __version__ as dfttk_ver from pymatgen.core import __version__ as pymatgen_ver +from dfttk.wflows import _get_deformations from dfttk.EVcheck_QHA import * from dfttk.pythelec import get_static_calculations from pymatgen.core import Structure @@ -58,7 +59,7 @@ @pytest.mark.QHAAnalysis def test_QHAAnalysis(): - tags = ['5e8b5a18-b2b9-4dcd-81a7-0bd75ee361ec'] + tags = ['700dd9c9-afb0-4a09-a39d-ad77622b3f08'] print(db_file) for tag in tags: vasp_db = VaspCalcDb.from_db_file(db_file, admin=False) @@ -98,7 +99,7 @@ def test_check_points_2(): tag = '19c9e217-4159-4bfe-9c3a-940fb40e023e' tag = 'd054780c-f051-4450-a611-d374d41d1884' tag = 'ed85a69b-4054-41d4-a724-7373934cdcc6' - tag = '0267947f-b5a0-4993-8b5e-58f9dfb4e362' + tag = '8e7b216d-c6b6-4da4-905e-e7afd44195aa' vasp_db = VaspCalcDb.from_db_file(db_file, admin=False) EV, POSCAR, INCAR = get_rec_from_metatag(vasp_db, tag, test=True) structure = Structure.from_str(POSCAR, fmt='POSCAR') @@ -106,6 +107,111 @@ def test_check_points_2(): proc.run_task({}) #assert False +POSCAR_STR = """STa1 +4.10 +0 .5 .5 +.5 0 .5 +.5 .5 0 +Al +1 +direct +0.000000 0.000000 0.000000 Al""" + + +@pytest.mark.check_points_3 +def test_check_points_3(): + settings = {'deformation_fraction': [-0.05, 0.05], 'num_deformations': 3, 'deformation_scheme': 'volume', 'run_isif': 4, 'phonon': True, 'phonon_supercell_matrix': [[-2, 2, 2], [2, -2, 2], [2, 2, -2]], 'override_default_vasp_params': {'user_incar_settings': {'EDIFF_PER_ATOM': 1e-07, 'Relax_settings': {'PREC': 'HIGH', 'grid_density': 1000}, 'Static_settings': {'PREC': 'HIGH', 'grid_density': 1000}}, 'user_kpoints_settings': {'grid_density': 1000}}, 'metadata': {'tag': '67783198-6d5a-40c2-8d49-4f03e50ac130'}} + + ################ PARAMETERS FOR WF ############################# + #str, the absolute path of db.json file, e.g. /storage/home/mjl6505/atomate/config/db.json + # If None, it will use the configuration in fireworks + #db_file = settings.get('db_file', DB_FILE) + db_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"] + #str, the vasp command, if None then find in the FWorker configuration + vasp_cmd = settings.get('vasp_cmd', VASP_CMD) + #dict, metadata to be included, this parameter is useful for filter the data, e.g. metadata={"phase": "BCC_A2", "tag": "AFM"} + metadata = settings.get('metadata',{}) + tag = metadata.get('tag', '{}'.format(str(uuid4()))) + metadata.update({'tag': tag}) + + #list/tuple(min, max) or float(-max, max), the maximum amplitude of deformation, e.g. (-0.15, 0.15) means (0.95, 1.1) in volume + deformation_fraction = settings.get('deformation_fraction', (-0.15, 0.20)) + #int, the number of initial deformations, e.g. 7 + num_deformations = settings.get('num_deformations', 8) + if num_deformations==1: + deformation_fraction[1] = deformation_fraction[0] + #bool, run phonon(True) or not(False) + phonon = settings.get('phonon', False) + #list(3x3), the supercell matrix for phonon, e.g. [[2.0, 0, 0], [0, 2.0, 0], [0, 0, 2.0]] + phonon_supercell_matrix = settings.get('phonon_supercell_matrix', None) + phonon_supercell_matrix_min = settings.get('phonon_supercell_matrix_min', None) + phonon_supercell_matrix_max = settings.get('phonon_supercell_matrix_max', None) + optimize_sc = settings.get('optimize_sc', False) + #The tolerance for phonon stable + stable_tor = settings.get('stable_tor', 0.01) + #float, the mimimum of temperature in QHA process, e.g. 5 + t_min = settings.get('t_min', 5) + #float, the maximum of temperature in QHA process, e.g. 2000 + t_max = settings.get('t_max', 2000) + #float, the step of temperature in QHA process, e.g. 5 + t_step = settings.get('t_step', 5) + #float, acceptable value for average RMS, recommend >= 0.005 + eos_tolerance = settings.get('eos_tolerance', 0.01) + + #Global settings for all vasp job, e.g. + #override_default_vasp_params = {'user_incar_settings': {}, 'user_kpoints_settings': {}, 'user_potcar_functional': str} + #If some value in 'user_incar_settings' is set to None, it will use vasp's default value + override_default_vasp_params = settings.get('override_default_vasp_params', {}) + + #dict, dict of class ModifyIncar with keywords in Workflow name. e.g. + modify_incar_params = settings.get('modify_incar_params', {}) + + #check if fworker_name is assigned + powerups = settings.get('powerups', {}) + if len(powerups)>0: + if 'user_incar_settings' not in override_default_vasp_params: + override_default_vasp_params.update({'user_incar_settings':{}}) + override_default_vasp_params['user_incar_settings'].update({'powerups':powerups}) + modify_incar_params.update({'powerups':powerups}) + + #dict, dict of class ModifyKpoints with keywords in Workflow name, similar with modify_incar_params + modify_kpoints_params = settings.get('modify_kpoints_params', {}) + #bool, print(True) or not(False) some informations, used for debug + verbose = settings.get('verbose', False) + #Save the volume data or not ("chgcar", "aeccar0", "aeccar2", "elfcar", "locpot") + store_volumetric_data = settings.get('store_volumetric_data', False) + + if phonon: + if isinstance(phonon_supercell_matrix, str): + if phonon_supercell_matrix=='Yphon': + phonon_supercell_matrix = supercell_scaling_by_Yphon(structure, + supercellsize=phonon_supercell_matrix_max) + else: + phonon_supercell_matrix = supercell_scaling_by_atom_lat_vol(structure, min_obj=phonon_supercell_matrix_min, + max_obj=phonon_supercell_matrix_max, scale_object=phonon_supercell_matrix, + target_shape='sc', lower_search_limit=-2, upper_search_limit=2, + verbose=verbose, sc_tolerance=1e-5, optimize_sc=optimize_sc) + + _deformations = _get_deformations(deformation_fraction, num_deformations) + if num_deformations > 1: vol_spacing = _deformations[1]-_deformations[0] + else: vol_spacing=0.05 + + structure = Structure.from_str(POSCAR_STR, fmt='POSCAR') + t_kwargs = {'t_min': t_min, 't_max': t_max, 't_step': t_step} + common_kwargs = {'vasp_cmd': vasp_cmd, 'db_file': db_file, "metadata": metadata, "tag": tag, + 'override_default_vasp_params': override_default_vasp_params} + vasp_kwargs = {'modify_incar_params': modify_incar_params, 'modify_kpoints_params': modify_kpoints_params} + eos_kwargs = {'deformations': _deformations, 'vol_spacing': vol_spacing, 'eos_tolerance': eos_tolerance, 'threshold': 14} + a_kwargs = {"structure":structure, "settings":settings, "eos_kwargs":eos_kwargs, + "static": True, "phonon":phonon, "phonon_supercell_matrix":phonon_supercell_matrix} + + proc = Crosscom_EVcheck_QHA(verbose=verbose, stable_tor=stable_tor, + run_num = 0, + store_volumetric_data=store_volumetric_data, a_kwargs=a_kwargs, + **eos_kwargs, **vasp_kwargs, **t_kwargs, **common_kwargs, test=True) + proc.run_task({}) + assert False + @pytest.mark.EVcheck_QHA_2 def test_EVcheck_QHA_2(): tag = '19c9e217-4159-4bfe-9c3a-940fb40e023e' @@ -115,7 +221,7 @@ def test_EVcheck_QHA_2(): @pytest.mark.get_static_calculations def test_get_static_calculations(): - tag = '0267947f-b5a0-4993-8b5e-58f9dfb4e362' + tag = '8e7b216d-c6b6-4da4-905e-e7afd44195aa' vasp_db = VaspCalcDb.from_db_file(db_file=db_file, admin = True) volumes, energies, dos_objs, _ = get_static_calculations(vasp_db,tag) #print(volumes, energies)