Skip to content

Commit 76fd810

Browse files
committed
Add species constraints checks to input species, seed, and reaction libraries.
Explicitly allow species by using the `allowed` flag in generatedSpeciesConstraints, which can be set to a list with 'input species','reaction libraries', or 'seed mechanisms' (or any combination of these categories). The species from the specified categories can bypass and ignore species constraints given in the input file. They are also added to a list of explicitlyAllowedMolecules. However, all family forbidden and globally forbidden groups are still forbidden. Additionally, now prints warnings for globally forbidden but allowed molecules. And gives exceptions if they were not allowed to begin with.
1 parent e5f7125 commit 76fd810

File tree

4 files changed

+95
-3
lines changed

4 files changed

+95
-3
lines changed

rmgpy/data/kinetics/family.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,7 @@ def __generateProductStructures(self, reactantStructures, maps, forward, **optio
11261126

11271127
# Apply the generated species constraints (if given)
11281128
if options:
1129+
explicitlyAllowedMolecules = options.get('explicitlyAllowedMolecules')
11291130
maxCarbonAtoms = options.get('maximumCarbonAtoms', 1000000)
11301131
maxHydrogenAtoms = options.get('maximumHydrogenAtoms', 1000000)
11311132
maxOxygenAtoms = options.get('maximumOxygenAtoms', 1000000)
@@ -1135,6 +1136,13 @@ def __generateProductStructures(self, reactantStructures, maps, forward, **optio
11351136
maxHeavyAtoms = options.get('maximumHeavyAtoms', 1000000)
11361137
maxRadicals = options.get('maximumRadicalElectrons', 1000000)
11371138
for struct in productStructures:
1139+
allowed = False
1140+
for molecule in explicitlyAllowedMolecules:
1141+
if struct.isIsomorphic(molecule):
1142+
allowed = True
1143+
break
1144+
if allowed:
1145+
continue
11381146
H = struct.getNumAtoms('H')
11391147
if struct.getNumAtoms('C') > maxCarbonAtoms:
11401148
raise ForbiddenStructureException()

rmgpy/rmg/input.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ def options(units='si', saveRestartPeriod=None, drawMolecules=False, generatePlo
253253

254254
def generatedSpeciesConstraints(**kwargs):
255255
validConstraints = [
256+
'allowed',
256257
'maximumCarbonAtoms',
257258
'maximumHydrogenAtoms',
258259
'maximumOxygenAtoms',

rmgpy/rmg/main.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
from rmgpy.solver.base import TerminationTime, TerminationConversion
5151
from rmgpy.solver.simple import SimpleReactor
5252
from rmgpy.data.rmg import RMGDatabase
53+
from rmgpy.data.base import ForbiddenStructureException
5354
from rmgpy.data.kinetics import KineticsLibrary, KineticsFamily, LibraryReaction, TemplateReaction
5455

5556
from rmgpy.reaction import Reaction
@@ -174,6 +175,7 @@ def loadInput(self, path=None):
174175
from input import readInputFile
175176
if path is None: path = self.inputFile
176177
readInputFile(path, self)
178+
self.speciesConstraints['explicitlyAllowedMolecules'] = []
177179
self.reactionModel.kineticsEstimator = self.kineticsEstimator
178180
# If the output directory is not yet set, then set it to the same
179181
# directory as the input file by default
@@ -346,6 +348,20 @@ def initialize(self, args):
346348
for library, option in self.reactionLibraries:
347349
self.reactionModel.addReactionLibraryToEdge(library)
348350

351+
# Perform species constraints and forbidden species checks on input species
352+
for spec in self.initialSpecies:
353+
if self.database.forbiddenStructures.isMoleculeForbidden(spec.molecule[0]):
354+
if 'allowed' in self.speciesConstraints and 'input species' in self.speciesConstraints['allowed']:
355+
logging.warning('Input species {0} is globally forbidden. It will behave as an inert unless found in a seed mechanism or reaction library.'.format(spec.label))
356+
else:
357+
raise ForbiddenStructureException("Input species {0} is globally forbidden. You may explicitly allow it, but it will remain inert unless found in a seed mechanism or reaction library.".format(spec.label))
358+
if self.reactionModel.failsSpeciesConstraints(spec):
359+
if 'allowed' in self.speciesConstraints and 'input species' in self.speciesConstraints['allowed']:
360+
self.speciesConstraints['explicitlyAllowedMolecules'].append(spec.molecule[0])
361+
pass
362+
else:
363+
raise ForbiddenStructureException("Species constraints forbids input species {0}. Please reformulate constraints, remove the species, or explicitly allow it.".format(spec.label))
364+
349365
# Add nonreactive species (e.g. bath gases) to core first
350366
# This is necessary so that the PDep algorithm can identify the bath gas
351367
self.reactionModel.enlarge([spec for spec in self.initialSpecies if not spec.reactive])

rmgpy/rmg/model.py

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
from rmgpy.pdep import SingleExponentialDown
4848
from rmgpy.statmech import Conformer
4949

50-
from rmgpy.data.base import Entry
50+
from rmgpy.data.base import Entry, ForbiddenStructureException
5151
from rmgpy.data.thermo import *
5252
from rmgpy.data.solvation import *
5353
from rmgpy.data.kinetics import *
@@ -1282,10 +1282,25 @@ def addSeedMechanismToCore(self, seedMechanism, react=False):
12821282
for entry in seedMechanism.entries.values():
12831283
rxn = LibraryReaction(reactants=entry.item.reactants[:], products=entry.item.products[:], library=seedMechanism, kinetics=entry.data)
12841284
r, isNew = self.makeNewReaction(rxn) # updates self.newSpeciesList and self.newReactionlist
1285+
1286+
# Perform species constraints and forbidden species checks
1287+
12851288
for spec in self.newSpeciesList:
1289+
if database.forbiddenStructures.isMoleculeForbidden(spec.molecule[0]):
1290+
if 'allowed' in self.speciesConstraints and 'seed mechanisms' in self.speciesConstraints['allowed']:
1291+
logging.warning("Species {0} from seed mechanism {1} is globally forbidden. It will behave as an inert unless found in a seed mechanism or reaction library.".format(spec.label, seedMechanism.label))
1292+
else:
1293+
raise ForbiddenStructureException("Species {0} from seed mechanism {1} is globally forbidden. You may explicitly allow it, but it will remain inert unless found in a seed mechanism or reaction library.".format(spec.label, seedMechanism.label))
1294+
if self.failsSpeciesConstraints(spec):
1295+
if 'allowed' in self.speciesConstraints and 'seed mechanisms' in self.speciesConstraints['allowed']:
1296+
self.speciesConstraints['explicitlyAllowedMolecules'].append(spec.molecule[0])
1297+
pass
1298+
else:
1299+
raise ForbiddenStructureException("Species constraints forbids species {0} from seed mechanism {1}. Please reformulate constraints, remove the species, or explicitly allow it.".format(spec.label, seedMechanism.label))
1300+
1301+
for spec in self.newSpeciesList:
12861302
if spec.reactive: spec.generateThermoData(database, quantumMechanics=self.quantumMechanics)
12871303
spec.generateTransportData(database)
1288-
for spec in self.newSpeciesList:
12891304
self.addSpeciesToCore(spec)
12901305

12911306
for rxn in self.newReactionList:
@@ -1332,10 +1347,24 @@ def addReactionLibraryToEdge(self, reactionLibrary):
13321347
rxn = LibraryReaction(reactants=entry.item.reactants[:], products=entry.item.products[:], library=reactionLibrary, kinetics=entry.data)
13331348
r, isNew = self.makeNewReaction(rxn) # updates self.newSpeciesList and self.newReactionlist
13341349
if not isNew: logging.info("This library reaction was not new: {0}".format(rxn))
1350+
1351+
# Perform species constraints and forbidden species checks
1352+
for spec in self.newSpeciesList:
1353+
if database.forbiddenStructures.isMoleculeForbidden(spec.molecule[0]):
1354+
if 'allowed' in self.speciesConstraints and 'reaction libraries' in self.speciesConstraints['allowed']:
1355+
logging.warning("Species {0} from reaction library {1} is globally forbidden. It will behave as an inert unless found in a seed mechanism or reaction library.".format(spec.label, reactionLibrary.label))
1356+
else:
1357+
raise ForbiddenStructureException("Species {0} from reaction library {1} is globally forbidden. You may explicitly allow it, but it will remain inert unless found in a seed mechanism or reaction library.".format(spec.label, reactionLibrary.label))
1358+
if self.failsSpeciesConstraints(spec):
1359+
if 'allowed' in self.speciesConstraints and 'reaction libraries' in self.speciesConstraints['allowed']:
1360+
self.speciesConstraints['explicitlyAllowedMolecules'].append(spec.molecule[0])
1361+
pass
1362+
else:
1363+
raise ForbiddenStructureException("Species constraints forbids species {0} from reaction library {1}. Please reformulate constraints, remove the species, or explicitly allow it.".format(spec.label, reactionLibrary.label))
1364+
13351365
for spec in self.newSpeciesList:
13361366
if spec.reactive: spec.generateThermoData(database, quantumMechanics=self.quantumMechanics)
13371367
spec.generateTransportData(database)
1338-
for spec in self.newSpeciesList:
13391368
self.addSpeciesToEdge(spec)
13401369

13411370
for rxn in self.newReactionList:
@@ -1676,3 +1705,41 @@ def saveChemkinFile(self, path, verbose_path, dictionaryPath=None, transportPath
16761705
saveChemkinFile(verbose_path, speciesList, rxnList, verbose = True, checkForDuplicates=False)
16771706
if dictionaryPath:
16781707
saveSpeciesDictionary(dictionaryPath, speciesList)
1708+
1709+
def failsSpeciesConstraints(self, species):
1710+
"""
1711+
Checks whether the species passes the speciesConstraints set by the user. If not,
1712+
returns `True` for failing speciesConstraints.
1713+
"""
1714+
explicitlyAllowedMolecules = self.speciesConstraints.get('explicitlyAllowedMolecules')
1715+
maxCarbonAtoms = self.speciesConstraints.get('maximumCarbonAtoms', 1000000)
1716+
maxHydrogenAtoms = self.speciesConstraints.get('maximumHydrogenAtoms', 1000000)
1717+
maxOxygenAtoms = self.speciesConstraints.get('maximumOxygenAtoms', 1000000)
1718+
maxNitrogenAtoms = self.speciesConstraints.get('maximumNitrogenAtoms', 1000000)
1719+
maxSiliconAtoms = self.speciesConstraints.get('maximumSiliconAtoms', 1000000)
1720+
maxSulfurAtoms = self.speciesConstraints.get('maximumSulfurAtoms', 1000000)
1721+
maxHeavyAtoms = self.speciesConstraints.get('maximumHeavyAtoms', 1000000)
1722+
maxRadicals = self.speciesConstraints.get('maximumRadicalElectrons', 1000000)
1723+
1724+
struct = species.molecule[0]
1725+
for molecule in explicitlyAllowedMolecules:
1726+
if struct.isIsomorphic(molecule):
1727+
return False
1728+
H = struct.getNumAtoms('H')
1729+
if struct.getNumAtoms('C') > maxCarbonAtoms:
1730+
return True
1731+
if H > maxHydrogenAtoms:
1732+
return True
1733+
if struct.getNumAtoms('O') > maxOxygenAtoms:
1734+
return True
1735+
if struct.getNumAtoms('N') > maxNitrogenAtoms:
1736+
return True
1737+
if struct.getNumAtoms('Si') > maxSiliconAtoms:
1738+
return True
1739+
if struct.getNumAtoms('S') > maxSulfurAtoms:
1740+
return True
1741+
if len(struct.atoms) - H > maxHeavyAtoms:
1742+
return True
1743+
if (struct.getNumberOfRadicalElectrons() > maxRadicals) and (len(struct.atoms) - H > 1):
1744+
return True
1745+
return False

0 commit comments

Comments
 (0)