Exemple #1
0
def get_db(name=''):
    """
    Returns the RMG database object that corresponds
    to the parameter name.

    First, the module level is queried. If this variable
    is empty, the broadcasted variables are queried.
    """
    global database

    if database:
        if name == '':
            return database
        elif name == 'kinetics':
            return database.kinetics
        elif name == 'thermo':
            return database.thermo
        elif name == 'transport':
            return database.transport
        elif name == 'solvation':
            return database.solvation
        elif name == 'statmech':
            return database.statmech
        elif name == 'forbidden':
            return database.forbidden_structures
        else:
            raise ValueError('Unrecognized database keyword: {}'.format(name))

    raise DatabaseError('Could not get database with name: {}'.format(name))
Exemple #2
0
    def load_entry(self, index, label, group, kinetics, reference=None, referenceType='', shortDesc='', longDesc='',
                   nodalDistance=None):
        """
        Method for parsing entries in database files.
        Note that these argument names are retained for backward compatibility.

        nodal_distance is the distance between a given entry and its parent specified by a float
        """
        if (group[0:3].upper() == 'OR{' or
                group[0:4].upper() == 'AND{' or
                group[0:7].upper() == 'NOT OR{' or
                group[0:8].upper() == 'NOT AND{'):
            item = make_logic_node(group)
        else:
            item = Group().from_adjacency_list(group)

        if label in self.entries:
            raise DatabaseError("Duplicate group name {label} found in kinetics groups for {family} "
                                "family.".format(label=label, family=self.label))
        self.entries[label] = Entry(
            index=index,
            label=label,
            item=item,
            data=kinetics,
            reference=reference,
            reference_type=referenceType,
            short_desc=shortDesc,
            long_desc=longDesc.strip(),
            nodal_distance=nodalDistance
        )
Exemple #3
0
    def loadEntry(self,
                  index,
                  label,
                  group,
                  kinetics,
                  reference=None,
                  referenceType='',
                  shortDesc='',
                  longDesc='',
                  nodalDistance=None):
        """
        nodalDistance is the distance between a given entry and its parent specified by a float
        """
        if group[0:3].upper() == 'OR{' or group[0:4].upper(
        ) == 'AND{' or group[0:7].upper() == 'NOT OR{' or group[0:8].upper(
        ) == 'NOT AND{':
            item = makeLogicNode(group)
        else:
            item = Group().fromAdjacencyList(group)

        if label in self.entries:
            raise DatabaseError(
                "Duplicate group name {label} found in kinetics groups for {family} family."
                .format(label=label, family=self.label))
        self.entries[label] = Entry(index=index,
                                    label=label,
                                    item=item,
                                    data=kinetics,
                                    reference=reference,
                                    referenceType=referenceType,
                                    shortDesc=shortDesc,
                                    longDesc=longDesc.strip(),
                                    nodalDistance=nodalDistance)
Exemple #4
0
 def loadOld(self, path, groups, numLabels):
     """
     Load a set of old rate rules for kinetics groups into this depository.
     """
     warnings.warn("The old kinetics databases are no longer supported and may be"
                   " removed in version 2.3.", DeprecationWarning)
     # Parse the old library
     entries = self.parseOldLibrary(os.path.join(path, 'rateLibrary.txt'), numParameters=10, numLabels=numLabels)
     
     self.entries = {}
     for entry in entries:
         index, label, data, shortDesc = entry
         if isinstance(data, (str,unicode)):
             kinetics = data
             rank = 0
         elif isinstance(data, tuple) and len(data) == 2:
             kinetics, rank = data
         else:
             raise DatabaseError('Unexpected data {0!r} for entry {1!s}.'.format(data, entry))
         reactants = [groups.entries[l].item for l in label.split(';')]
         item = Reaction(reactants=reactants, products=[])
         entry = Entry(
             index = index,
             label = label,
             item = item,
             data = kinetics,
             rank = rank,
             shortDesc = shortDesc
         )
         try:
             self.entries[label].append(entry)
         except KeyError:
             self.entries[label] = [entry]
     self.__loadOldComments(path)
