コード例 #1
0
def setUpModule():
    """A function that is run ONCE before all unit tests in this module."""
    global database
    database = RMGDatabase()
    database.load(
        path=os.path.join(settings['test_data.directory'], 'testing_database'),
        kinetics_families=['H_Abstraction', 'intra_H_migration'],
        testing=True,
        depository=False,
        solvation=False,
    )
    database.load_forbidden_structures()

    # Prepare the database by loading training reactions and averaging the rate rules
    for family in database.kinetics.families.values():
        family.add_rules_from_training(thermo_database=database.thermo)
        family.fill_rules_by_averaging_up(verbose=True)
コード例 #2
0
class RMGWebDatabase(object):
    """Wrapper class for RMGDatabase that provides loading functionality."""
    def __init__(self):
        self.database = RMGDatabase()
        self.database.kinetics = KineticsDatabase()
        self.database.thermo = ThermoDatabase()
        self.database.transport = TransportDatabase()
        self.database.statmech = StatmechDatabase()
        self.database.solvation = SolvationDatabase()
        self.database.load_forbidden_structures(
            os.path.join(rmgweb.settings.DATABASE_PATH,
                         'forbiddenStructures.py'))
        self.timestamps = {}

    @property
    def kinetics(self):
        """
        Get the kinetics database.
        """
        return self.database.kinetics

    @property
    def thermo(self):
        """
        Get the thermo database.
        """
        return self.database.thermo

    @property
    def transport(self):
        """
        Get the transport database.
        """
        return self.database.transport

    @property
    def statmech(self):
        """
        Get the statmech database.
        """
        return self.database.statmech

    @property
    def solvation(self):
        """
        Get the solvation database.
        """
        return self.database.solvation

    def reset_timestamp(self, path):
        """
        Reset the files timestamp in the dictionary of timestamps.
        """
        mtime = os.stat(path).st_mtime
        self.timestamps[path] = mtime

    def reset_dir_timestamps(self, dirpath):
        """
        Walk the directory tree from dirpath, calling reset_timestamp(file) on each file.
        """
        print(
            "Resetting 'last loaded' timestamps for {0} in process {1}".format(
                dirpath, os.getpid()))
        for root, dirs, files in os.walk(dirpath):
            for name in files:
                self.reset_timestamp(os.path.join(root, name))

    def is_file_modified(self, path):
        """
        Return True if the file at `path` has been modified since `reset_timestamp(path)` was last called.
        """
        # If path doesn't denote a file and were previously
        # tracking it, then it has been removed or the file type
        # has changed, so return True.
        if not os.path.isfile(path):
            return path in self.timestamps

        # If path wasn't being tracked then it's new, so return True
        elif path not in self.timestamps:
            return True

        # Force restart when modification time has changed, even
        # if time now older, as that could indicate older file
        # has been restored.
        elif os.stat(path).st_mtime != self.timestamps[path]:
            return True

        # All the checks have been passed, so the file was not modified
        else:
            return False

    def is_dir_modified(self, dirpath):
        """
        Returns True if anything in the directory at dirpath has been modified since reset_dir_timestamps(dirpath).
        """
        to_check = set(
            [path for path in self.timestamps if path.startswith(dirpath)])
        for root, dirs, files in os.walk(dirpath):
            for name in files:
                path = os.path.join(root, name)
                if self.is_file_modified(path):
                    return True
                to_check.remove(path)
        # If there's anything left in to_check, it's probably now gone and this will return True:
        for path in to_check:
            if self.is_file_modified(path):
                return True
        # Passed all tests.
        return False

    ################################################################################

    def load(self, component='', section=''):
        """
        Load the requested `component` of the RMG database if modified since last loaded.
        """
        if component in ['thermo', '']:
            if section in ['depository', '']:
                dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo',
                                       'depository')
                if self.is_dir_modified(dirpath):
                    self.database.thermo.load_depository(dirpath)
                    self.reset_dir_timestamps(dirpath)
            if section in ['libraries', '']:
                dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo',
                                       'libraries')
                if self.is_dir_modified(dirpath):
                    self.database.thermo.load_libraries(dirpath)
                    # put them in our preferred order, so that when we look up thermo in order to estimate kinetics,
                    # we use our favorite values first.
                    preferred_order = [
                        'primaryThermoLibrary',
                        'DFT_QCI_thermo',
                        'GRI-Mech3.0',
                        'CBS_QB3_1dHR',
                        'KlippensteinH2O2',
                    ]
                    new_order = [
                        i for i in preferred_order
                        if i in self.database.thermo.library_order
                    ]
                    for i in self.database.thermo.library_order:
                        if i not in new_order:
                            new_order.append(i)
                    self.database.thermo.library_order = new_order
                    self.reset_dir_timestamps(dirpath)
            if section in ['groups', '']:
                dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo',
                                       'groups')
                if self.is_dir_modified(dirpath):
                    self.database.thermo.load_groups(dirpath)
                    self.reset_dir_timestamps(dirpath)

        if component in ['transport', '']:
            if section in ['libraries', '']:
                dirpath = os.path.join(rmgweb.settings.DATABASE_PATH,
                                       'transport', 'libraries')
                if self.is_dir_modified(dirpath):
                    self.database.transport.load_libraries(dirpath)
                    self.reset_dir_timestamps(dirpath)
            if section in ['groups', '']:
                dirpath = os.path.join(rmgweb.settings.DATABASE_PATH,
                                       'transport', 'groups')
                if self.is_dir_modified(dirpath):
                    self.database.transport.load_groups(dirpath)
                    self.reset_dir_timestamps(dirpath)

        if component in ['solvation', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'solvation')
            if self.is_dir_modified(dirpath):
                self.database.solvation.load(dirpath)
                self.reset_dir_timestamps(dirpath)

        if component in ['kinetics', '']:
            if section in ['libraries', '']:
                dirpath = os.path.join(rmgweb.settings.DATABASE_PATH,
                                       'kinetics', 'libraries')
                if self.is_dir_modified(dirpath):
                    self.database.kinetics.load_libraries(dirpath)
                    self.reset_dir_timestamps(dirpath)
            if section in ['families', '']:
                dirpath = os.path.join(rmgweb.settings.DATABASE_PATH,
                                       'kinetics', 'families')
                if self.is_dir_modified(dirpath):
                    self.database.kinetics.load_families(dirpath,
                                                         families='all',
                                                         depositories='all')
                    self.reset_dir_timestamps(dirpath)

                    # Make sure to load the entire thermo database prior to adding training values to the rules
                    self.load('thermo', '')
                    for family in self.database.kinetics.families.values():
                        old_entries = len(family.rules.entries)
                        family.add_rules_from_training(
                            thermo_database=self.database.thermo)
                        new_entries = len(family.rules.entries)
                        if new_entries != old_entries:
                            print(
                                '{0} new entries added to {1} family after adding rules '
                                'from training set.'.format(
                                    new_entries - old_entries, family.label))
                        # Filling in rate rules in kinetics families by averaging...
                        family.fill_rules_by_averaging_up()

        if component in ['statmech', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'statmech')
            if self.is_dir_modified(dirpath):
                self.database.statmech.load(dirpath)
                self.reset_dir_timestamps(dirpath)

    def get_transport_database(self, section, subsection):
        """
        Return the component of the transport database corresponding to the
        given `section` and `subsection`. If either of these is invalid, a
        :class:`ValueError` is raised.
        """
        try:
            if section == 'libraries':
                db = self.database.transport.libraries[subsection]
            elif section == 'groups':
                db = self.database.transport.groups[subsection]
            else:
                raise ValueError('Invalid value "%s" for section parameter.' %
                                 section)
        except KeyError:
            raise ValueError('Invalid value "%s" for subsection parameter.' %
                             subsection)

        return db

    def get_solvation_database(self, section, subsection):
        """
        Return the component of the solvation database corresponding to the
        given `section` and `subsection`. If either of these is invalid, a
        :class:`ValueError` is raised.
        """
        try:
            if section == '':
                db = self.database.solvation  # return general SolvationDatabase
            elif section == 'libraries':
                db = self.database.solvation.libraries[subsection]
            elif section == 'groups':
                db = self.database.solvation.groups[subsection]
            else:
                raise ValueError('Invalid value "%s" for section parameter.' %
                                 section)
        except KeyError:
            raise ValueError('Invalid value "%s" for subsection parameter.' %
                             subsection)

        return db

    def get_statmech_database(self, section, subsection):
        """
        Return the component of the statmech database corresponding to the
        given `section` and `subsection`. If either of these is invalid, a
        :class:`ValueError` is raised.
        """
        try:
            if section == 'depository':
                db = self.database.statmech.depository[subsection]
            elif section == 'libraries':
                db = self.database.statmech.libraries[subsection]
            elif section == 'groups':
                db = self.database.statmech.groups[subsection]
            else:
                raise ValueError('Invalid value "%s" for section parameter.' %
                                 section)
        except KeyError:
            raise ValueError('Invalid value "%s" for subsection parameter.' %
                             subsection)

        return db

    def get_thermo_database(self, section, subsection):
        """
        Return the component of the thermodynamics database corresponding to the
        given `section` and `subsection`. If either of these is invalid, a
        :class:`ValueError` is raised.
        """
        try:
            if section == 'depository':
                db = self.database.thermo.depository[subsection]
            elif section == 'libraries':
                db = self.database.thermo.libraries[subsection]
            elif section == 'groups':
                db = self.database.thermo.groups[subsection]
            else:
                raise ValueError('Invalid value "%s" for section parameter.' %
                                 section)
        except KeyError:
            raise ValueError('Invalid value "%s" for subsection parameter.' %
                             subsection)

        return db

    def get_kinetics_database(self, section, subsection):
        """
        Return the component of the kinetics database corresponding to the
        given `section` and `subsection`. If either of these is invalid, a
        :class:`ValueError` is raised.
        """
        db = None
        try:
            if section == 'libraries':
                db = self.database.kinetics.libraries[subsection]
            elif section == 'families':
                subsection = subsection.split('/')
                if subsection[0] != '' and len(subsection) == 2:
                    family = self.database.kinetics.families[subsection[0]]
                    if subsection[1] == 'groups':
                        db = family.groups
                    elif subsection[1] == 'rules':
                        db = family.rules
                    else:
                        label = '{0}/{1}'.format(family.label, subsection[1])
                        db = next((d for d in family.depositories
                                   if d.label == label))
            else:
                raise ValueError('Invalid value "%s" for section parameter.' %
                                 section)
        except (KeyError, StopIteration):
            raise ValueError('Invalid value "%s" for subsection parameter.' %
                             subsection)
        return db