@@ -1078,7 +1078,7 @@ def applyRecipe(self, reactantStructures, forward=True, unique=True):
10781078 # Return the product structures
10791079 return productStructures
10801080
1081- def __generateProductStructures (self , reactantStructures , maps , forward , ** options ):
1081+ def __generateProductStructures (self , reactantStructures , maps , forward , failsSpeciesConstraints = None ):
10821082 """
10831083 For a given set of `reactantStructures` and a given set of `maps`,
10841084 generate and return the corresponding product structures. The
@@ -1087,6 +1087,8 @@ def __generateProductStructures(self, reactantStructures, maps, forward, **optio
10871087 parameter is a list of mappings of the top-level tree node of each
10881088 *template* reactant to the corresponding *structure*. This function
10891089 returns a list of the product structures.
1090+ `failsSpeciesConstraints` is a function that accepts a :class:`Molecule`
1091+ structure and returns `True` if it is forbidden.
10901092 """
10911093
10921094 productStructuresList = []
@@ -1125,33 +1127,11 @@ def __generateProductStructures(self, reactantStructures, maps, forward, **optio
11251127 productStructures .reverse ()
11261128
11271129 # Apply the generated species constraints (if given)
1128- if options :
1129- maxCarbonAtoms = options .get ('maximumCarbonAtoms' , 1000000 )
1130- maxHydrogenAtoms = options .get ('maximumHydrogenAtoms' , 1000000 )
1131- maxOxygenAtoms = options .get ('maximumOxygenAtoms' , 1000000 )
1132- maxNitrogenAtoms = options .get ('maximumNitrogenAtoms' , 1000000 )
1133- maxSiliconAtoms = options .get ('maximumSiliconAtoms' , 1000000 )
1134- maxSulfurAtoms = options .get ('maximumSulfurAtoms' , 1000000 )
1135- maxHeavyAtoms = options .get ('maximumHeavyAtoms' , 1000000 )
1136- maxRadicals = options .get ('maximumRadicalElectrons' , 1000000 )
1130+ if failsSpeciesConstraints :
11371131 for struct in productStructures :
1138- H = struct .getNumAtoms ('H' )
1139- if struct .getNumAtoms ('C' ) > maxCarbonAtoms :
1140- raise ForbiddenStructureException ()
1141- if H > maxHydrogenAtoms :
1142- raise ForbiddenStructureException ()
1143- if struct .getNumAtoms ('O' ) > maxOxygenAtoms :
1144- raise ForbiddenStructureException ()
1145- if struct .getNumAtoms ('N' ) > maxNitrogenAtoms :
1146- raise ForbiddenStructureException ()
1147- if struct .getNumAtoms ('Si' ) > maxSiliconAtoms :
1148- raise ForbiddenStructureException ()
1149- if struct .getNumAtoms ('S' ) > maxSulfurAtoms :
1150- raise ForbiddenStructureException ()
1151- if len (struct .atoms ) - H > maxHeavyAtoms :
1152- raise ForbiddenStructureException ()
1153- if (struct .getNumberOfRadicalElectrons () > maxRadicals ) and (len (struct .atoms ) - H > 1 ):
1154- raise ForbiddenStructureException ()
1132+ if failsSpeciesConstraints (struct ):
1133+ raise ForbiddenStructureException ()
1134+
11551135
11561136 # Generate other possible electronic states
11571137 electronicStructuresList1 = []
@@ -1389,7 +1369,7 @@ def __matchReactantToTemplate(self, reactant, templateReactant):
13891369 elif isinstance (struct , Group ):
13901370 return reactant .findSubgraphIsomorphisms (struct )
13911371
1392- def generateReactions (self , reactants , ** options ):
1372+ def generateReactions (self , reactants , failsSpeciesConstraints = None ):
13931373 """
13941374 Generate all reactions between the provided list of one or two
13951375 `reactants`, which should be either single :class:`Molecule` objects
@@ -1402,12 +1382,12 @@ def generateReactions(self, reactants, **options):
14021382 reactionList = []
14031383
14041384 # Forward direction (the direction in which kinetics is defined)
1405- reactionList .extend (self .__generateReactions (reactants , forward = True , ** options ))
1385+ reactionList .extend (self .__generateReactions (reactants , forward = True , failsSpeciesConstraints = failsSpeciesConstraints ))
14061386
14071387 if self .ownReverse :
14081388 # for each reaction, make its reverse reaction and store in a 'reverse' attribute
14091389 for rxn in reactionList :
1410- reactions = self .__generateReactions (rxn .products , products = rxn .reactants , forward = True , ** options )
1390+ reactions = self .__generateReactions (rxn .products , products = rxn .reactants , forward = True , failsSpeciesConstraints = failsSpeciesConstraints )
14111391 if len (reactions ) != 1 :
14121392 logging .error ("Expecting one matching reverse reaction, not {0} in reaction family {1} for forward reaction {2}.\n " .format (len (reactions ), self .label , str (rxn )))
14131393 for reactant in rxn .reactants :
@@ -1421,7 +1401,7 @@ def generateReactions(self, reactants, **options):
14211401
14221402 else : # family is not ownReverse
14231403 # Reverse direction (the direction in which kinetics is not defined)
1424- reactionList .extend (self .__generateReactions (reactants , forward = False , ** options ))
1404+ reactionList .extend (self .__generateReactions (reactants , forward = False , failsSpeciesConstraints = failsSpeciesConstraints ))
14251405
14261406 # Return the reactions as containing Species objects, not Molecule objects
14271407 for reaction in reactionList :
@@ -1450,14 +1430,16 @@ def calculateDegeneracy(self, reaction):
14501430 raise Exception ('Unable to calculate degeneracy for reaction {0} in reaction family {1}.' .format (reaction , self .label ))
14511431 return reactions [0 ].degeneracy
14521432
1453- def __generateReactions (self , reactants , products = None , forward = True , ** options ):
1433+ def __generateReactions (self , reactants , products = None , forward = True , failsSpeciesConstraints = None ):
14541434 """
14551435 Generate a list of all of the possible reactions of this family between
14561436 the list of `reactants`. The number of reactants provided must match
14571437 the number of reactants expected by the template, or this function
14581438 will return an empty list. Each item in the list of reactants should
14591439 be a list of :class:`Molecule` objects, each representing a resonance
14601440 isomer of the species of interest.
1441+ `failsSpeciesConstraints` is an optional function that accepts a :class:`Molecule`
1442+ structure and returns `True` if it is forbidden.
14611443 """
14621444
14631445 rxnList = []; speciesList = []
@@ -1493,7 +1475,7 @@ def __generateReactions(self, reactants, products=None, forward=True, **options)
14931475 for map in mappings :
14941476 reactantStructures = [molecule ]
14951477 try :
1496- productStructuresList = self .__generateProductStructures (reactantStructures , [map ], forward , ** options )
1478+ productStructuresList = self .__generateProductStructures (reactantStructures , [map ], forward , failsSpeciesConstraints = failsSpeciesConstraints )
14971479 except ForbiddenStructureException :
14981480 pass
14991481 else :
@@ -1521,7 +1503,7 @@ def __generateReactions(self, reactants, products=None, forward=True, **options)
15211503 for mapB in mappingsB :
15221504 reactantStructures = [moleculeA , moleculeB ]
15231505 try :
1524- productStructuresList = self .__generateProductStructures (reactantStructures , [mapA , mapB ], forward , ** options )
1506+ productStructuresList = self .__generateProductStructures (reactantStructures , [mapA , mapB ], forward , failsSpeciesConstraints = failsSpeciesConstraints )
15251507 except ForbiddenStructureException :
15261508 pass
15271509 else :
@@ -1542,7 +1524,7 @@ def __generateReactions(self, reactants, products=None, forward=True, **options)
15421524 for mapB in mappingsB :
15431525 reactantStructures = [moleculeA , moleculeB ]
15441526 try :
1545- productStructuresList = self .__generateProductStructures (reactantStructures , [mapA , mapB ], forward , ** options )
1527+ productStructuresList = self .__generateProductStructures (reactantStructures , [mapA , mapB ], forward , failsSpeciesConstraints = failsSpeciesConstraints )
15461528 except ForbiddenStructureException :
15471529 pass
15481530 else :
0 commit comments