Exemple #5
0
    def load_recommended_families(self, filepath):
        """
        Load the recommended families from the given file.
        The file is usually stored at 'kinetics/families/recommended.py'.

        The old style was as a dictionary named `recommendedFamilies`
        containing all family names as keys with True/False values.

        The new style is as multiple sets with unique names which can be
        used individually or in combination.

        Both styles can be loaded by this method.
        """
        import imp

        # Load the recommended.py file as a module
        try:
            rec = imp.load_source('rec', filepath)
        except Exception as e:
            raise DatabaseError('Unable to load recommended.py file for kinetics families: {0!s}'.format(e))

        # For backward compatibility, check for old-style recommendedFamilies dictionary
        if hasattr(rec, 'recommendedFamilies'):
            default = set()
            for family, recommended in rec.recommendedFamilies.items():
                if recommended:
                    default.add(family)
            self.recommended_families = {'default': default}
        else:
            self.recommended_families = {name: value
                                         for name, value in rec.__dict__.items()
                                         if not name.startswith('_')}
Exemple #6
0
    def test_write_entry_to_database(self):
        """Test we can write an entry to the database"""

        test_entry = Entry(
            index=100,
            label="Me111",
            binding_energies={
                'H': Energy(0., 'eV/molecule'),
                'C': Energy(0., 'eV/molecule'),
                'N': Energy(0., 'eV/molecule'),
                'O': Energy(0., 'eV/molecule'),
            },
            surface_site_density=SurfaceConcentration(0., 'mol/cm^2'),
            facet="111",
            metal="Me",
            short_desc=u"fcc",
            long_desc=u"""
        Test
            """,
        )

        MetalLib = self.database.libraries['surface']
        self.database.add_entry(test_entry)

        # test to see if the entry was added
        self.assertEqual(
            repr(self.database.get_binding_energies(test_entry.label)),
            repr(test_entry.binding_energies))
        self.assertEqual(
            repr(self.database.get_surface_site_density(test_entry.label)),
            repr(test_entry.surface_site_density))

        # write the new entry
        self.database.save(
            os.path.join(settings['database.directory'], 'surface'))
        # MetalLib.save_entry(os.path.join(settings['database.directory'], 'surface/libraries/metal.py'), test_entry)

        # test to see if entry was written
        with open(
                os.path.join(settings['database.directory'],
                             'surface/libraries/metal.py'), "r") as f:
            if "Me111" in f.read():
                self.database.remove_entry(test_entry)
                self.database.save(
                    os.path.join(settings['database.directory'], 'surface'))
            else:
                raise DatabaseError("Unable to write entry to database.")
Exemple #7
0
def getDB(name=''):
    """
    Returns the RMG database object that corresponds
    to the parameter name.

    First, the module level is queried. If this variable
    is empty, the broadcasted variables are queried.
    """
    global database

    if database:
        if name == '':
            return database
        elif name == 'kinetics':
            return database.kinetics
        elif name == 'thermo':
            return database.thermo
        elif name == 'transport':
            return database.transport
        elif name == 'solvation':
            return database.solvation
        elif name == 'statmech':
            return database.statmech
        elif name == 'forbidden':
            return database.forbiddenStructures
        else:
            raise Exception('Unrecognized database keyword: {}'.format(name))
    else:
        try:
            db = get(name)
            if db:
                return db
            else:
                raise DatabaseError
        except DatabaseError:
            logging.debug(
                "Did not find a way to obtain the broadcasted database for {}."
                .format(name))
            raise

    raise DatabaseError('Could not get database with name: {}'.format(name))
Exemple #8
0
 def loadRecommendedFamiliesList(self, filepath):
     """
     Load the list of recommended families from the given file
     
     The file is usually 'kinetics/families/recommended.py'.
     This is stored as a dictionary of True or False values (checked here),
     and should contain entries for every available family (checked in loadFamilies).
     """
     try:
         global_context = {}
         global_context['__builtins__'] = None
         global_context['True'] = True
         global_context['False'] = False
         local_context = {}
         local_context['__builtins__'] = None
         f = open(filepath, 'r')
         exec f in global_context, local_context
         f.close()
         self.recommendedFamilies = local_context['recommendedFamilies']
     except Exception, e:
         raise DatabaseError(
             'Error while reading list of recommended families from {0}/recommended.py.\n{1}'
             .format(filepath, e))
