-
Notifications
You must be signed in to change notification settings - Fork 225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
check multiplicity of reverse products if the family template reactants have multiplicity constraints (vdW groups) #2131
Conversation
d1f4ed5
to
f9cf02f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As well as the minor changes to the code that I suggested, please improve your commit message. It should describe what you're trying to achieve, and why, and how.
One of the first things I often do when debugging something is check commit messages of when the code was last updated, and try to get into the head of whoever implemented it at the time (even when it's my past self, I usually need the commit messages to help me remember). Understanding why something is done the way it is is immensely helpful, and this is usually best conveyed by commit messages. (Discussion on github pull requests and linked issues are better than nothing, but may get lost and aren't instantly visible in an IDE or git client. The commit message is there forever, and easily accessible)
rmgpy/data/kinetics/family.py
Outdated
# if applying the family in reverse and the template reactants restrict multiplicity, we need to make sure that | ||
# a reverse product matches the multiplicity-constrained template reactant because the forward template products | ||
# do not enforce the multiplicity restriction | ||
if not forward and reactant_type == 'mol': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you do
if not forward and reactant_type == 'mol': | |
if not forward and isinstance(reactant_structure, Molecule): |
could you do away with the reactant_type variable and remove the changes above?
rmgpy/data/kinetics/family.py
Outdated
match = self._match_reactant_to_template(struct, template) | ||
if match: | ||
break | ||
if not match: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complicated nested for
loops with if
and break
clauses etc. usually benefit greatly from some comments. I think this is correct, but I had to think very hard to check it. Please make life easier for reviewers future programmers by adding some comments here.
rmgpy/data/kinetics/family.py
Outdated
if isinstance(node.item, Group): | ||
if node.item.multiplicity != []: | ||
multiplicity_restricted_templates.append(node) | ||
if multiplicity_restricted_templates: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this if
is redundant. If the list is empty the following for
will just run zero times.
Thanks for the review @rwest, I'll work on those changes |
Thanks for making this fix, @davidfarinajr. It doesn't go un-noticed when you put effort into solving other people's problems. 🥇 |
dfea639
to
7d7b34b
Compare
Also added debug logging which looks like this for the unit test
|
This multiplicity check will not check logic nodes though. I don't think we have many (or any) of these with surface families, but perhaps we should figure out how to check those as well. You could have a logic node at the top which points to groups which have multiplicity restrictions (don't think we currently have any of these) |
Codecov Report
@@ Coverage Diff @@
## master #2131 +/- ##
==========================================
+ Coverage 47.40% 47.46% +0.05%
==========================================
Files 89 89
Lines 23953 23967 +14
Branches 6237 6246 +9
==========================================
+ Hits 11356 11376 +20
+ Misses 11390 11385 -5
+ Partials 1207 1206 -1
Continue to review full report at Codecov.
|
I guess we could check that the products of a reverse reaction always match the forward reaction, but perhaps that's a lot of checking and will slow things down too much ? |
How often do we think this will get hit, as currently implemented? |
We could check, but this is "checked" when we descend the tree to get the kinetics. If it doesn't at least match the top node, then we get |
🤔, not sure how prevalent this issue is. We would be hitting this check quite often for catalysis, but the majority of the time we should get a match because we don't usually have radicals on the surface and the reactant groups are restricted to singlet. |
…ict multiplicity If applying a family recipe in reverse and the template reactant groups restrict multiplicity, we need to make sure that a reverse product matches the multiplicity-constrained template reactant because the forward template products do not enforce the multiplicity restriction. This commit adds a check for this in the apply_recipe method and returns `None` (no reaction) if none of the products generated match the multiplicity-constrained template reactant.
Should speed it up a bit. This might not be called often enough for this optimization to matter, but I'm not sure. At first I just wanted to switch to %s formatting because it uses lazy evaluation of the sting formatting, but that still leaves the expensive to_adjacency_list() calls and the only way to avoid those is wrap the whole thing an if block.
This method is sometimes applied to Group objects, to generate the product templates, not just Molecule objects.
The logic used to be that if you start with a wildcard number of radicals (or pairs) then incrementing it will mean you have a wildcard that is at least 1 or more. But you could in fact increment by more than one, using a parameter to the method, so your new wildcard list shouldn't always start at 1 but should start at however many you incremented by. Could have done list(range(radical,5)) instead of [1,2,3,4][radical-1:] but the latter is faster.
037e47e
to
0632ab3
Compare
This looks OK to me, but I made the last 3 commits, so now need someone else to review it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks good to me. Thanks, Richard and David! I used this branch to run one of the problem input files and the previous issue is gone now.
Looks good to me as well! Thanks Richard and Ting-Chen! |
I've merged this because it fixes a known issue and has been approved by review. But it occurred to me there may be another approach, that we should perhaps discuss. I tried looking at it for a while, but it was taking too long to figure out. We generate the reverse template by applying the recipe to the forward template. This is done mostly using atom type actions, etc. so for example if you have a Thoughts? |
While I think the solution in this PR is fine for now, I think tracking multiplicity when applying recipe actions is probably cleaner and more consistent long term. |
Yes, this was my original thought: If we enforce multiplicity with the template reactants, we could determine the multiplicity of the template products from the actions. I like this approach, but I think it's more difficult to implement than it may seem. Consider this family for example:
Since the multiplicity is also determined by the atoms in the molecule that are not labeled in the group (an not affected by actions), it it difficult to restrict multiplicity in the template products. It also gets tricky if only one of the template reactants has a multiplicity constraint. If, for example This could also be affected by how the groups are written in the database. For this family, the
*2 and *3 have |
This PR attempt to fix this issue #2122
Motivation or Problem
If we are applying a family in reverse and the template reactants restrict multiplicity, we need to make sure that
a reverse product matches the multiplicity-constrained template reactant because the forward template products
do not enforce the multiplicity restriction. Without this check, we get an
UndeterminableKineticsError
if the reverse products have a multiplicity that does not match the multiplicity constraint of the template reactants.Description of Changes
Added a multiplicity check when applying the template in reverse.
Testing
Need to add unit test. Tested a few reactions which had
UndeterminableKineticsError
but now are no longer generated since they don't satisfy the multiplicity constraints in the template.