def main(ingname=""): """Get the last lattice from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "Last lattice (Angstroms);scale, a, b, c", ex: "Last lattice (Angstroms); scale 1, 4.01 0.2 0, 0 4.01 0, 0.1 0.1 4.01" """ trymeta = "%s/metadata.txt" % ingname frontstr = "Last lattice (Angstroms);" if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if myprogram in ['vasp', 'vasp_neb']: if os.path.isdir("%s/01" % ingname): tryfile = "%s/01/CONTCAR" % ingname else: tryfile = "%s/CONTCAR" % ingname cfile = MASTFile(tryfile) if len(cfile.data) == 0: return "%s N/A" % frontstr scale = cfile.data[1].strip() avec = cfile.data[2].strip() bvec = cfile.data[3].strip() cvec = cfile.data[4].strip() return "%s scale %s, %s, %s, %s" % (frontstr, scale, avec, bvec, cvec) else: return "%s N/A" % frontstr
def make_temp_manifest_from_scrambled_structure(self, ingdir, mystr, scrambledman): """Make a temporary manifest from a scrambled structure. Args: ingdir <str>: Ingredient directory (need scaling label) mystr <pymatgen Structure>: Scrambled structure that does not match a manifest scrambledman <str>: Scrambled manifest list that the structure does match namelabel <str>: Parent label of frac coords to find Returns: writes to scrambledman """ mymeta = Metadata(metafile="%s/metadata.txt" % ingdir) scaling_label = mymeta.read_data("scaling_label") if scaling_label == None: scaling_label = "" scrambledlist = list() for site in mystr.sites: fidx = self.find_any_frac_coord_in_atom_indices( site.frac_coords, site.species_string, scaling_label, False, 0.002) scrambledlist.append(fidx) self.write_manifest_file(scrambledlist, scrambledman) return
def main(ingname=""): """Get the last lattice from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "Last lattice (Angstroms);scale, a, b, c", ex: "Last lattice (Angstroms); scale 1, 4.01 0.2 0, 0 4.01 0, 0.1 0.1 4.01" """ trymeta = "%s/metadata.txt" % ingname frontstr = "Last lattice (Angstroms);" if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if myprogram in ['vasp','vasp_neb']: if os.path.isdir("%s/01" % ingname): tryfile = "%s/01/CONTCAR" % ingname else: tryfile = "%s/CONTCAR" % ingname cfile = MASTFile(tryfile) if len(cfile.data) == 0: return "%s N/A" % frontstr scale = cfile.data[1].strip() avec = cfile.data[2].strip() bvec = cfile.data[3].strip() cvec = cfile.data[4].strip() return "%s scale %s, %s, %s, %s" % (frontstr, scale, avec, bvec, cvec) else: return "%s N/A" % frontstr
def main(ingname=""): """Get the last volume value from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "Last volume (Angstroms^3);0.000", ex: "Last volume (Angstroms^3); 324.456" """ trymeta = "%s/metadata.txt" % ingname frontstr = "Last volume (Angstroms^3);" if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if myprogram in ['vasp', 'vasp_neb']: if os.path.isdir("%s/01" % ingname): tryfile = "%s/01/OUTCAR" % ingname else: tryfile = "%s/OUTCAR" % ingname grepvol = fileutil.grepme(tryfile, "volume of cell") if grepvol == []: return "%s N/A" % frontstr myvol = grepvol[-1].split(":")[1].strip() return "%s %s" % (frontstr, myvol) else: return "%s N/A" % frontstr
def main(ingname=""): """Get the energy from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "energy (eV);<energy as a string>", ex: "energy (eV); 3.0" Returns last E0 energy for a VASP run. Returns last E0 energy for all images for a VASP neb. Returns "N/A" otherwise. """ trymeta = "%s/metadata.txt" % ingname if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if 'induce' in ingname: #skip inducedefect ingredients myprogram = "None" if 'vasp' in myprogram: if os.path.isdir("%s/01" % ingname): estr = "energies (eV)" for subdir in dirutil.immediate_subdirs(ingname): mychecker = VaspChecker(name="%s/%s" % (ingname, subdir)) estr = estr + ";%3.3f" % mychecker.get_energy_from_energy_file( ) return estr else: mychecker = VaspChecker(name=ingname) return "energy (eV);%3.3f" % mychecker.get_energy_from_energy_file( ) else: return "energy (eV);N/A"
def main(ingname=""): """Get the energy from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "energy (eV);<energy as a string>", ex: "energy (eV); 3.0" Returns last E0 energy for a VASP run. Returns last E0 energy for all images for a VASP neb. Returns "N/A" otherwise. """ trymeta = "%s/metadata.txt" % ingname if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if 'induce' in ingname: #skip inducedefect ingredients myprogram = "None" if 'vasp' in myprogram: if os.path.isdir("%s/01" % ingname): estr = "energies (eV)" for subdir in dirutil.immediate_subdirs(ingname): mychecker = VaspChecker(name="%s/%s" % (ingname, subdir)) estr = estr + ";%3.3f" % mychecker.get_energy_from_energy_file() return estr else: mychecker = VaspChecker(name=ingname) return "energy (eV);%3.3f" % mychecker.get_energy_from_energy_file() else: return "energy (eV);N/A"
def main(ingname=""): """Get the last volume value from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "Last volume (Angstroms^3);0.000", ex: "Last volume (Angstroms^3); 324.456" """ trymeta = "%s/metadata.txt" % ingname frontstr = "Last volume (Angstroms^3);" if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if myprogram in ['vasp','vasp_neb']: if os.path.isdir("%s/01" % ingname): tryfile = "%s/01/OUTCAR" % ingname else: tryfile = "%s/OUTCAR" % ingname grepvol = fileutil.grepme(tryfile, "volume of cell") if grepvol == []: return "%s N/A" % frontstr myvol = grepvol[-1].split(":")[1].strip() return "%s %s" % (frontstr, myvol) else: return "%s N/A" % frontstr
def main(ingname=""): """Get the last pressure value from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "Last pressure (kbar);0.00", ex: "Last pressure (kbar);-23.55" """ trymeta = "%s/metadata.txt" % ingname frontstr = "Last pressure (kbar);" if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if myprogram in ['vasp','vasp_neb']: if os.path.isdir("%s/01" % ingname): tryfile = "%s/01/OUTCAR" % ingname else: tryfile = "%s/OUTCAR" % ingname greppress = fileutil.grepme(tryfile, "external pressure") #"external pressure = -1.97 kB Pullay stress = 0.00 kB" if greppress == []: return "%s N/A" % frontstr mypress = greppress[-1].strip().split()[3] return "%s %s" % (frontstr, mypress) else: return "%s N/A" % frontstr
def main(ingname=""): """Get the U value from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "LDAUU, LDAUJ (eV);x x x, x x x", ex: "LDAUU, LDAUJ (eV); 0 5 0, 0 1 0" """ trymeta = "%s/metadata.txt" % ingname frontstr = "LDAUU, LDAUJ (eV);" if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if myprogram in ['vasp', 'vasp_neb']: if os.path.isdir("%s/01" % ingname): tryfile = "%s/01/OUTCAR" % ingname else: tryfile = "%s/OUTCAR" % ingname grepldauu = fileutil.grepme(tryfile, "LDAUU") if grepldauu == []: return "%s N/A" % frontstr ldauuparse = grepldauu[0].split("=")[1].strip() grepldauj = fileutil.grepme(tryfile, "LDAUJ") ldaujparse = grepldauj[0].split("=")[1].strip() return "%s %s, %s" % (frontstr, ldauuparse, ldaujparse) else: return "%s N/A" % frontstr
def main(ingname=""): """Get the U value from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "LDAUU, LDAUJ (eV);x x x, x x x", ex: "LDAUU, LDAUJ (eV); 0 5 0, 0 1 0" """ trymeta = "%s/metadata.txt" % ingname frontstr = "LDAUU, LDAUJ (eV);" if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if myprogram in ['vasp','vasp_neb']: if os.path.isdir("%s/01" % ingname): tryfile = "%s/01/OUTCAR" % ingname else: tryfile = "%s/OUTCAR" % ingname grepldauu = fileutil.grepme(tryfile, "LDAUU") if grepldauu == []: return "%s N/A" % frontstr ldauuparse = grepldauu[0].split("=")[1].strip() grepldauj = fileutil.grepme(tryfile, "LDAUJ") ldaujparse = grepldauj[0].split("=")[1].strip() return "%s %s, %s" % (frontstr, ldauuparse, ldaujparse) else: return "%s N/A" % frontstr
def guess_manifest_from_ingredient_metadata(self, ingdir, nebpc=0): """Guess the manifest name from the ingredient. Not for phonon manifests. Args: ingdir <str>: ingredient name, full path nebpc <int>: 0 for first endpoint (default) 1 for final endpoint Returns: manname <str>: manifest name guess; returns None if errors """ mymeta=Metadata(metafile="%s/metadata.txt" % (ingdir)) #phonon_label = mymeta.read_data("phonon_label") scaling_label = mymeta.read_data("scaling_label") neb_label = mymeta.read_data("neb_label") defect_label = mymeta.read_data("defect_label") if scaling_label == None: scaling_label="" if defect_label == None: if neb_label == None: defect_label="" else: if nebpc == 0: defect_label = neb_label.split("-")[0].strip() else: defect_label = neb_label.split("-")[1].strip() manname="%s/manifest_%s_%s_%s" % (self.sdir, scaling_label, defect_label, neb_label) return manname
def guess_manifest_from_ingredient_metadata(self, ingdir, nebpc=0): """Guess the manifest name from the ingredient. Not for phonon manifests. Args: ingdir <str>: ingredient name, full path nebpc <int>: 0 for first endpoint (default) 1 for final endpoint Returns: manname <str>: manifest name guess; returns None if errors """ mymeta = Metadata(metafile="%s/metadata.txt" % (ingdir)) #phonon_label = mymeta.read_data("phonon_label") scaling_label = mymeta.read_data("scaling_label") neb_label = mymeta.read_data("neb_label") defect_label = mymeta.read_data("defect_label") if scaling_label == None: scaling_label = "" if defect_label == None: if neb_label == None: defect_label = "" else: if nebpc == 0: defect_label = neb_label.split("-")[0].strip() else: defect_label = neb_label.split("-")[1].strip() manname = "%s/manifest_%s_%s_%s" % (self.sdir, scaling_label, defect_label, neb_label) return manname
def main(ingname=""): """Get the last pressure value from an ingredient. Args: ingname <str>: Ingredient name, full path Returns: <string>: "Last pressure (kbar);0.00", ex: "Last pressure (kbar);-23.55" """ trymeta = "%s/metadata.txt" % ingname frontstr = "Last pressure (kbar);" if os.path.isfile(trymeta): mymeta = Metadata(metafile=trymeta) myprogram = mymeta.read_data("program") else: myprogram = "None" if myprogram in ['vasp', 'vasp_neb']: if os.path.isdir("%s/01" % ingname): tryfile = "%s/01/OUTCAR" % ingname else: tryfile = "%s/OUTCAR" % ingname greppress = fileutil.grepme(tryfile, "external pressure") #"external pressure = -1.97 kB Pullay stress = 0.00 kB" if greppress == []: return "%s N/A" % frontstr mypress = greppress[-1].strip().split()[3] return "%s %s" % (frontstr, mypress) else: return "%s N/A" % frontstr
def __init__(self, **kwargs): MASTObj.__init__(self, ALLOWED_KEYS, **kwargs) self.input_options = self.keywords['inputOptions'] self.template_file = self.keywords['templateFile'] self.personal_recipe = self.keywords['personalRecipe'] self.ingredient_list = list() self.metafile = Metadata(metafile='%s/metadata.txt' % self.keywords['working_directory']) self.chunks = list()
def __init__(self, allowed_keys, **kwargs): allowed_keys_base = dict() allowed_keys_base.update(allowed_keys) MASTObj.__init__(self, allowed_keys_base, **kwargs) work_dir = '/'.join(self.keywords['name'].split('/')[:-1]) topmeta = Metadata(metafile='%s/metadata.txt' % work_dir) data = topmeta.read_data(self.keywords['name'].split('/')[-1]) self.meta_dict = dict() if data: for datum in data.split(';'): self.meta_dict[datum.split(':')[0]] = datum.split(':')[1].strip() self.metafile = Metadata(metafile='%s/metadata.txt' % self.keywords['name']) self.program = self.keywords['program_keys']['mast_program'].lower() self.logger = loggerutils.get_mast_logger(self.keywords['name']) sdir=os.path.join(os.path.dirname(self.keywords['name']),"structure_index_files") if os.path.exists(sdir): self.atomindex = AtomIndex(structure_index_directory=sdir) else: self.atomindex = None if self.program == 'vasp': self.checker = VaspChecker(name=self.keywords['name'], program_keys = self.keywords['program_keys'], structure = self.keywords['structure']) self.errhandler = VaspError(name=self.keywords['name'], program_keys = self.keywords['program_keys'], structure = self.keywords['structure']) elif self.program == 'vasp_neb': self.checker = VaspNEBChecker(name=self.keywords['name'], program_keys = self.keywords['program_keys'], structure = self.keywords['structure']) self.errhandler = VaspNEBError(name=self.keywords['name'], program_keys = self.keywords['program_keys'], structure = self.keywords['structure']) elif self.program == 'phon': self.checker = PhonChecker(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) self.errhandler = PhonError(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) elif self.program == 'lammps': self.checker = LammpsChecker(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) self.errhandler = GenericError(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) elif self.program =='structopt': self.checker = StructoptChecker(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) self.errhandler = GenericError(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) else: allowed_keys={'name','program_keys','structure'} self.checker = GenericChecker(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) self.errhandler = GenericError(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure'])
def __init__(self, **kwargs): MASTObj.__init__(self, ALLOWED_KEYS, **kwargs) self.recipe_file = self.keywords['recipeFile'] self.input_options = self.keywords['inputOptions'] self.structure = self.keywords['structure'] self.work_dir = self.keywords['workingDirectory'] self.logger = loggerutils.get_mast_logger("recipe setup %s" % self.work_dir) self.metafile = Metadata(metafile='%s/metadata.txt' % self.work_dir) self.logger.debug( 'Setting up the recipe based on the personal recipe contents passed in self.recipe_file' )
def get_my_label(self, label): """Get the value of a label in the metadata file. Args: label <str>: Label to search for. Returns: <str>: Value of the label as a string, stripped. """ myname = self.keywords['name'] mymeta = Metadata(metafile=os.path.join(myname, "metadata.txt")) mylabel = mymeta.search_data(label) if mylabel == "": raise MASTError(self.__class__.__name__, "No metadata for tag %s" % label) return mylabel[1]
def update_atom_indices_from_structure(self, mystr, ing_label="", manname=""): """Add new information to each atom index Args: mystr <pymatgen Structure object> ing_label <str>: Ingredient name manname <str>: Manifest name """ self.logger.debug("Update atom indices from structure %s" % mystr) self.logger.debug("Manifest name %s" % manname) self.logger.debug("Current ingredient %s" % ing_label) self.logger.debug("Structure index directory %s" % self.sdir) mlist = list(self.read_manifest_file("%s/%s" % (self.sdir, manname))) self.logger.debug("MLIST %s" % mlist) for midx in range(0, len(mlist)): msplit = mlist[midx].split(";") ameta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, msplit[0])) ameta.write_data("%s_frac_coords" % ing_label, mystr.sites[midx].frac_coords) if len(msplit) > 1 and not (msplit[1] == "int"): ameta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, msplit[1])) ameta.write_data("%s_frac_coords" % ing_label, mystr.sites[midx].frac_coords) return
def write_undefected_atom_indices(self): """Write undefected atom indices, including scaled indices. Also write an undefected manifest file. """ scales = self.scaling.keys() scales.append("") for scaling_label in scales: if scaling_label == "": mySE = SE(struc_work1=self.startstr.copy()) mystruc = mySE.keywords['struc_work1'] else: mySE = SE( struc_work1=self.startstr.copy(), scaling_size=self.scaling[scaling_label]["mast_size"]) mystruc = mySE.scale_structure() alist = list() manname = os.path.join(self.sdir, "manifest_%s__" % scaling_label) for site in mystruc: akey = self.get_new_key() aname = "atom_index_%s" % akey aname = os.path.join(self.sdir, aname) ameta = Metadata(metafile=aname) ameta.write_data("atom_index", akey) ameta.write_data("original_frac_coords", site.frac_coords) ameta.write_data("element", site.species_string) ameta.write_data("scaling_label", scaling_label) alist.append(akey) self.write_manifest_file(alist, manname) return
def write_undefected_atom_indices(self): """Write undefected atom indices, including scaled indices. Also write an undefected manifest file. """ scales = self.scaling.keys() scales.append("") for scaling_label in scales: if scaling_label == "": mySE=SE(struc_work1=self.startstr.copy()) mystruc=mySE.keywords['struc_work1'] else: mySE=SE(struc_work1=self.startstr.copy(), scaling_size=self.scaling[scaling_label]["mast_size"]) mystruc=mySE.scale_structure() alist=list() manname=os.path.join(self.sdir,"manifest_%s__" % scaling_label) for site in mystruc: akey=self.get_new_key() aname="atom_index_%s" % akey aname = os.path.join(self.sdir, aname) ameta = Metadata(metafile=aname) ameta.write_data("atom_index",akey) ameta.write_data("original_frac_coords", site.frac_coords) ameta.write_data("element", site.species_string) ameta.write_data("scaling_label", scaling_label) alist.append(akey) self.write_manifest_file(alist,manname) return
def __init__(self, **kwargs): MASTObj.__init__(self, ALLOWED_KEYS, **kwargs) self.recipe_file = self.keywords['recipeFile'] self.input_options = self.keywords['inputOptions'] self.structure = self.keywords['structure'] self.work_dir = self.keywords['workingDirectory'] self.logger = loggerutils.get_mast_logger("recipe setup %s" % self.work_dir) self.metafile = Metadata(metafile='%s/metadata.txt' % self.work_dir) self.logger.debug('Setting up the recipe based on the personal recipe contents passed in self.recipe_file')
def __init__(self, **kwargs): MASTObj.__init__(self, ALLOWED_KEYS, **kwargs) self.input_options = self.keywords["inputOptions"] self.template_file = self.keywords["templateFile"] self.personal_recipe = self.keywords["personalRecipe"] self.ingredient_list = list() self.metafile = Metadata(metafile="%s/metadata.txt" % self.keywords["working_directory"]) self.chunks = list()
def find_orig_frac_coord_in_atom_indices(self, coord, element="", scaling_label="", find_multiple=False, tol=0.0001): """Find the atomic index of an original FRACTIONAL coordinate in the structure dictionary. Args: coord <numpy array of float>: coordinate to find element <str>: element symbol to match If blank, matches any element. scaling_label <str>: scaling label If blank, must match NO scaling (blank) find_multiple <boolean>: allow multiple matches. Default False. tol <float>: tolerance Returns: atomic index <hex string>: atomic index of match, if find_multiple is false list of atomic indices of matches, if find_multiple is true Returns None if no match is found """ import glob matchstring = "%s/atom_index_*" % self.sdir idxnames = glob.glob(matchstring) rtol=tol*100 coord_matches=list() elem_matches=list() scaling_matches=list() for aname in idxnames: ameta=Metadata(metafile=aname) aidx=ameta.read_data("atom_index") atom_ofc=ameta.read_data("original_frac_coords") atom_ofc_arr=np.array(atom_ofc[1:-1].split(),'float') if np.allclose(atom_ofc_arr,coord,rtol,tol): coord_matches.append(aidx) if element == "": elem_matches = list(coord_matches) else: for aidx in coord_matches: ameta=Metadata(metafile="%s/atom_index_%s" % (self.sdir, aidx)) atom_elem=ameta.read_data("element") if (element == atom_elem): elem_matches.append(aidx) for aidx in elem_matches: ameta=Metadata(metafile="%s/atom_index_%s" % (self.sdir, aidx)) ascale=ameta.read_data("scaling_label") if (scaling_label == ascale): scaling_matches.append(aidx) allmatches = list(scaling_matches) if len(allmatches) == 0: return None if len(allmatches) > 1: if not find_multiple: raise MASTError(self.__class__.__name__, "Multiple matches found for coordinate %s: %s" % (coord, allmatches)) else: return allmatches if len(allmatches) == 1: if not find_multiple: return allmatches[0] else: return allmatches return None
def get_sd_array(self, ing_label, multiple=False): """Get a selective dynamics array. Args: ing_label <str>: Ingredient name (fullpath) multiple <bool>: Multiple (T F F, F T F, etc. for each atom and direction) or single (T T T for all indicated atoms) array """ mymeta = Metadata(metafile="%s/metadata.txt" % (ing_label)) phonon_label = mymeta.read_data("phonon_label") scaling_label = mymeta.read_data("scaling_label") if scaling_label == None: scaling_label = "" nord_label = phonon_label.split("_")[0] if "-" in nord_label: neb_label = nord_label defect_label = neb_label.split('-')[0] #always parse from first ep else: neb_label = "" defect_label = nord_label phonon_only_label = phonon_label.split("_")[-1] phononman = "%s/manifest_phonon_sd_%s_%s_%s" % ( self.sdir, nord_label, phonon_only_label, scaling_label) structureman = "%s/manifest_%s_%s_%s" % (self.sdir, scaling_label, defect_label, neb_label) phononlist = self.read_manifest_file(phononman) structurelist = self.read_manifest_file(structureman) lensites = len(structurelist) if not multiple: mysd = np.zeros([lensites, 3], bool) for lidx in range(0, lensites): if structurelist[lidx] in phononlist: mysd[lidx] = np.ones(3, bool) return mysd elif multiple: mysdlist = list() for lidx in range(0, lensites): for myct in range(0, 3): mysd = np.zeros([lensites, 3], bool) mysd[lidx] = np.zeros(3, bool) if structurelist[lidx] in phononlist: mysd[lidx][myct] = 1 mysdlist.append(mysd) return mysdlist return
def get_sd_array(self, ing_label, multiple=False): """Get a selective dynamics array. Args: ing_label <str>: Ingredient name (fullpath) multiple <bool>: Multiple (T F F, F T F, etc. for each atom and direction) or single (T T T for all indicated atoms) array """ mymeta=Metadata(metafile="%s/metadata.txt" % (ing_label)) phonon_label = mymeta.read_data("phonon_label") scaling_label = mymeta.read_data("scaling_label") if scaling_label == None: scaling_label = "" nord_label = phonon_label.split("_")[0] if "-" in nord_label: neb_label = nord_label defect_label = neb_label.split('-')[0] #always parse from first ep else: neb_label = "" defect_label = nord_label phonon_only_label = phonon_label.split("_")[-1] phononman="%s/manifest_phonon_sd_%s_%s_%s" % (self.sdir, nord_label, phonon_only_label, scaling_label) structureman="%s/manifest_%s_%s_%s" % (self.sdir, scaling_label, defect_label, neb_label) phononlist = self.read_manifest_file(phononman) structurelist = self.read_manifest_file(structureman) lensites=len(structurelist) if not multiple: mysd=np.zeros([lensites,3],bool) for lidx in range(0, lensites): if structurelist[lidx] in phononlist: mysd[lidx]=np.ones(3,bool) return mysd elif multiple: mysdlist=list() for lidx in range(0, lensites): for myct in range(0,3): mysd = np.zeros([lensites,3],bool) mysd[lidx]=np.zeros(3,bool) if structurelist[lidx] in phononlist: mysd[lidx][myct]=1 mysdlist.append(mysd) return mysdlist return
def make_coordinate_and_element_list_from_manifest(self, manname, ing_label=""): """ Args: ing_label <str>: If blank, use orig_frac_coords. Otherwise, use <ing_label>_frac_coords """ if ing_label == "": ing_label = "original" coordlist = list() elemlist = list() mlist = list(self.read_manifest_file("%s/%s" % (self.sdir, manname))) for aidxline in mlist: aidxsplit = aidxline.split(";") aidx = aidxsplit[0] idxtorepl = "" if len(aidxsplit) > 1: idxtorepl = aidxsplit[1] ameta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, aidx)) if idxtorepl == "": frac_coords = ameta.read_data("%s_frac_coords" % ing_label) if frac_coords == None: raise MASTError( self.__class__.__name__, "No coordinates for %s_frac_coords building from manifest %s/%s using atom index %s" % (ing_label, self.sdir, manname, aidx)) elif idxtorepl == "int": #interstitial frac_coords = ameta.read_data("original_frac_coords") if frac_coords == None: raise MASTError( self.__class__.__name__, "No coordinates for %s_frac_coords building from manifest %s/%s using atom index %s" % (ing_label, self.sdir, manname, aidx)) else: #substitution replmeta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, idxtorepl)) frac_coords = replmeta.read_data("%s_frac_coords" % ing_label) if frac_coords == None: raise MASTError( self.__class__.__name__, "No coordinates for %s_frac_coords building from manifest %s/%s using atom index %s for coordinates and atom index %s for element" % (ing_label, self.sdir, manname, idxtorepl, aidx)) frac_coords = frac_coords.split("[")[1] frac_coords = frac_coords.split("]")[0] frac_array = np.array(frac_coords.split(), 'float') elem = ameta.read_data("element") coordlist.append(frac_array) elemlist.append(elem) return [coordlist, elemlist]
def make_temp_manifest_from_scrambled_structure(self, ingdir, mystr, scrambledman): """Make a temporary manifest from a scrambled structure. Args: ingdir <str>: Ingredient directory (need scaling label) mystr <pymatgen Structure>: Scrambled structure that does not match a manifest scrambledman <str>: Scrambled manifest list that the structure does match namelabel <str>: Parent label of frac coords to find Returns: writes to scrambledman """ mymeta=Metadata(metafile="%s/metadata.txt" % ingdir) scaling_label = mymeta.read_data("scaling_label") if scaling_label == None: scaling_label="" scrambledlist=list() for site in mystr.sites: fidx=self.find_any_frac_coord_in_atom_indices(site.frac_coords, site.species_string, scaling_label, False, 0.002) scrambledlist.append(fidx) self.write_manifest_file(scrambledlist, scrambledman) return
def update_atom_indices_from_structure(self, mystr, ing_label="", manname=""): """Add new information to each atom index Args: mystr <pymatgen Structure object> ing_label <str>: Ingredient name manname <str>: Manifest name """ self.logger.debug("Update atom indices from structure %s" % mystr) self.logger.debug("Manifest name %s" % manname) self.logger.debug("Current ingredient %s" % ing_label) self.logger.debug("Structure index directory %s" % self.sdir) mlist = list(self.read_manifest_file("%s/%s" % (self.sdir, manname))) self.logger.debug("MLIST %s" % mlist) for midx in range(0, len(mlist)): msplit=mlist[midx].split(";") ameta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, msplit[0])) ameta.write_data("%s_frac_coords" % ing_label, mystr.sites[midx].frac_coords) if len(msplit) > 1 and not (msplit[1] == "int"): ameta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, msplit[1])) ameta.write_data("%s_frac_coords" % ing_label, mystr.sites[midx].frac_coords) return
def make_coordinate_and_element_list_from_manifest(self, manname, ing_label=""): """ Args: ing_label <str>: If blank, use orig_frac_coords. Otherwise, use <ing_label>_frac_coords """ if ing_label == "": ing_label = "original" coordlist=list() elemlist=list() mlist=list(self.read_manifest_file("%s/%s" % (self.sdir,manname))) for aidxline in mlist: aidxsplit=aidxline.split(";") aidx=aidxsplit[0] idxtorepl="" if len(aidxsplit) > 1: idxtorepl=aidxsplit[1] ameta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, aidx)) if idxtorepl == "": frac_coords = ameta.read_data("%s_frac_coords" % ing_label) if frac_coords == None: raise MASTError(self.__class__.__name__, "No coordinates for %s_frac_coords building from manifest %s/%s using atom index %s" % (ing_label, self.sdir, manname, aidx)) elif idxtorepl == "int": #interstitial frac_coords = ameta.read_data("original_frac_coords") if frac_coords == None: raise MASTError(self.__class__.__name__, "No coordinates for %s_frac_coords building from manifest %s/%s using atom index %s" % (ing_label, self.sdir, manname, aidx)) else: #substitution replmeta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, idxtorepl)) frac_coords = replmeta.read_data("%s_frac_coords" % ing_label) if frac_coords == None: raise MASTError(self.__class__.__name__, "No coordinates for %s_frac_coords building from manifest %s/%s using atom index %s for coordinates and atom index %s for element" % (ing_label, self.sdir, manname, idxtorepl,aidx)) frac_coords=frac_coords.split("[")[1] frac_coords=frac_coords.split("]")[0] frac_array = np.array(frac_coords.split(), 'float') elem = ameta.read_data("element") coordlist.append(frac_array) elemlist.append(elem) return [coordlist, elemlist]
def _calculate_defect_formation_energies(self,scsize): perf_dirs = [] ingredients = self.recipe_plan.ingredients.keys() for i in range(len(ingredients)): if 'perfect' in ingredients[i]: perf_dirs.append(ingredients[i]) if len(perf_dirs)==0: raise MASTError(self.__class__.__name__, "A perfect final directory (has no children and has the word 'perfect' in its name) could not be found. Check recipe %s for a perfect directory." % self.directory) def_dir = ru.read_recipe(self.input_options.get_item("personal_recipe","personal_recipe_list"))[1]['madelung_utility'] defects = self.input_options.get_item('defects', 'defects') chempot = self.input_options.get_item('chemical_potentials') for i in range(len(perf_dirs)): perf_meta = Metadata(metafile='%s/%s/metadata.txt' % (self.directory, perf_dirs[i])) if scsize == perf_meta.read_data('scaling_size'): perf_dir = perf_dirs[i] perfpath = os.path.join(self.directory, perf_dir) if os.path.isfile(os.path.join(perfpath,"vasprun.xml")): e_perf = pmg.io.vaspio.vasp_output.Vasprun(os.path.join(perfpath, "vasprun.xml")).final_energy else: e_perf = float(open(os.path.join(perfpath, "OSZICAR")).readlines()[-1].split('E0=')[1].split()[0]) efermi = self.get_fermi_energy(perf_dir) struct_perf = self.get_structure(perf_dir) perf_species = dict() for site in struct_perf: if (str(site.specie) not in perf_species): perf_species[str(site.specie)] = 1 else: perf_species[str(site.specie)] += 1 #print 'Perfect composition: ', perf_species #First Loop through the conditions for the defects for conditions, potentials in chempot.items(): self.e_defects[conditions] = dict() # Loop through each defect for ddir in sorted(def_dir): def_meta = Metadata(metafile='%s/%s/metadata.txt' % (self.directory, ddir)) if scsize == def_meta.read_data('scaling_size'): label = def_meta.read_data('defect_label')+'_q='+def_meta.read_data('charge') charge = int(def_meta.read_data('charge')) if os.path.isfile(os.path.join(self.directory, ddir, "vasprun.xml")): energy = pmg.io.vaspio.vasp_output.Vasprun(self.directory+'/'+ddir+'/vasprun.xml').final_energy else: energy = float(open(self.directory+'/'+ddir+'/OSZICAR').readlines()[-1].split('E0=')[1].split()[0]) structure = self.get_structure(ddir) #if (label not in self.e_defects[conditions]): # self.e_defects[conditions][label] = list() # Find out how many atoms of each type are in the defects def_species = dict() for site in structure.sites: if (site.specie not in def_species): def_species[site.specie] = 1 else: def_species[site.specie] += 1 # Find the differences in the number of each atom type # between the perfect and the defect struct_diff = dict() for specie, number in def_species.items(): try: nperf = perf_species[str(specie)] except KeyError: nperf = 0 struct_diff[str(specie)] = number - nperf # Get the potential alignment correction alignment = self.get_potential_alignment(perf_dir, ddir) # Calculate the base DFE energy e_def = energy - e_perf # E_defect - E_perf for specie, number in struct_diff.items(): mu = potentials[str(specie)] e_def -= (number * mu) e_def += charge * (efermi + alignment) # Add in the shift here! #print '%-15s%-5i%12.5f%12.5f%12.5f%12.5f' % (label.split('_')[1], charge, energy, e_perf, efermi, alignment) #print 'DFE = %f' % e_def self.e_defects[conditions][label] = e_def
class RecipeSetup(MASTObj): """Parses the personalized recipe file, creates the recipe plan object, and prepares the ingredient directories. Attributes: self.recipe_file <str>: Recipe file name self.input_options <InputOptions>: Input options for recipe self.structure <pymatgen Structure>: Initial structure in recipe self.work_dir <str>: Working (recipe) directory) self.logger <logging Logger>: Recipe-level log """ def __init__(self, **kwargs): MASTObj.__init__(self, ALLOWED_KEYS, **kwargs) self.recipe_file = self.keywords['recipeFile'] self.input_options = self.keywords['inputOptions'] self.structure = self.keywords['structure'] self.work_dir = self.keywords['workingDirectory'] self.logger = loggerutils.get_mast_logger("recipe setup %s" % self.work_dir) self.metafile = Metadata(metafile='%s/metadata.txt' % self.work_dir) self.logger.debug('Setting up the recipe based on the personal recipe contents passed in self.recipe_file') def get_my_ingredient_options(self, name, ingredient_type): """Creates the ingredient based on the ingredient type. Notes: GRJ 6/19/2013: If the ingredient has not be specified in the input file we create it here, and append on the defaults. In addition, the defaults are appended on here, rather than in InputParser (since each ingredient is made here this makes more sense). TTM 8/19/13: Unspecified ingredient is "default" """ self.logger.debug('Initializing ingredient %s of type %s' % (name, ingredient_type)) global_defaults = self.input_options.get_item('ingredients', 'global') if (ingredient_type not in self.input_options.get_section_keys('ingredients')): self.logger.debug('Ingredient type %s has not been specified in the input file.' % ingredient_type) self.logger.debug('Using defaults from ingredients_global.') self.input_options.set_item('ingredients', ingredient_type, global_defaults) else: self.logger.debug('Copying over defaults from ingredients_global for ingredient %s.' % ingredient_type) ing_opt = self.input_options.get_item('ingredients', ingredient_type) for glob_key, glob_value in global_defaults.items(): if glob_key not in ing_opt: ing_opt[glob_key] = glob_value self.input_options.set_item('ingredients', ingredient_type, ing_opt) #self.program = self.input_options.options['ingredients'][ingredient_type]['mast_program'] ingredient_name = os.path.join(self.work_dir, name) pkey_d = self.input_options.get_item('ingredients', ingredient_type).copy() mydata = self.metafile.read_data(os.path.basename(ingredient_name)).split(';') defect_label="" neb_label="" charge="" phonon_label="" if 'defect_' in name.lower(): for datum in mydata: if 'defect_label' in datum: defect_label = datum.split(':')[-1].strip() if not 'defects' in self.input_options.options.keys(): raise MASTError(self.__class__.__name__, "No defects section in input file. Error setting up recipe %s." % self.work_dir) defdict = self.input_options.get_item('defects','defects') if not defect_label in defdict.keys(): raise MASTError(self.__class__.__name__, "No such label %s found in the defects section dictionary." % defect_label) mydefdict = dict() mydefdict['mast_defect_settings'] = defdict[defect_label] pkey_d.update(mydefdict) break if defect_label == "": raise MASTError(self.__class__.__name__, "No defect label for %s found in ingredient's metadata.txt" % ingredient_name) if 'inducedefect' not in ingredient_type: if 'q=' in name.lower(): for datum in mydata: if 'charge' in datum: charge = int(datum.split(':')[-1]) pkey_d['mast_charge'] = charge break if 'neb_' in name.lower(): for datum in mydata: if 'neb_label' in datum: neb_label = datum.split(':')[-1].strip() if not 'neb' in self.input_options.options.keys(): raise MASTError(self.__class__.__name__, "No neb section in input file. Error setting up recipe %s." % self.work_dir) nebdict = self.input_options.get_item('neb','nebs') if not neb_label in nebdict.keys(): raise MASTError(self.__class__.__name__, "No such label %s found in the neb section dictionary." % neb_label) mynebdict = dict() mynebdict['mast_neb_settings'] = nebdict[neb_label] pkey_d.update(mynebdict) break if neb_label == "": raise MASTError(self.__class__.__name__, "No neb label for %s found in ingredient's metadata.txt" % ingredient_name) if 'neb' in name.lower(): pkey_d.update(self.input_options.options['neb']) #if 'phonon' in self.input_options.options.keys(): # pkey_d.update(self.input_options.options['phonon']) if 'phonon_' in name.lower(): for datum in mydata: if 'phonon_label' in datum: phonon_label = datum.split(':')[-1].strip() def_or_neb_label = phonon_label.split('_')[0] phonon_key = phonon_label.split('_')[-1] defdict = self.input_options.get_item('defects','defects') nebdict = self.input_options.get_item('neb','nebs') phdict=dict() if def_or_neb_label in defdict.keys(): phdict['mast_phonon_settings'] = defdict[def_or_neb_label]['phonon'][phonon_key] elif def_or_neb_label in nebdict.keys(): phdict['mast_phonon_settings'] = nebdict[def_or_neb_label]['phonon'][phonon_key] else: raise MASTError(self.__class__.__name__, "Neither defect nor neb dictionaries have phonon key %s for ingredient %s." % (phonon_key, name)) pkey_d.update(phdict) break if phonon_label == "": raise MASTError(self.__class__.__name__, "No phonon label for %s found in ingredient's metadata.txt" % ingredient_name) if 'chemical_potentials' in self.input_options.options.keys(): chempotdict=dict() chempotdict['mast_chemical_potentials']=self.input_options.options['chemical_potentials'] pkey_d.update(chempotdict) allopt=dict() allopt['name'] = ingredient_name #allopt['program'] = self.program allopt['structure'] = self.structure allopt['program_keys'] = pkey_d self.logger.debug(pkey_d) # change to debug level for logging return allopt def get_method_from_ingredient_type(self, ingredtype, methodtype=""): """Get write, ready, run, complete, and update methods from an ingredient type like volrelax_to_singlerun Args: ingredtype <str>: ingredient type methodtype <str>: method type ("mast_write_method", etc.) Returns: methodname <str>: method name ("write_default", etc.) """ raise NotImplementedError mdict=self.input_options.get_item("ingredients", ingredtype) if methodtype in mdict.keys(): return mdict[methodtype] else: mdict=self.input_options.get_item("ingredients","global") if methodtype in mdict.keys(): return mdict[methodtype] else: return None def create_recipe_plan(self): """Creates a recipe object which has the ingredients and dependency information """ import inspect #'GRJ DEBUG: %s.%s' % (self.__class__.__name__, inspect.stack()[0][3]) [how_to_update, parents_to_check, how_to_run] = ru.read_recipe(self.recipe_file) recipe_obj = RecipePlan(self.work_dir) ingredlist = how_to_run.keys() for ingred in ingredlist: self.update_top_meta_for_ingred(ingred) ingredtype = how_to_run[ingred] recipe_obj.ingredients[ingred]="I" #set all to initialized recipe_obj.ingred_input_options[ingred] = self.get_my_ingredient_options(ingred, ingredtype) if not os.path.isdir(os.path.join(self.work_dir, ingred)): self.create_ingredient(recipe_obj.ingred_input_options[ingred]) recipe_obj.write_methods[ingred] = self.get_method_list(ingredtype, "mast_write_method") recipe_obj.ready_methods[ingred] = self.get_method_list(ingredtype, "mast_ready_method") recipe_obj.run_methods[ingred] = self.get_method_list(ingredtype, "mast_run_method") recipe_obj.complete_methods[ingred] = self.get_method_list(ingredtype, "mast_complete_method") recipe_obj.update_methods[ingred] = dict() for ichild in how_to_update[ingred].keys(): updingredtype = how_to_update[ingred][ichild] recipe_obj.update_methods[ingred][ichild] = self.get_method_list(updingredtype, "mast_update_children_method") recipe_obj.parents_to_check = dict(parents_to_check) recipe_obj.summary_options = self.get_summary_options() return recipe_obj def update_top_meta_for_ingred(self, myingred): """Update the top metafile for an ingredient. Args: myingred <str>: ingredient name """ datalist=list() datalist.append("ingredient type: %s " % myingred) scaling = self.input_options.get_item('scaling') scalingsize = None if scaling: for sckeys in scaling.keys(): if sckeys in myingred: scalingsize = sckeys if scalingsize: datalist.append("scaling_label: %s" % scalingsize) #TTM add scaling label for atom index datalist.append("scaling_size: [%s]" % scaling[scalingsize]['mast_size']) kpoints = scaling[scalingsize]['mast_kpoints'] datalist.append("kpoints: %s" % kpoints) #if 'nbands' in scaling[scalingsize].keys(): # datalist.append("nbands: %s" % scaling[scalingsize]['nbands'][0]) if 'defect_' in myingred: if scaling: defectlabel = myingred.split('defect_')[1].split('_')[1] else: defectlabel = myingred.split('defect_')[1].split('_')[0] if defectlabel.isdigit(): defectlabel = "defect_" + defectlabel datalist.append("defect_label: %s" % defectlabel) if 'q=' in myingred: chargestr = myingred.split('q=')[1].split('_')[0] if chargestr[0] == 'p': chargelabel=chargestr[1:] elif chargestr[0] == 'n': chargelabel='-'+chargestr[1:] else: chargelabel=chargestr datalist.append("charge: %s" % chargelabel) if 'neb_' in myingred: if scaling: neblabel = myingred.split('neb_')[1].split('_')[1] else: neblabel = myingred.split('neb_')[1].split('_')[0] datalist.append("neb_label: %s" % neblabel) if 'phonon_' in myingred: labels = myingred.split('phonon_')[1].split('_') try: labels.remove('parse') except ValueError: pass if scaling: labels.remove(scalingsize) phononlabel = '_'.join(labels) datalist.append("defect_label: %s" % labels[0]) #Assume phonon_<S>_<N>_<Q>_<P> datalist.append("phonon_label: %s" % phononlabel) data=';'.join(datalist) self.metafile.write_data(myingred, data, 1) def create_ingredient(self, my_ingred_input_options): """Create the ingredient directory and metadata file. Args: my_ingred_input_options <Input Options>: single ingredient input options """ allowed_keys = { 'name' : (str, str(), 'Name of optimization directory'), 'program': (str, str(), 'DFT program, e.g. "vasp"'), 'program_keys': (dict, dict(), 'Dictionary of program keywords'), 'structure': (Structure, None, 'Pymatgen Structure object') } myingred = BaseIngredient(allowed_keys, name=my_ingred_input_options['name'], structure=my_ingred_input_options['structure'], program_keys=my_ingred_input_options['program_keys']) myingred.write_directory() return def start(self): """Starts the setup process, parse the recipe file Use the input options and recipe info to create directories and classes required """ if not self.recipe_file: raise MASTError(self.__class__.__name__, "Recipe contents are empty!") """if not os.path.exists(self.recipe_file): raise MASTError(self.__class__.__name__, "Recipe file not Found!")""" if not self.input_options: raise MASTError(self.__class__.__name__, "Input Options not provided!") #print 'DEBUG:, ingredients info =', #for ingredient, value in ingredients_info.items(): # print ingredient, value recipe_plan = self.create_recipe_plan() return recipe_plan def get_method_list(self, ingredtype, methodtype): """Get a method list. Methods should be of the form: methodname arguments where methodname is the method name, and arguments are the arguments, as though listed through a command line. For example, copy_file CONTCAR POSCAR Multiple methods may exist with the same keyword in the ingredients section, and all will be applied. Methods should be separated by a semicolon: mast_update_children_method copy_file CONTCAR POSCAR; softlink_file WAVECAR Args: ingredtype <str>: ingredient type methodtype <str>: method type ("mast_write_method", etc.) Returns: mlist <list>: nested list containing entries [[method1name, arg1, arg2,...],[method2name...],...] """ ioptdict=self.input_options.get_item("ingredients", ingredtype) if methodtype in ioptdict.keys(): unparsed = ioptdict[methodtype] else: globaldict=self.input_options.get_item("ingredients","global") if methodtype in globaldict.keys(): unparsed = globaldict[methodtype] else: raise MASTError(self.__class__.__name__,"No method type %s in either ingredient type %s or global ingredient." % (methodtype, ingredtype)) splitmethods = unparsed.split(";") mlist = list() #self.logger.info(splitmethods) for method_arg_item in splitmethods: method_arg_item = method_arg_item.strip() method_arg_list = shlex.split(method_arg_item) methodname = method_arg_list[0].strip() arglist = list() for argitem in method_arg_list[1:]: arglist.append(argitem.strip()) minputs = list() minputs.append(methodname) minputs.extend(arglist) mlist.append(minputs) #if not methodname in mdict.keys(): # mdict[methodname]=list(arglist) #else: # self.logger.warning("Duplicate entry in method %s for ingredient type %s; ignoring the duplicate." % (methodtype, ingredtype)) #self.logger.info(mlist) return mlist #return mdict def get_summary_options(self): """Get the summary options and give them to the recipe plan.""" sum_opts = dict() if 'summary' in self.input_options.options.keys(): sumkeys = self.input_options.get_section_keys("summary") for sumkey in sumkeys: sum_opts[sumkey] = self.input_options.get_item("summary",sumkey) return sum_opts
def write_defected_atom_indices(self): """Write any additional defect atom indices and make manifests. """ defect_dict = self.input_options.get_item('defects', 'defects') if defect_dict == None: return None dlabels = defect_dict.keys() scales = self.scaling.keys() scales.append("") for scaling_label in scales: alist = list( self.read_manifest_file("%s/manifest_%s__" % (self.sdir, scaling_label))) if scaling_label == "": mySE = SE(struc_work1=self.startstr.copy()) else: mySE = SE( struc_work1=self.startstr.copy(), scaling_size=self.scaling[scaling_label]["mast_size"]) for dlabel in dlabels: dlist = list(alist) manname = os.path.join( self.sdir, "manifest_%s_%s_" % (scaling_label, dlabel)) dsubkeys = defect_dict[dlabel].keys() for dsubkey in dsubkeys: if "subdefect_" in dsubkey: dtype = defect_dict[dlabel][dsubkey]['type'] dcoords = defect_dict[dlabel][dsubkey]['coordinates'] delement = defect_dict[dlabel][dsubkey]['symbol'] if not (scaling_label == ""): dcoords = mySE.get_scaled_coordinates(dcoords) if dtype == "interstitial": didx = self.find_orig_frac_coord_in_atom_indices( dcoords, delement, scaling_label, False, 0.001) if didx == None: akey = self.get_new_key() aname = "atom_index_%s" % akey aname = os.path.join(self.sdir, aname) ameta = Metadata(metafile=aname) ameta.write_data("atom_index", akey) ameta.write_data("original_frac_coords", dcoords) ameta.write_data("element", delement) ameta.write_data("scaling_label", scaling_label) dlist.append("%s;int" % akey) #interstitial label else: dlist.append("%s;int" % didx) elif dtype == "vacancy": didx = self.find_orig_frac_coord_in_atom_indices( dcoords, delement, scaling_label, False, 0.001) try: dlist.remove(didx) except ValueError: raise MASTError( self.__class__.__name__, "For defect %s, cannot remove atom index %s from list: %s" % (dlabel, didx, dlist)) elif dtype in ["substitution", "antisite"]: didxlist = self.find_orig_frac_coord_in_atom_indices( dcoords, "", scaling_label, True, 0.001 ) #leave element empty; just search coords idxtorepl = list() for didx in didxlist: dmeta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, didx)) dmetaelem = dmeta.read_data("element") if not (delement == dmetaelem): if didx in dlist: dlist.remove(didx) idxtorepl.append(didx) if len(idxtorepl) > 1: raise MASTError( self.__class__.__name__, "Interstitial %s is attempting to replace more than one atom: %s" % (dlabel, idxtorepl)) didxsub = self.find_orig_frac_coord_in_atom_indices( dcoords, delement, scaling_label, False, 0.001 ) #leave element empty; just search coords if didxsub == None: akey = self.get_new_key() aname = "atom_index_%s" % akey aname = os.path.join(self.sdir, aname) ameta = Metadata(metafile=aname) ameta.write_data("atom_index", akey) ameta.write_data("original_frac_coords", dcoords) ameta.write_data("element", delement) #sub element here ameta.write_data("scaling_label", scaling_label) dlist.append("%s;%s" % (akey, idxtorepl[0])) else: dlist.append("%s;%s" % (didxsub, idxtorepl[0])) self.write_manifest_file(dlist, manname) return
def find_any_frac_coord_in_atom_indices(self, coord, element="", scaling_label="", find_multiple=False, tol=0.0001): """Find the atomic index of any FRACTIONAL coordinate in the structure dictionary. Args: coord <numpy array of float>: coordinate to find element <str>: element symbol to match If blank, matches any element. scaling_label <str>: scaling label If blank, must match NO scaling (blank) find_multiple <boolean>: allow multiple matches. Default False. tol <float>: tolerance Returns: atomic index <hex string>: atomic index of match, if find_multiple is false list of atomic indices of matches, if find_multiple is true Returns None if no match is found """ import glob matchstring = "%s/atom_index_*" % self.sdir idxnames = glob.glob(matchstring) rtol = tol * 100 coord_matches = list() elem_matches = list() scaling_matches = list() namelist = list() allfolders = immediate_subdirs(os.path.dirname(self.sdir)) #ing dirs for folder in allfolders: namelist.append("%s_frac_coords" % folder) for nametofind in namelist: for aname in idxnames: ameta = Metadata(metafile=aname) aidx = ameta.read_data("atom_index") atom_ofc = ameta.read_data(nametofind) if atom_ofc == None: continue if ";" in atom_ofc: atom_ofc = atom_ofc.split( ';')[-1].strip() # get most updated atom_ofc_arr = np.array(atom_ofc[1:-1].split(), 'float') if np.allclose(atom_ofc_arr, coord, rtol, tol): coord_matches.append(aidx) if element == "": elem_matches = list(coord_matches) else: for aidx in coord_matches: ameta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, aidx)) atom_elem = ameta.read_data("element") if (element == atom_elem): elem_matches.append(aidx) for aidx in elem_matches: ameta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, aidx)) ascale = ameta.read_data("scaling_label") if (scaling_label == ascale): scaling_matches.append(aidx) allmatches = list(scaling_matches) allmatches = list(set(allmatches)) # get unique values if len(allmatches) == 0: return None if len(allmatches) > 1: if not find_multiple: raise MASTError( self.__class__.__name__, "Multiple matches found for coordinate %s: %s" % (coord, allmatches)) else: return allmatches if len(allmatches) == 1: if not find_multiple: return allmatches[0] else: return allmatches return None
def parse_structure_section(self, section_name, section_content, options): """Parses the structure section and populate the options. Does not create the structure. Format is along the lines of: coord_type fractional begin coordinates Ga 0.000000 0.000000 0.000000 Ga 0.500000 0.500000 0.000000 Ga 0.000000 0.500000 0.500000 Ga 0.500000 0.000000 0.500000 As 0.250000 0.250000 0.250000 As 0.750000 0.750000 0.250000 As 0.250000 0.750000 0.750000 As 0.750000 0.250000 0.750000 end begin lattice 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 end Note that coord_type will default to "cartesian" if not specified. """ # Initialize with default values structure_dict = STRUCTURE_KEYWORDS.copy() subsection_dict = dict() for myline in section_content: line = myline.split() if (line[0] in structure_dict): structure_dict[line[0]] = line[1] elif ('begin' in line[0]): subsection = line[1] subsection_list = list() elif ('end' not in line): lsplit = myline.split() lineval = list() for lval in lsplit: lval.strip() if len(lval) > 0: lineval.append(lval) subsection_list.append(lineval) elif ('end' in line): subsection_dict[subsection] = subsection_list # GRJ: Since we lowercase the whole input file, and filenames may not # conform to this, we examine the current directory for any files that # may match and use that. If there are multiple matches, we'll throw # an error. if (structure_dict['posfile'] is not None): # Do we have a geometry file? # TTM for issue #423 posfiletry = os.path.join(os.getcwd(), structure_dict['posfile']) if os.path.isfile(posfiletry): self.logger.info("Using posfile %s in directory %s" % (structure_dict['posfile'], os.getcwd())) else: # First build a list of likely files origindir = os.path.dirname(self.keywords['inputfile']) if origindir == "": origindir = os.getcwd() metatry = os.path.join(os.getcwd(), 'metadata.txt') if os.path.isfile(metatry): myrecipemeta = Metadata(metafile=metatry) origindir = myrecipemeta.search_data('origin_dir')[1] myfiles = dirutil.walkfiles(origindir) file_list=list() for myfile in myfiles: if structure_dict['posfile'] in myfile: file_list.append(myfile) if (len(file_list) > 1): # If we have multiple files with the same name, but different capitalization, throw an error here self.logger.warning('Found multiple files with the name %s' % structure_dict['posfile']) self.logger.warning('Found the files:') for file in file_list: self.logger.warning(file) error='Found ambiguous file names' raise MASTError(self.__class__.__name__, error) elif len(file_list) == 0: raise MASTError(self.__class__.__name__, "No structure file %s found in %s" % (structure_dict['posfile'], origindir)) else: structure_dict['posfile'] = file_list[0] # print 'in InputParser.parse_structure_section:', subsection_dict # TM element_map = dict() atom_list = list() for key, value in subsection_dict.items(): if (key == 'coordinates'): value = np.array(value) # Here we use .title() to re-capitalize the first letter of all # the atomic symbols to comply with what # pymatgen needs atom_list = [val.title() for val in value[:, 0]] structure_dict['atom_list'] = atom_list coordinates = np.array(value[:, 1:], dtype='float') structure_dict['coordinates'] = coordinates if (key == 'lattice'): #print "VALUE: ", value lattice = np.array(value, dtype='float') structure_dict['lattice'] = lattice if (key == 'elementmap'): for elline in value: elkey = elline[0].strip().upper() #all caps elname = elline[1].strip().title() #Title case element_map[elkey]=elname structure_dict['element_map'] = element_map if len(element_map) > 0 and len(atom_list) > 0: new_atom_list = list() for atomval in atom_list: if atomval.upper() in element_map.keys(): new_atom_list.append(element_map[atomval]) else: new_atom_list.append(atomval) structure_dict['atom_list'] = new_atom_list for key, value in structure_dict.items(): options.set_item(section_name, key, value)
def parse_structure_section(self, section_name, section_content, options): """Parses the structure section and populate the options. Does not create the structure. Format is along the lines of: coord_type fractional begin coordinates Ga 0.000000 0.000000 0.000000 Ga 0.500000 0.500000 0.000000 Ga 0.000000 0.500000 0.500000 Ga 0.500000 0.000000 0.500000 As 0.250000 0.250000 0.250000 As 0.750000 0.750000 0.250000 As 0.250000 0.750000 0.750000 As 0.750000 0.250000 0.750000 end begin lattice 2.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 2.0 end Note that coord_type will default to "cartesian" if not specified. """ # Initialize with default values structure_dict = STRUCTURE_KEYWORDS.copy() subsection_dict = dict() for myline in section_content: line = myline.split() if (line[0] in structure_dict): structure_dict[line[0]] = line[1] elif ('begin' in line[0]): subsection = line[1] subsection_list = list() elif ('end' not in line): lsplit = myline.split() lineval = list() for lval in lsplit: lval.strip() if len(lval) > 0: lineval.append(lval) subsection_list.append(lineval) elif ('end' in line): subsection_dict[subsection] = subsection_list # GRJ: Since we lowercase the whole input file, and filenames may not # conform to this, we examine the current directory for any files that # may match and use that. If there are multiple matches, we'll throw # an error. if (structure_dict['posfile'] is not None): # Do we have a geometry file? # TTM for issue #423 posfiletry = os.path.join(os.getcwd(), structure_dict['posfile']) if os.path.isfile(posfiletry): self.logger.info("Using posfile %s in directory %s" % (structure_dict['posfile'], os.getcwd())) else: # First build a list of likely files origindir = os.path.dirname(self.keywords['inputfile']) if origindir == "": origindir = os.getcwd() metatry = os.path.join(os.getcwd(), 'metadata.txt') if os.path.isfile(metatry): myrecipemeta = Metadata(metafile=metatry) origindir = myrecipemeta.search_data('origin_dir')[1] myfiles = dirutil.walkfiles(origindir) file_list = list() for myfile in myfiles: if structure_dict['posfile'] in myfile: file_list.append(myfile) if (len(file_list) > 1): # If we have multiple files with the same name, but different capitalization, throw an error here self.logger.warning( 'Found multiple files with the name %s' % structure_dict['posfile']) self.logger.warning('Found the files:') for file in file_list: self.logger.warning(file) error = 'Found ambiguous file names' raise MASTError(self.__class__.__name__, error) elif len(file_list) == 0: raise MASTError( self.__class__.__name__, "No structure file %s found in %s" % (structure_dict['posfile'], origindir)) else: structure_dict['posfile'] = file_list[0] # print 'in InputParser.parse_structure_section:', subsection_dict # TM element_map = dict() atom_list = list() for key, value in subsection_dict.items(): if (key == 'coordinates'): value = np.array(value) # Here we use .title() to re-capitalize the first letter of all # the atomic symbols to comply with what # pymatgen needs atom_list = [val.title() for val in value[:, 0]] structure_dict['atom_list'] = atom_list coordinates = np.array(value[:, 1:], dtype='float') structure_dict['coordinates'] = coordinates if (key == 'lattice'): #print "VALUE: ", value lattice = np.array(value, dtype='float') structure_dict['lattice'] = lattice if (key == 'elementmap'): for elline in value: elkey = elline[0].strip().upper() #all caps elname = elline[1].strip().title() #Title case element_map[elkey] = elname structure_dict['element_map'] = element_map if len(element_map) > 0 and len(atom_list) > 0: new_atom_list = list() for atomval in atom_list: if atomval.upper() in element_map.keys(): new_atom_list.append(element_map[atomval]) else: new_atom_list.append(atomval) structure_dict['atom_list'] = new_atom_list for key, value in structure_dict.items(): options.set_item(section_name, key, value)
class BaseIngredient(MASTObj): """Base Ingredient class Attributes: self.meta_dict <dict>: Metadata dictionary self.metafile <Metadata>: Metadata file self.program <str>: program name, all lowercase, from 'mast_program' in input file self.checker <VaspChecker, PhonChecker, etc.>: program-dependent checker object self.errhandler <VaspError, PhonError, etc.>: program-dependent handler object self.atomindex <AtomIndex>: atom index object """ def __init__(self, allowed_keys, **kwargs): allowed_keys_base = dict() allowed_keys_base.update(allowed_keys) MASTObj.__init__(self, allowed_keys_base, **kwargs) work_dir = '/'.join(self.keywords['name'].split('/')[:-1]) topmeta = Metadata(metafile='%s/metadata.txt' % work_dir) data = topmeta.read_data(self.keywords['name'].split('/')[-1]) self.meta_dict = dict() if data: for datum in data.split(';'): self.meta_dict[datum.split(':')[0]] = datum.split( ':')[1].strip() self.metafile = Metadata(metafile='%s/metadata.txt' % self.keywords['name']) self.program = self.keywords['program_keys']['mast_program'].lower() self.logger = loggerutils.get_mast_logger(self.keywords['name']) sdir = os.path.join(os.path.dirname(self.keywords['name']), "structure_index_files") if os.path.exists(sdir): self.atomindex = AtomIndex(structure_index_directory=sdir) else: self.atomindex = None if self.program == 'vasp': self.checker = VaspChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = VaspError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) elif self.program == 'vasp_neb': self.checker = VaspNEBChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = VaspNEBError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) elif self.program == 'phon': self.checker = PhonChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = PhonError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) elif self.program == 'lammps': self.checker = LammpsChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = GenericError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) elif self.program == 'structopt': self.checker = StructoptChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = GenericError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) else: allowed_keys = {'name', 'program_keys', 'structure'} self.checker = GenericChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = GenericError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) def write_directory(self): try: os.makedirs(self.keywords['name']) self.metafile.write_data('directory created', time.asctime()) self.metafile.write_data('name', self.keywords['name'].split('/')[-1]) self.metafile.write_data('program', self.program) self.metafile.write_data('ingredient type', self.__class__.__name__) #if 'mast_charge' in self.keywords['program_keys']: # self.metafile.write_data('charge', self.keywords['program_keys']['mast_charge']) for key, value in self.meta_dict.items(): self.metafile.write_data(key, value) except OSError: self.logger.info("Directory for %s already exists." % self.keywords['name']) return def close_logger(self): """Close logger handlers (prevents IOError from too many handlers being open) """ handlerlist = list( self.logger.handlers) #TTM 428; also deleted return after OSError for myhandler in handlerlist: self.logger.removeHandler(myhandler) myhandler.flush() myhandler.close() return def is_complete(self): '''Function to check if Ingredient is ready''' if not self.checker.is_started(): return False #hasn't started running yet complete = self.checker.is_complete() frozen = self.checker.is_frozen() if complete or frozen: errct = self.errhandler.loop_through_errors() if errct > 0: if os.path.isfile( os.path.join(self.keywords['name'], 'error.5.tar.gz')): self.logger.error( "Ingredient directory already has 5 error zip files. A manual look is required." ) self.change_my_status("E") return False if 'mast_auto_correct' in self.keywords['program_keys'].keys(): if str(self.keywords['program_keys'] ['mast_auto_correct']).strip()[0].lower() == 'f': self.change_my_status("E") else: self.change_my_status("S") else: self.change_my_status("S") self.errhandler.clean_up_directory() return False else: if complete: self.metafile.write_data('completed on', time.asctime()) if 'get_energy_from_energy_file' in dirutil.list_methods( self.checker, 0): energy = self.checker.get_energy_from_energy_file() self.metafile.write_data('energy', energy) return True else: return False else: return False def directory_is_locked(self): return dirutil.directory_is_locked(self.keywords['name']) def lock_directory(self): return dirutil.lock_directory(self.keywords['name']) def unlock_directory(self): return dirutil.unlock_directory(self.keywords['name']) def wait_to_write(self): return dirutil.wait_to_write(self.keywords['name']) def is_ready_to_run(self): if self.directory_is_locked(): return False return self.checker.is_ready_to_run() def getpath(self): '''getpath returns the directory of the ingredient''' return self.keywords['name'] def write_submit_script(self): from MAST.submit import script_commands script_commands.write_submit_script(self.keywords) return def run(self, mode='serial', curdir=os.getcwd()): if "dagman" in dirutil.get_mast_platform(): return from MAST.submit import queue_commands if mode.lower() == 'noqsub': curdir = os.getcwd() os.chdir(self.keywords['name']) programpath = queue_commands.direct_shell_command() p = subprocess.Popen(programpath, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() os.chdir(curdir) self.metafile.write_data('run', time.asctime()) elif mode.lower() == 'serial': queuesub = queue_commands.write_to_submit_list( self.keywords['name']) #runme = subprocess.Popen(queuesub, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) #runme.wait() # for scheduling other jobs #runme.wait() self.metafile.write_data('queued', time.asctime()) return def get_name(self): return self.keywords['name'].split('/')[-1] @property def name(self): return self.get_name() def get_keywords(self): return self.keywords.copy() def __repr__(self): return 'Ingredient %s of type %s' % ( self.keywords['name'].split('/')[-1], self.__class__.__name__) def get_my_label(self, label): """Get the value of a label in the metadata file. Args: label <str>: Label to search for. Returns: <str>: Value of the label as a string, stripped. """ myname = self.keywords['name'] mymeta = Metadata(metafile=os.path.join(myname, "metadata.txt")) mylabel = mymeta.search_data(label) if mylabel == "": raise MASTError(self.__class__.__name__, "No metadata for tag %s" % label) return mylabel[1] def change_my_status(self, newstatus): """Change an ingredient status by writing the new status to change_status.txt in the ingredient folder, to get picked up by the recipe plan. Args: newstatus <str>: New status to which to change the ingredient. """ ingdir = self.keywords['name'] oneup = os.path.dirname(ingdir) tryrecipe = os.path.basename(oneup) statuspath = "" if dirutil.dir_is_in_scratch(tryrecipe): statuspath = "%s/change_status.txt" % ingdir else: twoup = os.path.dirname(oneup) tryrecipe = os.path.basename(twoup) if dirutil.dir_is_in_scratch(tryrecipe): statuspath = "%s/change_status.txt" % oneup else: raise MASTError( self.__class__.__name__, "Cannot change status of ingredient %s as recipe %s or %s is not found in $MAST_SCRATCH." % (self.keywords['name'], oneup, twoup)) if os.path.isfile(statuspath): statusfile = MASTFile(statuspath) else: statusfile = MASTFile() statusfile.data.append("%s:recommend:%s" % (newstatus, time.asctime())) statusfile.to_file(statuspath) self.logger.info("Recommending status change to %s" % newstatus)
def _calculate_defect_formation_energies(self, scsize): perf_dirs = [] ingredients = self.recipe_plan.ingredients.keys() for i in range(len(ingredients)): if 'perfect' in ingredients[i]: perf_dirs.append(ingredients[i]) if len(perf_dirs) == 0: raise MASTError( self.__class__.__name__, "A perfect final directory (has no children and has the word 'perfect' in its name) could not be found. Check recipe %s for a perfect directory." % self.directory) def_dir = ru.read_recipe( self.input_options.get_item( "personal_recipe", "personal_recipe_list"))[1]['madelung_utility'] defects = self.input_options.get_item('defects', 'defects') chempot = self.input_options.get_item('chemical_potentials') for i in range(len(perf_dirs)): perf_meta = Metadata(metafile='%s/%s/metadata.txt' % (self.directory, perf_dirs[i])) if scsize == perf_meta.read_data('scaling_size'): perf_dir = perf_dirs[i] perfpath = os.path.join(self.directory, perf_dir) if os.path.isfile(os.path.join(perfpath, "vasprun.xml")): e_perf = pmg.io.vaspio.vasp_output.Vasprun( os.path.join(perfpath, "vasprun.xml")).final_energy else: e_perf = float( open(os.path.join( perfpath, "OSZICAR")).readlines()[-1].split('E0=')[1].split()[0]) efermi = self.get_fermi_energy(perf_dir) struct_perf = self.get_structure(perf_dir) perf_species = dict() for site in struct_perf: if (str(site.specie) not in perf_species): perf_species[str(site.specie)] = 1 else: perf_species[str(site.specie)] += 1 #print 'Perfect composition: ', perf_species #First Loop through the conditions for the defects for conditions, potentials in chempot.items(): self.e_defects[conditions] = dict() # Loop through each defect for ddir in sorted(def_dir): def_meta = Metadata(metafile='%s/%s/metadata.txt' % (self.directory, ddir)) if scsize == def_meta.read_data('scaling_size'): label = def_meta.read_data( 'defect_label') + '_q=' + def_meta.read_data('charge') charge = int(def_meta.read_data('charge')) if os.path.isfile( os.path.join(self.directory, ddir, "vasprun.xml")): energy = pmg.io.vaspio.vasp_output.Vasprun( self.directory + '/' + ddir + '/vasprun.xml').final_energy else: energy = float( open(self.directory + '/' + ddir + '/OSZICAR').readlines()[-1].split('E0=') [1].split()[0]) structure = self.get_structure(ddir) #if (label not in self.e_defects[conditions]): # self.e_defects[conditions][label] = list() # Find out how many atoms of each type are in the defects def_species = dict() for site in structure.sites: if (site.specie not in def_species): def_species[site.specie] = 1 else: def_species[site.specie] += 1 # Find the differences in the number of each atom type # between the perfect and the defect struct_diff = dict() for specie, number in def_species.items(): try: nperf = perf_species[str(specie)] except KeyError: nperf = 0 struct_diff[str(specie)] = number - nperf # Get the potential alignment correction alignment = self.get_potential_alignment(perf_dir, ddir) # Calculate the base DFE energy e_def = energy - e_perf # E_defect - E_perf for specie, number in struct_diff.items(): mu = potentials[str(specie)] e_def -= (number * mu) e_def += charge * (efermi + alignment ) # Add in the shift here! #print '%-15s%-5i%12.5f%12.5f%12.5f%12.5f' % (label.split('_')[1], charge, energy, e_perf, efermi, alignment) #print 'DFE = %f' % e_def self.e_defects[conditions][label] = e_def
def calculate_single_defect_formation_energy(self, mylabel, conditions, potentials): """Calculate one defect formation energy. Args: mylabel <str>: Defect label conditions <str>: Environment condition, e.g. "As-rich" potentials <dict of float>: Dictionary of chemical potentials, e.g.: potentials['As']=-6.0383 potentials['Ga']=-3.6080 potentials['Bi']=-4.5650 Returns: <float>: Defect formation energy """ pdir = self.dirs[mylabel]['perfect'] ddir = self.dirs[mylabel]['defected'] #Get perfect data perf_meta = Metadata(metafile='%s/%s/metadata.txt' % (self.recdir, pdir)) e_perf = self.get_total_energy(pdir) #e_perf = float(perf_meta.read_data('energy').split(',')[-1]) #Sometimes the energy is listed more than once. efermi = self.get_fermi_energy(pdir) struct_perf = self.get_structure(pdir) perf_species = dict() for site in struct_perf: if (str(site.specie) not in perf_species): perf_species[str(site.specie)] = 1 else: perf_species[str(site.specie)] += 1 #print 'Perfect composition: ', perf_species #Get defected data def_meta = Metadata(metafile='%s/%s/metadata.txt' % (self.recdir, ddir)) #print def_meta label = def_meta.read_data('defect_label') charge = int(def_meta.read_data('charge')) energy = self.get_total_energy(ddir) #energy = float(def_meta.read_data('energy').split(',')[-1]) structure = self.get_structure(ddir) if (label not in self.e_defects[conditions]): self.e_defects[conditions][label] = list() print 'Calculating DFEs for defect %s with charge %3i.' % (label, charge) def_species = dict() for site in structure.sites: if (site.specie not in def_species): def_species[site.specie] = 1 else: def_species[site.specie] += 1 # Find the differences in the number of each atom type # between the perfect and the defect struct_diff = dict() for specie, number in def_species.items(): try: nperf = perf_species[str(specie)] except KeyError: nperf = 0 struct_diff[str(specie)] = number - nperf # Get the potential alignment correction alignment = self.get_potential_alignment(pdir, ddir) # Calculate the base DFE energy e_def = energy - e_perf # E_defect - E_perf print "TTM DEBUG: e_def: ", e_def for specie, number in struct_diff.items(): mu = potentials[str(specie)] #print str(specie), mu, number e_def -= (number * mu) print "TTM DEBUG: number: ", number print "TTM DEBUG: mu: ", mu print "TTM DEBUG: e_def -= number*mu: ", e_def print "TTM DEBUG: charge: ", charge print "TTM DEBUG: alignment: ", alignment print "TTM DEBUG: efermi: ", efermi e_def += charge * (efermi + alignment) # Add in the shift here! print "TTM DEBUG: e_def += charge*(efermi + alignment): ", e_def #print '%-15s%-5i%12.5f%12.5f%12.5f%12.5f' % (label.split('_')[1], charge, energy, e_perf, efermi, alignment) print 'DFE = %f' % e_def self.e_defects[conditions][label].append((charge, e_def)) return
class RecipeSetup(MASTObj): """Parses the personalized recipe file, creates the recipe plan object, and prepares the ingredient directories. Attributes: self.recipe_file <str>: Recipe file name self.input_options <InputOptions>: Input options for recipe self.structure <pymatgen Structure>: Initial structure in recipe self.work_dir <str>: Working (recipe) directory) self.logger <logging Logger>: Recipe-level log """ def __init__(self, **kwargs): MASTObj.__init__(self, ALLOWED_KEYS, **kwargs) self.recipe_file = self.keywords['recipeFile'] self.input_options = self.keywords['inputOptions'] self.structure = self.keywords['structure'] self.work_dir = self.keywords['workingDirectory'] self.logger = loggerutils.get_mast_logger("recipe setup %s" % self.work_dir) self.metafile = Metadata(metafile='%s/metadata.txt' % self.work_dir) self.logger.debug( 'Setting up the recipe based on the personal recipe contents passed in self.recipe_file' ) def get_my_ingredient_options(self, name, ingredient_type): """Creates the ingredient based on the ingredient type. Notes: GRJ 6/19/2013: If the ingredient has not be specified in the input file we create it here, and append on the defaults. In addition, the defaults are appended on here, rather than in InputParser (since each ingredient is made here this makes more sense). TTM 8/19/13: Unspecified ingredient is "default" """ self.logger.debug('Initializing ingredient %s of type %s' % (name, ingredient_type)) global_defaults = self.input_options.get_item('ingredients', 'global') if (ingredient_type not in self.input_options.get_section_keys('ingredients')): self.logger.debug( 'Ingredient type %s has not been specified in the input file.' % ingredient_type) self.logger.debug('Using defaults from ingredients_global.') self.input_options.set_item('ingredients', ingredient_type, global_defaults) else: self.logger.debug( 'Copying over defaults from ingredients_global for ingredient %s.' % ingredient_type) ing_opt = self.input_options.get_item('ingredients', ingredient_type) for glob_key, glob_value in global_defaults.items(): if glob_key not in ing_opt: ing_opt[glob_key] = glob_value self.input_options.set_item('ingredients', ingredient_type, ing_opt) #self.program = self.input_options.options['ingredients'][ingredient_type]['mast_program'] ingredient_name = os.path.join(self.work_dir, name) pkey_d = self.input_options.get_item('ingredients', ingredient_type).copy() mydata = self.metafile.read_data( os.path.basename(ingredient_name)).split(';') defect_label = "" neb_label = "" charge = "" phonon_label = "" if 'defect_' in name.lower(): for datum in mydata: if 'defect_label' in datum: defect_label = datum.split(':')[-1].strip() if not 'defects' in self.input_options.options.keys(): raise MASTError( self.__class__.__name__, "No defects section in input file. Error setting up recipe %s." % self.work_dir) defdict = self.input_options.get_item('defects', 'defects') if not defect_label in defdict.keys(): raise MASTError( self.__class__.__name__, "No such label %s found in the defects section dictionary." % defect_label) mydefdict = dict() mydefdict['mast_defect_settings'] = defdict[defect_label] pkey_d.update(mydefdict) break if defect_label == "": raise MASTError( self.__class__.__name__, "No defect label for %s found in ingredient's metadata.txt" % ingredient_name) if 'inducedefect' not in ingredient_type: if 'q=' in name.lower(): for datum in mydata: if 'charge' in datum: charge = int(datum.split(':')[-1]) pkey_d['mast_charge'] = charge break if 'neb_' in name.lower(): for datum in mydata: if 'neb_label' in datum: neb_label = datum.split(':')[-1].strip() if not 'neb' in self.input_options.options.keys(): raise MASTError( self.__class__.__name__, "No neb section in input file. Error setting up recipe %s." % self.work_dir) nebdict = self.input_options.get_item('neb', 'nebs') if not neb_label in nebdict.keys(): raise MASTError( self.__class__.__name__, "No such label %s found in the neb section dictionary." % neb_label) mynebdict = dict() mynebdict['mast_neb_settings'] = nebdict[neb_label] pkey_d.update(mynebdict) break if neb_label == "": raise MASTError( self.__class__.__name__, "No neb label for %s found in ingredient's metadata.txt" % ingredient_name) if 'neb' in name.lower(): pkey_d.update(self.input_options.options['neb']) #if 'phonon' in self.input_options.options.keys(): # pkey_d.update(self.input_options.options['phonon']) if 'phonon_' in name.lower(): for datum in mydata: if 'phonon_label' in datum: phonon_label = datum.split(':')[-1].strip() def_or_neb_label = phonon_label.split('_')[0] phonon_key = phonon_label.split('_')[-1] defdict = self.input_options.get_item('defects', 'defects') nebdict = self.input_options.get_item('neb', 'nebs') phdict = dict() if def_or_neb_label in defdict.keys(): phdict['mast_phonon_settings'] = defdict[ def_or_neb_label]['phonon'][phonon_key] elif def_or_neb_label in nebdict.keys(): phdict['mast_phonon_settings'] = nebdict[ def_or_neb_label]['phonon'][phonon_key] else: raise MASTError( self.__class__.__name__, "Neither defect nor neb dictionaries have phonon key %s for ingredient %s." % (phonon_key, name)) pkey_d.update(phdict) break if phonon_label == "": raise MASTError( self.__class__.__name__, "No phonon label for %s found in ingredient's metadata.txt" % ingredient_name) if 'chemical_potentials' in self.input_options.options.keys(): chempotdict = dict() chempotdict[ 'mast_chemical_potentials'] = self.input_options.options[ 'chemical_potentials'] pkey_d.update(chempotdict) allopt = dict() allopt['name'] = ingredient_name #allopt['program'] = self.program allopt['structure'] = self.structure allopt['program_keys'] = pkey_d self.logger.debug(pkey_d) # change to debug level for logging return allopt def get_method_from_ingredient_type(self, ingredtype, methodtype=""): """Get write, ready, run, complete, and update methods from an ingredient type like volrelax_to_singlerun Args: ingredtype <str>: ingredient type methodtype <str>: method type ("mast_write_method", etc.) Returns: methodname <str>: method name ("write_default", etc.) """ raise NotImplementedError mdict = self.input_options.get_item("ingredients", ingredtype) if methodtype in mdict.keys(): return mdict[methodtype] else: mdict = self.input_options.get_item("ingredients", "global") if methodtype in mdict.keys(): return mdict[methodtype] else: return None def create_recipe_plan(self): """Creates a recipe object which has the ingredients and dependency information """ import inspect #'GRJ DEBUG: %s.%s' % (self.__class__.__name__, inspect.stack()[0][3]) [how_to_update, parents_to_check, how_to_run] = ru.read_recipe(self.recipe_file) recipe_obj = RecipePlan(self.work_dir) ingredlist = how_to_run.keys() for ingred in ingredlist: self.update_top_meta_for_ingred(ingred) ingredtype = how_to_run[ingred] recipe_obj.ingredients[ingred] = "I" #set all to initialized recipe_obj.ingred_input_options[ ingred] = self.get_my_ingredient_options(ingred, ingredtype) if not os.path.isdir(os.path.join(self.work_dir, ingred)): self.create_ingredient(recipe_obj.ingred_input_options[ingred]) recipe_obj.write_methods[ingred] = self.get_method_list( ingredtype, "mast_write_method") recipe_obj.ready_methods[ingred] = self.get_method_list( ingredtype, "mast_ready_method") recipe_obj.run_methods[ingred] = self.get_method_list( ingredtype, "mast_run_method") recipe_obj.complete_methods[ingred] = self.get_method_list( ingredtype, "mast_complete_method") recipe_obj.update_methods[ingred] = dict() for ichild in how_to_update[ingred].keys(): updingredtype = how_to_update[ingred][ichild] recipe_obj.update_methods[ingred][ ichild] = self.get_method_list( updingredtype, "mast_update_children_method") recipe_obj.parents_to_check = dict(parents_to_check) recipe_obj.summary_options = self.get_summary_options() return recipe_obj def update_top_meta_for_ingred(self, myingred): """Update the top metafile for an ingredient. Args: myingred <str>: ingredient name """ datalist = list() datalist.append("ingredient type: %s " % myingred) scaling = self.input_options.get_item('scaling') scalingsize = None if scaling: for sckeys in scaling.keys(): if sckeys in myingred: scalingsize = sckeys if scalingsize: datalist.append( "scaling_label: %s" % scalingsize) #TTM add scaling label for atom index datalist.append("scaling_size: [%s]" % scaling[scalingsize]['mast_size']) kpoints = scaling[scalingsize]['mast_kpoints'] datalist.append("kpoints: %s" % kpoints) #if 'nbands' in scaling[scalingsize].keys(): # datalist.append("nbands: %s" % scaling[scalingsize]['nbands'][0]) if 'defect_' in myingred: if scaling: defectlabel = myingred.split('defect_')[1].split('_')[1] else: defectlabel = myingred.split('defect_')[1].split('_')[0] if defectlabel.isdigit(): defectlabel = "defect_" + defectlabel datalist.append("defect_label: %s" % defectlabel) if 'q=' in myingred: chargestr = myingred.split('q=')[1].split('_')[0] if chargestr[0] == 'p': chargelabel = chargestr[1:] elif chargestr[0] == 'n': chargelabel = '-' + chargestr[1:] else: chargelabel = chargestr datalist.append("charge: %s" % chargelabel) if 'neb_' in myingred: if scaling: neblabel = myingred.split('neb_')[1].split('_')[1] else: neblabel = myingred.split('neb_')[1].split('_')[0] datalist.append("neb_label: %s" % neblabel) if 'phonon_' in myingred: labels = myingred.split('phonon_')[1].split('_') try: labels.remove('parse') except ValueError: pass if scaling: labels.remove(scalingsize) phononlabel = '_'.join(labels) datalist.append("defect_label: %s" % labels[0]) #Assume phonon_<S>_<N>_<Q>_<P> datalist.append("phonon_label: %s" % phononlabel) data = ';'.join(datalist) self.metafile.write_data(myingred, data, 1) def create_ingredient(self, my_ingred_input_options): """Create the ingredient directory and metadata file. Args: my_ingred_input_options <Input Options>: single ingredient input options """ allowed_keys = { 'name': (str, str(), 'Name of optimization directory'), 'program': (str, str(), 'DFT program, e.g. "vasp"'), 'program_keys': (dict, dict(), 'Dictionary of program keywords'), 'structure': (Structure, None, 'Pymatgen Structure object') } myingred = BaseIngredient( allowed_keys, name=my_ingred_input_options['name'], structure=my_ingred_input_options['structure'], program_keys=my_ingred_input_options['program_keys']) myingred.write_directory() return def start(self): """Starts the setup process, parse the recipe file Use the input options and recipe info to create directories and classes required """ if not self.recipe_file: raise MASTError(self.__class__.__name__, "Recipe contents are empty!") """if not os.path.exists(self.recipe_file): raise MASTError(self.__class__.__name__, "Recipe file not Found!")""" if not self.input_options: raise MASTError(self.__class__.__name__, "Input Options not provided!") #print 'DEBUG:, ingredients info =', #for ingredient, value in ingredients_info.items(): # print ingredient, value recipe_plan = self.create_recipe_plan() return recipe_plan def get_method_list(self, ingredtype, methodtype): """Get a method list. Methods should be of the form: methodname arguments where methodname is the method name, and arguments are the arguments, as though listed through a command line. For example, copy_file CONTCAR POSCAR Multiple methods may exist with the same keyword in the ingredients section, and all will be applied. Methods should be separated by a semicolon: mast_update_children_method copy_file CONTCAR POSCAR; softlink_file WAVECAR Args: ingredtype <str>: ingredient type methodtype <str>: method type ("mast_write_method", etc.) Returns: mlist <list>: nested list containing entries [[method1name, arg1, arg2,...],[method2name...],...] """ ioptdict = self.input_options.get_item("ingredients", ingredtype) if methodtype in ioptdict.keys(): unparsed = ioptdict[methodtype] else: globaldict = self.input_options.get_item("ingredients", "global") if methodtype in globaldict.keys(): unparsed = globaldict[methodtype] else: raise MASTError( self.__class__.__name__, "No method type %s in either ingredient type %s or global ingredient." % (methodtype, ingredtype)) splitmethods = unparsed.split(";") mlist = list() #self.logger.info(splitmethods) for method_arg_item in splitmethods: method_arg_item = method_arg_item.strip() method_arg_list = shlex.split(method_arg_item) methodname = method_arg_list[0].strip() arglist = list() for argitem in method_arg_list[1:]: arglist.append(argitem.strip()) minputs = list() minputs.append(methodname) minputs.extend(arglist) mlist.append(minputs) #if not methodname in mdict.keys(): # mdict[methodname]=list(arglist) #else: # self.logger.warning("Duplicate entry in method %s for ingredient type %s; ignoring the duplicate." % (methodtype, ingredtype)) #self.logger.info(mlist) return mlist #return mdict def get_summary_options(self): """Get the summary options and give them to the recipe plan.""" sum_opts = dict() if 'summary' in self.input_options.options.keys(): sumkeys = self.input_options.get_section_keys("summary") for sumkey in sumkeys: sum_opts[sumkey] = self.input_options.get_item( "summary", sumkey) return sum_opts
def parse_ingredients_section(self, section_name, section_content, options): """Parses the ingredients section and populates the options. Section takes the form of: $ingredients begin ingredients_global mast_kpoints 3x3x3 mast_xc pbe end begin singlepoint encut 400 end begin optimize encut 300 ibrion 2 end $end mast_kpoints are parsed out as a 3 index list of integers. Everything else is parsed out as a string. Anything in ingredients_global is then appended onto each individual ingredient. """ global_dict = dict() ingredients_dict = dict() for line in section_content: if (line.startswith('begin')): # Each ingredient section starts with "begin". # Check for this line, and initialize the individual # ingredient dictionary ingredient_name = line.split()[1] ingredient_dict = dict() elif (not (line == 'end')): opt = line.split() # print opt if (opt[0] == 'mast_kpoints'): try: kpts = map(int, opt[1].split('x')) if len(opt) > 2: kpts.append(opt[2]) except ValueError: kpts = opt[1:] # Second option after mast_kpoints tells where to # center the k-point mesh. # If it's there, we append it onto the k-point grid list. ingredient_dict[opt[0]] = kpts elif (opt[0] == 'mast_pp_setup'): psp_dict = dict() for key in opt[1:]: key = key.split('=') ref = key[0].title() val = str().join(key[1][0].upper() + key[1][1:]) psp_dict[ref] = val ingredient_dict[opt[0]] = psp_dict #elif (opt[0] == 'mast_exec'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #elif (opt[0] == 'mast_strain'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #elif (opt[0] == 'ptemp'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #elif (opt[0] == 'rwigs'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #elif (opt[0] == 'mast_setmagmom'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line elif (opt[0] == 'mast_coordinates'): shortsplit = opt[1].split(",") filesplit=list() origindir = os.getcwd() metatry = os.path.join(os.getcwd(), 'metadata.txt') if os.path.isfile(metatry): myrecipemeta = Metadata(metafile=metatry) origindir = myrecipemeta.search_data('origin_dir')[1] myfiles = dirutil.walkfiles(origindir) for shortname in shortsplit: for fullfile in myfiles: if shortname.strip() in os.path.basename(fullfile): filesplit.append(fullfile) if not (len(filesplit) == len(shortsplit)): raise MASTError(self.__class__.__name__, "Not all files given by %s were found in %s." % (shortsplit, origindir)) ingredient_dict[opt[0]] = filesplit else: ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #ingredient_dict[opt[0]] = opt[1] #old behavior took only the first part if (opt[0] == 'mast_program') and (opt[1] == 'vasp' or opt[1] == 'vasp_neb'): if os.getenv('VASP_PSP_DIR') == None: raise MASTError(self.__class__.__name__, "Input file specifies program vasp, but no POTCAR directory is set in environment variable VASP_PSP_DIR") elif ('end' in line): # Each ingredient section ends with "end", if present finish # that current section and assign # the neccessary element in the ingredients dictionary and # create the global dictionary if (ingredient_name == 'ingredients_global'): global_dict = ingredient_dict else: ingredients_dict[ingredient_name] = ingredient_dict # Each value in ingredients_dict is a dictionary containing the relevant # ingredient and option(s). for ing_key, ing_value in ingredients_dict.items(): options.set_item(section_name, ing_key, ing_value) options.set_item(section_name, 'global', global_dict)
class BaseIngredient(MASTObj): """Base Ingredient class Attributes: self.meta_dict <dict>: Metadata dictionary self.metafile <Metadata>: Metadata file self.program <str>: program name, all lowercase, from 'mast_program' in input file self.checker <VaspChecker, PhonChecker, etc.>: program-dependent checker object self.errhandler <VaspError, PhonError, etc.>: program-dependent handler object self.atomindex <AtomIndex>: atom index object """ def __init__(self, allowed_keys, **kwargs): allowed_keys_base = dict() allowed_keys_base.update(allowed_keys) MASTObj.__init__(self, allowed_keys_base, **kwargs) work_dir = '/'.join(self.keywords['name'].split('/')[:-1]) topmeta = Metadata(metafile='%s/metadata.txt' % work_dir) data = topmeta.read_data(self.keywords['name'].split('/')[-1]) self.meta_dict = dict() if data: for datum in data.split(';'): self.meta_dict[datum.split(':')[0]] = datum.split(':')[1].strip() self.metafile = Metadata(metafile='%s/metadata.txt' % self.keywords['name']) self.program = self.keywords['program_keys']['mast_program'].lower() self.logger = loggerutils.get_mast_logger(self.keywords['name']) sdir=os.path.join(os.path.dirname(self.keywords['name']),"structure_index_files") if os.path.exists(sdir): self.atomindex = AtomIndex(structure_index_directory=sdir) else: self.atomindex = None if self.program == 'vasp': self.checker = VaspChecker(name=self.keywords['name'], program_keys = self.keywords['program_keys'], structure = self.keywords['structure']) self.errhandler = VaspError(name=self.keywords['name'], program_keys = self.keywords['program_keys'], structure = self.keywords['structure']) elif self.program == 'vasp_neb': self.checker = VaspNEBChecker(name=self.keywords['name'], program_keys = self.keywords['program_keys'], structure = self.keywords['structure']) self.errhandler = VaspNEBError(name=self.keywords['name'], program_keys = self.keywords['program_keys'], structure = self.keywords['structure']) elif self.program == 'phon': self.checker = PhonChecker(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) self.errhandler = PhonError(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) elif self.program == 'lammps': self.checker = LammpsChecker(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) self.errhandler = GenericError(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) elif self.program =='structopt': self.checker = StructoptChecker(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) self.errhandler = GenericError(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) else: allowed_keys={'name','program_keys','structure'} self.checker = GenericChecker(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) self.errhandler = GenericError(name=self.keywords['name'],program_keys=self.keywords['program_keys'],structure=self.keywords['structure']) def write_directory(self): try: os.makedirs(self.keywords['name']) self.metafile.write_data('directory created', time.asctime()) self.metafile.write_data('name', self.keywords['name'].split('/')[-1]) self.metafile.write_data('program', self.program) self.metafile.write_data('ingredient type', self.__class__.__name__) #if 'mast_charge' in self.keywords['program_keys']: # self.metafile.write_data('charge', self.keywords['program_keys']['mast_charge']) for key, value in self.meta_dict.items(): self.metafile.write_data(key, value) except OSError: self.logger.info("Directory for %s already exists." % self.keywords['name']) return def close_logger(self): """Close logger handlers (prevents IOError from too many handlers being open) """ handlerlist = list(self.logger.handlers) #TTM 428; also deleted return after OSError for myhandler in handlerlist: self.logger.removeHandler(myhandler) myhandler.flush() myhandler.close() return def is_complete(self): '''Function to check if Ingredient is ready''' if not self.checker.is_started(): return False #hasn't started running yet complete = self.checker.is_complete() frozen = self.checker.is_frozen() if complete or frozen: errct = self.errhandler.loop_through_errors() if errct > 0: if os.path.isfile(os.path.join(self.keywords['name'],'error.5.tar.gz')): self.logger.error("Ingredient directory already has 5 error zip files. A manual look is required.") self.change_my_status("E") return False if 'mast_auto_correct' in self.keywords['program_keys'].keys(): if str(self.keywords['program_keys']['mast_auto_correct']).strip()[0].lower() == 'f': self.change_my_status("E") else: self.change_my_status("S") else: self.change_my_status("S") self.errhandler.clean_up_directory() return False else: if complete: self.metafile.write_data('completed on', time.asctime()) if 'get_energy_from_energy_file' in dirutil.list_methods(self.checker,0): energy = self.checker.get_energy_from_energy_file() self.metafile.write_data('energy', energy) return True else: return False else: return False def directory_is_locked(self): return dirutil.directory_is_locked(self.keywords['name']) def lock_directory(self): return dirutil.lock_directory(self.keywords['name']) def unlock_directory(self): return dirutil.unlock_directory(self.keywords['name']) def wait_to_write(self): return dirutil.wait_to_write(self.keywords['name']) def is_ready_to_run(self): if self.directory_is_locked(): return False return self.checker.is_ready_to_run() def getpath(self): '''getpath returns the directory of the ingredient''' return self.keywords['name'] def write_submit_script(self): from MAST.submit import script_commands script_commands.write_submit_script(self.keywords) return def run(self, mode='serial', curdir=os.getcwd()): if "dagman" in dirutil.get_mast_platform(): return from MAST.submit import queue_commands if mode.lower() == 'noqsub': curdir = os.getcwd() os.chdir(self.keywords['name']) programpath = queue_commands.direct_shell_command() p = subprocess.Popen(programpath, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() os.chdir(curdir) self.metafile.write_data('run', time.asctime()) elif mode.lower() == 'serial': queuesub = queue_commands.write_to_submit_list(self.keywords['name']) #runme = subprocess.Popen(queuesub, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) #runme.wait() # for scheduling other jobs #runme.wait() self.metafile.write_data('queued', time.asctime()) return def get_name(self): return self.keywords['name'].split('/')[-1] @property def name(self): return self.get_name() def get_keywords(self): return self.keywords.copy() def __repr__(self): return 'Ingredient %s of type %s' % (self.keywords['name'].split('/')[-1], self.__class__.__name__) def get_my_label(self, label): """Get the value of a label in the metadata file. Args: label <str>: Label to search for. Returns: <str>: Value of the label as a string, stripped. """ myname = self.keywords['name'] mymeta = Metadata(metafile=os.path.join(myname, "metadata.txt")) mylabel = mymeta.search_data(label) if mylabel == "": raise MASTError(self.__class__.__name__, "No metadata for tag %s" % label) return mylabel[1] def change_my_status(self, newstatus): """Change an ingredient status by writing the new status to change_status.txt in the ingredient folder, to get picked up by the recipe plan. Args: newstatus <str>: New status to which to change the ingredient. """ ingdir = self.keywords['name'] oneup = os.path.dirname(ingdir) tryrecipe = os.path.basename(oneup) statuspath = "" if dirutil.dir_is_in_scratch(tryrecipe): statuspath = "%s/change_status.txt" % ingdir else: twoup = os.path.dirname(oneup) tryrecipe = os.path.basename(twoup) if dirutil.dir_is_in_scratch(tryrecipe): statuspath = "%s/change_status.txt" % oneup else: raise MASTError(self.__class__.__name__, "Cannot change status of ingredient %s as recipe %s or %s is not found in $MAST_SCRATCH." % (self.keywords['name'],oneup, twoup)) if os.path.isfile(statuspath): statusfile = MASTFile(statuspath) else: statusfile=MASTFile() statusfile.data.append("%s:recommend:%s" % (newstatus, time.asctime())) statusfile.to_file(statuspath) self.logger.info("Recommending status change to %s" % newstatus)
def __init__(self, allowed_keys, **kwargs): allowed_keys_base = dict() allowed_keys_base.update(allowed_keys) MASTObj.__init__(self, allowed_keys_base, **kwargs) work_dir = '/'.join(self.keywords['name'].split('/')[:-1]) topmeta = Metadata(metafile='%s/metadata.txt' % work_dir) data = topmeta.read_data(self.keywords['name'].split('/')[-1]) self.meta_dict = dict() if data: for datum in data.split(';'): self.meta_dict[datum.split(':')[0]] = datum.split( ':')[1].strip() self.metafile = Metadata(metafile='%s/metadata.txt' % self.keywords['name']) self.program = self.keywords['program_keys']['mast_program'].lower() self.logger = loggerutils.get_mast_logger(self.keywords['name']) sdir = os.path.join(os.path.dirname(self.keywords['name']), "structure_index_files") if os.path.exists(sdir): self.atomindex = AtomIndex(structure_index_directory=sdir) else: self.atomindex = None if self.program == 'vasp': self.checker = VaspChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = VaspError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) elif self.program == 'vasp_neb': self.checker = VaspNEBChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = VaspNEBError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) elif self.program == 'phon': self.checker = PhonChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = PhonError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) elif self.program == 'lammps': self.checker = LammpsChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = GenericError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) elif self.program == 'structopt': self.checker = StructoptChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = GenericError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) else: allowed_keys = {'name', 'program_keys', 'structure'} self.checker = GenericChecker( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure']) self.errhandler = GenericError( name=self.keywords['name'], program_keys=self.keywords['program_keys'], structure=self.keywords['structure'])
class RecipeTemplateParser(MASTObj): """Class for parsing the template recipe file in the input file and creating a "personalized" recipe file where any <sys> and <N> from the recipe template have been filled in according to information from the input file. Attributes: self.input_options <InputOptions>: Input options from input file. self.template_file <str>: Path to the recipe template file self.personal_recipe <str>: Path to the personalized recipe. self.ingredient_list <list of str>: List of ingredients mentioned in the recipe template file. self.chunks <list of list>: List of chunks """ def __init__(self, **kwargs): MASTObj.__init__(self, ALLOWED_KEYS, **kwargs) self.input_options = self.keywords['inputOptions'] self.template_file = self.keywords['templateFile'] self.personal_recipe = self.keywords['personalRecipe'] self.ingredient_list = list() self.metafile = Metadata(metafile='%s/metadata.txt' % self.keywords['working_directory']) self.chunks = list() def parse(self): """ Parses the template recipe file and creates the personalized recipe file """ if len(self.template_file) == 0: raise MASTError(self.__class__.__name__, "Recipe contents not provided!") if self.input_options is None: raise MASTError(self.__class__.__name__, "Input Options not provided!") if self.personal_recipe is None: raise MASTError(self.__class__.__name__, "Personal recipe file not provided!") #fetch required paramaters #f_ptr = open(self.template_file, "r") recipe_contents = list(self.template_file) #print recipe_contents o_ptr = open(self.personal_recipe, "a") system_name = self.input_options.get_item("mast", "system_name", "sys") n_defects = self.input_options.get_item("defects", "num_defects", 0) d_defects = self.input_options.get_item("defects", "defects") n_images = self.input_options.get_item("neb", "images", 0) d_neblines = self.input_options.get_item("neb", "neblines", {}) recipe_name = None # print system_name, self.input_options.get_item('mast', 'system_name') chunkcount = 0 mychunk = list() modchunk = False for line in recipe_contents: #f_ptr.readlines(): duplicate = line if ((len(duplicate) - len(duplicate.lstrip(' '))) % 4 != 0): raise MASTError( "parsers/recipetemplateparser", "Recipe at %s contains incorrect number of whitespace chars at the beginning of the line! Please convert all indentations to the appropriate number of groups of four spaces." % line) if '\t' in line: raise MASTError( "parsers/recipetemplateparser", "The tab character exists in recipe template %s. Please convert all tabs to the appropriate number of groups of four spaces." % self.template_file) if '{begin}' in line: self.chunks.append(list(mychunk)) mychunk = list() elif '{end}' in line: pass else: mychunk.append(line) if len(mychunk) > 0: self.chunks.append(list(mychunk)) #for chunk in self.chunks: # print chunk input_options_keys = self.input_options.get_sections() key = 'personal_recipe' expandedlist = list() if key in input_options_keys: return expandedlist else: for chunk in self.chunks: expanded = self.parse_chunk(chunk) expandedlist.extend(expanded) o_ptr.write("$personal_recipe\n") o_ptr.writelines(expandedlist) o_ptr.write("$end\n") #f_ptr.close() o_ptr.close() return expandedlist #self.chunks[chunkcount]=dict() #self.chunks[chunkcount]['modify'] = modchunk # #line = line.strip() # #line = line.lower() # processing_lines = [] # #shortcut straight copy + 6 # processing_lines.append(line) # output_str = "\n".join(processing_lines) # o_ptr.write("%s\n" % output_str) #f_ptr.close() #o_ptr.close() # print 'in RecipeParser.parse():', list(set(self.ingredient_list)) #return recipe_name def parse_chunk(self, chunk): """Parse a chunk of lines. Args: chunk <list>: List of lines Returns: expandedchunk <list>: List of lines """ origchunk = list(chunk) expandedchunk = list() needsdefects = 0 needscharges = 0 needsphonons = 0 needsnebs = 0 needsscaling = 0 for line in chunk: if "<N>" in line: needsdefects = 1 if "<B-E>" in line: needsnebs = 1 if "<P>" in line: needsphonons = 1 if "<Q>" in line: needscharges = 1 if "<B>" in line: needsnebs = 1 if "<E>" in line: needsnebs = 1 if "<S>" in line: needsscaling = 1 d_scaling = self.input_options.get_item("scaling") d_defects = self.input_options.get_item("defects", "defects") d_nebs = self.input_options.get_item("neb", "nebs") if needsscaling == 1: scalingsize = d_scaling.keys() scalingsize.sort() else: scalingsize = ['1x1x1'] for size in scalingsize: if needsdefects == 1: mydefects = d_defects.keys() mydefects.sort() for defectname in mydefects: for charge in d_defects[defectname]['charge']: if charge < 0: mycharge = 'q=n' + str(int(math.fabs(charge))) else: mycharge = 'q=p' + str(int(charge)) if needsphonons == 1: if len(d_defects[defectname]['phonon'].keys()) > 0: phononkeys = d_defects[defectname][ 'phonon'].keys() phononkeys.sort() for phonon in phononkeys: for line in origchunk: newline = line.replace( "<N>", defectname) if needscharges == 1: newline = newline.replace( "<Q>", mycharge) if needsscaling == 1: newline = newline.replace( "<S>", size) newline = newline.replace( "<P>", phonon) expandedchunk.append(newline) else: for line in origchunk: newline = line.replace("<N>", defectname) if needscharges == 1: newline = newline.replace("<Q>", mycharge) if needsscaling == 1: newline = newline.replace("<S>", size) expandedchunk.append(newline) elif needsnebs == 1: nebkeys = d_nebs.keys() nebkeys.sort() for neblabel in nebkeys: defbegin = neblabel.split('-')[0] defend = neblabel.split('-')[1] chargebegin = d_defects[defbegin]['charge'] chargeend = d_defects[defend]['charge'] chargeboth = set(chargebegin) & set(chargeend) for charge in chargeboth: if charge < 0: mycharge = 'q=n' + str(int(math.fabs(charge))) else: mycharge = 'q=p' + str(int(charge)) if needsphonons == 1: if len(d_nebs[neblabel]['phonon'].keys()) > 0: phononkeys = d_nebs[neblabel]['phonon'].keys() phononkeys.sort() for phonon in phononkeys: for line in origchunk: newline = line.replace("<B>", defbegin) newline = newline.replace( "<E>", defend) newline = newline.replace( "<B-E>", neblabel) if needscharges == 1: newline = newline.replace( "<Q>", mycharge) if needsscaling == 1: newline = newline.replace( "<S>", size) newline = newline.replace( "<P>", phonon) expandedchunk.append(newline) else: for line in origchunk: newline = line.replace("<B>", defbegin) newline = newline.replace("<E>", defend) newline = newline.replace("<B-E>", neblabel) if needscharges == 1: newline = newline.replace("<Q>", mycharge) if needsscaling == 1: newline = newline.replace("<S>", size) expandedchunk.append(newline) elif needsscaling == 1: for line in origchunk: newline = line.replace("<S>", size) expandedchunk.append(newline) else: expandedchunk = list(origchunk) return expandedchunk #origchunk = list(expandedchunk) #expandedchunk=list() #for defectname in self.d_defects: # for line in origchunk: # newline = line.replace("<N>", defectname) # expandedchunk.append(line) def old_parsing(self): raise MASTError(self.__class__.__name__, "This function is obsolete.") for line in linestr: #validate the input line if not line or line.startswith('#'): continue #collect recipe name line2 = line.split() if (line2[0].lower() == 'recipe'): recipe_name = line2[1] #collect ingredents line2 = line.split() if (line2[0].lower() == 'ingredient'): self.ingredient_list.append(line2[2]) #replace line params<N> #step 1 : replace <sys> with system_name #step 2 : replace <n-n> with appropriate hop combinations #step 3 : replace <img-n> with appropriate image numbers #step 4 : replace <n> with appropriate defect numbers processing_lines.append(line) #step 1 processing_lines = self.process_system_name( processing_lines, system_name) #step 4 processing_lines = self.process_defects(processing_lines, n_defects, d_defects) #step 2 processing_lines = self.process_hop_combinations( processing_lines, d_neblines) #step 3 processing_lines = self.process_images(processing_lines, n_images) self.make_metadata_entries(processing_lines) self.process_phononlines(processing_lines) #dump the processed lines to file output_str = "\n".join(processing_lines) o_ptr.write("%s\n" % output_str) f_ptr.close() o_ptr.close() # print 'in RecipeParser.parse():', list(set(self.ingredient_list)) return recipe_name def process_system_name(self, processing_lines, system_name): """replace <sys> with the system name from the input options """ raise MASTError(self.__class__.__name__, "This function is obsolete.") for index in xrange(len(processing_lines)): processing_lines[index] = processing_lines[index].replace( '<sys>', system_name) return processing_lines def process_hop_combinations(self, processing_lines, d_neblines): """replace <n-n> with neb labels which are keys of the neblines dict of the input options. Args: processing_lines <list of str>: recipe lines to process. d_neblines <dict of str>: dictionary of NEB lines. """ raise MASTError(self.__class__.__name__, "This function is obsolete.") new_lines = [] eval_lines = [] if not d_neblines: return processing_lines line = "" for line in processing_lines: if "<n-n>" in line: for neblabel in d_neblines.keys(): n_line = line.replace('<n-n>', neblabel) eval_lines.append(n_line) if 'ingredient' in n_line and not '<' in n_line: keyword = n_line.split()[1] data = 'neblabel: %s' % neblabel self.metafile.write_data(keyword, data) else: eval_lines.append(line) line = "" for line in eval_lines: #print "TTM DEBUG line: ", line if not 'neb' in line.split('_'): #print "TTM DEBUG line safe" new_lines.append(line) else: evalsplit = line.split('child') if len(evalsplit) == 1: new_lines.append(line) else: childsplit = evalsplit[1].split('_') parsplit = evalsplit[0].split('_') okay = 1 for neblabel in d_neblines.keys(): if okay == 1 and (neblabel in childsplit): parlabels = neblabel.split('-') #print "TTM DEBUG: parlabels: ",parlabels #print "TTM DEBUG: parsplit: ",parsplit if not parlabels[0] in parsplit and not ( parlabels[1] in parsplit): if not neblabel in parsplit: #image static okay = 0 if okay == 0: pass else: new_lines.append(line) return new_lines def process_images(self, processing_lines, n_images): """replace <img-n> with the equivalent number of lines based on the number of images found in the input_options """ raise MASTError(self.__class__.__name__, "This function is obsolete.") new_lines = [] if not n_images: return processing_lines for line in processing_lines: if '<img-n>' in line: for index in xrange(n_images): n_line = line.replace('<img-n>', str(index + 1).zfill(2)) if 'ingredient' in n_line and not '<' in n_line: keyword = n_line.split()[1] data = 'name: %s' % keyword self.metafile.write_data(keyword, data) new_lines.append(n_line) else: new_lines.append(line) return new_lines def process_defects(self, processing_lines, n_defects, d_defects): """replace <N> with the equivalent number of lines based on the number of defects given in the input options Args: processing_lines <list of str>: recipe lines to proceess n_defects <int>: number of defected systems d_defects <dict>: dictionary of defects, including labels and positions. """ raise MASTError(self.__class__.__name__, "This function is obsolete.") #import inspect #print 'GRJ DEBUG: %s.%s' % (self.__class__.__name__, inspect.stack()[0][3]) #print d_defects #print 'GRJ DEBUG: parse_defects() working_directory =', self.keywords['working_directory'] new_lines = list() if not n_defects: return processing_lines for line in processing_lines: #print 'GRJ DEBUG: line =', line if ('<n>' in line) or ('<q>' in line): for defect_key in d_defects.keys(): #print 'GRJ DEBUG: defect_key =', defect_key #defect_label = defect_key.split('_')[1] #defect_1, etc. def_line = line.replace("<n>", defect_key) charge_list = d_defects[defect_key]['charge'] #print 'GRJ DEBUG: charge_list =', charge_list #print 'GRJ DEBUG: def_line before charges:', def_line for charge in charge_list: if (charge < 0): clabel = 'q=n' + str(abs(charge)) else: clabel = 'q=p' + str(charge) #print 'GRJ DEBUG: clabel =', clabel new_def_line = def_line.replace('<q>', clabel) new_lines.append(new_def_line) #new_lines.append(def_line.replace('<q>', clabel)) if 'ingredient' in def_line: keyword = new_def_line.split()[1] data = 'defect_label: %s, charge: %i' % ( defect_key, charge) #print 'GRJ DEBUG: def_line, keyword, charge', new_def_line, keyword, charge self.metafile.write_data(keyword, data) else: new_lines.append(line) return new_lines def process_phononlines(self, processing_lines): """add phonon information to the metadata. Does not change line info. """ raise MASTError(self.__class__.__name__, "This function is obsolete.") for line in processing_lines: if 'ingredient' in line and 'phonon_' in line: nameval = line.split()[1] [dataline, dataval] = self.metafile.search_data(nameval) okay = 0 if not (dataval == None): datapcs = dataval.split(',') for datapc in datapcs: dlabel = datapc.split(":")[0].strip() dval = datapc.split(":")[1].strip() if dlabel == 'neblabel' or dlabel == 'defect_label': data = 'phononlabel: %s' % dval self.metafile.write_data(nameval, data) okay = 1 break if okay == 0: if 'perfect' in line: data = 'phononlabel: perfect' self.metafile.write_data(nameval, data) okay = 1 else: data = 'phononlabel: %s' % nameval self.metafile.write_data(nameval, data) okay = 1 return def make_metadata_entries(self, processing_lines): """Add metadata entry for all ingredients. Does not change line information. """ raise MASTError(self.__class__.__name__, "This function is obsolete.") for line in processing_lines: if 'ingredient' in line: nameval = line.split()[1] data = 'name: %s' % nameval self.metafile.write_data(nameval, data) return def get_unique_ingredients(self): """fetches the ingredients names""" raise MASTError(self.__class__.__name__, "This function is obsolete.") return list(set(self.ingredient_list))
def parse_ingredients_section(self, section_name, section_content, options): """Parses the ingredients section and populates the options. Section takes the form of: $ingredients begin ingredients_global mast_kpoints 3x3x3 mast_xc pbe end begin singlepoint encut 400 end begin optimize encut 300 ibrion 2 end $end mast_kpoints are parsed out as a 3 index list of integers. Everything else is parsed out as a string. Anything in ingredients_global is then appended onto each individual ingredient. """ global_dict = dict() ingredients_dict = dict() for line in section_content: if (line.startswith('begin')): # Each ingredient section starts with "begin". # Check for this line, and initialize the individual # ingredient dictionary ingredient_name = line.split()[1] ingredient_dict = dict() elif (not (line == 'end')): opt = line.split() # print opt if (opt[0] == 'mast_kpoints'): try: kpts = map(int, opt[1].split('x')) if len(opt) > 2: kpts.append(opt[2]) except ValueError: kpts = opt[1:] # Second option after mast_kpoints tells where to # center the k-point mesh. # If it's there, we append it onto the k-point grid list. ingredient_dict[opt[0]] = kpts elif (opt[0] == 'mast_pp_setup'): psp_dict = dict() for key in opt[1:]: key = key.split('=') ref = key[0].title() val = str().join(key[1][0].upper() + key[1][1:]) psp_dict[ref] = val ingredient_dict[opt[0]] = psp_dict #elif (opt[0] == 'mast_exec'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #elif (opt[0] == 'mast_strain'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #elif (opt[0] == 'ptemp'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #elif (opt[0] == 'rwigs'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line #elif (opt[0] == 'mast_setmagmom'): # ingredient_dict[opt[0]] = ' '.join(opt[1:]) #preserve whole line elif (opt[0] == 'mast_coordinates'): shortsplit = opt[1].split(",") filesplit = list() origindir = os.getcwd() metatry = os.path.join(os.getcwd(), 'metadata.txt') if os.path.isfile(metatry): myrecipemeta = Metadata(metafile=metatry) origindir = myrecipemeta.search_data('origin_dir')[1] myfiles = dirutil.walkfiles(origindir) for shortname in shortsplit: for fullfile in myfiles: if shortname.strip() in os.path.basename(fullfile): filesplit.append(fullfile) if not (len(filesplit) == len(shortsplit)): raise MASTError( self.__class__.__name__, "Not all files given by %s were found in %s." % (shortsplit, origindir)) ingredient_dict[opt[0]] = filesplit else: ingredient_dict[opt[0]] = ' '.join( opt[1:]) #preserve whole line #ingredient_dict[opt[0]] = opt[1] #old behavior took only the first part if (opt[0] == 'mast_program') and (opt[1] == 'vasp' or opt[1] == 'vasp_neb'): if os.getenv('VASP_PSP_DIR') == None: raise MASTError( self.__class__.__name__, "Input file specifies program vasp, but no POTCAR directory is set in environment variable VASP_PSP_DIR" ) elif ('end' in line): # Each ingredient section ends with "end", if present finish # that current section and assign # the neccessary element in the ingredients dictionary and # create the global dictionary if (ingredient_name == 'ingredients_global'): global_dict = ingredient_dict else: ingredients_dict[ingredient_name] = ingredient_dict # Each value in ingredients_dict is a dictionary containing the relevant # ingredient and option(s). for ing_key, ing_value in ingredients_dict.items(): options.set_item(section_name, ing_key, ing_value) options.set_item(section_name, 'global', global_dict)
class RecipeTemplateParser(MASTObj): """Class for parsing the template recipe file in the input file and creating a "personalized" recipe file where any <sys> and <N> from the recipe template have been filled in according to information from the input file. Attributes: self.input_options <InputOptions>: Input options from input file. self.template_file <str>: Path to the recipe template file self.personal_recipe <str>: Path to the personalized recipe. self.ingredient_list <list of str>: List of ingredients mentioned in the recipe template file. self.chunks <list of list>: List of chunks """ def __init__(self, **kwargs): MASTObj.__init__(self, ALLOWED_KEYS, **kwargs) self.input_options = self.keywords["inputOptions"] self.template_file = self.keywords["templateFile"] self.personal_recipe = self.keywords["personalRecipe"] self.ingredient_list = list() self.metafile = Metadata(metafile="%s/metadata.txt" % self.keywords["working_directory"]) self.chunks = list() def parse(self): """ Parses the template recipe file and creates the personalized recipe file """ if len(self.template_file) == 0: raise MASTError(self.__class__.__name__, "Recipe contents not provided!") if self.input_options is None: raise MASTError(self.__class__.__name__, "Input Options not provided!") if self.personal_recipe is None: raise MASTError(self.__class__.__name__, "Personal recipe file not provided!") # fetch required paramaters # f_ptr = open(self.template_file, "r") recipe_contents = list(self.template_file) # print recipe_contents o_ptr = open(self.personal_recipe, "a") system_name = self.input_options.get_item("mast", "system_name", "sys") n_defects = self.input_options.get_item("defects", "num_defects", 0) d_defects = self.input_options.get_item("defects", "defects") n_images = self.input_options.get_item("neb", "images", 0) d_neblines = self.input_options.get_item("neb", "neblines", {}) recipe_name = None # print system_name, self.input_options.get_item('mast', 'system_name') chunkcount = 0 mychunk = list() modchunk = False for line in recipe_contents: # f_ptr.readlines(): duplicate = line if (len(duplicate) - len(duplicate.lstrip(" "))) % 4 != 0: raise MASTError( "parsers/recipetemplateparser", "Recipe at %s contains incorrect number of whitespace chars at the beginning of the line! Please convert all indentations to the appropriate number of groups of four spaces." % line, ) if "\t" in line: raise MASTError( "parsers/recipetemplateparser", "The tab character exists in recipe template %s. Please convert all tabs to the appropriate number of groups of four spaces." % self.template_file, ) if "{begin}" in line: self.chunks.append(list(mychunk)) mychunk = list() elif "{end}" in line: pass else: mychunk.append(line) if len(mychunk) > 0: self.chunks.append(list(mychunk)) # for chunk in self.chunks: # print chunk input_options_keys = self.input_options.get_sections() key = "personal_recipe" expandedlist = list() if key in input_options_keys: return expandedlist else: for chunk in self.chunks: expanded = self.parse_chunk(chunk) expandedlist.extend(expanded) o_ptr.write("$personal_recipe\n") o_ptr.writelines(expandedlist) o_ptr.write("$end\n") # f_ptr.close() o_ptr.close() return expandedlist # self.chunks[chunkcount]=dict() # self.chunks[chunkcount]['modify'] = modchunk # #line = line.strip() # #line = line.lower() # processing_lines = [] # #shortcut straight copy + 6 # processing_lines.append(line) # output_str = "\n".join(processing_lines) # o_ptr.write("%s\n" % output_str) # f_ptr.close() # o_ptr.close() # print 'in RecipeParser.parse():', list(set(self.ingredient_list)) # return recipe_name def parse_chunk(self, chunk): """Parse a chunk of lines. Args: chunk <list>: List of lines Returns: expandedchunk <list>: List of lines """ origchunk = list(chunk) expandedchunk = list() needsdefects = 0 needscharges = 0 needsphonons = 0 needsnebs = 0 needsscaling = 0 for line in chunk: if "<N>" in line: needsdefects = 1 if "<B-E>" in line: needsnebs = 1 if "<P>" in line: needsphonons = 1 if "<Q>" in line: needscharges = 1 if "<B>" in line: needsnebs = 1 if "<E>" in line: needsnebs = 1 if "<S>" in line: needsscaling = 1 d_scaling = self.input_options.get_item("scaling") d_defects = self.input_options.get_item("defects", "defects") d_nebs = self.input_options.get_item("neb", "nebs") if needsscaling == 1: scalingsize = d_scaling.keys() scalingsize.sort() else: scalingsize = ["1x1x1"] for size in scalingsize: if needsdefects == 1: mydefects = d_defects.keys() mydefects.sort() for defectname in mydefects: for charge in d_defects[defectname]["charge"]: if charge < 0: mycharge = "q=n" + str(int(math.fabs(charge))) else: mycharge = "q=p" + str(int(charge)) if needsphonons == 1: if len(d_defects[defectname]["phonon"].keys()) > 0: phononkeys = d_defects[defectname]["phonon"].keys() phononkeys.sort() for phonon in phononkeys: for line in origchunk: newline = line.replace("<N>", defectname) if needscharges == 1: newline = newline.replace("<Q>", mycharge) if needsscaling == 1: newline = newline.replace("<S>", size) newline = newline.replace("<P>", phonon) expandedchunk.append(newline) else: for line in origchunk: newline = line.replace("<N>", defectname) if needscharges == 1: newline = newline.replace("<Q>", mycharge) if needsscaling == 1: newline = newline.replace("<S>", size) expandedchunk.append(newline) elif needsnebs == 1: nebkeys = d_nebs.keys() nebkeys.sort() for neblabel in nebkeys: defbegin = neblabel.split("-")[0] defend = neblabel.split("-")[1] chargebegin = d_defects[defbegin]["charge"] chargeend = d_defects[defend]["charge"] chargeboth = set(chargebegin) & set(chargeend) for charge in chargeboth: if charge < 0: mycharge = "q=n" + str(int(math.fabs(charge))) else: mycharge = "q=p" + str(int(charge)) if needsphonons == 1: if len(d_nebs[neblabel]["phonon"].keys()) > 0: phononkeys = d_nebs[neblabel]["phonon"].keys() phononkeys.sort() for phonon in phononkeys: for line in origchunk: newline = line.replace("<B>", defbegin) newline = newline.replace("<E>", defend) newline = newline.replace("<B-E>", neblabel) if needscharges == 1: newline = newline.replace("<Q>", mycharge) if needsscaling == 1: newline = newline.replace("<S>", size) newline = newline.replace("<P>", phonon) expandedchunk.append(newline) else: for line in origchunk: newline = line.replace("<B>", defbegin) newline = newline.replace("<E>", defend) newline = newline.replace("<B-E>", neblabel) if needscharges == 1: newline = newline.replace("<Q>", mycharge) if needsscaling == 1: newline = newline.replace("<S>", size) expandedchunk.append(newline) elif needsscaling == 1: for line in origchunk: newline = line.replace("<S>", size) expandedchunk.append(newline) else: expandedchunk = list(origchunk) return expandedchunk # origchunk = list(expandedchunk) # expandedchunk=list() # for defectname in self.d_defects: # for line in origchunk: # newline = line.replace("<N>", defectname) # expandedchunk.append(line) def old_parsing(self): raise MASTError(self.__class__.__name__, "This function is obsolete.") for line in linestr: # validate the input line if not line or line.startswith("#"): continue # collect recipe name line2 = line.split() if line2[0].lower() == "recipe": recipe_name = line2[1] # collect ingredents line2 = line.split() if line2[0].lower() == "ingredient": self.ingredient_list.append(line2[2]) # replace line params<N> # step 1 : replace <sys> with system_name # step 2 : replace <n-n> with appropriate hop combinations # step 3 : replace <img-n> with appropriate image numbers # step 4 : replace <n> with appropriate defect numbers processing_lines.append(line) # step 1 processing_lines = self.process_system_name(processing_lines, system_name) # step 4 processing_lines = self.process_defects(processing_lines, n_defects, d_defects) # step 2 processing_lines = self.process_hop_combinations(processing_lines, d_neblines) # step 3 processing_lines = self.process_images(processing_lines, n_images) self.make_metadata_entries(processing_lines) self.process_phononlines(processing_lines) # dump the processed lines to file output_str = "\n".join(processing_lines) o_ptr.write("%s\n" % output_str) f_ptr.close() o_ptr.close() # print 'in RecipeParser.parse():', list(set(self.ingredient_list)) return recipe_name def process_system_name(self, processing_lines, system_name): """replace <sys> with the system name from the input options """ raise MASTError(self.__class__.__name__, "This function is obsolete.") for index in xrange(len(processing_lines)): processing_lines[index] = processing_lines[index].replace("<sys>", system_name) return processing_lines def process_hop_combinations(self, processing_lines, d_neblines): """replace <n-n> with neb labels which are keys of the neblines dict of the input options. Args: processing_lines <list of str>: recipe lines to process. d_neblines <dict of str>: dictionary of NEB lines. """ raise MASTError(self.__class__.__name__, "This function is obsolete.") new_lines = [] eval_lines = [] if not d_neblines: return processing_lines line = "" for line in processing_lines: if "<n-n>" in line: for neblabel in d_neblines.keys(): n_line = line.replace("<n-n>", neblabel) eval_lines.append(n_line) if "ingredient" in n_line and not "<" in n_line: keyword = n_line.split()[1] data = "neblabel: %s" % neblabel self.metafile.write_data(keyword, data) else: eval_lines.append(line) line = "" for line in eval_lines: # print "TTM DEBUG line: ", line if not "neb" in line.split("_"): # print "TTM DEBUG line safe" new_lines.append(line) else: evalsplit = line.split("child") if len(evalsplit) == 1: new_lines.append(line) else: childsplit = evalsplit[1].split("_") parsplit = evalsplit[0].split("_") okay = 1 for neblabel in d_neblines.keys(): if okay == 1 and (neblabel in childsplit): parlabels = neblabel.split("-") # print "TTM DEBUG: parlabels: ",parlabels # print "TTM DEBUG: parsplit: ",parsplit if not parlabels[0] in parsplit and not (parlabels[1] in parsplit): if not neblabel in parsplit: # image static okay = 0 if okay == 0: pass else: new_lines.append(line) return new_lines def process_images(self, processing_lines, n_images): """replace <img-n> with the equivalent number of lines based on the number of images found in the input_options """ raise MASTError(self.__class__.__name__, "This function is obsolete.") new_lines = [] if not n_images: return processing_lines for line in processing_lines: if "<img-n>" in line: for index in xrange(n_images): n_line = line.replace("<img-n>", str(index + 1).zfill(2)) if "ingredient" in n_line and not "<" in n_line: keyword = n_line.split()[1] data = "name: %s" % keyword self.metafile.write_data(keyword, data) new_lines.append(n_line) else: new_lines.append(line) return new_lines def process_defects(self, processing_lines, n_defects, d_defects): """replace <N> with the equivalent number of lines based on the number of defects given in the input options Args: processing_lines <list of str>: recipe lines to proceess n_defects <int>: number of defected systems d_defects <dict>: dictionary of defects, including labels and positions. """ raise MASTError(self.__class__.__name__, "This function is obsolete.") # import inspect # print 'GRJ DEBUG: %s.%s' % (self.__class__.__name__, inspect.stack()[0][3]) # print d_defects # print 'GRJ DEBUG: parse_defects() working_directory =', self.keywords['working_directory'] new_lines = list() if not n_defects: return processing_lines for line in processing_lines: # print 'GRJ DEBUG: line =', line if ("<n>" in line) or ("<q>" in line): for defect_key in d_defects.keys(): # print 'GRJ DEBUG: defect_key =', defect_key # defect_label = defect_key.split('_')[1] #defect_1, etc. def_line = line.replace("<n>", defect_key) charge_list = d_defects[defect_key]["charge"] # print 'GRJ DEBUG: charge_list =', charge_list # print 'GRJ DEBUG: def_line before charges:', def_line for charge in charge_list: if charge < 0: clabel = "q=n" + str(abs(charge)) else: clabel = "q=p" + str(charge) # print 'GRJ DEBUG: clabel =', clabel new_def_line = def_line.replace("<q>", clabel) new_lines.append(new_def_line) # new_lines.append(def_line.replace('<q>', clabel)) if "ingredient" in def_line: keyword = new_def_line.split()[1] data = "defect_label: %s, charge: %i" % (defect_key, charge) # print 'GRJ DEBUG: def_line, keyword, charge', new_def_line, keyword, charge self.metafile.write_data(keyword, data) else: new_lines.append(line) return new_lines def process_phononlines(self, processing_lines): """add phonon information to the metadata. Does not change line info. """ raise MASTError(self.__class__.__name__, "This function is obsolete.") for line in processing_lines: if "ingredient" in line and "phonon_" in line: nameval = line.split()[1] [dataline, dataval] = self.metafile.search_data(nameval) okay = 0 if not (dataval == None): datapcs = dataval.split(",") for datapc in datapcs: dlabel = datapc.split(":")[0].strip() dval = datapc.split(":")[1].strip() if dlabel == "neblabel" or dlabel == "defect_label": data = "phononlabel: %s" % dval self.metafile.write_data(nameval, data) okay = 1 break if okay == 0: if "perfect" in line: data = "phononlabel: perfect" self.metafile.write_data(nameval, data) okay = 1 else: data = "phononlabel: %s" % nameval self.metafile.write_data(nameval, data) okay = 1 return def make_metadata_entries(self, processing_lines): """Add metadata entry for all ingredients. Does not change line information. """ raise MASTError(self.__class__.__name__, "This function is obsolete.") for line in processing_lines: if "ingredient" in line: nameval = line.split()[1] data = "name: %s" % nameval self.metafile.write_data(nameval, data) return def get_unique_ingredients(self): """fetches the ingredients names""" raise MASTError(self.__class__.__name__, "This function is obsolete.") return list(set(self.ingredient_list))
def write_defected_atom_indices(self): """Write any additional defect atom indices and make manifests. """ defect_dict=self.input_options.get_item('defects','defects') if defect_dict == None: return None dlabels=defect_dict.keys() scales = self.scaling.keys() scales.append("") for scaling_label in scales: alist=list(self.read_manifest_file("%s/manifest_%s__" % (self.sdir, scaling_label))) if scaling_label == "": mySE=SE(struc_work1=self.startstr.copy()) else: mySE=SE(struc_work1=self.startstr.copy(), scaling_size=self.scaling[scaling_label]["mast_size"]) for dlabel in dlabels: dlist = list(alist) manname=os.path.join(self.sdir,"manifest_%s_%s_" % (scaling_label, dlabel)) dsubkeys=defect_dict[dlabel].keys() for dsubkey in dsubkeys: if "subdefect_" in dsubkey: dtype=defect_dict[dlabel][dsubkey]['type'] dcoords=defect_dict[dlabel][dsubkey]['coordinates'] delement=defect_dict[dlabel][dsubkey]['symbol'] if not (scaling_label == ""): dcoords = mySE.get_scaled_coordinates(dcoords) if dtype == "interstitial": didx=self.find_orig_frac_coord_in_atom_indices(dcoords, delement, scaling_label, False, 0.001) if didx == None: akey=self.get_new_key() aname="atom_index_%s" % akey aname = os.path.join(self.sdir, aname) ameta = Metadata(metafile=aname) ameta.write_data("atom_index",akey) ameta.write_data("original_frac_coords", dcoords) ameta.write_data("element", delement) ameta.write_data("scaling_label", scaling_label) dlist.append("%s;int" % akey) #interstitial label else: dlist.append("%s;int" % didx) elif dtype == "vacancy": didx=self.find_orig_frac_coord_in_atom_indices(dcoords, delement, scaling_label, False, 0.001) try: dlist.remove(didx) except ValueError: raise MASTError(self.__class__.__name__, "For defect %s, cannot remove atom index %s from list: %s" % (dlabel, didx, dlist)) elif dtype in ["substitution","antisite"]: didxlist=self.find_orig_frac_coord_in_atom_indices(dcoords, "", scaling_label, True, 0.001) #leave element empty; just search coords idxtorepl=list() for didx in didxlist: dmeta = Metadata(metafile="%s/atom_index_%s" % (self.sdir, didx)) dmetaelem = dmeta.read_data("element") if not (delement == dmetaelem): if didx in dlist: dlist.remove(didx) idxtorepl.append(didx) if len(idxtorepl) > 1: raise MASTError(self.__class__.__name__, "Interstitial %s is attempting to replace more than one atom: %s" % (dlabel, idxtorepl)) didxsub=self.find_orig_frac_coord_in_atom_indices(dcoords, delement, scaling_label, False, 0.001) #leave element empty; just search coords if didxsub == None: akey=self.get_new_key() aname="atom_index_%s" % akey aname = os.path.join(self.sdir, aname) ameta = Metadata(metafile=aname) ameta.write_data("atom_index",akey) ameta.write_data("original_frac_coords", dcoords) ameta.write_data("element", delement) #sub element here ameta.write_data("scaling_label", scaling_label) dlist.append("%s;%s" % (akey, idxtorepl[0])) else: dlist.append("%s;%s" % (didxsub, idxtorepl[0])) self.write_manifest_file(dlist, manname) return
def calculate_single_defect_formation_energy(self, mylabel, conditions, potentials): """Calculate one defect formation energy. Args: mylabel <str>: Defect label conditions <str>: Environment condition, e.g. "As-rich" potentials <dict of float>: Dictionary of chemical potentials, e.g.: potentials['As']=-6.0383 potentials['Ga']=-3.6080 potentials['Bi']=-4.5650 Returns: <float>: Defect formation energy """ pdir = self.dirs[mylabel]['perfect'] ddir = self.dirs[mylabel]['defected'] #Get perfect data perf_meta = Metadata(metafile='%s/%s/metadata.txt' % (self.recdir, pdir)) e_perf = self.get_total_energy(pdir) #e_perf = float(perf_meta.read_data('energy').split(',')[-1]) #Sometimes the energy is listed more than once. efermi = self.get_fermi_energy(pdir) struct_perf = self.get_structure(pdir) perf_species = dict() for site in struct_perf: if (str(site.specie) not in perf_species): perf_species[str(site.specie)] = 1 else: perf_species[str(site.specie)] += 1 #print 'Perfect composition: ', perf_species #Get defected data def_meta = Metadata(metafile='%s/%s/metadata.txt' % (self.recdir, ddir)) #print def_meta label = def_meta.read_data('defect_label') charge = int(def_meta.read_data('charge')) energy = self.get_total_energy(ddir) #energy = float(def_meta.read_data('energy').split(',')[-1]) structure = self.get_structure(ddir) if (label not in self.e_defects[conditions]): self.e_defects[conditions][label] = list() print 'Calculating DFEs for defect %s with charge %3i.' % (label, charge) def_species = dict() for site in structure.sites: if (site.specie not in def_species): def_species[site.specie] = 1 else: def_species[site.specie] += 1 # Find the differences in the number of each atom type # between the perfect and the defect struct_diff = dict() for specie, number in def_species.items(): try: nperf = perf_species[str(specie)] except KeyError: nperf = 0 struct_diff[str(specie)] = number - nperf # Get the potential alignment correction alignment = self.get_potential_alignment(pdir, ddir) # Calculate the base DFE energy e_def = energy - e_perf # E_defect - E_perf print "TTM DEBUG: e_def: ", e_def for specie, number in struct_diff.items(): mu = potentials[str(specie)] #print str(specie), mu, number e_def -= (number * mu) print "TTM DEBUG: number: ", number print "TTM DEBUG: mu: ", mu print "TTM DEBUG: e_def -= number*mu: ", e_def print "TTM DEBUG: charge: ", charge print "TTM DEBUG: alignment: ", alignment print "TTM DEBUG: efermi: ", efermi e_def += charge * (efermi + alignment) # Add in the shift here! print "TTM DEBUG: e_def += charge*(efermi + alignment): ", e_def #print '%-15s%-5i%12.5f%12.5f%12.5f%12.5f' % (label.split('_')[1], charge, energy, e_perf, efermi, alignment) print 'DFE = %f' % e_def self.e_defects[conditions][label].append( (charge, e_def) ) return