-
Notifications
You must be signed in to change notification settings - Fork 187
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
Fixes for parallel collision detection #2195
Conversation
* three particle binding: Only work on cells available on the local node * virtual sites based methods: * Skip collision on a node which does not see both particles and at least one is non-ghost. * Add bonds only on the node where the particle is present * For glue to surface: A particle can only be glued once. To ensure this, delay the creationof the bond between the centers to occur at the smae time the glued particle is made iner by changing its type. Also execute the type change, on non-ghost particles, if only one of the particles is available on the node. The actual collision will be handled on the left neighbor which sees both particles. * Testcase: set box_l to (1,1,1) so that the clusters in the test actually span several nodes. Add Lennard-Jones-liquid based tests for virtual-sites based schemes to catch corner cases This needs to be integrated with espressomd#2156 Fixes espressomd#2102
* three particle binding: Only work on cells available on the local node * virtual sites based methods: * Skip collision on a node which does not see both particles and at least one is non-ghost. * Add bonds only on the node where the particle is present * For glue to surface: A particle can only be glued once. To ensure this, delay the creationof the bond between the centers to occur at the smae time the glued particle is made iner by changing its type. Also execute the type change, on non-ghost particles, if only one of the particles is available on the node. The actual collision will be handled on the left neighbor which sees both particles. * Testcase: set box_l to (1,1,1) so that the clusters in the test actually span several nodes. Add Lennard-Jones-liquid based tests for virtual-sites based schemes to catch corner cases This needs to be integrated with espressomd#2156 Fixes espressomd#2102
…so into coldet_par_fix
Codecov Report
@@ Coverage Diff @@
## python #2195 +/- ##
========================================
Coverage ? 69%
========================================
Files ? 474
Lines ? 31972
Branches ? 0
========================================
Hits ? 22071
Misses ? 9901
Partials ? 0
Continue to review full report at Codecov.
|
This reverts commit 80003b4.
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.
Overall I think this is correct now. The current_vs_pid
construction seems somewhat brittle to me, but changing this requires some refactoring, I think we can keep it for now.
src/core/collision.cpp
Outdated
// * or we have only one and it is a ghost | ||
// we only increase the counter for the ext id to use based on the | ||
// number of particles created by other nodes | ||
if ((!p1 and !p2) || |
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.
This condition is to complex. Please split it up.
src/core/collision.cpp
Outdated
@@ -507,6 +513,19 @@ static void three_particle_binding_do_search(Cell *basecell, Particle &p1, | |||
} | |||
} | |||
|
|||
Cell *responsible_collision_cell(Particle& p) |
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.
This should go into cells.cpp
, and can be reused there e.g. to make removing a particle O(1). It should also be renamed to something like find_current_cell
. This finds the actual cell a particles is in, as opposed to the cell a particle should be in (which is what position_to_cell
returns).
src/core/collision.cpp
Outdated
// number of particles created by other nodes | ||
if ((!p1 and !p2) || | ||
((p1 && p1->l.ghost) && (p2 && p2->l.ghost)) || | ||
(!p1 && p2->l.ghost) || (!p2 && p1->l.ghost)) { |
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.
Couldn't this whole conditional be rewritten as: ((!p1 || p1->l.ghost) && (!p2 || p2->l.ghost))
src/core/collision.cpp
Outdated
|
||
} else { // We have at least one | ||
} else { // We consider teh pair |
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.
Typo: "the". We could add here: "because at least one of p1 and p2 is local to this node".
src/core/collision.cpp
Outdated
|
||
// place virtual sites on the node where the base particle is not a | ||
// ghost | ||
if (!p1->l.ghost) |
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.
Is it safe to deref p1 here (and p2 in the following)?
There is the corner case that one of the two particle pointers is null and the other is local which is not caught by the if. This should not happen as the two particles got queued by a short_range_loop? Should we at least comment on that fact?
src/core/collision.cpp
Outdated
// but we still increase the particle counters, as other nodes | ||
// can not always know whether or not a vs is placed | ||
if ((p1->p.type == collision_params.part_type_after_glueing) || | ||
(p2->p.type == collision_params.part_type_after_glueing)) { |
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.
One conditional would suffice:
if (p1->p.type != collision_params.part_type_to_be_glued
|| p2->p.type != collision_params.part_type_to_be_glued) {
//...
}
However, keep both the comments.
src/core/collision.cpp
Outdated
|
||
// Add a bond between the centers of the colliding particles | ||
// The bond is placed on the node that has p1 | ||
if (!local_particles[c.pp1]->l.ghost) { |
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.
Why do we use local_particles[c.pp1]
here and not simply p1
?
Also below, there is another occurrence of a deref via local_particles
. But also a direct use of p1
.
> @@ -579,18 +605,38 @@ void handle_collisions() {
Particle *const p1 = local_particles[c.pp1];
Particle *const p2 = local_particles[c.pp2];
- // If we have none of the two partic;es, only increase the counter for the
- // next id to use
- if (p1 == NULL and p2 == NULL) {
+ // Only nodes take part in particle creation and binding
+ // that see both particles
+
+ // If we have
+ // * none of the two partic;es or
+ // * both are ghosts,
+ // * or we have only one and it is a ghost
+ // we only increase the counter for the ext id to use based on the
+ // number of particles created by other nodes
+ if ((!p1 and !p2) ||
+ ((p1 && p1->l.ghost) && (p2 && p2->l.ghost)) ||
+ (!p1 && p2->l.ghost) || (!p2 && p1->l.ghost)) {
Couldn't this whole conditional be rewritten as: `((!p1 || p1->l.ghost) && (!p2 || p2->l.ghost))`
Done
Typo: "the". We could add here: "because at least one of p1 and p2 is local to this node".
Done
> @@ -611,27 +657,61 @@ void handle_collisions() {
p1->p.rotation = ROTATION_X | ROTATION_Y | ROTATION_Z;
p2->p.rotation = ROTATION_X | ROTATION_Y | ROTATION_Z;
- // The vs placement is done by the node on which p1 is non-ghost
- if (!p1->l.ghost) {
- bind_at_point_of_collision_calc_vs_pos(p1, p2, pos1, pos2);
+ // Positions of the virtual sites
+ bind_at_point_of_collision_calc_vs_pos(p1, p2, pos1, pos2);
+
+ // place virtual sites on the node where the base particle is not a
+ // ghost
+ if (!p1->l.ghost)
Is it safe to deref p1 here (and p2 in the following)?
With the new condition, I think this woudl be caught by the other branch of the if.
> if (collision_params.mode & COLLISION_MODE_GLUE_TO_SURF) {
+ // If particles are made inert by a type change on collision
+ if (collision_params.part_type_after_glueing !=
+ collision_params.part_type_to_be_glued) {
+ // We skip the pair if one of the particles has already reacted
+ // but we still increase the particle counters, as other nodes
+ // can not always know whether or not a vs is placed
+ if ((p1->p.type == collision_params.part_type_after_glueing) ||
+ (p2->p.type == collision_params.part_type_after_glueing)) {
One conditional would suffice:
```c++
if (p1->p.type != collision_params.part_type_to_be_glued
|| p2->p.type != collision_params.part_type_to_be_glued) {
//...
}
```
Turned out to be to trigger-happy, because part_type_to_attach_vs_to
should not trigger a skip. Kept the old one
- const int pid = glue_to_surface_calc_vs_pos(p1, p2, pos);
+ const int pid = glue_to_surface_calc_vs_pos(*p1, *p2, pos);
+
+ // Add a bond between the centers of the colliding particles
+ // The bond is placed on the node that has p1
+ if (!local_particles[c.pp1]->l.ghost) {
I refactored both local_particle[] lookups away.
|
> @@ -507,6 +513,19 @@ static void three_particle_binding_do_search(Cell *basecell, Particle &p1,
}
}
+Cell *responsible_collision_cell(Particle& p)
This should go into `cells.cpp`, and can be reused there e.g. to make removing a particle O(1). It should also be renamed to something like `find_current_cell`. This finds the actual cell a particles is in, as opposed to the cell a particle should be in (which is what `position_to_cell` returns).
Done
|
src/core/collision.cpp
Outdated
@@ -598,7 +598,7 @@ void handle_collisions() { | |||
// ore one is ghost and one is not accessible | |||
// we only increase the counter for the ext id to use based on the | |||
// number of particles created by other nodes | |||
if ((!p1 or p1->l.ghost) and (!p2 or p2->l.ghost)) { | |||
if ((!p1 or p1->l.ghost) and (!p2 or p2->l.ghost) or !p1 or !p2) { |
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 the two !px
in the and
are now superfluous. This should be equivalent to:
if (!p1 || !p2 || (p1->l.ghost && p2->l.ghost))
Only work on cells available on the local node, but use p.l.p_old as a fallback (from @hirschsn)
and at least one is non-ghost.
delay the creationof the bond between the centers to occur at the smae
time the glued particle is made iner by changing its type.
Also execute the type change, on non-ghost particles, if only
one of the particles is available on the node. The actual collision
will be handled on the left neighbor which sees both particles.
span several nodes.
Add Lennard-Jones-liquid based tests for virtual-sites based schemes to catch
corner cases