예제 #1
0
def convertPrIMe(family):

    print 'Loading kinetics families...'
    database = RMGDatabase()
    database.kinetics = KineticsDatabase()
    database.kinetics.loadFamilies('input/kinetics/families')
    database.loadForbiddenStructures('input/forbiddenStructures.py')

    for depository in database.kinetics.families[family].depositories:
        if depository.label == '{0}/PrIMe'.format(family):
            break
    else:
        raise Exception(
            'Could not find PrIMe depository in {0} family.'.format(family))

    entries = []

    print 'Determining unique list of reactions...'
    for entry0 in depository.entries.values():
        for entry in entries:
            if entry.item.isIsomorphic(entry0.item):
                break
        else:
            entries.append(entry0)
    print 'Found {0:d} unique reactions out of {1:d} entries.'.format(
        len(entries), len(depository.entries))

    print 'Sorting unique reactions...'
    entries.sort(key=lambda entry: sum([
        1 for r in entry.item.reactants for a in r.atoms if a.isNonHydrogen()
    ]))

    print 'Saving reactions...'
    for index, entry in enumerate(entries):

        label = entry.label
        reaction = entry.item

        # Determine degeneracy in both directions
        reactions = database.kinetics.generateReactionsFromFamilies(
            reaction.reactants, reaction.products, only_families=[family])
        if len(reactions) != 1:
            print 'Warning: could not determine forward degeneracy for reaction #{0:d}.'.format(
                index + 1)
            forwardDegeneracy = 1
        else:
            forwardDegeneracy = reactions[0].degeneracy
        reactions = database.kinetics.generateReactionsFromFamilies(
            reaction.products, reaction.reactants, only_families=[family])
        if len(reactions) != 1:
            print 'Warning: could not determine reverse degeneracy for reaction #{0:d}.'.format(
                index + 1)
            reverseDegeneracy = 1
        else:
            reverseDegeneracy = reactions[0].degeneracy

        saveReaction(
            'input/kinetics/families/{0}/training/{0}.py'.format(
                family, index + 1), index + 1, label, reaction,
            forwardDegeneracy, reverseDegeneracy)
예제 #2
0
def convertPrIMe(family):

    print 'Loading kinetics families...'
    database = RMGDatabase()
    database.kinetics = KineticsDatabase()
    database.kinetics.loadFamilies('input/kinetics/families')
    database.loadForbiddenStructures('input/forbiddenStructures.py')
    
    for depository in database.kinetics.families[family].depositories:
        if depository.label == '{0}/PrIMe'.format(family):
            break
    else:
        raise Exception('Could not find PrIMe depository in {0} family.'.format(family))
    
    entries = []
    
    print 'Determining unique list of reactions...'
    for entry0 in depository.entries.values():
        for entry in entries:
            if entry.item.isIsomorphic(entry0.item):
                break
        else:
            entries.append(entry0)
    print 'Found {0:d} unique reactions out of {1:d} entries.'.format(len(entries), len(depository.entries))
    
    print 'Sorting unique reactions...'
    entries.sort(key=lambda entry: sum([1 for r in entry.item.reactants for a in r.atoms if a.isNonHydrogen()]))
    
    print 'Saving reactions...'
    for index, entry in enumerate(entries):
        
        label = entry.label
        reaction = entry.item
        
        # Determine degeneracy in both directions
        reactions = database.kinetics.generateReactionsFromFamilies(reaction.reactants, reaction.products, only_families=[family])
        if len(reactions) != 1:
            print 'Warning: could not determine forward degeneracy for reaction #{0:d}.'.format(index+1)
            forwardDegeneracy = 1
        else:
            forwardDegeneracy = reactions[0].degeneracy
        reactions = database.kinetics.generateReactionsFromFamilies(reaction.products, reaction.reactants, only_families=[family])
        if len(reactions) != 1:
            print 'Warning: could not determine reverse degeneracy for reaction #{0:d}.'.format(index+1)
            reverseDegeneracy = 1
        else:
            reverseDegeneracy = reactions[0].degeneracy
        
        saveReaction('input/kinetics/families/{0}/training/{0}.py'.format(family, index+1), index+1, label, reaction, forwardDegeneracy, reverseDegeneracy)