Exemple #9
0
    def get_reaction_template(self, reaction):
        """
        For a given `reaction` with properly-labeled :class:`Molecule` objects
        as the reactants, determine the most specific nodes in the tree that
        describe the reaction.
        """

        # Get forward reaction template and remove any duplicates
        forward_template = self.top[:]

        temporary = []
        symmetric_tree = False
        for entry in forward_template:
            if entry not in temporary:
                temporary.append(entry)
            else:
                # duplicate node found at top of tree
                # eg. R_recombination: ['Y_rad', 'Y_rad']
                if len(forward_template) != 2:
                    raise DatabaseError('Can currently only do symmetric trees with nothing else in them')
                symmetric_tree = True
        forward_template = temporary

        # Descend reactant trees as far as possible
        template = []
        special_cases = ['peroxyl_disproportionation', 'bimolec_hydroperoxide_decomposition']
        if (len(forward_template) == 1 and len(reaction.reactants) > len(forward_template) and
                self.label.lower().split('/')[0] not in special_cases):
            entry = forward_template[0]
            group = entry.item

            r = None
            for react in reaction.reactants:
                if isinstance(react, Species):
                    react = react.molecule[0]
                if r:
                    r = r.merge(react)
                else:
                    r = deepcopy(react)

            atoms = r.get_all_labeled_atoms()

            matched_node = self.descend_tree(r, atoms, root=entry, strict=True)

            if matched_node is not None:
                template.append(matched_node)

        else:
            for entry in forward_template:
                # entry is a top-level node that should be matched
                group = entry.item

                # Identify the atom labels in a group if it is not a logical node
                atom_list = []
                if not isinstance(entry.item, LogicNode):
                    atom_list = group.get_all_labeled_atoms()

                for reactant in reaction.reactants:
                    if isinstance(reactant, Species):
                        reactant = reactant.molecule[0]
                    # Match labeled atoms
                    # Check that this reactant has each of the atom labels in this group.
                    # If it is a LogicNode, the atom_list is empty and
                    # it will proceed directly to the descend_tree step.
                    if not all([reactant.contains_labeled_atom(label) for label in atom_list]):
                        continue  # don't try to match this structure - the atoms aren't there!
                    # Match structures
                    atoms = reactant.get_all_labeled_atoms()
                    # Descend the tree, making sure to match atomlabels exactly using strict = True
                    matched_node = self.descend_tree(reactant, atoms, root=entry, strict=True)
                    if matched_node is not None:
                        template.append(matched_node)
                    # else:
                    #    logging.warning("Couldn't find match for {0} in {1}".format(entry,atom_list))
                    #    logging.warning(reactant.to_adjacency_list())

            # Get fresh templates (with duplicate nodes back in)
            forward_template = self.top[:]
            if (self.label.lower().startswith('peroxyl_disproportionation') or
                    self.label.lower().startswith('bimolec_hydroperoxide_decomposition')):
                forward_template.append(forward_template[0])

        # Check that we were able to match the template.
        # template is a list of the actual matched nodes
        # forward_template is a list of the top level nodes that should be matched
        if len(template) != len(forward_template):
            msg = 'Unable to find matching template for reaction {0} in reaction family {1}.'.format(str(reaction),
                                                                                                     str(self))
            msg += 'Trying to match {0} but matched {1}'.format(str(forward_template), str(template))
            raise UndeterminableKineticsError(reaction, message=msg)

        return template
