Skip to content

Commit

Permalink
Collision detection refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
1234somesh committed Aug 22, 2024
1 parent 2eea0c0 commit d617584
Show file tree
Hide file tree
Showing 19 changed files with 1,028 additions and 549 deletions.
298 changes: 204 additions & 94 deletions src/core/collision.cpp

Large diffs are not rendered by default.

49 changes: 24 additions & 25 deletions src/core/collision.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,8 @@
#include "system/Leaf.hpp"

#include <memory>

#include <variant>
/** @brief Protocols for collision handling. */
enum class CollisionModeType : int {
/** @brief Deactivate collision detection. */
OFF = 0,
/** @brief Create bond between centers of colliding particles. */
BIND_CENTERS = 1,
/**
* @brief Create a bond between the centers of the colliding particles,
* plus two virtual sites at the point of collision and bind them
* together. This prevents the particles from sliding against each
* other. Requires VIRTUAL_SITES_RELATIVE.
*/
BIND_VS = 2,
/** @brief Glue a particle to a specific spot on another particle. */
GLUE_TO_SURF = 3,
};

/// Data type holding the info about a single collision
struct CollisionPair {
Expand All @@ -54,18 +39,27 @@ struct CollisionPair {

class CollisionDetection : public System::Leaf<CollisionDetection> {
public: //private: TODO make private again!
std::shared_ptr<Collision::MergedProtocol> m_protocol;
bool m_off;
std::shared_ptr<Collision::ActiveProtocol> m_protocol;
public:

CollisionDetection():m_protocol{std::make_shared<Collision::MergedProtocol>()}{}

CollisionDetection() = default;
/** @brief Get currently active Collision protocol. */
auto get_protocol() const {return m_protocol;}
/** @brief Set a new Collision protocol. */
void set_protocol(std::shared_ptr<Collision::ActiveProtocol> protocol);
/** @brief Delete the currently active Collision protocol. */
void unset_protocol();
/** @brief Validates parameters and creates particle types if needed. */
void initialize();

auto is_off() const { return m_off; }
auto is_off() const { return nullptr or std::get_if<Collision::Off>(m_protocol.get()) != nullptr; }

auto cutoff() const { return m_protocol->cutoff(); }
auto cutoff() const {
if (m_protocol == nullptr) {
return INACTIVE_CUTOFF;
}
return std::visit([](auto const &protocol) { return protocol.cutoff();}, *m_protocol);
}

/// Handle queued collisions
void handle_collisions(CellStructure &cell_structure);
Expand All @@ -75,10 +69,15 @@ class CollisionDetection : public System::Leaf<CollisionDetection> {
/** @brief Detect (and queue) a collision between the given particles. */
void detect_collision(Particle const &p1, Particle const &p2,
double const dist_sq) {
if (m_protocol->detect_collision(p1, p2, dist_sq))
local_collision_queue.push_back({p1.id(), p2.id()});
if (m_protocol){
bool collision_detected = std::visit([&p1, &p2, dist_sq](auto const &protocol) {
return protocol.detect_collision(p1, p2, dist_sq);
}, *m_protocol);

if (collision_detected) {
local_collision_queue.push_back({p1.id(), p2.id()});
}}
}

// private:
/// During force calculation, colliding particles are recorded in the queue.
/// The queue is processed after force calculation, when it is safe to add
Expand Down
307 changes: 201 additions & 106 deletions src/core/collision/protocols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,117 +7,212 @@
#include "nonbonded_interactions/nonbonded_interaction_data.hpp"
#include "bonded_interactions/bonded_interaction_data.hpp"

#include <variant>

struct CollisionPair;

namespace Collision{
enum class CollisionModeType : int {
/** @brief Deactivate collision detection. */
OFF = 0,
/** @brief Create bond between centers of colliding particles. */
BIND_CENTERS = 1,
/**
* @brief Create a bond between the centers of the colliding particles,
* plus two virtual sites at the point of collision and bind them
* together. This prevents the particles from sliding against each
* other. Requires VIRTUAL_SITES_RELATIVE.
*/
BIND_VS = 2,
/** @brief Glue a particle to a specific spot on another particle. */
GLUE_TO_SURF = 3,
};

class MergedProtocol {

class Off {
public:
Off() = default;

auto cutoff() const {
return INACTIVE_CUTOFF;
}

void initialize(BondedInteractionsMap &, InteractionsNonBonded &){
return ;
}

bool handle_collisions(CellStructure &, BoxGeometry const &, double , BondedInteractionsMap const &, std::vector<CollisionPair> &) {
// Off-specific collision handling
return false;
}
bool detect_collision(Particle const &p1, Particle const &p2,
double const dist_sq) const {
return false;
}
};

class BindCenters {

public:

double distance;
// Square of distance at which particle are bound
double distance_sq;

/// bond type used between centers of colliding particles
int bond_centers;

BindCenters(double distance, int bond_centers) : distance{distance}, distance_sq{distance*distance}, bond_centers{bond_centers}{}

void initialize(BondedInteractionsMap &bonded_ias, InteractionsNonBonded &nonbonded_ias);

auto cutoff() const {
return distance;
}

bool handle_collisions(CellStructure &cell_structure, BoxGeometry const &box_geo, double min_global_cut, BondedInteractionsMap const &bonded_ias, std::vector<CollisionPair> &local_collision_queue);

bool detect_collision(Particle const &p1, Particle const &p2,
double const dist_sq) const {
if (dist_sq > distance_sq)
return false;

// Ignore virtual particles
if (p1.is_virtual() or p2.is_virtual())
return false;

// Check, if there's already a bond between the particles
if (pair_bond_exists_on(p1.bonds(), p2.id(), bond_centers))
return false;

if (pair_bond_exists_on(p2.bonds(), p1.id(), bond_centers))
return false;

/* If we're still here, there is no previous bond between the particles,
we have a new collision */

// do not create bond between ghost particles
if (p1.is_ghost() and p2.is_ghost()) {
return false;
}
return true;
}
};

class BindVS {
public:
MergedProtocol()
: mode(CollisionModeType::OFF), distance(0.), distance_sq(0.),
bond_centers(-1), bond_vs(-1) {}

/// collision protocol
CollisionModeType mode;
/// distance at which particles are bound
double distance;
// Square of distance at which particle are bound
double distance_sq;

/// bond type used between centers of colliding particles
int bond_centers;
/// bond type used between virtual sites
int bond_vs;
/// particle type for virtual sites created on collision
int vs_particle_type;

/// For mode "glue to surface": The distance from the particle which is to be
/// glued to the new virtual site
double dist_glued_part_to_vs;
/// For mode "glue to surface": The particle type being glued
int part_type_to_be_glued;
/// For mode "glue to surface": The particle type to which the virtual site is
/// attached
int part_type_to_attach_vs_to;
/// Particle type to which the newly glued particle is converted
int part_type_after_glueing;
/** Placement of virtual sites for MODE_VS.
* 0=on same particle as related to,
* 1=on collision partner,
* 0.5=in the middle between
*/
double vs_placement;
/** @brief Validates parameters and creates particle types if needed. */
void initialize(BondedInteractionsMap &bonded_ias, InteractionsNonBonded &nonbonded_ias);

auto cutoff() const {
if (mode != CollisionModeType::OFF) {
return distance;
}
return INACTIVE_CUTOFF;
}

/// Handle queued collisions
bool handle_collisions(CellStructure &cell_structure, BoxGeometry const &box_geo, double min_global_cut, BondedInteractionsMap const &bonded_ias, std::vector<CollisionPair> &local_collision_queue);

/** @brief Detect (and queue) a collision between the given particles. */
bool detect_collision(Particle const &p1, Particle const &p2,
double const dist_sq) {
if (dist_sq > distance_sq)
return false;

// If we are in the glue to surface mode, check that the particles
// are of the right type
if (mode == CollisionModeType::GLUE_TO_SURF)
if (!glue_to_surface_criterion(p1, p2))
return false;

// Ignore virtual particles
if (p1.is_virtual() or p2.is_virtual())
return false;

// Check, if there's already a bond between the particles
if (pair_bond_exists_on(p1.bonds(), p2.id(), bond_centers))
return false;

if (pair_bond_exists_on(p2.bonds(), p1.id(), bond_centers))
return false;

/* If we're still here, there is no previous bond between the particles,
we have a new collision */

// do not create bond between ghost particles
if (p1.is_ghost() and p2.is_ghost()) {
return false;
}
return true;
}

/** @brief Check additional criteria for the glue_to_surface collision mode */
bool glue_to_surface_criterion(Particle const &p1, Particle const &p2) const {
return (((p1.type() == part_type_to_be_glued) and
double distance;
// Square of distance at which particle are bound
double distance_sq;

/// bond type used between centers of colliding particles
int bond_centers;
/// bond type used between virtual sites
int bond_vs;
/** Placement of virtual sites for MODE_VS.
* 0=on same particle as related to,
* 1=on collision partner,
* 0.5=in the middle between
*/
double vs_placement;
/// particle type for virtual sites created on collision
int part_type_vs;

BindVS(double distance, int bond_centers, int bond_vs, double vs_placement, int part_type_vs) : distance{distance}, distance_sq{distance*distance}, bond_centers{bond_centers}, bond_vs{bond_vs}, vs_placement{vs_placement}, part_type_vs{part_type_vs} {}

void initialize(BondedInteractionsMap &bonded_ias, InteractionsNonBonded &nonbonded_ias);

auto cutoff() const {
return distance;
}

bool handle_collisions(CellStructure &cell_structure, BoxGeometry const &box_geo, double min_global_cut, BondedInteractionsMap const &bonded_ias, std::vector<CollisionPair> &local_collision_queue);

bool detect_collision(Particle const &p1, Particle const &p2,
double const dist_sq) const {
if (dist_sq > distance_sq)
return false;

// Ignore virtual particles
if (p1.is_virtual() or p2.is_virtual())
return false;

// Check, if there's already a bond between the particles
if (pair_bond_exists_on(p1.bonds(), p2.id(), bond_centers))
return false;

if (pair_bond_exists_on(p2.bonds(), p1.id(), bond_centers))
return false;

/* If we're still here, there is no previous bond between the particles,
we have a new collision */

// do not create bond between ghost particles
if (p1.is_ghost() and p2.is_ghost()) {
return false;
}
return true;
}
};

class GlueToSurf{
public:
double distance;
// Square of distance at which particle are bound
double distance_sq;
/// bond type used between centers of colliding particles
int bond_centers;
/// bond type used between virtual sites
int bond_vs;
/// particle type for virtual sites created on collision
int part_type_vs;
/// For mode "glue to surface": The distance from the particle which is to be
/// glued to the new virtual site
double dist_glued_part_to_vs;
/// For mode "glue to surface": The particle type being glued
int part_type_to_be_glued;
/// For mode "glue to surface": The particle type to which the virtual site is
/// attached
int part_type_to_attach_vs_to;
/// Particle type to which the newly glued particle is converted
int part_type_after_glueing;


GlueToSurf(double distance, int bond_centers, int bond_vs, int part_type_vs, double dist_glued_part_to_vs, int part_type_to_be_glued, int part_type_to_attach_vs_to, int part_type_after_glueing) : distance{distance}, distance_sq{distance*distance}, bond_centers{bond_centers}, bond_vs{bond_vs}, part_type_vs{part_type_vs}, dist_glued_part_to_vs{dist_glued_part_to_vs}, part_type_to_be_glued{part_type_to_be_glued}, part_type_to_attach_vs_to{part_type_to_attach_vs_to}, part_type_after_glueing{part_type_after_glueing} {}

void initialize(BondedInteractionsMap &bonded_ias, InteractionsNonBonded &nonbonded_ias);

auto cutoff() const {
return distance;
}

/** @brief Check additional criteria for the glue_to_surface collision mode */
bool glue_to_surface_criterion(Particle const &p1, Particle const &p2) const {
return (((p1.type() == part_type_to_be_glued) and
(p2.type() == part_type_to_attach_vs_to)) or
((p2.type() == part_type_to_be_glued) and
(p1.type() == part_type_to_attach_vs_to)));
}

};
}

#endif // COLLISION_DETECTION
}

bool handle_collisions(CellStructure &cell_structure, BoxGeometry const &box_geo, double min_global_cut, BondedInteractionsMap const &bonded_ias, std::vector<CollisionPair> &local_collision_queue);

bool detect_collision(Particle const &p1, Particle const &p2,
double const dist_sq) const {
if (dist_sq > distance_sq)
return false;

// If we are in the glue to surface mode, check that the particles
// are of the right type

if (!glue_to_surface_criterion(p1, p2))
return false;

// Ignore virtual particles
if (p1.is_virtual() or p2.is_virtual())
return false;

// Check, if there's already a bond between the particles
if (pair_bond_exists_on(p1.bonds(), p2.id(), bond_centers))
return false;

if (pair_bond_exists_on(p2.bonds(), p1.id(), bond_centers))
return false;

/* If we're still here, there is no previous bond between the particles,
we have a new collision */

// do not create bond between ghost particles
if (p1.is_ghost() and p2.is_ghost()) {
return false;
}
return true;
}
};

using ActiveProtocol = std::variant<Off,BindCenters,BindVS,GlueToSurf>;
} // namespace Collision
#endif
Loading

0 comments on commit d617584

Please sign in to comment.