예제 #3
0
def loadDatabase(component='', section=''):
    """
    Load the requested `component` of the RMG database if modified since last loaded.
    """
    global database
    if not database:
        database = RMGDatabase()
        database.thermo = ThermoDatabase()
        database.kinetics = KineticsDatabase()
        database.loadForbiddenStructures(os.path.join(settings.DATABASE_PATH, 'forbiddenStructures.py'))

    if component in ['thermo', '']:
        if section in ['depository', '']:
            dirpath = os.path.join(settings.DATABASE_PATH, 'thermo', 'depository')
            if isDirModified(dirpath):
                database.thermo.loadDepository(dirpath)
                resetDirTimestamps(dirpath)
        if section in ['libraries', '']:
            dirpath = os.path.join(settings.DATABASE_PATH, 'thermo', 'libraries')
            if isDirModified(dirpath):
                database.thermo.loadLibraries(dirpath)
                # put them in our preferred order, so that when we look up thermo in order to estimate kinetics,
                # we use our favourite 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 database.thermo.libraryOrder]
                for i in database.thermo.libraryOrder:
                    if i not in new_order: new_order.append(i) 
                database.thermo.libraryOrder = new_order
                resetDirTimestamps(dirpath)
        if section in ['groups', '']:
            dirpath = os.path.join(settings.DATABASE_PATH, 'thermo', 'groups')
            if isDirModified(dirpath):
                database.thermo.loadGroups(dirpath)
                resetDirTimestamps(dirpath)
    if component in ['kinetics', '']:
        if section in ['libraries', '']:
            dirpath = os.path.join(settings.DATABASE_PATH, 'kinetics', 'libraries')
            if isDirModified(dirpath):
                database.kinetics.loadLibraries(dirpath)
                resetDirTimestamps(dirpath)
        if section in ['families', '']:
            dirpath = os.path.join(settings.DATABASE_PATH, 'kinetics', 'families')
            if isDirModified(dirpath):
                database.kinetics.loadFamilies(dirpath)
                resetDirTimestamps(dirpath)

    return database
예제 #4
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'),
        kineticsFamilies=['H_Abstraction', 'intra_H_migration'],
        testing=True,
        depository=False,
        solvation=False,
    )
    database.loadForbiddenStructures()

    # Prepare the database by loading training reactions and averaging the rate rules
    for family in database.kinetics.families.values():
        family.addKineticsRulesFromTrainingSet(thermoDatabase=database.thermo)
        family.fillKineticsRulesByAveragingUp(verbose=True)
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'),
        kineticsFamilies=[
            'H_Abstraction','intra_H_migration'
        ],
        testing=True,
        depository=False,
        solvation=False,
    )
    database.loadForbiddenStructures()

    # Prepare the database by loading training reactions and averaging the rate rules
    for family in database.kinetics.families.values():
        family.addKineticsRulesFromTrainingSet(thermoDatabase=database.thermo)
        family.fillKineticsRulesByAveragingUp(verbose=True)
예제 #6
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'),
        thermoLibraries=['primaryThermoLibrary'],
        reactionLibraries=['GRI-Mech3.0'],
        kineticsFamilies=[
            'R_Recombination',
            'Disproportionation',
            'R_Addition_MultipleBond',
        ],
        testing=True,
        depository=False,
        solvation=False,
    )
    database.loadForbiddenStructures()

    # Prepare the database by loading training reactions and averaging the rate rules
    for family in database.kinetics.families.values():
        family.addKineticsRulesFromTrainingSet(thermoDatabase=database.thermo)
        family.fillKineticsRulesByAveragingUp(verbose=True)