Exemple #10
0
def saveEntry(f, entry):
    """
    Save an `entry` in the kinetics database by writing a string to
    the given file object `f`.
    """
    from arkane.output import prettify

    def sortEfficiencies(efficiencies0):
        efficiencies = {}
        for mol, eff in efficiencies0.iteritems():
            if isinstance(mol, str):
                # already in SMILES string format
                smiles = mol
            else:
                smiles = mol.toSMILES()
                
            efficiencies[smiles] = eff
        keys = efficiencies.keys()
        keys.sort()
        return [(key, efficiencies[key]) for key in keys]

    f.write('entry(\n')
    f.write('    index = {0:d},\n'.format(entry.index))
    if entry.label != '':
        f.write('    label = "{0}",\n'.format(entry.label))


    #Entries for kinetic rules, libraries, training reactions
    #and depositories will have a Reaction object for its item
    if isinstance(entry.item, Reaction):
        #Write out additional data if depository or library
        #kinetic rules would have a Group object for its reactants instead of Species
        if isinstance(entry.item.reactants[0], Species):
            # Add degeneracy if the reaction is coming from a depository or kinetics library
            f.write('    degeneracy = {0:.1f},\n'.format(entry.item.degeneracy))
            if entry.item.duplicate:
                f.write('    duplicate = {0!r},\n'.format(entry.item.duplicate))
            if not entry.item.reversible:
                f.write('    reversible = {0!r},\n'.format(entry.item.reversible))
            if entry.item.allow_pdep_route:
                f.write('    allow_pdep_route = {0!r},\n'.format(entry.item.allow_pdep_route))
            if entry.item.elementary_high_p:
                f.write('    elementary_high_p = {0!r},\n'.format(entry.item.elementary_high_p))
            if entry.item.allow_max_rate_violation:
                f.write('    allow_max_rate_violation = {0!r},\n'.format(entry.item.allow_max_rate_violation))
    #Entries for groups with have a group or logicNode for its item
    elif isinstance(entry.item, Group):
        f.write('    group = \n')
        f.write('"""\n')
        f.write(entry.item.toAdjacencyList())
        f.write('""",\n')
    elif isinstance(entry.item, LogicNode):
        f.write('    group = "{0}",\n'.format(entry.item))
    else:
        raise DatabaseError("Encountered unexpected item of type {0} while saving database.".format(entry.item.__class__))

    # Write kinetics
    if isinstance(entry.data, str):
        f.write('    kinetics = "{0}",\n'.format(entry.data))
    elif entry.data is not None:
        efficiencies = None
        if hasattr(entry.data, 'efficiencies'):
            efficiencies = entry.data.efficiencies
            entry.data.efficiencies = dict(sortEfficiencies(entry.data.efficiencies))
        kinetics = prettify(repr(entry.data))
        kinetics = '    kinetics = {0},\n'.format(kinetics.replace('\n', '\n    '))
        f.write(kinetics)
        if hasattr(entry.data, 'efficiencies'):
            entry.data.efficiencies = efficiencies
    else:
        f.write('    kinetics = None,\n')
            
    # Write reference
    if entry.reference is not None:
        reference = entry.reference.toPrettyRepr()
        lines = reference.splitlines()
        f.write('    reference = {0}\n'.format(lines[0]))
        for line in lines[1:-1]:
            f.write('    {0}\n'.format(line))
        f.write('    ),\n'.format(lines[0]))
    
    if entry.referenceType != "":
        f.write('    referenceType = "{0}",\n'.format(entry.referenceType))
    if entry.rank is not None:
        f.write('    rank = {0},\n'.format(entry.rank))
        
    if entry.shortDesc.strip() !='':
        f.write('    shortDesc = u"""')
        try:
            f.write(entry.shortDesc.encode('utf-8'))
        except:
            f.write(entry.shortDesc.strip().encode('ascii', 'ignore')+ "\n")
        f.write('""",\n')
    
    if entry.longDesc.strip() !='':
        f.write('    longDesc = \n')
        f.write('u"""\n')
        try:
            f.write(entry.longDesc.strip().encode('utf-8') + "\n")
        except:
            f.write(entry.longDesc.strip().encode('ascii', 'ignore')+ "\n")
        f.write('""",\n')

    f.write(')\n\n')
Exemple #11
0
    if database:
        if name == 'kinetics':
            return database.kinetics
        elif name == 'thermo':
            return database.thermo
        elif name == 'transport':
            return database.transport
        elif name == 'solvation':
            return database.solvation
        elif name == 'statmech':
            return database.statmech
        elif name == 'forbidden':
            return database.forbiddenStructures
        else:
            raise Exception('Unrecognized database keyword: {}'.format(name))
    else:
        try:
            db = get(name)
            if db:
                return db
            else:
                raise DatabaseError
        except DatabaseError, e:
            logging.debug(
                "Did not find a way to obtain the broadcasted database for {}."
                .format(name))
            raise e

    raise DatabaseError('Could not get database with name: {}'.format(name))
