def check_POSCAR(self, config): ''' First line must like [1,0]32 to match the elements in POSCAR, 0 could not ignored. ''' # To check the sum of occupancies for m in range(len(self.site_ratios)): sum_occupancy = 0 for n in range(len(self.occupancies[m])): sum_occupancy += self.occupancies[m][n] if abs(sum_occupancy - 1) > 1e-10: print( 'The sum of occupancies in %s is NOT equal to 1, please check!' % self.occupancies[m]) return (False) # To check config and occupancy temp_struct = Structure.from_file(self.poscarfile) namelist_elements = [] numlist_elements = [] for e, a in temp_struct.composition.items(): namelist_elements.append(e) numlist_elements.append(a) # [8.0, 24.0] num_element_firstline = 0 for ocs in self.occupancies: num_element_firstline += len(ocs) if len(numlist_elements) != num_element_firstline: print( 'The number of element kind(%s) in first line of POASCAR is NOT same one in the structure(%s), maybe "0" occupancy should be added.' % (num_element_firstline, len(numlist_elements))) return (False) index = 0 for m in range(len(self.site_ratios)): if len(config[m]) < len(self.occupancies[m]): num_occupancy = 0 for n in range(len(self.occupancies[m])): num_occupancy += self.occupancies[m][n] * self.site_ratios[ m] if abs(num_occupancy - numlist_elements[index]) > 1e-10: print( 'The sum of sites in %s%s is NOT equal to %s(Element: %s), please check!' % (self.occupancies[m], self.site_ratios[m], numlist_elements[index], namelist_elements[index])) return (False) index += len(self.occupancies[m]) else: for n in range(len(self.occupancies[m])): if abs(numlist_elements[index] - self.occupancies[m][n] * self.site_ratios[m]) > 1e-10: print( 'The sites in %s * %s is NOT equal to %s(Element: %s), please check!' % (self.occupancies[m][n], self.site_ratios[m], numlist_elements[index], namelist_elements[index])) return (False) index += 1 return (True)
def run(args): """ Run dfttk Currently, only support get_wf_gibbs Parameters STR_FOLDER = args.STRUCTURE_FOLDER folder/file containing structures MATCH_PATTERN = args.MATCH_PATTERN Match patterns for structure file, e.g. *POSCAR RECURSIVE = args.RECURSIVE recursive or not WORKFLOW = args.WORKFLOW workflow, current only get_wf_gibbs LAUNCH = args.LAUNCH Launch to lpad or not MAX_JOB = args.MAX_JOB Max job to submit SETTINGS = args.SETTINGS Settings file WRITE_OUT_WF = args.WRITE_OUT_WF Write out wf file or not """ STR_FOLDER = args.STRUCTURE_FOLDER # folder/file containing structures MATCH_PATTERN = args.MATCH_PATTERN # Match patterns for structure file, e.g. *POSCAR RECURSIVE = args.RECURSIVE # recursive or not WORKFLOW = args.WORKFLOW # workflow, current only get_wf_gibbs PHONON = args.PHONON # run phonon LAUNCH = args.LAUNCH # Launch to lpad or not MAX_JOB = args.MAX_JOB # Max job to submit SETTINGS = args.SETTINGS # Settings file WRITE_OUT_WF = args.WRITE_OUT_WF # Write out wf file or not TAG = args.TAG # Metadata from the command line APPEND = args.APPEND # Append calculations, e.g. appending volumes or phonon or born db_file = args.db_file # user supplier db_file such as db.json if not db_file: if os.path.exists('db.json'): db_file = 'db.json' elif not os.path.exists(db_file): db_file = None ## Initial wfs and metadatas wfs = [] metadatas = {} if APPEND: if TAG: metadatas = { os.path.join(os.path.abspath('./'), 'POSCAR'): { 'tag': TAG } } elif os.path.exists('METADATAS.yaml'): metadatas = loadfn('METADATAS.yaml') else: raise ValueError( 'For APPEND model, please provide TAG with -tag or provide METADATAS.yaml file' ) for keyi in metadatas: (STR_PATH, STR_FILENAME_WITH_EXT) = os.path.split(keyi) (STR_FILENAME, STR_EXT) = os.path.splitext(STR_FILENAME_WITH_EXT) user_settings = get_user_settings(STR_FILENAME_WITH_EXT, STR_PATH=STR_PATH, NEW_SETTING=SETTINGS) metadata = user_settings.get('metadata', {}) metadata.update(metadatas[keyi]) user_settings.update({'metadata': metadata}) structure = get_eq_structure_by_metadata(metadata=metadata, db_file=db_file) if structure is None: raise FileNotFoundError( 'There is no static results under current metadata tag({})' .format(metadata['tag'])) if PHONON: user_settings.update({'phonon': True}) phonon_supercell_matrix = user_settings.get( 'phonon_supercell_matrix', None) if phonon_supercell_matrix is None: user_settings.update({"phonon_supercell_matrix": "atoms"}) wf = get_wf_single(structure, WORKFLOW=WORKFLOW, settings=user_settings, db_file=db_file) wf = Customizing_Workflows(wf, powerups_options=user_settings.get( 'powerups', None)) if isinstance(wf, list): wfs = wfs + wf else: wfs.append(wf) if WRITE_OUT_WF: dfttk_wf_filename = os.path.join( STR_PATH, "dfttk_wf-" + STR_FILENAME_WITH_EXT + ".yaml") dumpfn(wf, dfttk_wf_filename) else: if os.path.exists('METADATAS.yaml'): metadatas = loadfn('METADATAS.yaml') ## Get the file names of files STR_FILES = get_structure_file(STR_FOLDER=STR_FOLDER, RECURSIVE=RECURSIVE, MATCH_PATTERN=MATCH_PATTERN) ## generat the wf for STR_FILE in STR_FILES: (STR_PATH, STR_FILENAME_WITH_EXT) = os.path.split(STR_FILE) (STR_FILENAME, STR_EXT) = os.path.splitext(STR_FILENAME_WITH_EXT) str_filename = STR_FILENAME.lower() if (str_filename.endswith("-" + SETTINGS.lower()) or str_filename.startswith(SETTINGS.lower() + "-") or (str_filename == SETTINGS.lower())): print( STR_FILE + " is a setting file, not structure file, and skipped when reading the structure." ) elif STR_FILE == os.path.abspath(__file__): #This is current file pass else: flag_run = False try: structure = Structure.from_file(STR_FILE) flag_run = True except Exception as e: warnings.warn("The name or the contant of " + STR_FILE + " is not supported by dfttk, and skipped. " + \ "Ref. https://pymatgen.org/pymatgen.core.structure.html#pymatgen.core.structure.IStructure.from_file") if flag_run: user_settings = get_user_settings(STR_FILENAME_WITH_EXT, STR_PATH=STR_PATH, NEW_SETTING=SETTINGS) metadatai = metadatas.get(STR_FILE, None) if metadatai: user_settings.update({'metadata': metadatai}) if PHONON: user_settings.update({'phonon': True}) phonon_supercell_matrix = user_settings.get( 'phonon_supercell_matrix', None) if phonon_supercell_matrix is None: user_settings.update( {"phonon_supercell_matrix": "atoms"}) wf = get_wf_single(structure, WORKFLOW=WORKFLOW, settings=user_settings) wf = Customizing_Workflows( wf, powerups_options=user_settings.get('powerups', None)) metadatas[STR_FILE] = wf.as_dict()["metadata"] wfs.append(wf) if WRITE_OUT_WF: dfttk_wf_filename = os.path.join( STR_PATH, "dfttk_wf-" + STR_FILENAME_WITH_EXT + ".yaml") dumpfn(wf.to_dict(), dfttk_wf_filename) #Write Out the metadata for POST and continue purpose dumpfn(metadatas, "METADATAS.yaml") """ _fws = [] for wflow in wfs: revised_wflow = Customizing_Workflows(wflow,user_settings={}) _fws.append(revised_wflow) fws = _fws """ if LAUNCH: from fireworks import LaunchPad lpad = LaunchPad.auto_load() for wflow in wfs: lpad.add_wf(wflow) if MAX_JOB: # Not False or Empty if MAX_JOB == 1: os.system("qlaunch singleshot") else: os.system("qlaunch rapidfire -m " + str(MAX_JOB))
modify_incar_params = { 'Full relax': {'incar_update': {"LAECHG":False,"LCHARG":False,"LWAVE":False}}, 'PreStatic': {'incar_update': {"LAECHG":False,"LCHARG":False,"LWAVE":False}}, 'PS2': {'incar_update': {"LAECHG":False,"LCHARG":False,"LWAVE":False}}, 'static': {'incar_update': {"LAECHG":False,"LCHARG":False,"LWAVE":False}}, """ modify_incar_params={} #dict, dict of class ModifyKpoints with keywords in Workflow name, similar with modify_incar_params modify_kpoints_params={} #bool, print(True) or not(False) some informations, used for debug verbose=False ###################### DO NOT CHANGE THE FOLLOWING LINES ############################## from pymatgen.ext.matproj import MPRester, Structure from dfttk.wflows import get_wf_gibbs structure = Structure.from_file(TEMPLATE_STRUCTURE_FILENAME) if magmom: structure.add_site_property('magmom', magmom) if not db_file: from fireworks.fw_config import config_to_dict from monty.serialization import loadfn db_file = loadfn(config_to_dict()["FWORKER_LOC"])["env"]["db_file"] wf = get_wf_gibbs(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, tolerance=tolerance, volume_spacing_min=volume_spacing_min,vasp_cmd=vasp_cmd, db_file=db_file, metadata=metadata, name='EV_QHA', symmetry_tolerance=symmetry_tolerance, run_isif2=run_isif2, pass_isif4=pass_isif4, passinitrun=passinitrun, relax_path=relax_path, modify_incar_params=modify_incar_params, modify_kpoints_params=modify_kpoints_params,
def check_symmetry(tol_energy=0.025, tol_strain=0.05, tol_bond=0.10, site_properties=None): ''' Check symmetry for vasp run. This should be run for each vasp run Parameter --------- tol_energy: float The tolerance of energy tol_strain: float The tolerance of strain tol_bond: float The tolerance of bond Return symm_data: dict It will store the initial structure/final_structure, isif, initial_energy_per_atom, final_energy_per_atom, symmetry_checks_passed, tolerances, failures, number_of_failures ------ ''' # Get relevant files as pmg objects incar = Incar.from_file("INCAR") outcar = Outcar('OUTCAR') vasprun = Vasprun("vasprun.xml") inp_struct = Structure.from_file("POSCAR") out_struct = Structure.from_file("CONTCAR") if site_properties: if 'magmom' in site_properties: in_mag = incar.as_dict()['MAGMOM'] inp_struct.add_site_property('magmom', in_mag) out_mag = [m['tot'] for m in outcar.magnetization] if len(out_mag) == 0: out_mag = copy.deepcopy(in_mag) out_struct.add_site_property('magmom', out_mag) site_properties.pop('magmom') for site_property in site_properties: inp_struct.add_site_property(site_property, site_properties[site_property]) out_struct.add_site_property(site_property, site_properties[site_property]) current_isif = incar['ISIF'] initial_energy = float( vasprun.ionic_steps[0]['e_wo_entrp']) / len(inp_struct) final_energy = float(vasprun.final_energy) / len(out_struct) # perform all symmetry breaking checks failures = [] energy_difference = np.abs(final_energy - initial_energy) if energy_difference > tol_energy: fail_dict = { 'reason': 'energy', 'tolerance': tol_energy, 'value': energy_difference, } failures.append(fail_dict) strain_norm = get_non_isotropic_strain(inp_struct.lattice.matrix, out_struct.lattice.matrix) if strain_norm > tol_strain: fail_dict = { 'reason': 'strain', 'tolerance': tol_strain, 'value': strain_norm, } failures.append(fail_dict) bond_distance_change = get_bond_distance_change(inp_struct, out_struct) if bond_distance_change > tol_bond: fail_dict = { 'reason': 'bond distance', 'tolerance': tol_bond, 'value': bond_distance_change, } failures.append(fail_dict) symm_data = { "initial_structure": inp_struct.as_dict(), "final_structure": out_struct.as_dict(), "isif": current_isif, "initial_energy_per_atom": initial_energy, "final_energy_per_atom": final_energy, "real_value": { "energy": energy_difference, "strain": strain_norm, "bond": bond_distance_change }, "tolerances": { "energy": tol_energy, "strain": tol_strain, "bond": tol_bond, }, "failures": failures, "number_of_failures": len(failures), "symmetry_checks_passed": len(failures) == 0, } return symm_data