From 2eea0c000fe97f2b2513970f57aa018a25b361d6 Mon Sep 17 00:00:00 2001 From: Somesh Kurahatti Date: Fri, 9 Aug 2024 16:45:46 +0200 Subject: [PATCH] Step 1: everything passes the testsuite --- src/core/collision.cpp | 51 +++++--- src/core/collision.hpp | 89 ++----------- src/core/collision/protocols.hpp | 123 ++++++++++++++++++ src/core/forces.cpp | 2 +- src/core/system/System.cpp | 2 +- .../CollisionDetection.hpp | 64 ++++----- 6 files changed, 202 insertions(+), 129 deletions(-) create mode 100644 src/core/collision/protocols.hpp diff --git a/src/core/collision.cpp b/src/core/collision.cpp index 0070d90100..9effb0dea6 100644 --- a/src/core/collision.cpp +++ b/src/core/collision.cpp @@ -74,8 +74,8 @@ Particle &get_part(CellStructure &cell_structure, int id) { return *p; } } // namespace - -void CollisionDetection::initialize() { +namespace Collision { +void MergedProtocol::initialize(BondedInteractionsMap &bonded_ias, InteractionsNonBonded &nonbonded_ias) { // If mode is OFF, no further checks if (mode == CollisionModeType::OFF) { return; @@ -111,10 +111,6 @@ void CollisionDetection::initialize() { } #endif - auto &system = get_system(); - auto &bonded_ias = *system.bonded_ias; - auto &nonbonded_ias = *system.nonbonded_ias; - // Check if bond exists assert(mode != CollisionModeType::BIND_CENTERS or bonded_ias.contains(bond_centers)); @@ -172,15 +168,14 @@ void CollisionDetection::initialize() { nonbonded_ias.make_particle_type_exist(part_type_after_glueing); } - system.on_short_range_ia_change(); } - +} /** @brief Calculate position of vs for GLUE_TO_SURFACE mode. * Returns id of particle to bind vs to. */ static auto const &glue_to_surface_calc_vs_pos( Particle const &p1, Particle const &p2, BoxGeometry const &box_geo, - CollisionDetection const &collision_params, Utils::Vector3d &pos) { + Collision::MergedProtocol const &collision_params, Utils::Vector3d &pos) { double ratio; auto const vec21 = box_geo.get_mi_vector(p1.pos(), p2.pos()); auto const dist = vec21.norm(); @@ -204,7 +199,7 @@ static auto const &glue_to_surface_calc_vs_pos( static void bind_at_point_of_collision_calc_vs_pos( Particle const &p1, Particle const &p2, BoxGeometry const &box_geo, - CollisionDetection const &collision_params, Utils::Vector3d &pos1, + Collision::MergedProtocol const &collision_params, Utils::Vector3d &pos1, Utils::Vector3d &pos2) { auto const vec21 = box_geo.get_mi_vector(p1.pos(), p2.pos()); pos1 = p1.pos() - vec21 * collision_params.vs_placement; @@ -214,7 +209,7 @@ static void bind_at_point_of_collision_calc_vs_pos( #ifdef VIRTUAL_SITES_RELATIVE static void place_vs_and_relate_to_particle( CellStructure &cell_structure, BoxGeometry const &box_geo, - CollisionDetection const &collision_params, double const min_global_cut, + Collision::MergedProtocol const &collision_params, double const min_global_cut, int const current_vs_pid, Utils::Vector3d const &pos, int const relate_to) { Particle new_part; new_part.id() = current_vs_pid; @@ -227,7 +222,7 @@ static void place_vs_and_relate_to_particle( static void bind_at_poc_create_bond_between_vs( CellStructure &cell_structure, BondedInteractionsMap const &bonded_ias, - CollisionDetection const &collision_params, int const current_vs_pid, + Collision::MergedProtocol const &collision_params, int const current_vs_pid, CollisionPair const &c) { switch (number_of_partners(*bonded_ias.at(collision_params.bond_vs))) { case 1: { @@ -253,7 +248,7 @@ static void bind_at_poc_create_bond_between_vs( static void glue_to_surface_bind_part_to_vs( Particle const *const p1, Particle const *const p2, - int const vs_pid_plus_one, CollisionDetection const &collision_params, + int const vs_pid_plus_one, Collision::MergedProtocol const &collision_params, CellStructure &cell_structure) { // Create bond between the virtual particles const int bondG[] = {vs_pid_plus_one - 1}; @@ -281,6 +276,17 @@ static auto gather_collision_queue(std::vector const &local) { } void CollisionDetection::handle_collisions(CellStructure &cell_structure) { + auto &system = get_system(); + auto const &box_geo = *system.box_geo; + auto const min_global_cut = system.get_min_global_cut(); + auto update_propagations = m_protocol->handle_collisions(cell_structure, box_geo, min_global_cut, *system.bonded_ias, local_collision_queue); + if (update_propagations) { + system.update_used_propagations(); + } + clear_queue(); +} + +bool Collision::MergedProtocol::handle_collisions(CellStructure &cell_structure, BoxGeometry const &box_geo, double min_global_cut, BondedInteractionsMap const &bonded_ias, std::vector &local_collision_queue) { // Note that the glue to surface mode adds bonds between the centers // but does so later in the process. This is needed to guarantee that // a particle can only be glued once, even if queued twice in a single @@ -301,9 +307,6 @@ void CollisionDetection::handle_collisions(CellStructure &cell_structure) { } #ifdef VIRTUAL_SITES_RELATIVE - auto &system = get_system(); - auto const &box_geo = *system.box_geo; - auto const min_global_cut = system.get_min_global_cut(); if ((mode == CollisionModeType::BIND_VS) || (mode == CollisionModeType::GLUE_TO_SURF)) { // Gather the global collision queue, because only one node has a collision @@ -387,7 +390,7 @@ void CollisionDetection::handle_collisions(CellStructure &cell_structure) { current_vs_pid++; // Create bonds between the vs. - bind_at_poc_create_bond_between_vs(cell_structure, *system.bonded_ias, + bind_at_poc_create_bond_between_vs(cell_structure,bonded_ias, *this, current_vs_pid, c); } // mode VS @@ -455,11 +458,19 @@ void CollisionDetection::handle_collisions(CellStructure &cell_structure) { cell_structure.update_ghosts_and_resort_particle( Cells::DATA_PART_PROPERTIES | Cells::DATA_PART_BONDS); } - system.update_used_propagations(); + return true; } // are we in one of the vs_based methods #endif // defined VIRTUAL_SITES_RELATIVE - - clear_queue(); + return false; } +void CollisionDetection::initialize() { + auto &system = get_system(); + auto &bonded_ias = *system.bonded_ias; + auto &nonbonded_ias = *system.nonbonded_ias; + m_protocol->initialize(bonded_ias, nonbonded_ias); + system.on_short_range_ia_change(); + } + + #endif // COLLISION_DETECTION diff --git a/src/core/collision.hpp b/src/core/collision.hpp index 0a5545c16e..db8c13d0e9 100644 --- a/src/core/collision.hpp +++ b/src/core/collision.hpp @@ -20,13 +20,15 @@ #pragma once #include "config/config.hpp" - +#include "collision/protocols.hpp" #include "BondList.hpp" #include "Particle.hpp" #include "cell_system/CellStructure.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" #include "system/Leaf.hpp" +#include + /** @brief Protocols for collision handling. */ enum class CollisionModeType : int { /** @brief Deactivate collision detection. */ @@ -51,51 +53,19 @@ struct CollisionPair { }; class CollisionDetection : public System::Leaf { +public: //private: TODO make private again! + std::shared_ptr m_protocol; + bool m_off; public: - CollisionDetection() - : 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; + + CollisionDetection():m_protocol{std::make_shared()}{} /** @brief Validates parameters and creates particle types if needed. */ void initialize(); - auto cutoff() const { - if (mode != CollisionModeType::OFF) { - return distance; - } - return INACTIVE_CUTOFF; - } + auto is_off() const { return m_off; } + + auto cutoff() const { return m_protocol->cutoff(); } /// Handle queued collisions void handle_collisions(CellStructure &cell_structure); @@ -105,34 +75,8 @@ class CollisionDetection : public System::Leaf { /** @brief Detect (and queue) a collision between the given particles. */ void detect_collision(Particle const &p1, Particle const &p2, double const dist_sq) { - if (dist_sq > distance_sq) - return; - - // 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; - - // Ignore virtual particles - if (p1.is_virtual() or p2.is_virtual()) - return; - - // Check, if there's already a bond between the particles - if (pair_bond_exists_on(p1.bonds(), p2.id(), bond_centers)) - return; - - if (pair_bond_exists_on(p2.bonds(), p1.id(), bond_centers)) - return; - - /* 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; - } - local_collision_queue.push_back({p1.id(), p2.id()}); + if (m_protocol->detect_collision(p1, p2, dist_sq)) + local_collision_queue.push_back({p1.id(), p2.id()}); } // private: @@ -141,11 +85,4 @@ class CollisionDetection : public System::Leaf { /// particles. std::vector local_collision_queue; - /** @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))); - } }; diff --git a/src/core/collision/protocols.hpp b/src/core/collision/protocols.hpp new file mode 100644 index 0000000000..77333c78f9 --- /dev/null +++ b/src/core/collision/protocols.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include + +#ifdef COLLISION_DETECTION + +#include "nonbonded_interactions/nonbonded_interaction_data.hpp" +#include "bonded_interactions/bonded_interaction_data.hpp" + + +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 { +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 &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 + (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 diff --git a/src/core/forces.cpp b/src/core/forces.cpp index b9881e166c..1184439603 100644 --- a/src/core/forces.cpp +++ b/src/core/forces.cpp @@ -197,7 +197,7 @@ void System::System::calculate_forces() { coulomb_kernel_ptr, dipoles_kernel_ptr, elc_kernel_ptr); #ifdef COLLISION_DETECTION - if (collision_detection.mode != CollisionModeType::OFF) { + if (not collision_detection.is_off()) { collision_detection.detect_collision(p1, p2, d.dist2); } #endif diff --git a/src/core/system/System.cpp b/src/core/system/System.cpp index 676b824155..1bb7f8d079 100644 --- a/src/core/system/System.cpp +++ b/src/core/system/System.cpp @@ -503,7 +503,7 @@ unsigned System::get_global_ghost_flags() const { } #ifdef COLLISION_DETECTION - if (collision_detection->mode != CollisionModeType::OFF) { + if (not collision_detection->is_off()) { data_parts |= Cells::DATA_PART_BONDS; } #endif diff --git a/src/script_interface/collision_detection/CollisionDetection.hpp b/src/script_interface/collision_detection/CollisionDetection.hpp index bb1727fd0d..38889e4dac 100644 --- a/src/script_interface/collision_detection/CollisionDetection.hpp +++ b/src/script_interface/collision_detection/CollisionDetection.hpp @@ -33,6 +33,7 @@ #include "core/bonded_interactions/bonded_interaction_data.hpp" #include "core/collision.hpp" +#include "core/collision/protocols.hpp" #include #include @@ -53,21 +54,21 @@ class CollisionDetection std::unique_ptr m_params; std::weak_ptr m_bonded_ias; - std::unordered_map const cd_mode_to_name = { - {CollisionModeType::OFF, "off"}, - {CollisionModeType::BIND_CENTERS, "bind_centers"}, - {CollisionModeType::BIND_VS, "bind_at_point_of_collision"}, - {CollisionModeType::GLUE_TO_SURF, "glue_to_surface"}, + std::unordered_map const cd_mode_to_name = { + {Collision::CollisionModeType::OFF, "off"}, + {Collision::CollisionModeType::BIND_CENTERS, "bind_centers"}, + {Collision::CollisionModeType::BIND_VS, "bind_at_point_of_collision"}, + {Collision::CollisionModeType::GLUE_TO_SURF, "glue_to_surface"}, }; - std::unordered_map cd_name_to_mode; - std::unordered_map cd_name_to_mode; + std::unordered_map> const cd_mode_to_parameters = { - {CollisionModeType::OFF, {"mode"}}, - {CollisionModeType::BIND_CENTERS, {"mode", "bond_centers", "distance"}}, - {CollisionModeType::BIND_VS, + {Collision::CollisionModeType::OFF, {"mode"}}, + {Collision::CollisionModeType::BIND_CENTERS, {"mode", "bond_centers", "distance"}}, + {Collision::CollisionModeType::BIND_VS, {"mode", "bond_centers", "bond_vs", "part_type_vs", "distance", "vs_placement"}}, - {CollisionModeType::GLUE_TO_SURF, + {Collision::CollisionModeType::GLUE_TO_SURF, {"mode", "bond_centers", "bond_vs", "part_type_vs", "part_type_to_be_glued", "part_type_to_attach_vs_to", "part_type_after_glueing", "distance", @@ -98,9 +99,10 @@ class CollisionDetection [this](Variant const &v) { auto const name = get_value(v); check_mode_name(name); - m_handle->mode = cd_name_to_mode.at(name); + m_handle->m_protocol->mode = cd_name_to_mode.at(name); + m_handle->m_off = m_handle->m_protocol->mode == Collision::CollisionModeType::OFF; }, - [this]() { return cd_mode_to_name.at(m_handle->mode); }}, + [this]() { return cd_mode_to_name.at(m_handle->m_protocol->mode); }}, {"bond_centers", [this](Variant const &v) { auto const bond_id = find_bond_id(v); @@ -108,9 +110,9 @@ class CollisionDetection throw std::invalid_argument("Bond in parameter 'bond_centers' was " "not added to the system"); } - m_handle->bond_centers = bond_id.value(); + m_handle->m_protocol->bond_centers = bond_id.value(); }, - [this]() { return m_handle->bond_centers; }}, + [this]() { return m_handle->m_protocol->bond_centers; }}, {"bond_vs", [this](Variant const &v) { auto const bond_id = find_bond_id(v); @@ -118,44 +120,44 @@ class CollisionDetection throw std::invalid_argument( "Bond in parameter 'bond_vs' was not added to the system"); } - m_handle->bond_vs = bond_id.value(); + m_handle->m_protocol->bond_vs = bond_id.value(); }, - [this]() { return m_handle->bond_vs; }}, + [this]() { return m_handle->m_protocol->bond_vs; }}, {"distance", [this](Variant const &v) { - m_handle->distance = get_value(v); + m_handle->m_protocol->distance = get_value(v); }, - [this]() { return m_handle->distance; }}, + [this]() { return m_handle->m_protocol->distance; }}, {"distance_glued_particle_to_vs", [this](Variant const &v) { - m_handle->dist_glued_part_to_vs = get_value(v); + m_handle->m_protocol->dist_glued_part_to_vs = get_value(v); }, - [this]() { return m_handle->dist_glued_part_to_vs; }}, + [this]() { return m_handle->m_protocol->dist_glued_part_to_vs; }}, {"vs_placement", [this](Variant const &v) { - m_handle->vs_placement = get_value(v); + m_handle->m_protocol->vs_placement = get_value(v); }, - [this]() { return m_handle->vs_placement; }}, + [this]() { return m_handle->m_protocol->vs_placement; }}, {"part_type_vs", [this](Variant const &v) { - m_handle->vs_particle_type = get_value(v); + m_handle->m_protocol->vs_particle_type = get_value(v); }, - [this]() { return m_handle->vs_particle_type; }}, + [this]() { return m_handle->m_protocol->vs_particle_type; }}, {"part_type_to_be_glued", [this](Variant const &v) { - m_handle->part_type_to_be_glued = get_value(v); + m_handle->m_protocol->part_type_to_be_glued = get_value(v); }, - [this]() { return m_handle->part_type_to_be_glued; }}, + [this]() { return m_handle->m_protocol->part_type_to_be_glued; }}, {"part_type_to_attach_vs_to", [this](Variant const &v) { - m_handle->part_type_to_attach_vs_to = get_value(v); + m_handle->m_protocol->part_type_to_attach_vs_to = get_value(v); }, - [this]() { return m_handle->part_type_to_attach_vs_to; }}, + [this]() { return m_handle->m_protocol->part_type_to_attach_vs_to; }}, {"part_type_after_glueing", [this](Variant const &v) { - m_handle->part_type_after_glueing = get_value(v); + m_handle->m_protocol->part_type_after_glueing = get_value(v); }, - [this]() { return m_handle->part_type_after_glueing; }}, + [this]() { return m_handle->m_protocol->part_type_after_glueing; }}, }); }