Exemple #12
0
def species(label, *args, **kwargs):
    """Load a species from an input file"""
    global species_dict, job_list
    if label in species_dict:
        raise ValueError(
            'Multiple occurrences of species with label {0!r}.'.format(label))
    logging.info('Loading species {0}...'.format(label))

    spec = Species(label=label)
    species_dict[label] = spec

    path = None
    if len(args) == 1:
        # The argument is a path to a conformer input file
        path = args[0]
        job = StatMechJob(species=spec, path=path)
        logging.debug('Added species {0} to a stat mech job.'.format(label))
        job_list.append(job)
    elif len(args) > 1:
        raise InputError('species {0} can only have two non-keyword argument '
                         'which should be the species label and the '
                         'path to a quantum file.'.format(spec.label))

    if len(kwargs) > 0:
        # The species parameters are given explicitly
        structure = None
        E0 = None
        modes = []
        spin_multiplicity = 0
        optical_isomers = 1
        molecular_weight = None
        collision_model = None
        energy_transfer_model = None
        thermo = None
        reactive = True
        for key, value in kwargs.items():
            if key == 'structure':
                structure = value
            elif key == 'E0':
                E0 = value
            elif key == 'modes':
                modes = value
            elif key == 'spinMultiplicity':
                spin_multiplicity = value
            elif key == 'opticalIsomers':
                optical_isomers = value
            elif key == 'molecularWeight':
                molecular_weight = value
            elif key == 'collisionModel':
                collision_model = value
            elif key == 'energyTransferModel':
                energy_transfer_model = value
            elif key == 'thermo':
                thermo = value
            elif key == 'reactive':
                reactive = value
            else:
                raise TypeError(
                    'species() got an unexpected keyword argument {0!r}.'.
                    format(key))

        if structure:
            spec.molecule = [structure]
        spec.conformer = Conformer(E0=E0,
                                   modes=modes,
                                   spin_multiplicity=spin_multiplicity,
                                   optical_isomers=optical_isomers)
        if molecular_weight is not None:
            spec.molecular_weight = molecular_weight
        elif spec.molecular_weight is None and is_pdep(job_list):
            # If a structure was given, simply calling spec.molecular_weight will calculate the molecular weight
            # If one of the jobs is pdep and no molecular weight is given or calculated, raise an error
            raise ValueError(
                "No molecularWeight was entered for species {0}. Since a structure wasn't given"
                " as well, the molecularWeight, which is important for pressure dependent jobs,"
                " cannot be reconstructed.".format(spec.label))
        spec.transport_data = collision_model
        spec.energy_transfer_model = energy_transfer_model
        spec.thermo = thermo
        spec.reactive = reactive

        if spec.reactive and path is None and spec.thermo is None and spec.conformer.E0 is None:
            if not spec.molecule:
                raise InputError(
                    'Neither thermo, E0, species file path, nor structure specified, cannot estimate'
                    ' thermo properties of species {0}'.format(spec.label))
            try:
                db = get_db('thermo')
                if db is None:
                    raise DatabaseError('Thermo database is None.')
            except DatabaseError:
                logging.warning(
                    "The database isn't loaded, cannot estimate thermo for {0}. "
                    "If it is a bath gas, set reactive = False to avoid generating "
                    "thermo.".format(spec.label))
            else:
                logging.info(
                    'No E0 or thermo found, estimating thermo and E0 of species {0} using'
                    ' RMG-Database...'.format(spec.label))
                spec.thermo = db.get_thermo_data(spec)
                if spec.thermo.E0 is None:
                    th = spec.thermo.to_wilhoit()
                    spec.conformer.E0 = th.E0
                    spec.thermo.E0 = th.E0
                else:
                    spec.conformer.E0 = spec.thermo.E0

        if spec.reactive and spec.thermo and not spec.has_statmech(
        ) and structure is not None:
            # generate stat mech info if it wasn't provided before
            spec.generate_statmech()

        if not energy_transfer_model:
            # default to RMG's method of generating energy_transfer_model
            spec.generate_energy_transfer_model()

    return spec
