Skip to content
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

Introduced a bugfix to solve the infinite loop in constant pH algorithm #4200

Closed
wants to merge 7 commits into from

Conversation

pm-blanco
Copy link
Contributor

@pm-blanco pm-blanco commented Apr 6, 2021

Fixes #4197

When attempting to do a reaction step using the constant pH algorithm, if there are not enough reactants nor product particles, the program simply not does the operation. The apparition of an infinite loop is prevented by existing the reaction subroutine in case that neither direction of the reaction is possible.

Description of changes:

  • The program checks if at least one direction of the reaction is possible and otherwise exits the subroutine returning a 1. This value should be later processed so the user gets a warning message informing of this error (work in progress).

…n algorithm when any direction of the acid-base reaction is possible. The program checks if at least one reaction is possible and otherwise exits the subrutine returning a 1. This value should be later processed so the user gets a warning message informing of this error.
Comment on lines 1500 to 1511
bool reaction_possible = false;

for (int reaction_id = 0; reaction_id < reactions.size(); reaction_id++) {
if (all_reactant_particles_exist(reaction_id)) {
reaction_possible = true;
}
}

if (reaction_possible == false) {
return 1;
}

Copy link
Member

@KaiSzuttor KaiSzuttor Apr 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't it possible to get this kind of logic implicitly? If no particle of the reactant type is found nothing should happen automatically without manually checking?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem that causes the infinite loop has its source in the while loop in lines 1521-1546. This while loop searches the particle ids that have a type that matches the reactant/product types. Of course, if you do not create such particle, then this loop runs for ever.
As you suggest, another possible solution would be to do this task without using a while statement so that if there is no reactant then the program does nothing. However, in my opinion, manually checking it has the advantage that we can integrate an exception error preventing the user from doing such simulation (since I cannot think where one would attempt to run the algorithm without reactants if it is not by mistake).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point is that such situation should not occur. If it occurs, then it is an error in the system setup, so it cannot be a simple no-op. It should raise an error.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my mind the reaction algorithm itself should be independent of the state of the system. I can also define a non bonded interaction of two non existing particle types without having an infinite loop. The reaction of reactants is also some kind of particle interaction, right? Why should it be special here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All methods default to a no-op when not enough particles are present, except for WidomInsertion which throws an error. I don't immediately see why it should be an issue to not have enough particles of type HA if there is at least one particle of type A-. Could you please clarify this for us?
Also if you reverse the reactant types with the adduct types, you will get a bug in the other direction, if I understand e4104d2 correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jngrad thank you for your clarification, now I understand your point. Now I agree with you that the desired output would be a no-op so one could couple the acid/base reaction with other reactions

Copy link
Contributor

@kosovan kosovan Apr 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, @jngrad is right that all reactants could be consumed if different reactions are competing for the same product or reactant. However, I would discourage anybody from intentionally using RxMC in this regime. It suffers from serious finite-size artifacts if the number of (any type of) reacting particles is on the order of unity. It is related to the fact that particle numbers in a simulation have to be integers whereas most existing theories work with concentrations as continuous variables.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: SN2 refers to a specific reaction mechanism. A reaction of the type A- + BX <--> AB + X- is not compatible with the way currently reactions are implemented in Espresso. The current implementation allows to create or destroy particles at random positions but it does not allow to transfer a particle between two binding partners. It is also one of the points on our wishlist.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be aware it definitely depends on what you mean:
Of course it is totally valid to create this reaction
A+B <-> C+D
Whit artbitrary A, B, C, D. I.e. also :
A- + BX <--> AB + X-
However all the types will be "primitive" beads i.e. not have bonds in the bead "BX". But it is completely fine for the "BX" type to have different lenard jones parameters (i.e. appear bigger) etc...
Maybe this would require having a type dependent exclusion radius for some more extreme variations...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A reaction of the type A- + BX <--> AB + X- is not compatible with the way currently reactions are implemented in Espresso. The current implementation allows to create or destroy particles at random positions but it does not allow to transfer a particle between two binding partners.

Good point. I also thought about the case of the titration curve of a buffer solution, i.e. a mixture of a weak acid and a strong acid. Titration by a strong base can trigger the bug once the buffer capacity is used up. But that's an edge case, one probably wouldn't want to add more base than there is buffer.

@RudolfWeeber
Copy link
Contributor

RudolfWeeber commented Apr 6, 2021

In my view, there are two issues:

  • The function ConstantPHEnsemble::get_random_valid_p_id() is incorrect, because it contains an empty loop if it has no solution. This should be fixed by changing the return type to std::optional<int> and returning {} if the system is empty. The quickest fix is to check that the total number of particles is >0. Long-term, the function can be replaced by something more efficient for the case that there are many holes in the particle id list.
  • The question of what should happen if no adducts are present, more more technically, what should happen in do_reaction() if get_random_valid_pid() returns {}. In my view, no-op is the correct behavior. This is analogous to running
system.cell_system.skin = 0
system.time_step = 1
system.integrator.run(1)

without particles (no-op, as-well)

@RudolfWeeber
Copy link
Contributor

Espresso also allows definition of non-bonded interactions for types for which there are (at that point) no particles.
The interaction will become used as soon as relevant particles are there.
So, there as well no-op would be the consistent behavior.

The Python call re.reaction() might return the number of attempted and performed reactions, just like system.integrator.run() does.
In this way, the user could handle the case of no educts present, if they wish to.

@kosovan
Copy link
Contributor

kosovan commented Apr 6, 2021

The Python call re.reaction() might return the number of attempted and performed reactions, just like system.integrator.run() does.
In this way, the user could handle the case of no educts present, if they wish to.

I like the solution proposed by @RudolfWeeber Indeed, the user might want to first create a reaction and then particles.

However, if we change the behaviour and return value of re.reaction(), then it would require more extensive changes, beyond a simple bugfix. I have some other suggestions on my list when it comes to modifying the reaction ensemble behaviour. Therefore, I propose to implement a simple bugfix now (throw an exception) and start creating a wishlist of deeper changes for the next coding day.

@jonaslandsgesell
Copy link
Member

jonaslandsgesell commented Apr 6, 2021

The problem #4197 is fixed via circumventing the asymetric proposal probability in #4207. The PR effectively shortens the code and makes it simpler. There is no need for a more complicated solution or further discussion of symptomatic fixes ;)

@jngrad
Copy link
Member

jngrad commented May 18, 2021

PR superseded by #4207.

@jngrad jngrad closed this May 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Constant pH method can enter an infinite loop if some particles are not created initially
6 participants