Esempio n. 1
0
 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
Esempio n. 2
0
 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
Esempio n. 3
0
 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 
Esempio n. 4
0
 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
Esempio n. 5
0
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))
Esempio n. 6
0
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)
Esempio n. 7
0
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
Esempio n. 8
0
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))
Esempio n. 9
0
 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 
Esempio n. 10
0
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
Esempio n. 11
0
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)
Esempio n. 12
0
    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