Exemple #13
0
    def loadFamilies(self, path, families=None, depositories=None):
        """
        Load the kinetics families from the given `path` on disk, where `path`
        points to the top-level folder of the kinetics families.

        The `families` argument accepts a single item or list of the following:
            - Specific kinetics family labels
            - Names of family sets defined in recommended.py
            - 'all'
            - 'none'

        If all items begin with a `!` (e.g. ['!H_Abstraction']), then the
        selection will be inverted to families NOT in the list.
        """
        for (root, dirs, files) in os.walk(os.path.join(path)):
            if root == path:
                break  # all we wanted was the list of dirs in the base path

        all_families = set(dirs)

        # Convert input to a list to simplify processing
        if not isinstance(families, list):
            families = [families]

        # Check for ! syntax, which allows specification of undesired families
        if all(item.startswith('!') for item in families):
            inverse = True
            families = [family[1:] for family in families]
        elif not any(item.startswith('!') for item in families):
            inverse = False
        else:
            raise DatabaseError(
                'Families list must either all or none have prefix "!", but not a mix.'
            )

        # Compile the set of selected families
        selected_families = set()
        for item in families:
            if item.lower() == 'all':
                selected_families = all_families
                break
            elif item.lower() == 'none':
                selected_families = set()
                break
            elif item in self.recommendedFamilies:
                family_set = self.recommendedFamilies[item]
                missing_fams = [
                    fam for fam in family_set if fam not in all_families
                ]
                if missing_fams:
                    raise DatabaseError(
                        'Unable to load recommended set "{0}", '
                        'some families could not be found: {1}'.format(
                            item, missing_fams))
                selected_families.update(family_set)
            elif item in all_families:
                selected_families.add(item)
            else:
                raise DatabaseError(
                    'Unrecognized item "{0}" in list of families to load. '
                    'Items should be names of kinetics families, '
                    'a predefined subset from recommended.py, '
                    'or the "all" or "none" options.'.format(item))

        # If families were specified using ! syntax, invert the selection
        if inverse:
            selected_families = all_families - selected_families

        # Sort alphabetically for consistency, this also converts to a list
        selected_families = sorted(selected_families)

        # Now we know what families to load, so let's load them
        self.families = {}
        for label in selected_families:
            familyPath = os.path.join(path, label)
            family = KineticsFamily(label=label)
            family.load(familyPath,
                        self.local_context,
                        self.global_context,
                        depositoryLabels=depositories)
            self.families[label] = family
Exemple #14
0
class KineticsDatabase(object):
    """
    A class for working with the RMG kinetics database.
    """
    def __init__(self):
        self.recommendedFamilies = {}
        self.families = {}
        self.libraries = {}
        self.libraryOrder = [
        ]  # a list of tuples in the format ('library_label', LibraryType),
        # where LibraryType is set to either 'Reaction Library' or 'Seed'.
        self.local_context = {
            'KineticsData': KineticsData,
            'Arrhenius': Arrhenius,
            'ArrheniusEP': ArrheniusEP,
            'MultiArrhenius': MultiArrhenius,
            'MultiPDepArrhenius': MultiPDepArrhenius,
            'PDepArrhenius': PDepArrhenius,
            'Chebyshev': Chebyshev,
            'ThirdBody': ThirdBody,
            'Lindemann': Lindemann,
            'Troe': Troe,
            'R': constants.R,
        }
        self.global_context = {}

    def __reduce__(self):
        """
        A helper function used when pickling a KineticsDatabase object.
        """
        d = {
            'families': self.families,
            'libraries': self.libraries,
            'libraryOrder': self.libraryOrder,
        }
        return (KineticsDatabase, (), d)

    def __setstate__(self, d):
        """
        A helper function used when unpickling a KineticsDatabase object.
        """
        self.families = d['families']
        self.libraries = d['libraries']
        self.libraryOrder = d['libraryOrder']

    def load(self, path, families=None, libraries=None, depositories=None):
        """
        Load the kinetics database from the given `path` on disk, where `path`
        points to the top-level folder of the families database.
        """
        self.loadRecommendedFamiliesList(
            os.path.join(path, 'families', 'recommended.py')),
        self.loadFamilies(os.path.join(path, 'families'), families,
                          depositories)
        self.loadLibraries(os.path.join(path, 'libraries'), libraries)

    def loadRecommendedFamiliesList(self, filepath):
        """
        Load the list of recommended families from the given file
        
        The file is usually 'kinetics/families/recommended.py'.
        This is stored as a dictionary of True or False values (checked here),
        and should contain entries for every available family (checked in loadFamilies).
        """
        try:
            global_context = {}
            global_context['__builtins__'] = None
            global_context['True'] = True
            global_context['False'] = False
            local_context = {}
            local_context['__builtins__'] = None
            f = open(filepath, 'r')
            exec f in global_context, local_context
            f.close()
            self.recommendedFamilies = local_context['recommendedFamilies']
        except Exception, e:
            raise DatabaseError(
                'Error while reading list of recommended families from {0}/recommended.py.\n{1}'
                .format(filepath, e))
        for recommended in self.recommendedFamilies.values():
            if not isinstance(recommended, bool):
                raise DatabaseError(
                    "recommendedFamilies dictionary should contain only True or False values"
                )