예제 #7
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'),
        thermoLibraries=['primaryThermoLibrary'],
        reactionLibraries=['GRI-Mech3.0'],
        kineticsFamilies=[
            'R_Recombination',
            'Disproportionation',
            'R_Addition_MultipleBond',
        ],
        testing=True,
        depository=False,
        solvation=False,
    )
    database.loadForbiddenStructures()

    # Prepare the database by loading training reactions and averaging the rate rules
    for family in database.kinetics.families.values():
        family.addKineticsRulesFromTrainingSet(thermoDatabase=database.thermo)
        family.fillKineticsRulesByAveragingUp(verbose=True)
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.loadForbiddenStructures(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.loadDepository(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.loadLibraries(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.libraryOrder]
                    for i in self.database.thermo.libraryOrder:
                        if i not in new_order:
                            new_order.append(i)
                    self.database.thermo.libraryOrder = 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.loadGroups(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.loadLibraries(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.loadGroups(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.loadLibraries(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.loadFamilies(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():
                        oldentries = len(family.rules.entries)
                        family.addKineticsRulesFromTrainingSet(thermoDatabase=self.database.thermo)
                        newentries = len(family.rules.entries)
                        if newentries != oldentries:
                            print '{0} new entries added to {1} family after adding rules from training set.'.format(
                                newentries - oldentries, family.label)
                        # Filling in rate rules in kinetics families by averaging...
                        family.fillKineticsRulesByAveragingUp()

        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 = (d for d in family.depositories if d.label == label).next()
            else:
                raise ValueError('Invalid value "%s" for section parameter.' % section)
        except (KeyError, StopIteration):
            raise ValueError('Invalid value "%s" for subsection parameter.' % subsection)
        return db
예제 #9
0
def loadDatabase(component='', section=''):
    """
    Load the requested `component` of the RMG database if modified since last loaded.
    """
    global database
    if not database:
        database = RMGDatabase()
        database.solvation = SolvationDatabase()
        database.thermo = ThermoDatabase()
        database.kinetics = KineticsDatabase()
        database.transport = TransportDatabase()
        database.statmech = StatmechDatabase()
        database.loadForbiddenStructures(
            os.path.join(rmgweb.settings.DATABASE_PATH,
                         'forbiddenStructures.py'))

    if component == 'initialize':
        return database
    if component in ['thermo', '']:
        if section in ['depository', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo',
                                   'depository')
            if isDirModified(dirpath):
                database.thermo.loadDepository(dirpath)
                resetDirTimestamps(dirpath)
        if section in ['libraries', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo',
                                   'libraries')
            if isDirModified(dirpath):
                database.thermo.loadLibraries(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 database.thermo.libraryOrder
                ]
                for i in database.thermo.libraryOrder:
                    if i not in new_order: new_order.append(i)
                database.thermo.libraryOrder = new_order
                resetDirTimestamps(dirpath)
        if section in ['groups', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo',
                                   'groups')
            if isDirModified(dirpath):
                database.thermo.loadGroups(dirpath)
                resetDirTimestamps(dirpath)

    if component in ['transport', '']:
        if section in ['libraries', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'transport',
                                   'libraries')
            if isDirModified(dirpath):
                database.transport.loadLibraries(dirpath)
                resetDirTimestamps(dirpath)
        if section in ['groups', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'transport',
                                   'groups')
            if isDirModified(dirpath):
                database.transport.loadGroups(dirpath)
                resetDirTimestamps(dirpath)

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

    if component in ['kinetics', '']:
        if section in ['libraries', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'kinetics',
                                   'libraries')
            if isDirModified(dirpath):
                database.kinetics.loadLibraries(dirpath)
                resetDirTimestamps(dirpath)
        if section in ['families', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'kinetics',
                                   'families')
            if isDirModified(dirpath):
                database.kinetics.loadFamilies(dirpath,
                                               families='all',
                                               depositories='all')
                resetDirTimestamps(dirpath)

                # Make sure to load the entire thermo database prior to adding training values to the rules
                loadDatabase('thermo', '')
                for family in database.kinetics.families.values():
                    oldentries = len(family.rules.entries)
                    family.addKineticsRulesFromTrainingSet(
                        thermoDatabase=database.thermo)
                    newentries = len(family.rules.entries)
                    if newentries != oldentries:
                        print '{0} new entries added to {1} family after adding rules from training set.'.format(
                            newentries - oldentries, family.label)
                    # Filling in rate rules in kinetics families by averaging...
                    family.fillKineticsRulesByAveragingUp()

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

    return database
예제 #10
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.loadForbiddenStructures(
            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.loadDepository(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.loadLibraries(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.libraryOrder
                    ]
                    for i in self.database.thermo.libraryOrder:
                        if i not in new_order:
                            new_order.append(i)
                    self.database.thermo.libraryOrder = 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.loadGroups(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.loadLibraries(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.loadGroups(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.loadLibraries(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.loadFamilies(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():
                        oldentries = len(family.rules.entries)
                        family.addKineticsRulesFromTrainingSet(
                            thermoDatabase=self.database.thermo)
                        newentries = len(family.rules.entries)
                        if newentries != oldentries:
                            print '{0} new entries added to {1} family after adding rules from training set.'.format(
                                newentries - oldentries, family.label)
                        # Filling in rate rules in kinetics families by averaging...
                        family.fillKineticsRulesByAveragingUp()

        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 = (d for d in family.depositories
                              if d.label == label).next()
            else:
                raise ValueError('Invalid value "%s" for section parameter.' %
                                 section)
        except (KeyError, StopIteration):
            raise ValueError('Invalid value "%s" for subsection parameter.' %
                             subsection)
        return db
예제 #11
0
def loadDatabase(component='', section=''):
    """
    Load the requested `component` of the RMG database if modified since last loaded.
    """
    global database
    if not database:
        database = RMGDatabase()
        database.solvation = SolvationDatabase()
        database.thermo = ThermoDatabase()
        database.kinetics = KineticsDatabase()
        database.transport = TransportDatabase()
        database.statmech = StatmechDatabase()
        database.loadForbiddenStructures(os.path.join(rmgweb.settings.DATABASE_PATH, 'forbiddenStructures.py'))

    if component == 'initialize':
        return database
    if component in ['thermo', '']:
        if section in ['depository', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo', 'depository')
            if isDirModified(dirpath):
                database.thermo.loadDepository(dirpath)
                resetDirTimestamps(dirpath)
        if section in ['libraries', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo', 'libraries')
            if isDirModified(dirpath):
                database.thermo.loadLibraries(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 database.thermo.libraryOrder]
                for i in database.thermo.libraryOrder:
                    if i not in new_order: new_order.append(i) 
                database.thermo.libraryOrder = new_order
                resetDirTimestamps(dirpath)
        if section in ['groups', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'thermo', 'groups')
            if isDirModified(dirpath):
                database.thermo.loadGroups(dirpath)
                resetDirTimestamps(dirpath)  
                              
    if component in ['transport', '']:
        if section in ['libraries', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'transport', 'libraries')
            if isDirModified(dirpath):
                database.transport.loadLibraries(dirpath)
                resetDirTimestamps(dirpath)
        if section in ['groups', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'transport', 'groups')
            if isDirModified(dirpath):
                database.transport.loadGroups(dirpath)
                resetDirTimestamps(dirpath)
                
    if component in ['solvation', '']:
        dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'solvation')
        if isDirModified(dirpath):
            database.solvation.load(dirpath)
            resetDirTimestamps(dirpath)
                
    if component in ['kinetics', '']:
        if section in ['libraries', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'kinetics', 'libraries')
            if isDirModified(dirpath):
                database.kinetics.loadLibraries(dirpath)
                resetDirTimestamps(dirpath)
        if section in ['families', '']:
            dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'kinetics', 'families')
            if isDirModified(dirpath):
                database.kinetics.loadFamilies(dirpath, families = 'all', depositories = 'all')
                resetDirTimestamps(dirpath)
                
                # Make sure to load the entire thermo database prior to adding training values to the rules
                loadDatabase('thermo','')
                for family in database.kinetics.families.values():
                    oldentries = len(family.rules.entries)
                    family.addKineticsRulesFromTrainingSet(thermoDatabase=database.thermo)
                    newentries = len(family.rules.entries)
                    if newentries != oldentries:
                        print '{0} new entries added to {1} family after adding rules from training set.'.format(newentries-oldentries, family.label)
                    # Filling in rate rules in kinetics families by averaging...
                    family.fillKineticsRulesByAveragingUp()
                    
    if component in ['statmech', '']:
        dirpath = os.path.join(rmgweb.settings.DATABASE_PATH, 'statmech')
        if isDirModified(dirpath):
            database.statmech.load(dirpath)
            resetDirTimestamps(dirpath)

    return database
예제 #12
0
class TestReact(unittest.TestCase):
    def setUp(self):
        """
        A function run before each unit test in this class.
        """

        # load kinetics database
        db_path = settings['database.directory']
        self.database = RMGDatabase()

        # forbidden structure loading
        self.database.loadForbiddenStructures(
            os.path.join(db_path, 'forbiddenStructures.py'))
        # kinetics family loading
        self.database.loadKinetics(os.path.join(db_path, 'kinetics'),
                                   kineticsFamilies=[
                                       'R_Recombination', 'H_Abstraction',
                                       '1,2_Insertion_carbene'
                                   ],
                                   reactionLibraries=[])

    def test_react_fragments1(self):

        frag1 = afm.fragment.Fragment(
            label='frag1').from_SMILES_like_string('c1ccccc1CCCR')
        fragment_tuple = (frag1, )
        reactions = afm.react.react_fragments(
            self.database.kinetics,
            fragment_tuple,
            only_families=['R_Recombination'],
            prod_resonance=False)

        self.assertTrue(len(reactions) == 28)

    def test_react_fragments2(self):

        frag1 = afm.fragment.Fragment(
            label='frag1').from_SMILES_like_string('c1ccccc1CCCR')
        frag2 = afm.fragment.Fragment(
            label='frag2').from_SMILES_like_string('[CH2]CR')
        fragment_tuple = (frag1, frag2)
        reactions = afm.react.react_fragments(self.database.kinetics,
                                              fragment_tuple,
                                              only_families=['H_Abstraction'],
                                              prod_resonance=False)

        self.assertTrue(len(reactions) == 11)

    def test_generate_reactions_from_families1(self):

        frag1 = afm.fragment.Fragment(
            label='frag1').from_SMILES_like_string('CC')
        spec1 = Species(molecule=[frag1])
        spec_tuple = (spec1, )

        reactions = self.database.kinetics.generate_reactions_from_families(
            spec_tuple)

        self.assertTrue(len(reactions) == 3)

    def test_generate_reactions_from_families2(self):

        frag1 = afm.fragment.Fragment(
            label='frag1').from_SMILES_like_string('CCR')
        spec1 = Species(molecule=[frag1])
        spec_tuple = (spec1, )

        reactions = self.database.kinetics.generate_reactions_from_families(
            spec_tuple)

        self.assertTrue(len(reactions) == 4)