Exemple #15
0
    def loadFamilies(self, path, families=None, depositories=None):
        """
        Load the kinetics families from the given `path` on disk, where `path`
        points to the top-level folder of the kinetics families.
        """

        familiesToLoad = []
        for (root, dirs, files) in os.walk(os.path.join(path)):
            if root == path:
                break  # all we wanted was the list of dirs in the base path

        if families == 'default':
            logging.info(
                'Loading default kinetics families from {0}'.format(path))
            for d in dirs:  # load them in directory listing order, like other methods (better than a random dict order)
                try:
                    recommended = self.recommendedFamilies[d]
                except KeyError:
                    raise DatabaseError(
                        'Family {0} not found in recommendation list (probably at {1}/recommended.py)'
                        .format(d, path))
                if recommended:
                    familiesToLoad.append(d)
            for label, value in self.recommendedFamilies.iteritems():
                if label not in dirs:
                    raise DatabaseError(
                        'Family {0} found (in {1}/recommended.py) not found on disk.'
                        .format(label, path))

        elif families == 'all':
            # All families are loaded
            logging.info(
                'Loading all of the kinetics families from {0}'.format(path))
            for d in dirs:
                familiesToLoad.append(d)
        elif families == 'none':
            logging.info(
                'Not loading any of the kinetics families from {0}'.format(
                    path))
            # Don't load any of the families
            familiesToLoad = []
        elif isinstance(families, list):
            logging.info(
                'Loading the user-specified kinetics families from {0}'.format(
                    path))
            # If all items in the list start with !, all families will be loaded except these
            if len(families) == 0:
                raise DatabaseError(
                    'Kinetics families should be a non-empty list, or set to `default`, `all`, or `none`.'
                )
            elif all([label.startswith('!') for label in families]):
                for d in dirs:
                    if '!{0}'.format(d) not in families:
                        familiesToLoad.append(d)
            elif any([label.startswith('!') for label in families]):
                raise DatabaseError(
                    'Families list must either all or none have prefix "!", but not a mix.'
                )
            else:  # only the families given will be loaded
                for d in dirs:
                    if d in families:
                        familiesToLoad.append(d)
                for label in families:
                    if label not in dirs:
                        raise DatabaseError(
                            'Family {0} not found on disk.'.format(label))
        else:
            raise DatabaseError(
                'Kinetics families was not specified properly.  Should be set to `default`,`all`,`none`, or a list.'
            )

        # Now we know what families to load, so let's load them
        self.families = {}
        for label in familiesToLoad:
            familyPath = os.path.join(path, label)
            family = KineticsFamily(label=label)
            family.load(familyPath,
                        self.local_context,
                        self.global_context,
                        depositoryLabels=depositories)
            self.families[label] = family