diff --git a/samples/electrophoresis.py b/samples/electrophoresis.py index 907fa07bbe2..efecee935cb 100644 --- a/samples/electrophoresis.py +++ b/samples/electrophoresis.py @@ -33,9 +33,6 @@ logging.basicConfig(level=logging.INFO) -# Use a fixed int for a deterministic behavior -np.random.seed() - required_features = ["P3M", "EXTERNAL_FORCES", "WCA"] espressomd.assert_features(required_features) @@ -133,7 +130,8 @@ # activate electrostatics ############################################################# -p3m = espressomd.electrostatics.P3M(prefactor=1.0, accuracy=1e-2) +p3m_params = {"prefactor": 1., "accuracy": 1e-2} +p3m = espressomd.electrostatics.P3M(**p3m_params) system.electrostatics.solver = p3m # apply external force (external electric field) @@ -160,17 +158,15 @@ obs=obs_bond_length, delta_N=1) system.auto_update_accumulators.add(acc_bond_length) -# data storage for python analysis -############################################################# -pos = np.full((N_SAMPLES, N_MONOMERS, 3), np.nan) +obs_pos = espressomd.observables.ParticlePositions(ids=range(N_MONOMERS)) +acc_pos = espressomd.accumulators.TimeSeries(obs=obs_pos, delta_N=100) +system.auto_update_accumulators.add(acc_pos) # sampling Loop ############################################################# -for i in range(N_SAMPLES): - if i % 100 == 0: - logging.info(f"\rsampling: {i:4d}") - system.integrator.run(N_INT_STEPS) - pos[i] = system.part.by_ids(range(N_MONOMERS)).pos +for i in range(N_SAMPLES // 100): + logging.info(f"\rsampling: {100 * i:4d}") + system.integrator.run(100 * N_INT_STEPS) logging.info("\nsampling finished!\n") @@ -179,6 +175,7 @@ # calculate center of mass (COM) and its velocity ############################################################# +pos = acc_pos.time_series() COM = pos.sum(axis=1) / N_MONOMERS COM_v = (COM[1:] - COM[:-1]) / (N_INT_STEPS * system.time_step) @@ -220,7 +217,7 @@ def exponential(x, lp): # ...second by using observables -def persistence_length_obs( +def persistence_length_from_obs( acc_bond_length, acc_persistence_angles, exponential): bond_lengths_obs = np.array(acc_bond_length.mean()) sampling_positions_obs = np.insert( @@ -233,7 +230,7 @@ def persistence_length_obs( return sampling_positions_obs, cos_thetas_obs, opt_obs[0] -sampling_positions_obs, cos_thetas_obs, persistence_length_obs = persistence_length_obs( +sampling_positions_obs, cos_thetas_obs, persistence_length_obs = persistence_length_from_obs( acc_bond_length, acc_persistence_angles, exponential) logging.info(f"persistence length (observables): {persistence_length_obs}") diff --git a/src/core/BoxGeometry.hpp b/src/core/BoxGeometry.hpp index 7224ec4a2b7..6ba20e48e86 100644 --- a/src/core/BoxGeometry.hpp +++ b/src/core/BoxGeometry.hpp @@ -16,8 +16,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef ESPRESSO_SRC_CORE_BOX_GEOMETRY_HPP -#define ESPRESSO_SRC_CORE_BOX_GEOMETRY_HPP + +#pragma once #include "algorithm/periodic_fold.hpp" #include "lees_edwards/LeesEdwardsBC.hpp" @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace detail { @@ -68,6 +69,28 @@ template T get_mi_coord(T a, T b, T box_length, bool periodic) { return get_mi_coord(a, b, box_length, 1. / box_length, 0.5 * box_length, periodic); } + +/** @brief Calculate image box shift vector. + * @param image_box image box offset + * @param box box length + * @return Image box coordinates. + */ +inline auto image_shift(Utils::Vector3i const &image_box, + Utils::Vector3d const &box) { + return hadamard_product(image_box, box); +} + +/** @brief Unfold particle coordinates to image box. + * @param pos coordinate to unfold + * @param image_box image box offset + * @param box box length + * @return Unfolded coordinates. + */ +inline auto unfolded_position(Utils::Vector3d const &pos, + Utils::Vector3i const &image_box, + Utils::Vector3d const &box) { + return pos + image_shift(image_box, box); +} } // namespace detail enum class BoxType { CUBOID = 0, LEES_EDWARDS = 1 }; @@ -120,7 +143,7 @@ class BoxGeometry { * @return true iff periodic in direction. */ constexpr bool periodic(unsigned coord) const { - assert(coord <= 2); + assert(coord <= 2u); return m_periodic[coord]; } @@ -192,11 +215,11 @@ class BoxGeometry { auto a_tmp = a; auto b_tmp = b; a_tmp[shear_plane_normal] = Algorithm::periodic_fold( - a_tmp[shear_plane_normal], length()[shear_plane_normal]); + a_tmp[shear_plane_normal], m_length[shear_plane_normal]); b_tmp[shear_plane_normal] = Algorithm::periodic_fold( - b_tmp[shear_plane_normal], length()[shear_plane_normal]); - return lees_edwards_bc().distance(a_tmp - b_tmp, length(), length_half(), - length_inv(), m_periodic); + b_tmp[shear_plane_normal], m_length[shear_plane_normal]); + return lees_edwards_bc().distance(a_tmp - b_tmp, m_length, m_length_half, + m_length_inv, m_periodic); } assert(type() == BoxType::CUBOID); return {get_mi_coord(a[0], b[0], 0), get_mi_coord(a[1], b[1], 1), @@ -238,61 +261,54 @@ class BoxGeometry { } return ret; } -}; - -/** @brief Fold a coordinate to primary simulation box. - * @param pos coordinate to fold - * @param image_box image box offset - * @param length box length - */ -inline std::pair fold_coordinate(double pos, int image_box, - double const &length) { - std::tie(pos, image_box) = Algorithm::periodic_fold(pos, image_box, length); - - if ((image_box == std::numeric_limits::min()) || - (image_box == std::numeric_limits::max())) { - throw std::runtime_error( - "Overflow in the image box count while folding a particle coordinate " - "into the primary simulation box. Maybe a particle experienced a " - "huge force."); - } - return {pos, image_box}; -} - -/** @brief Fold particle coordinates to primary simulation box. - * Lees-Edwards offset is ignored. - * @param[in,out] pos coordinate to fold - * @param[in,out] image_box image box offset - * @param[in] box box parameters (side lengths, periodicity) - */ -inline void fold_position(Utils::Vector3d &pos, Utils::Vector3i &image_box, - const BoxGeometry &box) { - for (unsigned int i = 0; i < 3; i++) { - if (box.periodic(i)) { - std::tie(pos[i], image_box[i]) = - fold_coordinate(pos[i], image_box[i], box.length()[i]); + /** @brief Fold coordinates to primary simulation box in-place. + * Lees-Edwards offset is ignored. + * @param[in,out] pos coordinate to fold + * @param[in,out] image_box image box offset + */ + void fold_position(Utils::Vector3d &pos, Utils::Vector3i &image_box) const { + for (unsigned int i = 0u; i < 3u; i++) { + if (m_periodic[i]) { + auto const result = + Algorithm::periodic_fold(pos[i], image_box[i], m_length[i]); + if (result.second == std::numeric_limits::min() or + result.second == std::numeric_limits::max()) { + throw std::runtime_error( + "Overflow in the image box count while folding a particle " + "coordinate into the primary simulation box. Maybe a particle " + "experienced a huge force."); + } + std::tie(pos[i], image_box[i]) = result; + } } } -} -/** @brief Fold particle coordinates to primary simulation box. - * @param p coordinate to fold - * @param box box parameters (side lengths, periodicity) - * @return Folded coordinates. - */ -inline Utils::Vector3d folded_position(const Utils::Vector3d &p, - const BoxGeometry &box) { - Utils::Vector3d p_folded; - for (unsigned int i = 0; i < 3; i++) { - if (box.periodic(i)) { - p_folded[i] = Algorithm::periodic_fold(p[i], box.length()[i]); - } else { - p_folded[i] = p[i]; + /** @brief Calculate coordinates folded to primary simulation box. + * @param p coordinate to fold + * @return Folded coordinates. + */ + auto folded_position(Utils::Vector3d const &p) const { + Utils::Vector3d p_folded; + for (unsigned int i = 0u; i < 3u; i++) { + if (m_periodic[i]) { + p_folded[i] = Algorithm::periodic_fold(p[i], m_length[i]); + } else { + p_folded[i] = p[i]; + } } + + return p_folded; } - return p_folded; -} + /** @brief Calculate image box shift vector */ + auto image_shift(Utils::Vector3i const &image_box) const { + return detail::image_shift(image_box, m_length); + } -#endif + /** @brief Unfold particle coordinates to image box. */ + auto unfolded_position(Utils::Vector3d const &pos, + Utils::Vector3i const &image_box) const { + return detail::unfolded_position(pos, image_box, m_length); + } +}; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6aa9c4aa872..5cd399788a4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -33,7 +33,6 @@ add_library( forcecap.cpp forces.cpp ghosts.cpp - grid.cpp immersed_boundaries.cpp interactions.cpp event.cpp diff --git a/src/core/EspressoSystemStandAlone.cpp b/src/core/EspressoSystemStandAlone.cpp index bc71ba4742f..694ec3200e6 100644 --- a/src/core/EspressoSystemStandAlone.cpp +++ b/src/core/EspressoSystemStandAlone.cpp @@ -19,10 +19,13 @@ #include "config/config.hpp" +#include "BoxGeometry.hpp" #include "EspressoSystemStandAlone.hpp" +#include "cell_system/CellStructure.hpp" +#include "cell_system/CellStructureType.hpp" +#include "cells.hpp" #include "communication.hpp" #include "event.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "system/System.hpp" #include "system/System.impl.hpp" @@ -48,16 +51,20 @@ EspressoSystemStandAlone::EspressoSystemStandAlone(int argc, char **argv) { #ifdef VIRTUAL_SITES set_virtual_sites(std::make_shared()); #endif - ::System::set_system(std::make_shared<::System::System>()); + auto system = std::make_shared<::System::System>(); + ::System::set_system(system); + auto &cell_structure = *system->cell_structure; + cells_re_init(cell_structure, CellStructureType::CELL_STRUCTURE_REGULAR); } void EspressoSystemStandAlone::set_box_l(Utils::Vector3d const &box_l) const { - set_box_length(box_l); + System::get_system().box_geo->set_length(box_l); + on_boxl_change(); } void EspressoSystemStandAlone::set_node_grid( Utils::Vector3i const &node_grid) const { - ::set_node_grid(node_grid); + ::communicator.set_node_grid(node_grid); } void EspressoSystemStandAlone::set_time_step(double time_step) const { diff --git a/src/core/LocalBox.hpp b/src/core/LocalBox.hpp index 432c52f2aee..f78e3f99123 100644 --- a/src/core/LocalBox.hpp +++ b/src/core/LocalBox.hpp @@ -16,25 +16,25 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef ESPRESSO_SRC_CORE_LOCALBOX_HPP -#define ESPRESSO_SRC_CORE_LOCALBOX_HPP + +#pragma once #include "cell_system/CellStructureType.hpp" #include #include -template class LocalBox { - Utils::Vector m_local_box_l = {1, 1, 1}; - Utils::Vector m_lower_corner = {0, 0, 0}; - Utils::Vector m_upper_corner = {1, 1, 1}; +class LocalBox { + Utils::Vector3d m_local_box_l = {1., 1., 1.}; + Utils::Vector3d m_lower_corner = {0., 0., 0.}; + Utils::Vector3d m_upper_corner = {1., 1., 1.}; Utils::Array m_boundaries = {}; CellStructureType m_cell_structure_type; public: LocalBox() = default; - LocalBox(Utils::Vector const &lower_corner, - Utils::Vector const &local_box_length, + LocalBox(Utils::Vector3d const &lower_corner, + Utils::Vector3d const &local_box_length, Utils::Array const &boundaries, CellStructureType const cell_structure_type) : m_local_box_l(local_box_length), m_lower_corner(lower_corner), @@ -42,11 +42,11 @@ template class LocalBox { m_boundaries(boundaries), m_cell_structure_type(cell_structure_type) {} /** Left (bottom, front) corner of this nodes local box. */ - Utils::Vector const &my_left() const { return m_lower_corner; } + auto const &my_left() const { return m_lower_corner; } /** Right (top, back) corner of this nodes local box. */ - Utils::Vector const &my_right() const { return m_upper_corner; } + auto const &my_right() const { return m_upper_corner; } /** Dimensions of the box a single node is responsible for. */ - Utils::Vector const &length() const { return m_local_box_l; } + auto const &length() const { return m_local_box_l; } /** @brief Boundary information for the local box. * * This returns for each of the faces of the local box if @@ -56,17 +56,32 @@ template class LocalBox { * * @return Array with boundary information. */ - Utils::Array const &boundary() const { return m_boundaries; } + auto const &boundary() const { return m_boundaries; } /** Return cell structure type. */ - CellStructureType const &cell_structure_type() const { - return m_cell_structure_type; - } + auto const &cell_structure_type() const { return m_cell_structure_type; } /** Set cell structure type. */ void set_cell_structure_type(CellStructureType cell_structure_type) { m_cell_structure_type = cell_structure_type; } -}; -#endif + static LocalBox make_regular_decomposition(Utils::Vector3d const &box_l, + Utils::Vector3i const &node_index, + Utils::Vector3i const &node_grid) { + + auto const local_length = Utils::hadamard_division(box_l, node_grid); + auto const my_left = Utils::hadamard_product(node_index, local_length); + + decltype(LocalBox::m_boundaries) boundaries; + for (unsigned int dir = 0u; dir < 3u; dir++) { + /* left boundary ? */ + boundaries[2u * dir] = (node_index[dir] == 0); + /* right boundary ? */ + boundaries[2u * dir + 1u] = -(node_index[dir] + 1 == node_grid[dir]); + } + + return {my_left, local_length, boundaries, + CellStructureType::CELL_STRUCTURE_REGULAR}; + } +}; diff --git a/src/core/PartCfg.cpp b/src/core/PartCfg.cpp index 55227795edb..53087faf9cc 100644 --- a/src/core/PartCfg.cpp +++ b/src/core/PartCfg.cpp @@ -19,8 +19,9 @@ #include "PartCfg.hpp" -#include "grid.hpp" +#include "BoxGeometry.hpp" #include "particle_node.hpp" +#include "system/System.hpp" #include @@ -31,6 +32,8 @@ void PartCfg::update() { if (m_valid) return; + auto const &box_geo = *System::get_system().box_geo; + m_parts.clear(); auto const ids = get_particle_ids(); @@ -48,7 +51,7 @@ void PartCfg::update() { m_parts.push_back(get_particle_data(id)); auto &p = m_parts.back(); - p.pos() += image_shift(p.image_box(), box_geo.length()); + p.pos() += box_geo.image_shift(p.image_box()); p.image_box() = {}; } diff --git a/src/core/algorithm/periodic_fold.hpp b/src/core/algorithm/periodic_fold.hpp index cb2278cc2ed..6e00e42a420 100644 --- a/src/core/algorithm/periodic_fold.hpp +++ b/src/core/algorithm/periodic_fold.hpp @@ -33,10 +33,10 @@ namespace Algorithm { * @return x folded into [0, l) and number of folds. */ template -std::pair periodic_fold(T x, I i, T const &l) { +std::pair periodic_fold(T x, I i, T const l) { using limits = std::numeric_limits; - while ((x < 0) && (i > limits::min())) { + while ((x < T{0}) && (i > limits::min())) { x += l; --i; } @@ -56,7 +56,7 @@ std::pair periodic_fold(T x, I i, T const &l) { * @param l Length of primary interval * @return x folded into [0, l). */ -template T periodic_fold(T x, T const &l) { +template T periodic_fold(T x, T const l) { #ifndef __FAST_MATH__ /* Can't fold if either x or l is nan or inf. */ if (std::isnan(x) or std::isnan(l) or std::isinf(x) or (l == 0)) { diff --git a/src/core/analysis/statistics.cpp b/src/core/analysis/statistics.cpp index c8effaf24d9..38a0e9db61a 100644 --- a/src/core/analysis/statistics.cpp +++ b/src/core/analysis/statistics.cpp @@ -26,10 +26,10 @@ #include "analysis/statistics.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "partCfg_global.hpp" #include "system/System.hpp" @@ -48,6 +48,7 @@ double mindist(PartCfg &partCfg, std::vector const &set1, std::vector const &set2) { using Utils::contains; + auto const &box_geo = *System::get_system().box_geo; auto mindist_sq = std::numeric_limits::infinity(); for (auto jt = partCfg.begin(); jt != partCfg.end(); ++jt) { @@ -75,6 +76,8 @@ double mindist(PartCfg &partCfg, std::vector const &set1, Utils::Vector3d calc_linear_momentum(bool include_particles, bool include_lbfluid) { Utils::Vector3d momentum{}; + auto const &system = System::get_system(); + auto &cell_structure = *system.cell_structure; if (include_particles) { auto const particles = cell_structure.local_particles(); momentum = @@ -83,7 +86,6 @@ Utils::Vector3d calc_linear_momentum(bool include_particles, return m + p.mass() * p.v(); }); } - auto const &system = System::get_system(); if (include_lbfluid and system.lb.is_solver_set()) { momentum += system.lb.get_momentum() * system.lb.get_lattice_speed(); } @@ -141,6 +143,7 @@ std::vector nbhood(PartCfg &partCfg, Utils::Vector3d const &pos, double dist) { std::vector ids; auto const dist_sq = dist * dist; + auto const &box_geo = *System::get_system().box_geo; for (auto const &p : partCfg) { auto const r_sq = box_geo.get_mi_vector(pos, p.pos()).norm2(); @@ -157,6 +160,7 @@ calc_part_distribution(PartCfg &partCfg, std::vector const &p1_types, std::vector const &p2_types, double r_min, double r_max, int r_bins, bool log_flag, bool int_flag) { + auto const &box_geo = *System::get_system().box_geo; auto const r_max2 = Utils::sqr(r_max); auto const r_min2 = Utils::sqr(r_min); auto const start_dist2 = Utils::sqr(r_max + 1.); @@ -239,6 +243,7 @@ structure_factor(PartCfg &partCfg, std::vector const &p_types, int order) { if (order < 1) throw std::domain_error("order has to be a strictly positive number"); + auto const &box_geo = *System::get_system().box_geo; auto const order_sq = Utils::sqr(static_cast(order)); auto const twoPI_L = 2. * Utils::pi() * box_geo.length_inv()[0]; std::vector ff(2 * order_sq + 1); diff --git a/src/core/analysis/statistics_chain.cpp b/src/core/analysis/statistics_chain.cpp index 8787674c8f1..097781947e8 100644 --- a/src/core/analysis/statistics_chain.cpp +++ b/src/core/analysis/statistics_chain.cpp @@ -24,9 +24,10 @@ #include "analysis/statistics_chain.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" -#include "grid.hpp" #include "particle_node.hpp" +#include "system/System.hpp" #include #include @@ -36,6 +37,7 @@ #include std::array calc_re(int chain_start, int n_chains, int chain_length) { + auto const &box_geo = *System::get_system().box_geo; double dist = 0.0, dist2 = 0.0, dist4 = 0.0; std::array re; @@ -44,9 +46,8 @@ std::array calc_re(int chain_start, int n_chains, int chain_length) { get_particle_data(chain_start + i * chain_length + chain_length - 1); auto const &p2 = get_particle_data(chain_start + i * chain_length); - auto const d = - unfolded_position(p1.pos(), p1.image_box(), box_geo.length()) - - unfolded_position(p2.pos(), p2.image_box(), box_geo.length()); + auto const d = box_geo.unfolded_position(p1.pos(), p1.image_box()) - + box_geo.unfolded_position(p2.pos(), p2.image_box()); auto const norm2 = d.norm2(); dist += sqrt(norm2); dist2 += norm2; @@ -61,6 +62,7 @@ std::array calc_re(int chain_start, int n_chains, int chain_length) { } std::array calc_rg(int chain_start, int n_chains, int chain_length) { + auto const &box_geo = *System::get_system().box_geo; double r_G = 0.0, r_G2 = 0.0, r_G4 = 0.0; std::array rg; @@ -75,16 +77,14 @@ std::array calc_rg(int chain_start, int n_chains, int chain_length) { "Gyration tensor is not well-defined for chains including virtual " "sites. Virtual sites do not have a meaningful mass."); } - r_CM += unfolded_position(p.pos(), p.image_box(), box_geo.length()) * - p.mass(); + r_CM += box_geo.unfolded_position(p.pos(), p.image_box()) * p.mass(); M += p.mass(); } r_CM /= M; double tmp = 0.0; for (int j = 0; j < chain_length; ++j) { auto const &p = get_particle_data(chain_start + i * chain_length + j); - Utils::Vector3d const d = - unfolded_position(p.pos(), p.image_box(), box_geo.length()) - r_CM; + auto const d = box_geo.unfolded_position(p.pos(), p.image_box()) - r_CM; tmp += d.norm2(); } tmp /= static_cast(chain_length); @@ -101,6 +101,7 @@ std::array calc_rg(int chain_start, int n_chains, int chain_length) { } std::array calc_rh(int chain_start, int n_chains, int chain_length) { + auto const &box_geo = *System::get_system().box_geo; double r_H = 0.0, r_H2 = 0.0; std::array rh; @@ -113,9 +114,8 @@ std::array calc_rh(int chain_start, int n_chains, int chain_length) { auto const &p1 = get_particle_data(i); for (int j = i + 1; j < chain_start + chain_length * (p + 1); j++) { auto const &p2 = get_particle_data(j); - auto const d = - unfolded_position(p1.pos(), p1.image_box(), box_geo.length()) - - unfolded_position(p2.pos(), p2.image_box(), box_geo.length()); + auto const d = box_geo.unfolded_position(p1.pos(), p1.image_box()) - + box_geo.unfolded_position(p2.pos(), p2.image_box()); ri += 1.0 / d.norm(); } } diff --git a/src/core/bond_breakage/bond_breakage.cpp b/src/core/bond_breakage/bond_breakage.cpp index f50275f2344..efe151e4def 100644 --- a/src/core/bond_breakage/bond_breakage.cpp +++ b/src/core/bond_breakage/bond_breakage.cpp @@ -16,13 +16,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include "bond_breakage/bond_breakage.hpp" #include "bond_breakage/actions.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" +#include "system/System.hpp" #include @@ -137,6 +139,8 @@ ActionSet actions_for_breakage(QueueEntry const &e) { return {DeleteBond{e.particle_id, *(e.bond_partners[0]), e.bond_type}}; } #ifdef VIRTUAL_SITES_RELATIVE + auto const &system = System::get_system(); + auto const &cell_structure = *system.cell_structure; // revert bind at point of collision for pair bonds if ((*spec).action_type == ActionType::REVERT_BIND_AT_POINT_OF_COLLISION and not is_angle_bond(e.bond_partners)) { @@ -217,21 +221,25 @@ static void remove_pair_bonds_to(Particle &p, int other_pid) { // Handler for the different delete events class execute : public boost::static_visitor<> { + CellStructure &cell_structure; + public: + execute() : cell_structure{*System::get_system().cell_structure} {} + void operator()(DeleteBond const &d) const { - if (auto p = ::cell_structure.get_local_particle(d.particle_id)) { + if (auto p = cell_structure.get_local_particle(d.particle_id)) { remove_bond(*p, BondView(d.bond_type, {&d.bond_partner_id, 1})); } on_particle_change(); } void operator()(DeleteAngleBond const &d) const { - if (auto p = ::cell_structure.get_local_particle(d.particle_id)) { + if (auto p = cell_structure.get_local_particle(d.particle_id)) { remove_bond(*p, BondView(d.bond_type, {&d.bond_partner_id[0], 2})); } on_particle_change(); } void operator()(DeleteAllBonds const &d) const { - if (auto p = ::cell_structure.get_local_particle(d.particle_id_1)) { + if (auto p = cell_structure.get_local_particle(d.particle_id_1)) { remove_pair_bonds_to(*p, d.particle_id_2); } on_particle_change(); diff --git a/src/core/bonded_interactions/angle_common.hpp b/src/core/bonded_interactions/angle_common.hpp index 3da4b2e7d45..8c12849be3f 100644 --- a/src/core/bonded_interactions/angle_common.hpp +++ b/src/core/bonded_interactions/angle_common.hpp @@ -25,49 +25,41 @@ */ #include "config/config.hpp" -#include "grid.hpp" #include +#include #include +namespace detail { +inline double sanitize_cosine(double cosine) { + if (cosine > TINY_COS_VALUE) + cosine = TINY_COS_VALUE; + if (cosine < -TINY_COS_VALUE) + cosine = -TINY_COS_VALUE; + return cosine; +} +} // namespace detail + /** Compute the cosine of the angle between three particles. * - * Also return all intermediate quantities: normalized vectors - * @f$ \vec{r_{ij}} @f$ (from particle @f$ j @f$ to particle @f$ i @f$) - * and @f$ \vec{r_{kj}} @f$, and their normalization constants. - * - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. * @param[in] sanitize_cosine Sanitize the cosine of the angle. * @return @f$ \vec{r_{ij}} @f$, @f$ \vec{r_{kj}} @f$, * @f$ \left\|\vec{r_{ij}}\right\|^{-1} @f$, * @f$ \left\|\vec{r_{kj}}\right\|^{-1} @f$, * @f$ \cos(\theta_{ijk}) @f$ */ -inline std::tuple -calc_vectors_and_cosine(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right, - bool sanitize_cosine = false) { - /* normalized vector from p_mid to p_left */ - auto vec1 = box_geo.get_mi_vector(r_left, r_mid); - auto const d1i = 1.0 / vec1.norm(); - vec1 *= d1i; - /* normalized vector from p_mid to p_right */ - auto vec2 = box_geo.get_mi_vector(r_right, r_mid); - auto const d2i = 1.0 / vec2.norm(); - vec2 *= d2i; +inline double calc_cosine(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2, + bool sanitize_cosine = false) { /* cosine of the angle between vec1 and vec2 */ - auto cosine = vec1 * vec2; + auto cos_phi = (vec1 * vec2) / std::sqrt(vec1.norm2() * vec2.norm2()); if (sanitize_cosine) { - if (cosine > TINY_COS_VALUE) - cosine = TINY_COS_VALUE; - if (cosine < -TINY_COS_VALUE) - cosine = -TINY_COS_VALUE; + cos_phi = detail::sanitize_cosine(cos_phi); } - return std::make_tuple(vec1, vec2, d1i, d2i, cosine); + return cos_phi; } /** Compute a three-body angle interaction force. @@ -75,9 +67,8 @@ calc_vectors_and_cosine(Utils::Vector3d const &r_mid, * See the details in @ref bondedIA_angle_force. The @f$ K(\theta_{ijk}) @f$ * term is provided as a lambda function in @p forceFactor. * - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. * @param[in] forceFactor Angle force term. * @param[in] sanitize_cosine Sanitize the cosine of the angle. * @tparam ForceFactor Function evaluating the angle force term @@ -86,16 +77,21 @@ calc_vectors_and_cosine(Utils::Vector3d const &r_mid, */ template std::tuple -angle_generic_force(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right, ForceFactor forceFactor, - bool sanitize_cosine) { - auto const [vec1, vec2, d1i, d2i, cosine] = - calc_vectors_and_cosine(r_mid, r_left, r_right, sanitize_cosine); +angle_generic_force(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2, + ForceFactor forceFactor, bool sanitize_cosine) { + auto const d1 = vec1.norm(); + auto const d2 = vec2.norm(); + auto cos_phi = (vec1 * vec2) / (d1 * d2); + if (sanitize_cosine) { + cos_phi = detail::sanitize_cosine(cos_phi); + } /* force factor */ - auto const fac = forceFactor(cosine); + auto const fac = forceFactor(cos_phi); /* distribute forces */ - auto f_left = (fac * d1i) * (vec1 * cosine - vec2); - auto f_right = (fac * d2i) * (vec2 * cosine - vec1); + auto const v1 = vec1 / d1; + auto const v2 = vec2 / d2; + auto f_left = (fac / d1) * (v1 * cos_phi - v2); + auto f_right = (fac / d2) * (v2 * cos_phi - v1); auto f_mid = -(f_left + f_right); return std::make_tuple(f_mid, f_left, f_right); } diff --git a/src/core/bonded_interactions/angle_cosine.hpp b/src/core/bonded_interactions/angle_cosine.hpp index b9918fd102f..4e455b0b1fc 100644 --- a/src/core/bonded_interactions/angle_cosine.hpp +++ b/src/core/bonded_interactions/angle_cosine.hpp @@ -26,6 +26,7 @@ * @ref bondedIA_angle_cosine. */ +#include "BoxGeometry.hpp" #include "angle_common.hpp" #include @@ -52,10 +53,8 @@ struct AngleCosineBond { AngleCosineBond(double bend, double phi0); std::tuple - forces(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const; - double energy(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const; + forces(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; + double energy(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; private: friend boost::serialization::access; @@ -69,15 +68,13 @@ struct AngleCosineBond { }; /** Compute the three-body angle interaction force. - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. * @return Forces on the second, first and third particles, in that order. */ inline std::tuple -AngleCosineBond::forces(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const { +AngleCosineBond::forces(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { auto forceFactor = [this](double const cos_phi) { auto const sin_phi = sqrt(1 - Utils::sqr(cos_phi)); @@ -86,19 +83,16 @@ AngleCosineBond::forces(Utils::Vector3d const &r_mid, return -bend * (sin_phi * cos_phi0 - cos_phi * sin_phi0) / sin_phi; }; - return angle_generic_force(r_mid, r_left, r_right, forceFactor, false); + return angle_generic_force(vec1, vec2, forceFactor, false); } /** Computes the three-body angle interaction energy. - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. */ -inline double AngleCosineBond::energy(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const { - auto const vectors = calc_vectors_and_cosine(r_mid, r_left, r_right, true); - auto const cos_phi = std::get<4>(vectors); +inline double AngleCosineBond::energy(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { + auto const cos_phi = calc_cosine(vec1, vec2, true); auto const sin_phi = sqrt(1 - Utils::sqr(cos_phi)); // potential: U(phi) = k * [1 - cos(phi - phi0)] // trig identity: cos(phi - phi0) = cos(phi)cos(phi0) + sin(phi)sin(phi0) diff --git a/src/core/bonded_interactions/angle_cossquare.hpp b/src/core/bonded_interactions/angle_cossquare.hpp index 473ea7817d2..b29d6c9cbeb 100644 --- a/src/core/bonded_interactions/angle_cossquare.hpp +++ b/src/core/bonded_interactions/angle_cossquare.hpp @@ -49,10 +49,8 @@ struct AngleCossquareBond { AngleCossquareBond(double bend, double phi0); std::tuple - forces(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const; - double energy(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const; + forces(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; + double energy(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; private: friend boost::serialization::access; @@ -65,33 +63,28 @@ struct AngleCossquareBond { }; /** Compute the three-body angle interaction force. - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. * @return Forces on the second, first and third particles, in that order. */ inline std::tuple -AngleCossquareBond::forces(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const { +AngleCossquareBond::forces(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { auto forceFactor = [this](double const cos_phi) { return bend * (cos_phi - cos_phi0); }; - return angle_generic_force(r_mid, r_left, r_right, forceFactor, false); + return angle_generic_force(vec1, vec2, forceFactor, false); } /** Computes the three-body angle interaction energy. - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. */ -inline double AngleCossquareBond::energy(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const { - auto const vectors = calc_vectors_and_cosine(r_mid, r_left, r_right, true); - auto const cos_phi = std::get<4>(vectors); +inline double AngleCossquareBond::energy(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { + auto const cos_phi = calc_cosine(vec1, vec2, true); return 0.5 * bend * Utils::sqr(cos_phi - cos_phi0); } diff --git a/src/core/bonded_interactions/angle_harmonic.hpp b/src/core/bonded_interactions/angle_harmonic.hpp index a1f53d08da2..f0c813d3766 100644 --- a/src/core/bonded_interactions/angle_harmonic.hpp +++ b/src/core/bonded_interactions/angle_harmonic.hpp @@ -51,10 +51,8 @@ struct AngleHarmonicBond { } std::tuple - forces(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const; - double energy(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const; + forces(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; + double energy(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; private: friend boost::serialization::access; @@ -66,15 +64,13 @@ struct AngleHarmonicBond { }; /** Compute the three-body angle interaction force. - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. * @return Forces on the second, first and third particles, in that order. */ inline std::tuple -AngleHarmonicBond::forces(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const { +AngleHarmonicBond::forces(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { auto forceFactor = [this](double const cos_phi) { auto const sin_phi = sqrt(1 - Utils::sqr(cos_phi)); @@ -82,19 +78,16 @@ AngleHarmonicBond::forces(Utils::Vector3d const &r_mid, return -bend * (phi - phi0) / sin_phi; }; - return angle_generic_force(r_mid, r_left, r_right, forceFactor, true); + return angle_generic_force(vec1, vec2, forceFactor, true); } /** Compute the three-body angle interaction energy. - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. */ -inline double AngleHarmonicBond::energy(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const { - auto const vectors = calc_vectors_and_cosine(r_mid, r_left, r_right, true); - auto const cos_phi = std::get<4>(vectors); +inline double AngleHarmonicBond::energy(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { + auto const cos_phi = calc_cosine(vec1, vec2, true); auto const phi = acos(cos_phi); return 0.5 * bend * Utils::sqr(phi - phi0); } diff --git a/src/core/bonded_interactions/bonded_interactions.dox b/src/core/bonded_interactions/bonded_interactions.dox index 314415a1378..b559a6c6996 100644 --- a/src/core/bonded_interactions/bonded_interactions.dox +++ b/src/core/bonded_interactions/bonded_interactions.dox @@ -134,8 +134,8 @@ * @code * # enable boost::variant with more than 20 types * target_compile_options( - * EspressoCppFlags INTERFACE -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS - * -DBOOST_MPL_LIMIT_LIST_SIZE=40) + * espresso_cpp_flags INTERFACE -DBOOST_MPL_CFG_NO_PREPROCESSED_HEADERS + * -DBOOST_MPL_LIMIT_LIST_SIZE=40) * @endcode * * In forces_inline.hpp: * - A call to the new bond's force calculation needs to be placed in either diff --git a/src/core/bonded_interactions/bonded_tab.hpp b/src/core/bonded_interactions/bonded_tab.hpp index 0725aad8fe1..70739fad20d 100644 --- a/src/core/bonded_interactions/bonded_tab.hpp +++ b/src/core/bonded_interactions/bonded_tab.hpp @@ -92,10 +92,8 @@ struct TabulatedAngleBond : public TabulatedBond { TabulatedAngleBond(double min, double max, std::vector const &energy, std::vector const &force); std::tuple - forces(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const; - double energy(Utils::Vector3d const &r_mid, Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const; + forces(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; + double energy(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; }; /** Parameters for 4-body tabulated potential. */ @@ -109,12 +107,11 @@ struct TabulatedDihedralBond : public TabulatedBond { std::vector const &force); boost::optional> - forces(Utils::Vector3d const &r1, Utils::Vector3d const &r2, - Utils::Vector3d const &r3, Utils::Vector3d const &r4) const; - boost::optional energy(Utils::Vector3d const &r1, - Utils::Vector3d const &r2, - Utils::Vector3d const &r3, - Utils::Vector3d const &r4) const; + forces(Utils::Vector3d const &v12, Utils::Vector3d const &v23, + Utils::Vector3d const &v34) const; + boost::optional energy(Utils::Vector3d const &v12, + Utils::Vector3d const &v23, + Utils::Vector3d const &v34) const; }; /** Compute a tabulated bond length force. @@ -155,15 +152,13 @@ TabulatedDistanceBond::energy(Utils::Vector3d const &dx) const { } /** Compute the three-body angle interaction force. - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. * @return Forces on the second, first and third particles, in that order. */ inline std::tuple -TabulatedAngleBond::forces(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const { +TabulatedAngleBond::forces(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { auto forceFactor = [this](double const cos_phi) { auto const sin_phi = sqrt(1 - Utils::sqr(cos_phi)); @@ -177,22 +172,19 @@ TabulatedAngleBond::forces(Utils::Vector3d const &r_mid, return -gradient / sin_phi; }; - return angle_generic_force(r_mid, r_left, r_right, forceFactor, true); + return angle_generic_force(vec1, vec2, forceFactor, true); } /** Compute the three-body angle interaction energy. * It is assumed that the potential is tabulated * for all angles between 0 and Pi. * - * @param[in] r_mid Position of second/middle particle. - * @param[in] r_left Position of first/left particle. - * @param[in] r_right Position of third/right particle. + * @param[in] vec1 Vector from central particle to left particle. + * @param[in] vec2 Vector from central particle to right particle. */ -inline double TabulatedAngleBond::energy(Utils::Vector3d const &r_mid, - Utils::Vector3d const &r_left, - Utils::Vector3d const &r_right) const { - auto const vectors = calc_vectors_and_cosine(r_mid, r_left, r_right, true); - auto const cos_phi = std::get<4>(vectors); +inline double TabulatedAngleBond::energy(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { + auto const cos_phi = calc_cosine(vec1, vec2, true); /* calculate phi */ #ifdef TABANGLEMINUS auto const phi = acos(-cos_phi); @@ -206,28 +198,25 @@ inline double TabulatedAngleBond::energy(Utils::Vector3d const &r_mid, * The forces have a singularity at @f$ \phi = 0 @f$ and @f$ \phi = \pi @f$ * (see @cite swope92a page 592). * - * @param[in] r1 Position of the first particle. - * @param[in] r2 Position of the second particle. - * @param[in] r3 Position of the third particle. - * @param[in] r4 Position of the fourth particle. + * @param[in] v12 Vector from @p p1 to @p p2 + * @param[in] v23 Vector from @p p2 to @p p3 + * @param[in] v34 Vector from @p p3 to @p p4 * @return the forces on @p p2, @p p1, @p p3 */ inline boost::optional> -TabulatedDihedralBond::forces(Utils::Vector3d const &r1, - Utils::Vector3d const &r2, - Utils::Vector3d const &r3, - Utils::Vector3d const &r4) const { +TabulatedDihedralBond::forces(Utils::Vector3d const &v12, + Utils::Vector3d const &v23, + Utils::Vector3d const &v34) const { /* vectors for dihedral angle calculation */ - Utils::Vector3d v12, v23, v34, v12Xv23, v23Xv34; + Utils::Vector3d v12Xv23, v23Xv34; double l_v12Xv23, l_v23Xv34; /* dihedral angle, cosine of the dihedral angle */ double phi, cos_phi; /* dihedral angle */ - auto const angle_is_undefined = - calc_dihedral_angle(r1, r2, r3, r4, v12, v23, v34, v12Xv23, l_v12Xv23, - v23Xv34, l_v23Xv34, cos_phi, phi); + auto const angle_is_undefined = calc_dihedral_angle( + v12, v23, v34, v12Xv23, l_v12Xv23, v23Xv34, l_v23Xv34, cos_phi, phi); /* dihedral angle not defined - force zero */ if (angle_is_undefined) { return {}; @@ -255,22 +244,21 @@ TabulatedDihedralBond::forces(Utils::Vector3d const &r1, /** Compute the four-body dihedral interaction energy. * The energy doesn't have any singularity if the angle phi is well-defined. * - * @param[in] r1 Position of the first particle. - * @param[in] r2 Position of the second particle. - * @param[in] r3 Position of the third particle. - * @param[in] r4 Position of the fourth particle. + * @param[in] v12 Vector from @p p1 to @p p2 + * @param[in] v23 Vector from @p p2 to @p p3 + * @param[in] v34 Vector from @p p3 to @p p4 */ -inline boost::optional TabulatedDihedralBond::energy( - Utils::Vector3d const &r1, Utils::Vector3d const &r2, - Utils::Vector3d const &r3, Utils::Vector3d const &r4) const { +inline boost::optional +TabulatedDihedralBond::energy(Utils::Vector3d const &v12, + Utils::Vector3d const &v23, + Utils::Vector3d const &v34) const { /* vectors for dihedral calculations. */ - Utils::Vector3d v12, v23, v34, v12Xv23, v23Xv34; + Utils::Vector3d v12Xv23, v23Xv34; double l_v12Xv23, l_v23Xv34; /* dihedral angle, cosine of the dihedral angle */ double phi, cos_phi; - auto const angle_is_undefined = - calc_dihedral_angle(r1, r2, r3, r4, v12, v23, v34, v12Xv23, l_v12Xv23, - v23Xv34, l_v23Xv34, cos_phi, phi); + auto const angle_is_undefined = calc_dihedral_angle( + v12, v23, v34, v12Xv23, l_v12Xv23, v23Xv34, l_v23Xv34, cos_phi, phi); /* dihedral angle not defined - energy zero */ if (angle_is_undefined) { return {}; diff --git a/src/core/bonded_interactions/dihedral.hpp b/src/core/bonded_interactions/dihedral.hpp index 63c28fef1cd..f5281dd0061 100644 --- a/src/core/bonded_interactions/dihedral.hpp +++ b/src/core/bonded_interactions/dihedral.hpp @@ -27,9 +27,7 @@ * the maximal bond length! */ -#include "BoxGeometry.hpp" #include "config/config.hpp" -#include "grid.hpp" #include #include @@ -57,13 +55,12 @@ struct DihedralBond { boost::optional> - forces(Utils::Vector3d const &r1, Utils::Vector3d const &r2, - Utils::Vector3d const &r3, Utils::Vector3d const &r4) const; + forces(Utils::Vector3d const &v12, Utils::Vector3d const &v23, + Utils::Vector3d const &v34) const; - inline boost::optional energy(Utils::Vector3d const &r1, - Utils::Vector3d const &r2, - Utils::Vector3d const &r3, - Utils::Vector3d const &r4) const; + boost::optional energy(Utils::Vector3d const &v12, + Utils::Vector3d const &v23, + Utils::Vector3d const &v34) const; private: friend boost::serialization::access; @@ -85,10 +82,9 @@ struct DihedralBond { * If the a,b or b,c are parallel the dihedral angle is not defined in which * case the function returns true. Calling functions should check for that. * - * @param[in] r1 , r2 , r3 , r4 Positions of the particles forming the dihedral - * @param[out] a Vector from @p p1 to @p p2 - * @param[out] b Vector from @p p2 to @p p3 - * @param[out] c Vector from @p p3 to @p p4 + * @param[in] a Vector from @p p1 to @p p2 + * @param[in] b Vector from @p p2 to @p p3 + * @param[in] c Vector from @p p3 to @p p4 * @param[out] aXb Vector product of a and b * @param[out] l_aXb |aXB| * @param[out] bXc Vector product of b and c @@ -97,15 +93,11 @@ struct DihedralBond { * @param[out] phi Dihedral angle in the range [0, pi] * @return Whether the angle is undefined. */ -inline bool -calc_dihedral_angle(Utils::Vector3d const &r1, Utils::Vector3d const &r2, - Utils::Vector3d const &r3, Utils::Vector3d const &r4, - Utils::Vector3d &a, Utils::Vector3d &b, Utils::Vector3d &c, - Utils::Vector3d &aXb, double &l_aXb, Utils::Vector3d &bXc, - double &l_bXc, double &cosphi, double &phi) { - a = box_geo.get_mi_vector(r2, r1); - b = box_geo.get_mi_vector(r3, r2); - c = box_geo.get_mi_vector(r4, r3); +inline bool calc_dihedral_angle(Utils::Vector3d const &a, + Utils::Vector3d const &b, + Utils::Vector3d const &c, Utils::Vector3d &aXb, + double &l_aXb, Utils::Vector3d &bXc, + double &l_bXc, double &cosphi, double &phi) { /* calculate vector product a X b and b X c */ aXb = vector_product(a, b); @@ -141,27 +133,24 @@ calc_dihedral_angle(Utils::Vector3d const &r1, Utils::Vector3d const &r2, * The forces have a singularity at @f$ \phi = 0 @f$ and @f$ \phi = \pi @f$ * (see @cite swope92a page 592). * - * @param[in] r1 Position of the first particle. - * @param[in] r2 Position of the second particle. - * @param[in] r3 Position of the third particle. - * @param[in] r4 Position of the fourth particle. + * @param[in] v12 Vector from @p p1 to @p p2 + * @param[in] v23 Vector from @p p2 to @p p3 + * @param[in] v34 Vector from @p p3 to @p p4 * @return the forces on @p p2, @p p1, @p p3 */ inline boost::optional> -DihedralBond::forces(Utils::Vector3d const &r1, Utils::Vector3d const &r2, - Utils::Vector3d const &r3, - Utils::Vector3d const &r4) const { +DihedralBond::forces(Utils::Vector3d const &v12, Utils::Vector3d const &v23, + Utils::Vector3d const &v34) const { /* vectors for dihedral angle calculation */ - Utils::Vector3d v12, v23, v34, v12Xv23, v23Xv34; + Utils::Vector3d v12Xv23, v23Xv34; double l_v12Xv23, l_v23Xv34; /* dihedral angle, cosine of the dihedral angle */ double phi, cos_phi, sin_mphi_over_sin_phi; /* dihedral angle */ - auto const angle_is_undefined = - calc_dihedral_angle(r1, r2, r3, r4, v12, v23, v34, v12Xv23, l_v12Xv23, - v23Xv34, l_v23Xv34, cos_phi, phi); + auto const angle_is_undefined = calc_dihedral_angle( + v12, v23, v34, v12Xv23, l_v12Xv23, v23Xv34, l_v23Xv34, cos_phi, phi); /* dihedral angle not defined - force zero */ if (angle_is_undefined) { return {}; @@ -199,24 +188,21 @@ DihedralBond::forces(Utils::Vector3d const &r1, Utils::Vector3d const &r2, /** Compute the four-body dihedral interaction energy. * The energy doesn't have any singularity if the angle phi is well-defined. * - * @param[in] r1 Position of the first particle. - * @param[in] r2 Position of the second particle. - * @param[in] r3 Position of the third particle. - * @param[in] r4 Position of the fourth particle. + * @param[in] v12 Vector from @p p1 to @p p2 + * @param[in] v23 Vector from @p p2 to @p p3 + * @param[in] v34 Vector from @p p3 to @p p4 */ inline boost::optional -DihedralBond::energy(Utils::Vector3d const &r1, Utils::Vector3d const &r2, - Utils::Vector3d const &r3, - Utils::Vector3d const &r4) const { +DihedralBond::energy(Utils::Vector3d const &v12, Utils::Vector3d const &v23, + Utils::Vector3d const &v34) const { /* vectors for dihedral calculations. */ - Utils::Vector3d v12, v23, v34, v12Xv23, v23Xv34; + Utils::Vector3d v12Xv23, v23Xv34; double l_v12Xv23, l_v23Xv34; /* dihedral angle, cosine of the dihedral angle */ double phi, cos_phi; - auto const angle_is_undefined = - calc_dihedral_angle(r1, r2, r3, r4, v12, v23, v34, v12Xv23, l_v12Xv23, - v23Xv34, l_v23Xv34, cos_phi, phi); + auto const angle_is_undefined = calc_dihedral_angle( + v12, v23, v34, v12Xv23, l_v12Xv23, v23Xv34, l_v23Xv34, cos_phi, phi); /* dihedral angle not defined - energy zero */ if (angle_is_undefined) { return {}; diff --git a/src/core/cell_system/AtomDecomposition.cpp b/src/core/cell_system/AtomDecomposition.cpp index 66618d2a580..bd538039767 100644 --- a/src/core/cell_system/AtomDecomposition.cpp +++ b/src/core/cell_system/AtomDecomposition.cpp @@ -102,7 +102,7 @@ void AtomDecomposition::mark_cells() { void AtomDecomposition::resort(bool global_flag, std::vector &diff) { for (auto &p : local().particles()) { - fold_position(p.pos(), p.image_box(), m_box); + m_box.fold_position(p.pos(), p.image_box()); p.pos_at_last_verlet_update() = p.pos(); } diff --git a/src/core/cell_system/CellStructure.cpp b/src/core/cell_system/CellStructure.cpp index 0ecdcc00ce9..7eedbcd27ed 100644 --- a/src/core/cell_system/CellStructure.cpp +++ b/src/core/cell_system/CellStructure.cpp @@ -27,7 +27,6 @@ #include "cell_system/RegularDecomposition.hpp" #include "cell_system/CellStructureType.hpp" -#include "grid.hpp" #include "lees_edwards/lees_edwards.hpp" #include @@ -256,7 +255,7 @@ void CellStructure::resort_particles(bool global_flag, BoxGeometry const &box) { void CellStructure::set_atom_decomposition(boost::mpi::communicator const &comm, BoxGeometry const &box, - LocalBox &local_geo) { + LocalBox &local_geo) { set_particle_decomposition(std::make_unique(comm, box)); m_type = CellStructureType::CELL_STRUCTURE_NSQUARE; local_geo.set_cell_structure_type(m_type); @@ -264,7 +263,7 @@ void CellStructure::set_atom_decomposition(boost::mpi::communicator const &comm, void CellStructure::set_regular_decomposition( boost::mpi::communicator const &comm, double range, BoxGeometry const &box, - LocalBox &local_geo) { + LocalBox &local_geo) { set_particle_decomposition( std::make_unique(comm, range, box, local_geo)); m_type = CellStructureType::CELL_STRUCTURE_REGULAR; @@ -273,8 +272,7 @@ void CellStructure::set_regular_decomposition( void CellStructure::set_hybrid_decomposition( boost::mpi::communicator const &comm, double cutoff_regular, - BoxGeometry const &box, LocalBox &local_geo, - std::set n_square_types) { + BoxGeometry const &box, LocalBox &local_geo, std::set n_square_types) { set_particle_decomposition(std::make_unique( comm, cutoff_regular, box, local_geo, n_square_types)); m_type = CellStructureType::CELL_STRUCTURE_HYBRID; diff --git a/src/core/cell_system/CellStructure.hpp b/src/core/cell_system/CellStructure.hpp index 27c487e9b3d..3b5b0b4e49d 100644 --- a/src/core/cell_system/CellStructure.hpp +++ b/src/core/cell_system/CellStructure.hpp @@ -19,8 +19,7 @@ * along with this program. If not, see . */ -#ifndef ESPRESSO_SRC_CORE_CELL_SYSTEM_CELL_STRUCTURE_HPP -#define ESPRESSO_SRC_CORE_CELL_SYSTEM_CELL_STRUCTURE_HPP +#pragma once #include "cell_system/ParticleDecomposition.hpp" @@ -40,8 +39,6 @@ #include #include -#include -#include #include #include @@ -53,6 +50,10 @@ #include #include +namespace boost::mpi { +class communicator; +} + namespace Cells { enum Resort : unsigned { RESORT_NONE = 0u, @@ -517,8 +518,7 @@ struct CellStructure { * @param local_geo Geometry of the local box (holds cell structure type). */ void set_atom_decomposition(boost::mpi::communicator const &comm, - BoxGeometry const &box, - LocalBox &local_geo); + BoxGeometry const &box, LocalBox &local_geo); /** * @brief Set the particle decomposition to @ref RegularDecomposition. @@ -530,7 +530,7 @@ struct CellStructure { */ void set_regular_decomposition(boost::mpi::communicator const &comm, double range, BoxGeometry const &box, - LocalBox &local_geo); + LocalBox &local_geo); /** * @brief Set the particle decomposition to @ref HybridDecomposition. @@ -543,7 +543,7 @@ struct CellStructure { */ void set_hybrid_decomposition(boost::mpi::communicator const &comm, double cutoff_regular, BoxGeometry const &box, - LocalBox &local_geo, + LocalBox &local_geo, std::set n_square_types); private: @@ -744,5 +744,3 @@ struct CellStructure { } } }; - -#endif diff --git a/src/core/cell_system/HybridDecomposition.cpp b/src/core/cell_system/HybridDecomposition.cpp index 073c03b636e..a921eecde05 100644 --- a/src/core/cell_system/HybridDecomposition.cpp +++ b/src/core/cell_system/HybridDecomposition.cpp @@ -43,7 +43,7 @@ HybridDecomposition::HybridDecomposition(boost::mpi::communicator comm, double cutoff_regular, BoxGeometry const &box_geo, - LocalBox const &local_box, + LocalBox const &local_box, std::set n_square_types) : m_comm(std::move(comm)), m_box(box_geo), m_cutoff_regular(cutoff_regular), m_regular_decomposition(RegularDecomposition( diff --git a/src/core/cell_system/HybridDecomposition.hpp b/src/core/cell_system/HybridDecomposition.hpp index 6db52dbc5eb..d58ffbf326d 100644 --- a/src/core/cell_system/HybridDecomposition.hpp +++ b/src/core/cell_system/HybridDecomposition.hpp @@ -77,8 +77,7 @@ class HybridDecomposition : public ParticleDecomposition { public: HybridDecomposition(boost::mpi::communicator comm, double cutoff_regular, - BoxGeometry const &box_geo, - LocalBox const &local_box, + BoxGeometry const &box_geo, LocalBox const &local_box, std::set n_square_types); Utils::Vector3i get_cell_grid() const { diff --git a/src/core/cell_system/RegularDecomposition.cpp b/src/core/cell_system/RegularDecomposition.cpp index 6500a57a829..b3be169b98e 100644 --- a/src/core/cell_system/RegularDecomposition.cpp +++ b/src/core/cell_system/RegularDecomposition.cpp @@ -23,9 +23,10 @@ #include "cell_system/Cell.hpp" +#include "communication.hpp" #include "error_handling/RuntimeErrorStream.hpp" #include "errorhandling.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -53,7 +54,7 @@ Cell *RegularDecomposition::position_to_cell(const Utils::Vector3d &pos) { Utils::Vector3i cpos; - for (unsigned int i = 0; i < 3; i++) { + for (unsigned int i = 0u; i < 3u; i++) { cpos[i] = static_cast(std::floor(pos[i] * inv_cell_size[i])) + 1 - cell_offset[i]; @@ -63,14 +64,14 @@ Cell *RegularDecomposition::position_to_cell(const Utils::Vector3d &pos) { the particle belongs here and could otherwise potentially be dismissed due to rounding errors. */ if (cpos[i] < 1) { - if ((!m_box.periodic(i) or (pos[i] >= m_box.length()[i])) && - m_local_box.boundary()[2 * i]) + if ((!m_box.periodic(i) or (pos[i] >= m_box.length()[i])) and + m_local_box.boundary()[2u * i]) cpos[i] = 1; else return nullptr; } else if (cpos[i] > cell_grid[i]) { - if ((!m_box.periodic(i) or (pos[i] < m_box.length()[i])) && - m_local_box.boundary()[2 * i + 1]) + if ((!m_box.periodic(i) or (pos[i] < m_box.length()[i])) and + m_local_box.boundary()[2u * i + 1u]) cpos[i] = cell_grid[i]; else return nullptr; @@ -102,18 +103,20 @@ void RegularDecomposition::move_left_or_right(ParticleList &src, ParticleList &left, ParticleList &right, int dir) const { + auto const is_open_boundary_left = m_local_box.boundary()[2 * dir] != 0; + auto const is_open_boundary_right = m_local_box.boundary()[2 * dir + 1] != 0; + auto const can_move_left = m_box.periodic(dir) or not is_open_boundary_left; + auto const can_move_right = m_box.periodic(dir) or not is_open_boundary_right; + auto const my_left = m_local_box.my_left()[dir]; + auto const my_right = m_local_box.my_right()[dir]; for (auto it = src.begin(); it != src.end();) { - if ((m_box.get_mi_coord(it->pos()[dir], m_local_box.my_left()[dir], dir) < - 0.0) and - (m_box.periodic(dir) || (m_local_box.boundary()[2 * dir] == 0))) { - left.insert(std::move(*it)); - it = src.erase(it); - } else if ((m_box.get_mi_coord(it->pos()[dir], m_local_box.my_right()[dir], - dir) >= 0.0) and - (m_box.periodic(dir) || - (m_local_box.boundary()[2 * dir + 1] == 0))) { + auto const pos = it->pos()[dir]; + if (m_box.get_mi_coord(pos, my_right, dir) >= 0. and can_move_right) { right.insert(std::move(*it)); it = src.erase(it); + } else if (m_box.get_mi_coord(pos, my_left, dir) < 0. and can_move_left) { + left.insert(std::move(*it)); + it = src.erase(it); } else { ++it; } @@ -162,16 +165,14 @@ void RegularDecomposition::exchange_neighbors( } } -namespace { /** * @brief Fold coordinates to box and reset the old position. */ -void fold_and_reset(Particle &p, BoxGeometry const &box_geo) { - fold_position(p.pos(), p.image_box(), box_geo); +static void fold_and_reset(Particle &p, BoxGeometry const &box_geo) { + box_geo.fold_position(p.pos(), p.image_box()); p.pos_at_last_verlet_update() = p.pos(); } -} // namespace void RegularDecomposition::resort(bool global, std::vector &diff) { @@ -393,9 +394,11 @@ template auto make_flat_set(Comparator &&comp) { void RegularDecomposition::init_cell_interactions() { + auto const &box_geo = *System::get_system().box_geo; auto const halo = Utils::Vector3i{1, 1, 1}; auto const cart_info = Utils::Mpi::cart_get<3>(m_comm); - auto const node_pos = cart_info.coords; + auto const &node_pos = cart_info.coords; + auto const &node_grid = ::communicator.node_grid; auto const global_halo_offset = hadamard_product(node_pos, cell_grid) - halo; auto const global_size = hadamard_product(node_grid, cell_grid); @@ -633,7 +636,7 @@ GhostCommunicator RegularDecomposition::prepare_comm() { RegularDecomposition::RegularDecomposition(boost::mpi::communicator comm, double range, BoxGeometry const &box_geo, - LocalBox const &local_geo) + LocalBox const &local_geo) : m_comm(std::move(comm)), m_box(box_geo), m_local_box(local_geo) { /* set up new regular decomposition cell structure */ create_cell_grid(range); diff --git a/src/core/cell_system/RegularDecomposition.hpp b/src/core/cell_system/RegularDecomposition.hpp index 77ccc09aa3b..0072f4e1c7e 100644 --- a/src/core/cell_system/RegularDecomposition.hpp +++ b/src/core/cell_system/RegularDecomposition.hpp @@ -79,7 +79,7 @@ struct RegularDecomposition : public ParticleDecomposition { boost::mpi::communicator m_comm; BoxGeometry const &m_box; - LocalBox m_local_box; + LocalBox m_local_box; std::vector cells; std::vector m_local_cells; std::vector m_ghost_cells; @@ -88,8 +88,7 @@ struct RegularDecomposition : public ParticleDecomposition { public: RegularDecomposition(boost::mpi::communicator comm, double range, - BoxGeometry const &box_geo, - LocalBox const &local_geo); + BoxGeometry const &box_geo, LocalBox const &local_geo); GhostCommunicator const &exchange_ghosts_comm() const override { return m_exchange_ghosts_comm; diff --git a/src/core/cells.cpp b/src/core/cells.cpp index 1272800b4a7..416980f4a13 100644 --- a/src/core/cells.cpp +++ b/src/core/cells.cpp @@ -36,9 +36,9 @@ #include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "particle_node.hpp" +#include "system/System.hpp" #include #include @@ -53,9 +53,6 @@ #include #include -/** Type of cell structure in use */ -CellStructure cell_structure{box_geo}; - /** * @brief Get pairs of particles that are closer than a distance and fulfill a * filter criterion. @@ -77,6 +74,7 @@ std::vector> get_pairs_filtered(double const distance, ret.emplace_back(p1.id(), p2.id()); }; + auto &cell_structure = *System::get_system().cell_structure; cell_structure.non_bonded_loop(pair_kernel); /* Sort pairs */ @@ -90,6 +88,8 @@ std::vector> get_pairs_filtered(double const distance, namespace detail { static auto get_max_neighbor_search_range() { + auto const &system = System::get_system(); + auto const &cell_structure = *system.cell_structure; return *boost::min_element(cell_structure.max_range()); } static void search_distance_sanity_check_max_range(double const distance) { @@ -104,6 +104,8 @@ static void search_distance_sanity_check_max_range(double const distance) { } } static void search_distance_sanity_check_cell_structure(double const distance) { + auto const &system = System::get_system(); + auto const &cell_structure = *system.cell_structure; if (cell_structure.decomposition_type() == CellStructureType::CELL_STRUCTURE_HYBRID) { throw std::runtime_error("Cannot search for neighbors in the hybrid " @@ -127,9 +129,10 @@ get_short_range_neighbors(int const pid, double const distance) { ret.emplace_back(p2.id()); } }; - auto const p = ::cell_structure.get_local_particle(pid); + auto &cell_structure = *System::get_system().cell_structure; + auto const p = cell_structure.get_local_particle(pid); if (p and not p->is_ghost()) { - ::cell_structure.run_on_particle_short_range_neighbors(*p, kernel); + cell_structure.run_on_particle_short_range_neighbors(*p, kernel); return {ret}; } return {}; @@ -139,7 +142,8 @@ get_short_range_neighbors(int const pid, double const distance) { * @brief Get pointers to all interacting neighbors of a central particle. */ static auto get_interacting_neighbors(Particle const &p) { - auto const distance = *boost::min_element(::cell_structure.max_range()); + auto &cell_structure = *System::get_system().cell_structure; + auto const distance = *boost::min_element(cell_structure.max_range()); detail::search_neighbors_sanity_checks(distance); std::vector ret; auto const cutoff2 = Utils::sqr(distance); @@ -149,7 +153,7 @@ static auto get_interacting_neighbors(Particle const &p) { ret.emplace_back(&p2); } }; - ::cell_structure.run_on_particle_short_range_neighbors(p, kernel); + cell_structure.run_on_particle_short_range_neighbors(p, kernel); return ret; } @@ -175,6 +179,7 @@ std::vector non_bonded_loop_trace(int const rank) { Distance const &d) { pairs.emplace_back(p1.id(), p2.id(), p1.pos(), p2.pos(), d.vec21, rank); }; + auto &cell_structure = *System::get_system().cell_structure; cell_structure.non_bonded_loop(pair_kernel); return pairs; } @@ -190,7 +195,8 @@ std::vector get_neighbor_pids() { } ret.emplace_back(p.id(), neighbor_pids); }; - for (auto const &p : ::cell_structure.local_particles()) { + auto &cell_structure = *System::get_system().cell_structure; + for (auto const &p : cell_structure.local_particles()) { kernel(p, get_interacting_neighbors(p)); } return ret; @@ -198,12 +204,19 @@ std::vector get_neighbor_pids() { void set_hybrid_decomposition(std::set n_square_types, double cutoff_regular) { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &local_geo = *system.local_geo; + auto &cell_structure = *system.cell_structure; cell_structure.set_hybrid_decomposition(comm_cart, cutoff_regular, box_geo, local_geo, n_square_types); on_cell_structure_change(); } -void cells_re_init(CellStructureType new_cs) { +void cells_re_init(CellStructure &cell_structure, CellStructureType new_cs) { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &local_geo = *system.local_geo; switch (new_cs) { case CellStructureType::CELL_STRUCTURE_REGULAR: cell_structure.set_regular_decomposition(comm_cart, interaction_range(), @@ -230,6 +243,8 @@ void cells_re_init(CellStructureType new_cs) { } void check_resort_particles() { + auto &cell_structure = *System::get_system().cell_structure; + auto const level = (cell_structure.check_resort_required( cell_structure.local_particles(), skin)) ? Cells::RESORT_LOCAL @@ -239,6 +254,10 @@ void check_resort_particles() { } void cells_update_ghosts(unsigned data_parts) { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; + /* data parts that are only updated on resort */ auto constexpr resort_only_parts = Cells::DATA_PART_PROPERTIES | Cells::DATA_PART_BONDS; @@ -272,7 +291,3 @@ void cells_update_ghosts(unsigned data_parts) { cell_structure.ghosts_update(data_parts & ~resort_only_parts); } } - -Cell *find_current_cell(Particle const &p) { - return cell_structure.find_current_cell(p); -} diff --git a/src/core/cells.hpp b/src/core/cells.hpp index 0dbcd3004f6..704007e1f03 100644 --- a/src/core/cells.hpp +++ b/src/core/cells.hpp @@ -47,8 +47,7 @@ * should be treated using N-square. */ -#ifndef ESPRESSO_SRC_CORE_CELLS_HPP -#define ESPRESSO_SRC_CORE_CELLS_HPP +#pragma once #include "cell_system/Cell.hpp" #include "cell_system/CellStructure.hpp" @@ -74,9 +73,6 @@ enum { CELL_GLOBAL_EXCHANGE = 1 }; -/** Type of cell structure in use. */ -extern CellStructure cell_structure; - /** Initialize cell structure @ref HybridDecomposition * @param n_square_types Types of particles to place in the N-square cells. * @param cutoff_regular Cutoff for the regular decomposition. @@ -85,9 +81,14 @@ void set_hybrid_decomposition(std::set n_square_types, double cutoff_regular); /** Reinitialize the cell structures. + * @param cell_structure The cell structure to modify * @param new_cs The new topology to use afterwards. */ -void cells_re_init(CellStructureType new_cs); +void cells_re_init(CellStructure &cell_structure, CellStructureType new_cs); + +inline void cells_re_init(CellStructure &cell_structure) { + cells_re_init(cell_structure, cell_structure.decomposition_type()); +} /** Update ghost information. If needed, * the particles are also resorted. @@ -143,16 +144,6 @@ void serialize(Archive &ar, NeighborPIDs &n, unsigned int const /* version */) { */ std::vector get_neighbor_pids(); -/** - * @brief Find the cell in which a particle is stored. - * - * Uses position_to_cell on p.pos(). If this is not on the node's domain, - * uses position at last Verlet list rebuild (p.p_old()). - * - * @return pointer to the cell or nullptr if the particle is not on the node - */ -Cell *find_current_cell(Particle const &p); - class PairInfo { public: PairInfo() = default; @@ -187,5 +178,3 @@ void serialize(Archive &ar, PairInfo &p, unsigned int const /* version */) { * non-bonded loop. */ std::vector non_bonded_loop_trace(int rank); - -#endif diff --git a/src/core/cluster_analysis/Cluster.cpp b/src/core/cluster_analysis/Cluster.cpp index b29d0340535..841b056f1d2 100644 --- a/src/core/cluster_analysis/Cluster.cpp +++ b/src/core/cluster_analysis/Cluster.cpp @@ -28,8 +28,8 @@ #include "BoxGeometry.hpp" #include "Particle.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "particle_node.hpp" +#include "system/System.hpp" #include @@ -52,6 +52,7 @@ Utils::Vector3d Cluster::center_of_mass() { Utils::Vector3d Cluster::center_of_mass_subcluster(std::vector const &particle_ids) { sanity_checks(); + auto const &box_geo = *System::get_system().box_geo; Utils::Vector3d com{}; // The distances between the particles are "folded", such that all distances @@ -59,11 +60,11 @@ Cluster::center_of_mass_subcluster(std::vector const &particle_ids) { // of the cluster is arbitrarily chosen as reference. auto const reference_position = - folded_position(get_particle_data(particles[0]).pos(), box_geo); + box_geo.folded_position(get_particle_data(particles[0]).pos()); double total_mass = 0.; for (int pid : particle_ids) { auto const folded_pos = - folded_position(get_particle_data(pid).pos(), box_geo); + box_geo.folded_position(get_particle_data(pid).pos()); auto const dist_to_reference = box_geo.get_mi_vector(folded_pos, reference_position); com += dist_to_reference * get_particle_data(pid).mass(); @@ -77,11 +78,12 @@ Cluster::center_of_mass_subcluster(std::vector const &particle_ids) { com += reference_position; // Fold into simulation box - return folded_position(com, box_geo); + return box_geo.folded_position(com); } double Cluster::longest_distance() { sanity_checks(); + auto const &box_geo = *System::get_system().box_geo; double ld = 0.; for (auto a = particles.begin(); a != particles.end(); a++) { for (auto b = a; ++b != particles.end();) { @@ -105,6 +107,7 @@ double Cluster::radius_of_gyration() { double Cluster::radius_of_gyration_subcluster(std::vector const &particle_ids) { sanity_checks(); + auto const &box_geo = *System::get_system().box_geo; // Center of mass Utils::Vector3d com = center_of_mass_subcluster(particle_ids); double sum_sq_dist = 0.; @@ -133,6 +136,7 @@ std::vector sort_indices(const std::vector &v) { std::pair Cluster::fractal_dimension(double dr) { #ifdef GSL sanity_checks(); + auto const &box_geo = *System::get_system().box_geo; Utils::Vector3d com = center_of_mass(); // calculate Df using linear regression on the logarithms of the radii of // gyration against the number of particles in sub-clusters. Particles are @@ -182,7 +186,8 @@ std::pair Cluster::fractal_dimension(double dr) { } void Cluster::sanity_checks() const { - if (::box_geo.type() != BoxType::CUBOID) { + auto const &box_geo = *System::get_system().box_geo; + if (box_geo.type() != BoxType::CUBOID) { throw std::runtime_error( "Cluster analysis is not compatible with non-cuboid box types"); } diff --git a/src/core/cluster_analysis/ClusterStructure.cpp b/src/core/cluster_analysis/ClusterStructure.cpp index 6cd7a03cd3b..0f32c1a6519 100644 --- a/src/core/cluster_analysis/ClusterStructure.cpp +++ b/src/core/cluster_analysis/ClusterStructure.cpp @@ -22,9 +22,9 @@ #include "Cluster.hpp" #include "PartCfg.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "partCfg_global.hpp" #include "particle_node.hpp" +#include "system/System.hpp" #include @@ -195,7 +195,7 @@ int ClusterStructure::get_next_free_cluster_id() { } void ClusterStructure::sanity_checks() const { - if (::box_geo.type() != BoxType::CUBOID) { + if (System::get_system().box_geo->type() != BoxType::CUBOID) { throw std::runtime_error( "Cluster analysis is not compatible with non-cuboid box types"); } diff --git a/src/core/collision.cpp b/src/core/collision.cpp index a32dec37243..e85367f4b3d 100644 --- a/src/core/collision.cpp +++ b/src/core/collision.cpp @@ -20,15 +20,17 @@ #include "collision.hpp" #ifdef COLLISION_DETECTION +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "bonded_interactions/bonded_interaction_data.hpp" #include "cell_system/Cell.hpp" +#include "cell_system/CellStructure.hpp" #include "cells.hpp" #include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" +#include "system/System.hpp" #include "virtual_sites.hpp" #include @@ -73,7 +75,7 @@ static std::vector local_collision_queue; Collision_parameters collision_params; namespace { -Particle &get_part(int id) { +Particle &get_part(CellStructure &cell_structure, int id) { auto const p = cell_structure.get_local_particle(id); if (not p) { @@ -234,45 +236,46 @@ void queue_collision(const int part1, const int part2) { /** @brief Calculate position of vs for GLUE_TO_SURFACE mode. * Returns id of particle to bind vs to. */ -const Particle &glue_to_surface_calc_vs_pos(const Particle &p1, - const Particle &p2, - Utils::Vector3d &pos) { +static auto const &glue_to_surface_calc_vs_pos(Particle const &p1, + Particle const &p2, + BoxGeometry const &box_geo, + Utils::Vector3d &pos) { double c; auto const vec21 = box_geo.get_mi_vector(p1.pos(), p2.pos()); - const double dist_betw_part = vec21.norm(); + auto const dist = vec21.norm(); // Find out, which is the particle to be glued. if ((p1.type() == collision_params.part_type_to_be_glued) and (p2.type() == collision_params.part_type_to_attach_vs_to)) { - c = 1 - collision_params.dist_glued_part_to_vs / dist_betw_part; + c = 1. - collision_params.dist_glued_part_to_vs / dist; } else if ((p2.type() == collision_params.part_type_to_be_glued) and (p1.type() == collision_params.part_type_to_attach_vs_to)) { - c = collision_params.dist_glued_part_to_vs / dist_betw_part; + c = collision_params.dist_glued_part_to_vs / dist; } else { throw std::runtime_error("This should never be thrown. Bug."); } - for (int i = 0; i < 3; i++) { - pos[i] = p2.pos()[i] + vec21[i] * c; - } + pos = p2.pos() + vec21 * c; if (p1.type() == collision_params.part_type_to_attach_vs_to) return p1; return p2; } -void bind_at_point_of_collision_calc_vs_pos(const Particle *const p1, - const Particle *const p2, - 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; - pos2 = p1->pos() - vec21 * (1. - collision_params.vs_placement); +static void bind_at_point_of_collision_calc_vs_pos(Particle const &p1, + Particle const &p2, + BoxGeometry const &box_geo, + 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; + pos2 = p1.pos() - vec21 * (1. - collision_params.vs_placement); } // Considers three particles for three_particle_binding and performs // the binding if the criteria are met -void coldet_do_three_particle_bond(Particle &p, Particle const &p1, - Particle const &p2) { +static void coldet_do_three_particle_bond(Particle &p, Particle const &p1, + Particle const &p2, + BoxGeometry const &box_geo) { // If p1 and p2 are not closer or equal to the cutoff distance, skip // p1: if (box_geo.get_mi_vector(p.pos(), p1.pos()).norm() > @@ -337,63 +340,65 @@ void coldet_do_three_particle_bond(Particle &p, Particle const &p1, } #ifdef VIRTUAL_SITES_RELATIVE -void place_vs_and_relate_to_particle(const int current_vs_pid, - const Utils::Vector3d &pos, - int relate_to) { +static void place_vs_and_relate_to_particle(CellStructure &cell_structure, + BoxGeometry const &box_geo, + int const current_vs_pid, + Utils::Vector3d const &pos, + int const relate_to) { Particle new_part; new_part.id() = current_vs_pid; new_part.pos() = pos; auto p_vs = cell_structure.add_particle(std::move(new_part)); - vs_relate_to(*p_vs, get_part(relate_to)); + vs_relate_to(*p_vs, get_part(cell_structure, relate_to), box_geo); p_vs->set_virtual(true); p_vs->type() = collision_params.vs_particle_type; } -void bind_at_poc_create_bond_between_vs(const int current_vs_pid, - const CollisionPair &c) { +static void bind_at_poc_create_bond_between_vs(CellStructure &cell_structure, + int const current_vs_pid, + CollisionPair const &c) { switch (get_bond_num_partners(collision_params.bond_vs)) { case 1: { // Create bond between the virtual particles const int bondG[] = {current_vs_pid - 2}; // Only add bond if vs was created on this node - if (cell_structure.get_local_particle(current_vs_pid - 1)) - get_part(current_vs_pid - 1) - .bonds() - .insert({collision_params.bond_vs, bondG}); + if (auto p = cell_structure.get_local_particle(current_vs_pid - 1)) + p->bonds().insert({collision_params.bond_vs, bondG}); break; } case 2: { // Create 1st bond between the virtual particles const int bondG[] = {c.pp1, c.pp2}; // Only add bond if vs was created on this node - if (cell_structure.get_local_particle(current_vs_pid - 1)) - get_part(current_vs_pid - 1) - .bonds() - .insert({collision_params.bond_vs, bondG}); - if (cell_structure.get_local_particle(current_vs_pid - 2)) - get_part(current_vs_pid - 2) - .bonds() - .insert({collision_params.bond_vs, bondG}); + if (auto p = cell_structure.get_local_particle(current_vs_pid - 1)) + p->bonds().insert({collision_params.bond_vs, bondG}); + if (auto p = cell_structure.get_local_particle(current_vs_pid - 2)) + p->bonds().insert({collision_params.bond_vs, bondG}); break; } } } -void glue_to_surface_bind_part_to_vs(const Particle *const p1, - const Particle *const p2, - const int vs_pid_plus_one, - const CollisionPair &) { +static void glue_to_surface_bind_part_to_vs(Particle const *const p1, + Particle const *const p2, + int const vs_pid_plus_one, + CollisionPair const &, + CellStructure &cell_structure) { // Create bond between the virtual particles const int bondG[] = {vs_pid_plus_one - 1}; if (p1->type() == collision_params.part_type_after_glueing) { - get_part(p1->id()).bonds().insert({collision_params.bond_vs, bondG}); + get_part(cell_structure, p1->id()) + .bonds() + .insert({collision_params.bond_vs, bondG}); } else { - get_part(p2->id()).bonds().insert({collision_params.bond_vs, bondG}); + get_part(cell_structure, p2->id()) + .bonds() + .insert({collision_params.bond_vs, bondG}); } } -#endif +#endif // VIRTUAL_SITES_RELATIVE std::vector gather_global_collision_queue() { std::vector res = local_collision_queue; @@ -405,29 +410,30 @@ std::vector gather_global_collision_queue() { } static void three_particle_binding_do_search(Cell *basecell, Particle &p1, - Particle &p2) { - auto handle_cell = [&p1, &p2](Cell *c) { - for (auto &P : c->particles()) { + Particle &p2, + BoxGeometry const &box_geo) { + auto handle_cell = [&p1, &p2, &box_geo](Cell *c) { + for (auto &p : c->particles()) { // Skip collided particles themselves - if ((P.id() == p1.id()) || (P.id() == p2.id())) { + if ((p.id() == p1.id()) or (p.id() == p2.id())) { continue; } // We need all cyclical permutations, here (bond is placed on 1st // particle, order of bond partners does not matter, so we don't need // non-cyclic permutations). - // coldet_do_three_particle_bond checks the bonding criterion and if + // @ref coldet_do_three_particle_bond checks the bonding criterion and if // the involved particles are not already bonded before it binds them. - if (!P.is_ghost()) { - coldet_do_three_particle_bond(P, p1, p2); + if (!p.is_ghost()) { + coldet_do_three_particle_bond(p, p1, p2, box_geo); } if (!p1.is_ghost()) { - coldet_do_three_particle_bond(p1, P, p2); + coldet_do_three_particle_bond(p1, p, p2, box_geo); } if (!p2.is_ghost()) { - coldet_do_three_particle_bond(p2, P, p1); + coldet_do_three_particle_bond(p2, p, p1, box_geo); } } }; @@ -444,8 +450,9 @@ static void three_particle_binding_do_search(Cell *basecell, Particle &p1, // Goes through the collision queue and for each pair in it // looks for a third particle by using the domain decomposition // cell system. If found, it performs three particle binding -void three_particle_binding_domain_decomposition( - const std::vector &gathered_queue) { +static void three_particle_binding_domain_decomposition( + CellStructure &cell_structure, BoxGeometry const &box_geo, + std::vector const &gathered_queue) { for (auto &c : gathered_queue) { // If we have both particles, at least as ghosts, Get the corresponding cell @@ -454,20 +461,21 @@ void three_particle_binding_domain_decomposition( cell_structure.get_local_particle(c.pp2)) { Particle &p1 = *cell_structure.get_local_particle(c.pp1); Particle &p2 = *cell_structure.get_local_particle(c.pp2); - auto cell1 = find_current_cell(p1); - auto cell2 = find_current_cell(p2); + auto cell1 = cell_structure.find_current_cell(p1); + auto cell2 = cell_structure.find_current_cell(p2); if (cell1) - three_particle_binding_do_search(cell1, p1, p2); + three_particle_binding_do_search(cell1, p1, p2, box_geo); if (cell2 and cell1 != cell2) - three_particle_binding_do_search(cell2, p1, p2); + three_particle_binding_do_search(cell2, p1, p2, box_geo); } // If local particles exist } // Loop over total collisions } // Handle the collisions stored in the queue -void handle_collisions() { +void handle_collisions(CellStructure &cell_structure) { + auto const &box_geo = *System::get_system().box_geo; // 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 @@ -481,7 +489,9 @@ void handle_collisions() { const int bondG[] = {c.pp2}; - get_part(c.pp1).bonds().insert({collision_params.bond_centers, bondG}); + get_part(cell_structure, c.pp1) + .bonds() + .insert({collision_params.bond_centers, bondG}); } } @@ -546,11 +556,12 @@ void handle_collisions() { p2->set_can_rotate_all_axes(); // Positions of the virtual sites - bind_at_point_of_collision_calc_vs_pos(p1, p2, pos1, pos2); + bind_at_point_of_collision_calc_vs_pos(*p1, *p2, box_geo, pos1, pos2); auto handle_particle = [&](Particle *p, Utils::Vector3d const &pos) { if (not p->is_ghost()) { - place_vs_and_relate_to_particle(current_vs_pid, pos, p->id()); + place_vs_and_relate_to_particle(cell_structure, box_geo, + current_vs_pid, pos, p->id()); // Particle storage locations may have changed due to // added particle p1 = cell_structure.get_local_particle(c.pp1); @@ -569,7 +580,7 @@ void handle_collisions() { current_vs_pid++; // Create bonds between the vs. - bind_at_poc_create_bond_between_vs(current_vs_pid, c); + bind_at_poc_create_bond_between_vs(cell_structure, current_vs_pid, c); } // mode VS if (collision_params.mode == CollisionModeType::GLUE_TO_SURF) { @@ -587,15 +598,16 @@ void handle_collisions() { } Utils::Vector3d pos; - const Particle &attach_vs_to = - glue_to_surface_calc_vs_pos(*p1, *p2, pos); + Particle const &attach_vs_to = + glue_to_surface_calc_vs_pos(*p1, *p2, box_geo, pos); // Add a bond between the centers of the colliding particles // The bond is placed on the node that has p1 if (!p1->is_ghost()) { const int bondG[] = {c.pp2}; - get_part(c.pp1).bonds().insert( - {collision_params.bond_centers, bondG}); + get_part(cell_structure, c.pp1) + .bonds() + .insert({collision_params.bond_centers, bondG}); } // Change type of particle being attached, to make it inert @@ -608,7 +620,8 @@ void handle_collisions() { // Vs placement happens on the node that has p1 if (!attach_vs_to.is_ghost()) { - place_vs_and_relate_to_particle(current_vs_pid, pos, + place_vs_and_relate_to_particle(cell_structure, box_geo, + current_vs_pid, pos, attach_vs_to.id()); // Particle storage locations may have changed due to // added particle @@ -618,7 +631,8 @@ void handle_collisions() { } else { // Just update the books current_vs_pid++; } - glue_to_surface_bind_part_to_vs(p1, p2, current_vs_pid, c); + glue_to_surface_bind_part_to_vs(p1, p2, current_vs_pid, c, + cell_structure); } } // we considered the pair } // Loop over all collisions in the queue @@ -639,10 +653,11 @@ void handle_collisions() { // three-particle-binding part if (collision_params.mode == CollisionModeType::BIND_THREE_PARTICLES) { auto gathered_queue = gather_global_collision_queue(); - three_particle_binding_domain_decomposition(gathered_queue); + three_particle_binding_domain_decomposition(cell_structure, box_geo, + gathered_queue); } // if TPB local_collision_queue.clear(); } -#endif +#endif // COLLISION_DETECTION diff --git a/src/core/collision.hpp b/src/core/collision.hpp index e46a6d7baf2..339e47f81a8 100644 --- a/src/core/collision.hpp +++ b/src/core/collision.hpp @@ -16,11 +16,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef CORE_COLLISION_HPP -#define CORE_COLLISION_HPP + +#pragma once #include "config/config.hpp" +#include "cell_system/CellStructure.hpp" + #include "BondList.hpp" #include "Particle.hpp" @@ -99,7 +101,7 @@ extern Collision_parameters collision_params; void prepare_local_collision_queue(); /// Handle the collisions recorded in the queue -void handle_collisions(); +void handle_collisions(CellStructure &cell_structure); /** @brief Add the collision between the given particle ids to the collision * queue @@ -156,5 +158,3 @@ inline double collision_detection_cutoff() { #endif return -1.; } - -#endif diff --git a/src/core/communication.cpp b/src/core/communication.cpp index 7c4a430306a..4a8813610ba 100644 --- a/src/core/communication.cpp +++ b/src/core/communication.cpp @@ -25,23 +25,26 @@ #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" #ifdef WALBERLA #include #endif +#include #include #include +#include #include #include #include +#include #include boost::mpi::communicator comm_cart; +Communicator communicator{}; namespace Communication { static auto const &mpi_datatype_cache = @@ -60,19 +63,12 @@ MpiCallbacks &mpiCallbacks() { using Communication::mpiCallbacks; int this_node = -1; -int n_nodes = -1; namespace Communication { void init(std::shared_ptr mpi_env) { Communication::mpi_env = std::move(mpi_env); - MPI_Comm_size(MPI_COMM_WORLD, &n_nodes); - node_grid = Utils::Mpi::dims_create<3>(n_nodes); - - comm_cart = - Utils::Mpi::cart_create(comm_cart, node_grid, /* reorder */ false); - - this_node = comm_cart.rank(); + communicator.full_initialization(); Communication::m_callbacks = std::make_unique(comm_cart); @@ -87,6 +83,35 @@ void init(std::shared_ptr mpi_env) { } } // namespace Communication +Communicator::Communicator() + : comm{::comm_cart}, node_grid{}, this_node{::this_node}, size{-1} {} + +void Communicator::init_comm_cart() { + auto constexpr reorder = false; + comm = Utils::Mpi::cart_create(comm, node_grid, reorder); + this_node = comm.rank(); + // check topology validity + std::ignore = Utils::Mpi::cart_neighbors<3>(comm); +} + +void Communicator::full_initialization() { + assert(this_node == -1); + assert(size == -1); + MPI_Comm_size(MPI_COMM_WORLD, &size); + node_grid = Utils::Mpi::dims_create<3>(size); + init_comm_cart(); +} + +void Communicator::set_node_grid(Utils::Vector3i const &value) { + node_grid = value; + init_comm_cart(); + on_node_grid_change(); +} + +Utils::Vector3i Communicator::calc_node_index() const { + return Utils::Mpi::cart_coords<3>(comm, this_node); +} + std::shared_ptr mpi_init(int argc, char **argv) { return std::make_shared(argc, argv); } diff --git a/src/core/communication.hpp b/src/core/communication.hpp index a7dbcf42800..7bf9178c100 100644 --- a/src/core/communication.hpp +++ b/src/core/communication.hpp @@ -46,6 +46,8 @@ #include "MpiCallbacks.hpp" +#include + #include #include @@ -54,11 +56,28 @@ /** The number of this node. */ extern int this_node; -/** The total number of nodes. */ -extern int n_nodes; /** The communicator */ extern boost::mpi::communicator comm_cart; +struct Communicator { + boost::mpi::communicator &comm; + Utils::Vector3i node_grid; + /** @brief The MPI rank. */ + int &this_node; + /** @brief The MPI world size. */ + int size; + + Communicator(); + void init_comm_cart(); + void full_initialization(); + /** @brief Calculate the node index in the Cartesian topology. */ + Utils::Vector3i calc_node_index() const; + /** @brief Set new Cartesian topology. */ + void set_node_grid(Utils::Vector3i const &value); +}; + +extern Communicator communicator; + namespace Communication { /** * @brief Returns a reference to the global callback class instance. diff --git a/src/core/constraints/Constraints.hpp b/src/core/constraints/Constraints.hpp index 8c19dbf6678..edc46cc20cc 100644 --- a/src/core/constraints/Constraints.hpp +++ b/src/core/constraints/Constraints.hpp @@ -19,8 +19,9 @@ #ifndef CORE_CONSTRAINTS_CONSTRAINTS_HPP #define CORE_CONSTRAINTS_CONSTRAINTS_HPP +#include "BoxGeometry.hpp" #include "Observable_stat.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -53,6 +54,7 @@ template class Constraints { return std::find(begin(), end(), constraint) != end(); } void add(std::shared_ptr const &constraint) { + auto const &box_geo = *System::get_system().box_geo; if (not constraint->fits_in_box(box_geo.length())) { throw std::runtime_error("Constraint not compatible with box size."); } @@ -71,27 +73,28 @@ template class Constraints { const_iterator begin() const { return m_constraints.begin(); } const_iterator end() const { return m_constraints.end(); } - void add_forces(ParticleRange &particles, double t) const { + void add_forces(BoxGeometry const &box_geo, ParticleRange &particles, + double time) const { if (m_constraints.empty()) return; reset_forces(); for (auto &p : particles) { - auto const pos = folded_position(p.pos(), box_geo); + auto const pos = box_geo.folded_position(p.pos()); ParticleForce force{}; for (auto const &constraint : *this) { - force += constraint->force(p, pos, t); + force += constraint->force(p, pos, time); } p.force_and_torque() += force; } } - void add_energy(const ParticleRange &particles, double time, - Observable_stat &obs_energy) const { - for (auto &p : particles) { - auto const pos = folded_position(p.pos(), box_geo); + void add_energy(BoxGeometry const &box_geo, ParticleRange const &particles, + double time, Observable_stat &obs_energy) const { + for (auto const &p : particles) { + auto const pos = box_geo.folded_position(p.pos()); for (auto const &constraint : *this) { constraint->add_energy(p, pos, time, obs_energy); diff --git a/src/core/constraints/ShapeBasedConstraint.cpp b/src/core/constraints/ShapeBasedConstraint.cpp index 9b4e2fe2107..450544ef39e 100644 --- a/src/core/constraints/ShapeBasedConstraint.cpp +++ b/src/core/constraints/ShapeBasedConstraint.cpp @@ -27,7 +27,6 @@ #include "energy_inline.hpp" #include "errorhandling.hpp" #include "forces_inline.hpp" -#include "grid.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" #include "system/System.hpp" #include "thermostat.hpp" @@ -51,17 +50,18 @@ double ShapeBasedConstraint::total_normal_force() const { } double ShapeBasedConstraint::min_dist(const ParticleRange &particles) { + auto const &box_geo = *System::get_system().box_geo; double global_mindist = std::numeric_limits::infinity(); auto const local_mindist = std::accumulate( particles.begin(), particles.end(), std::numeric_limits::infinity(), - [this](double min, Particle const &p) { + [this, &box_geo](double min, Particle const &p) { auto const &ia_params = get_ia_param(p.type(), part_rep.type()); if (checkIfInteraction(ia_params)) { double dist; Utils::Vector3d vec; - m_shape->calculate_dist(folded_position(p.pos(), box_geo), dist, vec); + m_shape->calculate_dist(box_geo.folded_position(p.pos()), dist, vec); return std::min(min, dist); } return min; diff --git a/src/core/cuda/init.cpp b/src/core/cuda/init.cpp index 5aca865c74d..13776e951e8 100644 --- a/src/core/cuda/init.cpp +++ b/src/core/cuda/init.cpp @@ -83,7 +83,8 @@ std::vector cuda_gather_gpus() { } } - int const n_gpus = static_cast(devices_local.size()); + auto const n_gpus = static_cast(devices_local.size()); + auto const n_nodes = ::communicator.size; if (this_node == 0) { std::set device_set; diff --git a/src/core/dpd.cpp b/src/core/dpd.cpp index 369b513c19e..794b3119b51 100644 --- a/src/core/dpd.cpp +++ b/src/core/dpd.cpp @@ -27,13 +27,15 @@ #include "dpd.hpp" +#include "BoxGeometry.hpp" +#include "cell_system/CellStructure.hpp" #include "cells.hpp" #include "event.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "interactions.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" #include "random.hpp" +#include "system/System.hpp" #include "thermostat.hpp" #include @@ -49,8 +51,6 @@ #include #include -using Utils::Vector3d; - /** Return a random uniform 3D vector with the Philox thermostat. * Random numbers depend on * 1. dpd_rng_counter (initialized by seed) which is increased on integration @@ -58,7 +58,7 @@ using Utils::Vector3d; * 3. Two particle IDs (order-independent, decorrelates particles, gets rid of * seed-per-node) */ -Vector3d dpd_noise(int pid1, int pid2) { +Utils::Vector3d dpd_noise(int pid1, int pid2) { return Random::noise_uniform( dpd.rng_counter(), dpd.rng_seed(), (pid1 < pid2) ? pid2 : pid1, (pid1 < pid2) ? pid1 : pid2); @@ -84,8 +84,9 @@ static double weight(int type, double r_cut, double k, double r) { return 1. - pow((r / r_cut), k); } -Vector3d dpd_pair_force(DPDParameters const ¶ms, Vector3d const &v, - double dist, Vector3d const &noise) { +Utils::Vector3d dpd_pair_force(DPDParameters const ¶ms, + Utils::Vector3d const &v, double dist, + Utils::Vector3d const &noise) { if (dist < params.cutoff) { auto const omega = weight(params.wf, params.cutoff, params.k, dist); auto const omega2 = Utils::sqr(omega); @@ -107,12 +108,14 @@ Utils::Vector3d dpd_pair_force(Particle const &p1, Particle const &p2, return {}; } + auto const &box_geo = *System::get_system().box_geo; + auto const v21 = box_geo.velocity_difference(p1.pos(), p2.pos(), p1.v(), p2.v()); auto const noise_vec = (ia_params.dpd.radial.pref > 0.0 || ia_params.dpd.trans.pref > 0.0) ? dpd_noise(p1.id(), p2.id()) - : Vector3d{}; + : Utils::Vector3d{}; auto const f_r = dpd_pair_force(ia_params.dpd.radial, v21, dist, noise_vec); auto const f_t = dpd_pair_force(ia_params.dpd.trans, v21, dist, noise_vec); @@ -126,28 +129,32 @@ Utils::Vector3d dpd_pair_force(Particle const &p1, Particle const &p2, } static auto dpd_viscous_stress_local() { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; on_observable_calc(); Utils::Matrix stress{}; - cell_structure.non_bonded_loop( - [&stress](const Particle &p1, const Particle &p2, Distance const &d) { - auto const v21 = - box_geo.velocity_difference(p1.pos(), p2.pos(), p1.v(), p2.v()); + cell_structure.non_bonded_loop([&stress, &box_geo](Particle const &p1, + Particle const &p2, + Distance const &d) { + auto const v21 = + box_geo.velocity_difference(p1.pos(), p2.pos(), p1.v(), p2.v()); - auto const &ia_params = get_ia_param(p1.type(), p2.type()); - auto const dist = std::sqrt(d.dist2); + auto const &ia_params = get_ia_param(p1.type(), p2.type()); + auto const dist = std::sqrt(d.dist2); - auto const f_r = dpd_pair_force(ia_params.dpd.radial, v21, dist, {}); - auto const f_t = dpd_pair_force(ia_params.dpd.trans, v21, dist, {}); + auto const f_r = dpd_pair_force(ia_params.dpd.radial, v21, dist, {}); + auto const f_t = dpd_pair_force(ia_params.dpd.trans, v21, dist, {}); - /* Projection operator to radial direction */ - auto const P = tensor_product(d.vec21 / d.dist2, d.vec21); - /* This is equivalent to P * f_r + (1 - P) * f_t, but with - * doing only one matrix-vector multiplication */ - auto const f = P * (f_r - f_t) + f_t; + /* Projection operator to radial direction */ + auto const P = tensor_product(d.vec21 / d.dist2, d.vec21); + /* This is equivalent to P * f_r + (1 - P) * f_t, but with + * doing only one matrix-vector multiplication */ + auto const f = P * (f_r - f_t) + f_t; - stress += tensor_product(d.vec21, f); - }); + stress += tensor_product(d.vec21, f); + }); return stress; } @@ -168,6 +175,7 @@ static auto dpd_viscous_stress_local() { * @return Stress tensor contribution. */ Utils::Vector9d dpd_stress(boost::mpi::communicator const &comm) { + auto const &box_geo = *System::get_system().box_geo; auto const local_stress = dpd_viscous_stress_local(); std::remove_const_t global_stress; diff --git a/src/core/ek/EKWalberla.cpp b/src/core/ek/EKWalberla.cpp index 2a23fd24348..a828440c5b8 100644 --- a/src/core/ek/EKWalberla.cpp +++ b/src/core/ek/EKWalberla.cpp @@ -21,10 +21,10 @@ #ifdef WALBERLA +#include "BoxGeometry.hpp" #include "ek/EKReactions.hpp" #include "ek/EKWalberla.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "lb/Implementation.hpp" #include "lb/LBWalberla.hpp" @@ -110,8 +110,9 @@ void EKWalberla::veto_time_step(double time_step) const { } void EKWalberla::sanity_checks() const { + auto const &box_geo = *System::get_system().box_geo; auto const &lattice = ek_container->get_lattice(); - auto const agrid = ::box_geo.length()[0] / lattice.get_grid_dimensions()[0]; + auto const agrid = box_geo.length()[0] / lattice.get_grid_dimensions()[0]; auto [my_left, my_right] = lattice.get_local_domain(); my_left *= agrid; my_right *= agrid; diff --git a/src/core/electrostatics/coulomb.cpp b/src/core/electrostatics/coulomb.cpp index afdaaf7e27d..036e558bc1a 100644 --- a/src/core/electrostatics/coulomb.cpp +++ b/src/core/electrostatics/coulomb.cpp @@ -28,7 +28,7 @@ #include "ParticleRange.hpp" #include "actor/visit_try_catch.hpp" #include "actor/visitors.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "electrostatics/icc.hpp" #include "errorhandling.hpp" @@ -327,9 +327,9 @@ static auto calc_charge_excess_ratio(std::vector const &charges) { void check_charge_neutrality(double relative_tolerance) { // collect non-zero particle charges from all nodes - auto const &local_particles = cell_structure.local_particles(); + auto &cell_structure = *System::get_system().cell_structure; std::vector local_charges; - for (auto const &p : local_particles) { + for (auto const &p : cell_structure.local_particles()) { local_charges.push_back(p.q()); } std::vector> node_charges; diff --git a/src/core/electrostatics/coulomb_inline.hpp b/src/core/electrostatics/coulomb_inline.hpp index 81b6cecec67..e3365c9ba33 100644 --- a/src/core/electrostatics/coulomb_inline.hpp +++ b/src/core/electrostatics/coulomb_inline.hpp @@ -26,6 +26,7 @@ #include "electrostatics/solver.hpp" #include "Particle.hpp" +#include "system/System.hpp" #include #include @@ -85,9 +86,11 @@ struct ShortRangeForceCorrectionsKernel { result_type operator()(std::shared_ptr const &ptr) const { auto const &actor = *ptr; - return kernel_type{[&actor](Particle &p1, Particle &p2, double q1q2) { - actor.add_pair_force_corrections(p1, p2, q1q2); - }}; + auto const &box_geo = *System::get_system().box_geo; + return kernel_type{ + [&actor, &box_geo](Particle &p1, Particle &p2, double q1q2) { + actor.add_pair_force_corrections(p1, p2, q1q2, box_geo); + }}; } #endif // P3M }; @@ -134,15 +137,16 @@ struct ShortRangeEnergyKernel { result_type operator()(std::shared_ptr const &ptr) const { auto const &actor = *ptr; + auto const &box_geo = *System::get_system().box_geo; auto const energy_kernel = std::visit(*this, actor.base_solver); - return kernel_type{[&actor, energy_kernel]( + return kernel_type{[&actor, &box_geo, energy_kernel]( Particle const &p1, Particle const &p2, double q1q2, Utils::Vector3d const &d, double dist) { auto energy = 0.; if (energy_kernel) { energy = (*energy_kernel)(p1, p2, q1q2, d, dist); } - return energy + actor.pair_energy_correction(q1q2, p1, p2); + return energy + actor.pair_energy_correction(p1, p2, q1q2, box_geo); }}; } #endif // P3M diff --git a/src/core/electrostatics/elc.cpp b/src/core/electrostatics/elc.cpp index 3ce90953a84..09ad631286e 100644 --- a/src/core/electrostatics/elc.cpp +++ b/src/core/electrostatics/elc.cpp @@ -30,13 +30,14 @@ #include "electrostatics/p3m.hpp" #include "electrostatics/p3m_gpu.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -124,7 +125,8 @@ static std::vector calc_sc_cache(ParticleRange const &particles, } static std::pair -prepare_sc_cache(ParticleRange const &particles, double far_cut) { +prepare_sc_cache(ParticleRange const &particles, BoxGeometry const &box_geo, + double far_cut) { assert(far_cut >= 0.); auto const n_freq_x = static_cast(std::ceil(far_cut * box_geo.length()[0]) + 1.); @@ -200,6 +202,7 @@ void ElectrostaticLayerCorrection::check_gap(Particle const &p) const { void ElectrostaticLayerCorrection::add_dipole_force( ParticleRange const &particles) const { constexpr std::size_t size = 3; + auto const &box_geo = *System::get_system().box_geo; auto const pref = prefactor * 4. * Utils::pi() / box_geo.volume(); /* for non-neutral systems, this shift gives the background contribution @@ -265,6 +268,7 @@ void ElectrostaticLayerCorrection::add_dipole_force( double ElectrostaticLayerCorrection::dipole_energy( ParticleRange const &particles) const { constexpr std::size_t size = 7; + auto const &box_geo = *System::get_system().box_geo; auto const pref = prefactor * 2. * Utils::pi() / box_geo.volume(); auto const lz = box_geo.length()[2]; /* for nonneutral systems, this shift gives the background contribution @@ -339,21 +343,30 @@ double ElectrostaticLayerCorrection::dipole_energy( /*****************************************************************/ -static auto image_sum_b(double q, double z, double d) { - auto const shift = box_geo.length_half()[2]; - auto const lz = box_geo.length()[2]; - return q / (1. - d) * (z - 2. * d * lz / (1. - d)) - q * shift / (1. - d); -} +struct ImageSum { + double delta; + double shift; + double lz; + double dci; // delta complement inverse -static auto image_sum_t(double q, double z, double d) { - auto const shift = box_geo.length_half()[2]; - auto const lz = box_geo.length()[2]; - return q / (1. - d) * (z + 2. * d * lz / (1. - d)) - q * shift / (1. - d); -} + ImageSum(double delta, double shift, double lz) + : delta{delta}, shift{shift}, lz{lz}, dci{1. / (1. - delta)} {} + + /** @brief Image sum from the bottom layer. */ + double b(double q, double z) const { + return q * dci * (z - 2. * delta * lz * dci) - q * dci * shift; + } + + /** @brief Image sum from the top layer. */ + double t(double q, double z) const { + return q * dci * (z + 2. * delta * lz * dci) - q * dci * shift; + } +}; double ElectrostaticLayerCorrection::z_energy(ParticleRange const &particles) const { constexpr std::size_t size = 4; + auto const &box_geo = *System::get_system().box_geo; auto const xy_area_inv = box_geo.length_inv()[0] * box_geo.length_inv()[1]; auto const pref = prefactor * 2. * Utils::pi() * xy_area_inv; auto const delta = elc.delta_mid_top * elc.delta_mid_bot; @@ -363,7 +376,8 @@ ElectrostaticLayerCorrection::z_energy(ParticleRange const &particles) const { /* for non-neutral systems, this shift gives the background contribution * (rsp. for this shift, the DM of the background is zero) */ - double const shift = box_geo.length_half()[2]; + auto const shift = box_geo.length_half()[2]; + auto const lz = box_geo.length()[2]; if (elc.dielectric_contrast_on) { if (elc.const_pot) { @@ -386,6 +400,7 @@ ElectrostaticLayerCorrection::z_energy(ParticleRange const &particles) const { // metallic boundaries clear_vec(gblcblk, size); auto const h = elc.box_h; + ImageSum const image_sum{delta, shift, lz}; for (auto const &p : particles) { auto const z = p.pos()[2]; auto const q = p.q(); @@ -394,26 +409,25 @@ ElectrostaticLayerCorrection::z_energy(ParticleRange const &particles) const { if (elc.dielectric_contrast_on) { if (z < elc.space_layer) { gblcblk[2] += fac_delta * (elc.delta_mid_bot + 1.) * q; - gblcblk[3] += q * (image_sum_b(elc.delta_mid_bot * delta, - -(2. * h + z), delta) + - image_sum_b(delta, -(2. * h - z), delta)); + gblcblk[3] += + q * (image_sum.b(elc.delta_mid_bot * delta, -(2. * h + z)) + + image_sum.b(delta, -(2. * h - z))); } else { gblcblk[2] += fac_delta_mid_bot * (1. + elc.delta_mid_top) * q; - gblcblk[3] += q * (image_sum_b(elc.delta_mid_bot, -z, delta) + - image_sum_b(delta, -(2. * h - z), delta)); + gblcblk[3] += q * (image_sum.b(elc.delta_mid_bot, -z) + + image_sum.b(delta, -(2. * h - z))); } if (z > (h - elc.space_layer)) { // note the minus sign here which is required due to |z_i-z_j| gblcblk[2] -= fac_delta * (elc.delta_mid_top + 1.) * q; gblcblk[3] -= - q * (image_sum_t(elc.delta_mid_top * delta, 4. * h - z, delta) + - image_sum_t(delta, 2. * h + z, delta)); + q * (image_sum.t(elc.delta_mid_top * delta, 4. * h - z) + + image_sum.t(delta, 2. * h + z)); } else { // note the minus sign here which is required due to |z_i-z_j| gblcblk[2] -= fac_delta_mid_top * (1. + elc.delta_mid_bot) * q; - gblcblk[3] -= - q * (image_sum_t(elc.delta_mid_top, 2. * h - z, delta) + - image_sum_t(delta, 2. * h + z, delta)); + gblcblk[3] -= q * (image_sum.t(elc.delta_mid_top, 2. * h - z) + + image_sum.t(delta, 2. * h + z)); } } } @@ -428,6 +442,7 @@ ElectrostaticLayerCorrection::z_energy(ParticleRange const &particles) const { void ElectrostaticLayerCorrection::add_z_force( ParticleRange const &particles) const { constexpr std::size_t size = 1; + auto const &box_geo = *System::get_system().box_geo; auto const xy_area_inv = box_geo.length_inv()[0] * box_geo.length_inv()[1]; auto const pref = prefactor * 2. * Utils::pi() * xy_area_inv; auto const delta = elc.delta_mid_top * elc.delta_mid_bot; @@ -488,6 +503,7 @@ void setup_PoQ(elc_data const &elc, double prefactor, std::size_t index, double omega, ParticleRange const &particles) { assert(index >= 1); constexpr std::size_t size = 4; + auto const &box_geo = *System::get_system().box_geo; auto const xy_area_inv = box_geo.length_inv()[0] * box_geo.length_inv()[1]; auto const pref_di = prefactor * 4. * Utils::pi() * xy_area_inv; auto const pref = -pref_di / expm1(omega * box_geo.length()[2]); @@ -629,6 +645,7 @@ static void setup_PQ(elc_data const &elc, double prefactor, std::size_t index_p, assert(index_p >= 1); assert(index_q >= 1); constexpr std::size_t size = 8; + auto const &box_geo = *System::get_system().box_geo; auto const xy_area_inv = box_geo.length_inv()[0] * box_geo.length_inv()[1]; auto const pref_di = prefactor * 8 * Utils::pi() * xy_area_inv; auto const pref = -pref_di / expm1(omega * box_geo.length()[2]); @@ -753,7 +770,8 @@ static void setup_PQ(elc_data const &elc, double prefactor, std::size_t index_p, } static void add_PQ_force(std::size_t index_p, std::size_t index_q, double omega, - const ParticleRange &particles) { + ParticleRange const &particles, + BoxGeometry const &box_geo) { auto constexpr c_2pi = 2. * Utils::pi(); auto const pref_x = c_2pi * box_geo.length_inv()[0] * static_cast(index_p) / omega; @@ -813,7 +831,8 @@ static double PQ_energy(double omega, std::size_t n_part) { void ElectrostaticLayerCorrection::add_force( ParticleRange const &particles) const { auto constexpr c_2pi = 2. * Utils::pi(); - auto const n_freqs = prepare_sc_cache(particles, elc.far_cut); + auto const &box_geo = *System::get_system().box_geo; + auto const n_freqs = prepare_sc_cache(particles, box_geo, elc.far_cut); auto const n_scxcache = std::get<0>(n_freqs); auto const n_scycache = std::get<1>(n_freqs); partblk.resize(particles.size() * 8); @@ -859,7 +878,7 @@ void ElectrostaticLayerCorrection::add_force( Utils::sqr(box_geo.length_inv()[1] * static_cast(q))); setup_PQ(elc, prefactor, p, q, omega, particles); distribute(8); - add_PQ_force(p, q, omega, particles); + add_PQ_force(p, q, omega, particles, box_geo); } } } @@ -867,8 +886,9 @@ void ElectrostaticLayerCorrection::add_force( double ElectrostaticLayerCorrection::calc_energy( ParticleRange const &particles) const { auto constexpr c_2pi = 2. * Utils::pi(); + auto const &box_geo = *System::get_system().box_geo; auto energy = dipole_energy(particles) + z_energy(particles); - auto const n_freqs = prepare_sc_cache(particles, elc.far_cut); + auto const n_freqs = prepare_sc_cache(particles, box_geo, elc.far_cut); auto const n_scxcache = std::get<0>(n_freqs); auto const n_scycache = std::get<1>(n_freqs); @@ -923,6 +943,7 @@ double ElectrostaticLayerCorrection::calc_energy( double ElectrostaticLayerCorrection::tune_far_cut() const { // Largest reasonable cutoff for far formula auto constexpr maximal_far_cut = 50.; + auto const &box_geo = *System::get_system().box_geo; auto const box_l_x_inv = box_geo.length_inv()[0]; auto const box_l_y_inv = box_geo.length_inv()[1]; auto const min_inv_boxl = std::min(box_l_x_inv, box_l_y_inv); @@ -953,6 +974,7 @@ double ElectrostaticLayerCorrection::tune_far_cut() const { } static auto calc_total_charge() { + auto &cell_structure = *System::get_system().cell_structure; auto local_q = 0.; for (auto const &p : cell_structure.local_particles()) { local_q += p.q(); @@ -961,6 +983,7 @@ static auto calc_total_charge() { } void ElectrostaticLayerCorrection::sanity_checks_periodicity() const { + auto const &box_geo = *System::get_system().box_geo; if (!box_geo.periodic(0) || !box_geo.periodic(1) || !box_geo.periodic(2)) { throw std::runtime_error("ELC: requires periodicity (True, True, True)"); } @@ -995,6 +1018,7 @@ void ElectrostaticLayerCorrection::adapt_solver() { } void ElectrostaticLayerCorrection::recalc_box_h() { + auto const &box_geo = *System::get_system().box_geo; auto const new_box_h = box_geo.length()[2] - elc.gap_size; if (new_box_h < 0.) { throw std::runtime_error("ELC gap size (" + std::to_string(elc.gap_size) + @@ -1032,9 +1056,9 @@ elc_data::elc_data(double maxPWerror, double gap_size, double far_cut, bool neutralize, double delta_top, double delta_bot, bool with_const_pot, double potential_diff) : maxPWerror{maxPWerror}, gap_size{gap_size}, - box_h{box_geo.length()[2] - gap_size}, far_cut{far_cut}, far_cut2{-1.}, - far_calculated{far_cut == -1.}, dielectric_contrast_on{delta_top != 0. or - delta_bot != 0.}, + box_h{System::get_system().box_geo->length()[2] - gap_size}, + far_cut{far_cut}, far_cut2{-1.}, far_calculated{far_cut == -1.}, + dielectric_contrast_on{delta_top != 0. or delta_bot != 0.}, const_pot{with_const_pot and dielectric_contrast_on}, neutralize{neutralize and !dielectric_contrast_on}, delta_mid_top{std::clamp(delta_top, -1., +1.)}, delta_mid_bot{std::clamp( @@ -1083,11 +1107,6 @@ ElectrostaticLayerCorrection::ElectrostaticLayerCorrection( adapt_solver(); } -Utils::Vector3d elc_data::get_mi_vector(Utils::Vector3d const &a, - Utils::Vector3d const &b) const { - return box_geo.get_mi_vector(a, b); -} - static void p3m_assign_image_charge(elc_data const &elc, CoulombP3M &p3m, double q, Utils::Vector3d const &pos) { if (pos[2] < elc.space_layer) { @@ -1170,6 +1189,7 @@ double ElectrostaticLayerCorrection::long_range_energy( auto const energy = std::visit( [this, &particles](auto const &solver_ptr) { auto &solver = *solver_ptr; + auto const &box_geo = *System::get_system().box_geo; // assign the original charges (they may not have been assigned yet) solver.charge_assign(particles); @@ -1180,7 +1200,8 @@ double ElectrostaticLayerCorrection::long_range_energy( auto energy = 0.; energy += 0.5 * solver.long_range_energy(particles); - energy += 0.5 * elc.dielectric_layers_self_energy(solver, particles); + energy += + 0.5 * elc.dielectric_layers_self_energy(solver, box_geo, particles); // assign both original and image charges charge_assign(elc, solver, particles); @@ -1207,9 +1228,10 @@ void ElectrostaticLayerCorrection::add_long_range_forces( [this, &particles](auto const &solver_ptr) { auto &solver = *solver_ptr; if (elc.dielectric_contrast_on) { + auto const &box_geo = *System::get_system().box_geo; modify_p3m_sums(elc, solver, particles); charge_assign(elc, solver, particles); - elc.dielectric_layers_self_forces(solver, particles); + elc.dielectric_layers_self_forces(solver, box_geo, particles); } else { solver.charge_assign(particles); } diff --git a/src/core/electrostatics/elc.hpp b/src/core/electrostatics/elc.hpp index 197aa5fe0f4..d0071881ea3 100644 --- a/src/core/electrostatics/elc.hpp +++ b/src/core/electrostatics/elc.hpp @@ -40,6 +40,7 @@ #include "electrostatics/p3m.hpp" #include "electrostatics/p3m_gpu.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" @@ -118,29 +119,31 @@ struct elc_data { /// pairwise contributions from the lowest and top layers template void dielectric_layers_contribution(CoulombP3M const &p3m, + BoxGeometry const &box_geo, Utils::Vector3d const &pos1, Utils::Vector3d const &pos2, double q1q2, Kernel &&kernel) const { if (pos1[2] < space_layer) { auto const q_eff = delta_mid_bot * q1q2; - auto const d = get_mi_vector(pos2, {pos1[0], pos1[1], -pos1[2]}); + auto const d = box_geo.get_mi_vector(pos2, {pos1[0], pos1[1], -pos1[2]}); kernel(q_eff, d); } if (pos1[2] > (box_h - space_layer)) { auto const q_eff = delta_mid_top * q1q2; - auto const l = 2. * box_h; - auto const d = get_mi_vector(pos2, {pos1[0], pos1[1], l - pos1[2]}); + auto const z = 2. * box_h - pos1[2]; + auto const d = box_geo.get_mi_vector(pos2, {pos1[0], pos1[1], z}); kernel(q_eff, d); } } /// self energies of top and bottom layers with their virtual images double dielectric_layers_self_energy(CoulombP3M const &p3m, + BoxGeometry const &box_geo, ParticleRange const &particles) const { auto energy = 0.; for (auto const &p : particles) { dielectric_layers_contribution( - p3m, p.pos(), p.pos(), Utils::sqr(p.q()), + p3m, box_geo, p.pos(), p.pos(), Utils::sqr(p.q()), [&](double q1q2, Utils::Vector3d const &d) { energy += p3m.pair_energy(q1q2, d.norm()); }); @@ -150,19 +153,16 @@ struct elc_data { /// forces of particles in border layers with themselves void dielectric_layers_self_forces(CoulombP3M const &p3m, + BoxGeometry const &box_geo, ParticleRange const &particles) const { for (auto &p : particles) { dielectric_layers_contribution( - p3m, p.pos(), p.pos(), Utils::sqr(p.q()), + p3m, box_geo, p.pos(), p.pos(), Utils::sqr(p.q()), [&](double q1q2, Utils::Vector3d const &d) { p.force() += p3m.pair_force(q1q2, d, d.norm()); }); } } - -private: - Utils::Vector3d get_mi_vector(Utils::Vector3d const &a, - Utils::Vector3d const &b) const; }; struct ElectrostaticLayerCorrection @@ -252,23 +252,23 @@ struct ElectrostaticLayerCorrection } /** @brief Calculate short-range pair energy correction. */ - double pair_energy_correction(double q1q2, Particle const &p1, - Particle const &p2) const { + double pair_energy_correction(Particle const &p1, Particle const &p2, + double q1q2, BoxGeometry const &box_geo) const { double energy = 0.; if (elc.dielectric_contrast_on) { energy = std::visit( - [this, &p1, &p2, q1q2](auto &p3m_ptr) { + [this, &p1, &p2, q1q2, &box_geo](auto &p3m_ptr) { auto const &pos1 = p1.pos(); auto const &pos2 = p2.pos(); auto const &p3m = *p3m_ptr; auto energy = 0.; elc.dielectric_layers_contribution( - p3m, pos1, pos2, q1q2, + p3m, box_geo, pos1, pos2, q1q2, [&](double q_eff, Utils::Vector3d const &d) { energy += p3m.pair_energy(q_eff, d.norm()); }); elc.dielectric_layers_contribution( - p3m, pos2, pos1, q1q2, + p3m, box_geo, pos2, pos1, q1q2, [&](double q_eff, Utils::Vector3d const &d) { energy += p3m.pair_energy(q_eff, d.norm()); }); @@ -280,21 +280,21 @@ struct ElectrostaticLayerCorrection } /** @brief Add short-range pair force corrections. */ - void add_pair_force_corrections(Particle &p1, Particle &p2, - double q1q2) const { + void add_pair_force_corrections(Particle &p1, Particle &p2, double q1q2, + BoxGeometry const &box_geo) const { if (elc.dielectric_contrast_on) { std::visit( - [this, &p1, &p2, q1q2](auto &p3m_ptr) { + [this, &p1, &p2, q1q2, &box_geo](auto &p3m_ptr) { auto const &pos1 = p1.pos(); auto const &pos2 = p2.pos(); auto const &p3m = *p3m_ptr; elc.dielectric_layers_contribution( - p3m, pos1, pos2, q1q2, + p3m, box_geo, pos1, pos2, q1q2, [&](double q_eff, Utils::Vector3d const &d) { p1.force() += p3m.pair_force(q_eff, d, d.norm()); }); elc.dielectric_layers_contribution( - p3m, pos2, pos1, q1q2, + p3m, box_geo, pos2, pos1, q1q2, [&](double q_eff, Utils::Vector3d const &d) { p2.force() += p3m.pair_force(q_eff, d, d.norm()); }); diff --git a/src/core/electrostatics/icc.cpp b/src/core/electrostatics/icc.cpp index 1a2590ba570..9b4ebf359b8 100644 --- a/src/core/electrostatics/icc.cpp +++ b/src/core/electrostatics/icc.cpp @@ -36,7 +36,6 @@ #include "ParticleRange.hpp" #include "actor/visitors.hpp" #include "cell_system/CellStructure.hpp" -#include "cells.hpp" #include "communication.hpp" #include "electrostatics/coulomb.hpp" #include "electrostatics/coulomb_inline.hpp" @@ -289,6 +288,7 @@ void update_icc_particles() { if (system.coulomb.impl->extension) { if (auto icc = std::get_if>( get_ptr(system.coulomb.impl->extension))) { + auto &cell_structure = *system.cell_structure; (**icc).iteration(cell_structure, cell_structure.local_particles(), cell_structure.ghost_particles()); } diff --git a/src/core/electrostatics/mmm1d.cpp b/src/core/electrostatics/mmm1d.cpp index 8bb7aa1782f..5a7b9962cf4 100644 --- a/src/core/electrostatics/mmm1d.cpp +++ b/src/core/electrostatics/mmm1d.cpp @@ -29,12 +29,14 @@ #include "electrostatics/mmm-common.hpp" #include "electrostatics/mmm-modpsi.hpp" +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" #include "Particle.hpp" #include "cell_system/CellStructureType.hpp" #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" #include "specfunc.hpp" +#include "system/System.hpp" #include "tuning.hpp" #include @@ -56,6 +58,7 @@ #endif static double far_error(int P, double minrad) { + auto const &box_geo = *System::get_system().box_geo; auto const wavenumber = 2. * Utils::pi() * box_geo.length_inv()[2]; // this uses an upper bound to all force components and the potential auto const rhores = wavenumber * minrad; @@ -67,6 +70,7 @@ static double far_error(int P, double minrad) { static double determine_minrad(double maxPWerror, int P) { // bisection to search for where the error is maxPWerror auto constexpr min_rad = 0.01; + auto const &box_geo = *System::get_system().box_geo; auto const rgranularity = min_rad * box_geo.length()[2]; auto rmin = rgranularity; auto rmax = std::min(box_geo.length()[0], box_geo.length()[1]); @@ -138,12 +142,14 @@ CoulombMMM1D::CoulombMMM1D(double prefactor, double maxPWerror, } void CoulombMMM1D::sanity_checks_periodicity() const { + auto const &box_geo = *System::get_system().box_geo; if (box_geo.periodic(0) || box_geo.periodic(1) || !box_geo.periodic(2)) { throw std::runtime_error("MMM1D requires periodicity (False, False, True)"); } } void CoulombMMM1D::sanity_checks_cell_structure() const { + auto const &local_geo = *System::get_system().local_geo; if (local_geo.cell_structure_type() != CellStructureType::CELL_STRUCTURE_NSQUARE) { throw std::runtime_error("MMM1D requires the N-square cellsystem"); @@ -151,6 +157,8 @@ void CoulombMMM1D::sanity_checks_cell_structure() const { } void CoulombMMM1D::recalc_boxl_parameters() { + auto const &box_geo = *System::get_system().box_geo; + if (far_switch_radius_sq >= Utils::sqr(box_geo.length()[2])) far_switch_radius_sq = 0.8 * Utils::sqr(box_geo.length()[2]); @@ -165,6 +173,7 @@ void CoulombMMM1D::recalc_boxl_parameters() { Utils::Vector3d CoulombMMM1D::pair_force(double q1q2, Utils::Vector3d const &d, double dist) const { auto constexpr c_2pi = 2. * Utils::pi(); + auto const &box_geo = *System::get_system().box_geo; auto const n_modPsi = static_cast(modPsi.size()) >> 1; auto const rxy2 = d[0] * d[0] + d[1] * d[1]; auto const rxy2_d = rxy2 * uz2; @@ -258,6 +267,7 @@ double CoulombMMM1D::pair_energy(double const q1q2, Utils::Vector3d const &d, return 0.; auto constexpr c_2pi = 2. * Utils::pi(); + auto const &box_geo = *System::get_system().box_geo; auto const n_modPsi = static_cast(modPsi.size()) >> 1; auto const rxy2 = d[0] * d[0] + d[1] * d[1]; auto const rxy2_d = rxy2 * uz2; @@ -321,6 +331,7 @@ void CoulombMMM1D::tune() { recalc_boxl_parameters(); if (far_switch_radius_sq < 0.) { + auto const &box_geo = *System::get_system().box_geo; auto const maxrad = box_geo.length()[2]; auto min_time = std::numeric_limits::infinity(); auto min_rad = -1.; diff --git a/src/core/electrostatics/mmm1d_gpu.cpp b/src/core/electrostatics/mmm1d_gpu.cpp index 9d73f35c67e..fbe58285653 100644 --- a/src/core/electrostatics/mmm1d_gpu.cpp +++ b/src/core/electrostatics/mmm1d_gpu.cpp @@ -23,10 +23,11 @@ #include "electrostatics/mmm1d_gpu.hpp" +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" #include "cell_system/CellStructureType.hpp" #include "communication.hpp" #include "event.hpp" -#include "grid.hpp" #include "system/GpuParticleData.hpp" #include "system/System.hpp" @@ -38,6 +39,7 @@ CoulombMMM1DGpu::CoulombMMM1DGpu(double prefactor, double maxPWerror, far_switch_radius_sq{-1.}, bessel_cutoff{bessel_cutoff}, m_is_tuned{ false} { set_prefactor(prefactor); + auto const &box_geo = *System::get_system().box_geo; if (maxPWerror <= 0.) { throw std::domain_error("Parameter 'maxPWerror' must be > 0"); } @@ -62,12 +64,14 @@ CoulombMMM1DGpu::CoulombMMM1DGpu(double prefactor, double maxPWerror, } void CoulombMMM1DGpu::sanity_checks_periodicity() const { + auto const &box_geo = *System::get_system().box_geo; if (box_geo.periodic(0) || box_geo.periodic(1) || !box_geo.periodic(2)) { throw std::runtime_error("MMM1D requires periodicity (False, False, True)"); } } void CoulombMMM1DGpu::sanity_checks_cell_structure() const { + auto const &local_geo = *System::get_system().local_geo; if (local_geo.cell_structure_type() != CellStructureType::CELL_STRUCTURE_NSQUARE) { throw std::runtime_error("MMM1D requires the N-square cellsystem"); diff --git a/src/core/electrostatics/p3m.cpp b/src/core/electrostatics/p3m.cpp index 244faa27f8d..a5b01443c4f 100644 --- a/src/core/electrostatics/p3m.cpp +++ b/src/core/electrostatics/p3m.cpp @@ -38,15 +38,16 @@ #include "p3m/fft.hpp" #include "p3m/influence_function.hpp" +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" #include "actor/visitors.hpp" +#include "cell_system/CellStructure.hpp" #include "cell_system/CellStructureType.hpp" -#include "cells.hpp" #include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "system/System.hpp" #include "tuning.hpp" @@ -77,6 +78,7 @@ #include void CoulombP3M::count_charged_particles() { + auto &cell_structure = *System::get_system().cell_structure; auto local_n = 0; auto local_q2 = 0.0; auto local_q = 0.0; @@ -106,6 +108,7 @@ void CoulombP3M::count_charged_particles() { * @cite deserno98a @cite deserno98b. */ void CoulombP3M::calc_influence_function_force() { + auto const &box_geo = *System::get_system().box_geo; auto const start = Utils::Vector3i{p3m.fft.plan[3].start}; auto const size = Utils::Vector3i{p3m.fft.plan[3].new_mesh}; @@ -117,6 +120,7 @@ void CoulombP3M::calc_influence_function_force() { * self energy correction. */ void CoulombP3M::calc_influence_function_energy() { + auto const &box_geo = *System::get_system().box_geo; auto const start = Utils::Vector3i{p3m.fft.plan[3].start}; auto const size = Utils::Vector3i{p3m.fft.plan[3].new_mesh}; @@ -169,6 +173,7 @@ static void p3m_tune_aliasing_sums(int nx, int ny, int nz, */ static double p3m_real_space_error(double pref, double r_cut_iL, int n_c_part, double sum_q2, double alpha_L) { + auto const &box_geo = *System::get_system().box_geo; return (2. * pref * sum_q2 * exp(-Utils::sqr(r_cut_iL * alpha_L))) / sqrt(static_cast(n_c_part) * r_cut_iL * box_geo.length()[0] * box_geo.volume()); @@ -189,6 +194,7 @@ static double p3m_real_space_error(double pref, double r_cut_iL, int n_c_part, static double p3m_k_space_error(double pref, Utils::Vector3i const &mesh, int cao, int n_c_part, double sum_q2, double alpha_L) { + auto const &box_geo = *System::get_system().box_geo; auto const mesh_i = Utils::hadamard_division(Utils::Vector3d::broadcast(1.), mesh); auto const alpha_L_i = 1. / alpha_L; @@ -225,6 +231,7 @@ static double p3m_k_space_error(double pref, Utils::Vector3i const &mesh, static double p3mgpu_k_space_error(double prefactor, Utils::Vector3i const &mesh, int cao, int npart, double sum_q2, double alpha_L) { + auto const &box_geo = *System::get_system().box_geo; auto ks_err = 0.; if (this_node == 0) { ks_err = p3m_k_space_error_gpu(prefactor, mesh.data(), cao, npart, sum_q2, @@ -240,12 +247,16 @@ void CoulombP3M::init() { assert(p3m.params.cao >= 1 and p3m.params.cao <= 7); assert(p3m.params.alpha > 0.); + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &local_geo = *system.local_geo; + p3m.params.cao3 = Utils::int_pow<3>(p3m.params.cao); p3m.params.recalc_a_ai_cao_cut(box_geo.length()); sanity_checks(); - auto const &solver = System::get_system().coulomb.impl->solver; + auto const &solver = system.coulomb.impl->solver; double elc_layer = 0.; if (auto actor = get_actor_by_type(solver)) { elc_layer = actor->elc.space_layer; @@ -254,9 +265,9 @@ void CoulombP3M::init() { p3m.local_mesh.calc_local_ca_mesh(p3m.params, local_geo, skin, elc_layer); p3m.sm.resize(comm_cart, p3m.local_mesh); - int ca_mesh_size = - fft_init(p3m.local_mesh.dim, p3m.local_mesh.margin, p3m.params.mesh, - p3m.params.mesh_off, p3m.ks_pnum, p3m.fft, node_grid, comm_cart); + int ca_mesh_size = fft_init(p3m.local_mesh.dim, p3m.local_mesh.margin, + p3m.params.mesh, p3m.params.mesh_off, p3m.ks_pnum, + p3m.fft, ::communicator.node_grid, comm_cart); p3m.rs_mesh.resize(ca_mesh_size); for (auto &e : p3m.E_mesh) { @@ -342,7 +353,6 @@ void CoulombP3M::assign_charge(double q, Utils::Vector3d const &real_pos) { real_pos); } -namespace { template struct AssignForces { void operator()(p3m_data_struct &p3m, double force_prefac, ParticleRange const &particles) const { @@ -373,21 +383,17 @@ template struct AssignForces { } }; -auto dipole_moment(Particle const &p, BoxGeometry const &box) { - return p.q() * unfolded_position(p.pos(), p.image_box(), box.length()); -} - -auto calc_dipole_moment(boost::mpi::communicator const &comm, - ParticleRange const &particles, - BoxGeometry const &box) { +static auto calc_dipole_moment(boost::mpi::communicator const &comm, + ParticleRange const &particles, + BoxGeometry const &box_geo) { auto const local_dip = boost::accumulate( - particles, Utils::Vector3d{}, [&box](Utils::Vector3d dip, auto const &p) { - return dip + dipole_moment(p, box); + particles, Utils::Vector3d{}, + [&box_geo](Utils::Vector3d const &dip, auto const &p) { + return dip + p.q() * box_geo.unfolded_position(p.pos(), p.image_box()); }); return boost::mpi::all_reduce(comm, local_dip, std::plus<>()); } -} // namespace /** @details Calculate the long range electrostatics part of the pressure * tensor. This is part \f$\Pi_{\textrm{dir}, \alpha, \beta}\f$ eq. (2.6) @@ -397,6 +403,8 @@ auto calc_dipole_moment(boost::mpi::communicator const &comm, Utils::Vector9d CoulombP3M::p3m_calc_kspace_pressure_tensor() { using namespace detail::FFT_indexing; + auto const &box_geo = *System::get_system().box_geo; + Utils::Vector9d node_k_space_pressure_tensor{}; if (p3m.sum_q2 > 0.) { @@ -452,6 +460,8 @@ Utils::Vector9d CoulombP3M::p3m_calc_kspace_pressure_tensor() { double CoulombP3M::long_range_kernel(bool force_flag, bool energy_flag, ParticleRange const &particles) { + auto const &box_geo = *System::get_system().box_geo; + /* Gather information for FFT grid inside the nodes domain (inner local mesh) * and perform forward 3D FFT (Charge Assignment Mesh). */ p3m.sm.gather_grid(p3m.rs_mesh.data(), comm_cart, p3m.local_mesh.dim); @@ -567,8 +577,10 @@ class CoulombTuningAlgorithm : public TuningAlgorithm { void on_solver_change() const override { on_coulomb_change(); } void setup_logger(bool verbose) override { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; #ifdef CUDA - auto const &solver = System::get_system().coulomb.impl->solver; + auto const &solver = system.coulomb.impl->solver; auto const on_gpu = has_actor_of_type(solver); #else auto const on_gpu = false; @@ -628,6 +640,7 @@ class CoulombTuningAlgorithm : public TuningAlgorithm { } void determine_mesh_limits() override { + auto const &box_geo = *System::get_system().box_geo; auto const mesh_density = static_cast(p3m.params.mesh[0]) * box_geo.length_inv()[0]; @@ -660,10 +673,12 @@ class CoulombTuningAlgorithm : public TuningAlgorithm { } TuningAlgorithm::Parameters get_time() override { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &solver = system.coulomb.impl->solver; auto tuned_params = TuningAlgorithm::Parameters{}; auto time_best = time_sentinel; auto mesh_density = m_mesh_density_min; - auto const &solver = System::get_system().coulomb.impl->solver; while (mesh_density <= m_mesh_density_max) { auto trial_params = TuningAlgorithm::Parameters{}; if (m_tune_mesh) { @@ -707,6 +722,7 @@ class CoulombTuningAlgorithm : public TuningAlgorithm { }; void CoulombP3M::tune() { + auto const &box_geo = *System::get_system().box_geo; if (p3m.params.alpha_L == 0. and p3m.params.alpha != 0.) { p3m.params.alpha_L = p3m.params.alpha * box_geo.length()[0]; } @@ -739,7 +755,10 @@ void CoulombP3M::tune() { } void CoulombP3M::sanity_checks_boxl() const { - for (unsigned int i = 0; i < 3; i++) { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &local_geo = *system.local_geo; + for (unsigned int i = 0u; i < 3u; i++) { /* check k-space cutoff */ if (p3m.params.cao_cut[i] >= box_geo.length_half()[i]) { std::stringstream msg; @@ -767,6 +786,7 @@ void CoulombP3M::sanity_checks_boxl() const { } void CoulombP3M::sanity_checks_periodicity() const { + auto const &box_geo = *System::get_system().box_geo; if (!box_geo.periodic(0) || !box_geo.periodic(1) || !box_geo.periodic(2)) { throw std::runtime_error( "CoulombP3M: requires periodicity (True, True, True)"); @@ -774,6 +794,7 @@ void CoulombP3M::sanity_checks_periodicity() const { } void CoulombP3M::sanity_checks_cell_structure() const { + auto const &local_geo = *System::get_system().local_geo; if (local_geo.cell_structure_type() != CellStructureType::CELL_STRUCTURE_REGULAR && local_geo.cell_structure_type() != @@ -781,8 +802,8 @@ void CoulombP3M::sanity_checks_cell_structure() const { throw std::runtime_error( "CoulombP3M: requires the regular or hybrid decomposition cell system"); } - if (n_nodes > 1 && local_geo.cell_structure_type() == - CellStructureType::CELL_STRUCTURE_HYBRID) { + if (::communicator.size > 1 && local_geo.cell_structure_type() == + CellStructureType::CELL_STRUCTURE_HYBRID) { throw std::runtime_error( "CoulombP3M: does not work with the hybrid decomposition cell system, " "if using more than one MPI node"); @@ -790,6 +811,7 @@ void CoulombP3M::sanity_checks_cell_structure() const { } void CoulombP3M::sanity_checks_node_grid() const { + auto const &node_grid = ::communicator.node_grid; if (node_grid[0] < node_grid[1] || node_grid[1] < node_grid[2]) { throw std::runtime_error( "CoulombP3M: node grid must be sorted, largest first"); @@ -797,6 +819,7 @@ void CoulombP3M::sanity_checks_node_grid() const { } void CoulombP3M::scaleby_box_l() { + auto const &box_geo = *System::get_system().box_geo; p3m.params.r_cut = p3m.params.r_cut_iL * box_geo.length()[0]; p3m.params.alpha = p3m.params.alpha_L * box_geo.length_inv()[0]; p3m.params.recalc_a_ai_cao_cut(box_geo.length()); diff --git a/src/core/electrostatics/scafacos_impl.cpp b/src/core/electrostatics/scafacos_impl.cpp index 365eaeeb2a0..1a0895fa8fc 100644 --- a/src/core/electrostatics/scafacos_impl.cpp +++ b/src/core/electrostatics/scafacos_impl.cpp @@ -26,11 +26,13 @@ #include "electrostatics/scafacos.hpp" #include "electrostatics/scafacos_impl.hpp" -#include "cells.hpp" +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "event.hpp" -#include "grid.hpp" #include "integrate.hpp" +#include "system/System.hpp" #include "tuning.hpp" #include @@ -51,11 +53,15 @@ make_coulomb_scafacos(std::string const &method, } void CoulombScafacosImpl::update_particle_data() { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; + positions.clear(); charges.clear(); for (auto const &p : cell_structure.local_particles()) { - auto const pos = folded_position(p.pos(), box_geo); + auto const pos = box_geo.folded_position(p.pos()); positions.push_back(pos[0]); positions.push_back(pos[1]); positions.push_back(pos[2]); @@ -67,6 +73,8 @@ void CoulombScafacosImpl::update_particle_forces() const { if (positions.empty()) return; + auto &cell_structure = *System::get_system().cell_structure; + auto it_fields = fields.begin(); for (auto &p : cell_structure.local_particles()) { p.force() += prefactor * p.q() * @@ -85,6 +93,9 @@ double CoulombScafacosImpl::time_r_cut(double r_cut) { void CoulombScafacosImpl::tune_r_cut() { auto constexpr convergence_threshold = 1e-3; + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &local_geo = *system.local_geo; auto const min_box_l = *boost::min_element(box_geo.length()); auto const min_local_box_l = *boost::min_element(local_geo.length()); diff --git a/src/core/energy.cpp b/src/core/energy.cpp index 8b1645e2108..b91fcfa7645 100644 --- a/src/core/energy.cpp +++ b/src/core/energy.cpp @@ -22,7 +22,9 @@ * Energy calculation. */ +#include "BoxGeometry.hpp" #include "Observable_stat.hpp" +#include "cells.hpp" #include "communication.hpp" #include "constraints.hpp" #include "energy_inline.hpp" @@ -49,30 +51,33 @@ std::shared_ptr calculate_energy() { return obs_energy_ptr; } + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; auto &obs_energy = *obs_energy_ptr; #if defined(CUDA) and (defined(ELECTROSTATICS) or defined(DIPOLES)) - auto &gpu_particle_data = System::get_system().gpu; + auto &gpu_particle_data = system.gpu; gpu_particle_data.clear_energy_on_device(); gpu_particle_data.update(); #endif on_observable_calc(); + auto const &box_geo = *system.box_geo; auto const local_parts = cell_structure.local_particles(); + auto const n_nodes = ::communicator.size; for (auto const &p : local_parts) { obs_energy.kinetic[0] += calc_kinetic_energy(p); } - auto const &system = System::get_system(); auto const coulomb_kernel = system.coulomb.pair_energy_kernel(); auto const dipoles_kernel = system.dipoles.pair_energy_kernel(); short_range_loop( - [&obs_energy, coulomb_kernel_ptr = get_ptr(coulomb_kernel)]( + [&obs_energy, coulomb_kernel_ptr = get_ptr(coulomb_kernel), &box_geo]( Particle const &p1, int bond_id, Utils::Span partners) { auto const &iaparams = *bonded_ia_params.at(bond_id); - auto const result = - calc_bonded_energy(iaparams, p1, partners, coulomb_kernel_ptr); + auto const result = calc_bonded_energy(iaparams, p1, partners, box_geo, + coulomb_kernel_ptr); if (result) { obs_energy.bonded_contribution(bond_id)[0] += result.get(); return false; @@ -86,7 +91,7 @@ std::shared_ptr calculate_energy() { coulomb_kernel_ptr, dipoles_kernel_ptr, obs_energy); }, - maximal_cutoff(n_nodes), maximal_cutoff_bonded()); + cell_structure, maximal_cutoff(n_nodes), maximal_cutoff_bonded()); #ifdef ELECTROSTATICS /* calculate k-space part of electrostatic interaction. */ @@ -98,7 +103,8 @@ std::shared_ptr calculate_energy() { obs_energy.dipolar[1] = system.dipoles.calc_energy_long_range(local_parts); #endif - Constraints::constraints.add_energy(local_parts, get_sim_time(), obs_energy); + Constraints::constraints.add_energy(box_geo, local_parts, get_sim_time(), + obs_energy); #if defined(CUDA) and (defined(ELECTROSTATICS) or defined(DIPOLES)) auto const energy_host = gpu_particle_data.copy_energy_to_host(); @@ -114,6 +120,8 @@ std::shared_ptr calculate_energy() { } double particle_short_range_energy_contribution(int pid) { + auto const &system = System::get_system(); + auto &cell_structure = *system.cell_structure; double ret = 0.0; if (cell_structure.get_resort_particles()) { @@ -121,7 +129,7 @@ double particle_short_range_energy_contribution(int pid) { } if (auto const p = cell_structure.get_local_particle(pid)) { - auto const &coulomb = System::get_system().coulomb; + auto const &coulomb = system.coulomb; auto const coulomb_kernel = coulomb.pair_energy_kernel(); auto kernel = [&ret, coulomb_kernel_ptr = get_ptr(coulomb_kernel)]( Particle const &p, Particle const &p1, @@ -142,8 +150,10 @@ double particle_short_range_energy_contribution(int pid) { #ifdef DIPOLE_FIELD_TRACKING void calc_long_range_fields() { + auto const &system = System::get_system(); + auto const &dipoles = system.dipoles; + auto &cell_structure = *system.cell_structure; auto particles = cell_structure.local_particles(); - auto const &dipoles = System::get_system().dipoles; dipoles.calc_long_range_field(particles); } #endif diff --git a/src/core/energy_inline.hpp b/src/core/energy_inline.hpp index f4c09b93a7e..40cbe84dbc1 100644 --- a/src/core/energy_inline.hpp +++ b/src/core/energy_inline.hpp @@ -49,6 +49,7 @@ #include "nonbonded_interactions/thole.hpp" #include "nonbonded_interactions/wca.hpp" +#include "BoxGeometry.hpp" #include "Observable_stat.hpp" #include "Particle.hpp" #include "bond_error.hpp" @@ -202,7 +203,7 @@ inline void add_non_bonded_pair_energy( inline boost::optional calc_bonded_energy(Bonded_IA_Parameters const &iaparams, Particle const &p1, - Utils::Span partners, + Utils::Span partners, BoxGeometry const &box_geo, Coulomb::ShortRangeEnergyKernel::kernel_type const *kernel) { auto const n_partners = static_cast(partners.size()); @@ -245,17 +246,19 @@ calc_bonded_energy(Bonded_IA_Parameters const &iaparams, Particle const &p1, throw BondUnknownTypeError(); } // 1 partner if (n_partners == 2) { + auto const vec1 = box_geo.get_mi_vector(p2->pos(), p1.pos()); + auto const vec2 = box_geo.get_mi_vector(p3->pos(), p1.pos()); if (auto const *iap = boost::get(&iaparams)) { - return iap->energy(p1.pos(), p2->pos(), p3->pos()); + return iap->energy(vec1, vec2); } if (auto const *iap = boost::get(&iaparams)) { - return iap->energy(p1.pos(), p2->pos(), p3->pos()); + return iap->energy(vec1, vec2); } if (auto const *iap = boost::get(&iaparams)) { - return iap->energy(p1.pos(), p2->pos(), p3->pos()); + return iap->energy(vec1, vec2); } if (auto const *iap = boost::get(&iaparams)) { - return iap->energy(p1.pos(), p2->pos(), p3->pos()); + return iap->energy(vec1, vec2); } if (boost::get(&iaparams)) { runtimeWarningMsg() << "Unsupported bond type " + @@ -266,11 +269,15 @@ calc_bonded_energy(Bonded_IA_Parameters const &iaparams, Particle const &p1, throw BondUnknownTypeError(); } // 2 partners if (n_partners == 3) { + // note: particles in a dihedral bond are ordered as p2-p1-p3-p4 + auto const v12 = box_geo.get_mi_vector(p1.pos(), p2->pos()); + auto const v23 = box_geo.get_mi_vector(p3->pos(), p1.pos()); + auto const v34 = box_geo.get_mi_vector(p4->pos(), p3->pos()); if (auto const *iap = boost::get(&iaparams)) { - return iap->energy(p2->pos(), p1.pos(), p3->pos(), p4->pos()); + return iap->energy(v12, v23, v34); } if (auto const *iap = boost::get(&iaparams)) { - return iap->energy(p2->pos(), p1.pos(), p3->pos(), p4->pos()); + return iap->energy(v12, v23, v34); } if (boost::get(&iaparams)) { runtimeWarningMsg() << "Unsupported bond type " + diff --git a/src/core/event.cpp b/src/core/event.cpp index b78142796ac..7fa4acaf646 100644 --- a/src/core/event.cpp +++ b/src/core/event.cpp @@ -25,6 +25,8 @@ */ #include "event.hpp" +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" #include "bonded_interactions/thermalized_bond.hpp" #include "cell_system/CellStructureType.hpp" #include "cells.hpp" @@ -37,7 +39,6 @@ #include "electrostatics/coulomb.hpp" #include "electrostatics/icc.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "immersed_boundaries.hpp" #include "integrate.hpp" #include "interactions.hpp" @@ -68,11 +69,6 @@ void on_program_start() { } #endif - init_node_grid(); - - /* initially go for regular decomposition */ - cells_re_init(CellStructureType::CELL_STRUCTURE_REGULAR); - /* make sure interaction 0<->0 always exists */ make_particle_type_exist(0); } @@ -103,13 +99,14 @@ void on_integration_start(double time_step) { } #ifdef NPT - npt_ensemble_init(box_geo); + npt_ensemble_init(*system.box_geo); #endif partCfg().invalidate(); invalidate_fetch_cache(); #ifdef ADDITIONAL_CHECKS + auto &cell_structure = *system.cell_structure; if (!Utils::Mpi::all_compare(comm_cart, cell_structure.use_verlet_list)) { runtimeErrorMsg() << "Nodes disagree about use of verlet lists."; } @@ -167,6 +164,9 @@ void on_particle_local_change() { } void on_particle_change() { + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + if (cell_structure.decomposition_type() == CellStructureType::CELL_STRUCTURE_HYBRID) { cell_structure.set_resort_particles(Cells::RESORT_GLOBAL); @@ -174,14 +174,10 @@ void on_particle_change() { cell_structure.set_resort_particles(Cells::RESORT_LOCAL); } #ifdef ELECTROSTATICS - if (System::is_system_set()) { - System::get_system().coulomb.on_particle_change(); - } + system.coulomb.on_particle_change(); #endif #ifdef DIPOLES - if (System::is_system_set()) { - System::get_system().dipoles.on_particle_change(); - } + system.dipoles.on_particle_change(); #endif recalc_forces = true; @@ -222,7 +218,8 @@ void on_non_bonded_ia_change() { } void on_short_range_ia_change() { - cells_re_init(cell_structure.decomposition_type()); + auto const &system = System::get_system(); + cells_re_init(*system.cell_structure); recalc_forces = true; } @@ -230,15 +227,19 @@ void on_constraint_change() { recalc_forces = true; } void on_lb_boundary_conditions_change() { recalc_forces = true; } +static void update_local_geo(System::System &system) { + *system.local_geo = LocalBox::make_regular_decomposition( + system.box_geo->length(), ::communicator.calc_node_index(), + ::communicator.node_grid); +} + void on_boxl_change(bool skip_method_adaption) { - grid_changed_box_l(box_geo); - /* Electrostatics cutoffs mostly depend on the system size, - * therefore recalculate them. */ - cells_re_init(cell_structure.decomposition_type()); + auto &system = System::get_system(); + update_local_geo(system); + cells_re_init(*system.cell_structure); /* Now give methods a chance to react to the change in box length */ if (not skip_method_adaption) { - auto &system = System::get_system(); system.lb.on_boxl_change(); system.ek.on_boxl_change(); #ifdef ELECTROSTATICS @@ -288,6 +289,7 @@ void on_periodicity_change() { #ifdef STOKESIAN_DYNAMICS if (integ_switch == INTEG_METHOD_SD) { + auto const &box_geo = *System::get_system().box_geo; if (box_geo.periodic(0) || box_geo.periodic(1) || box_geo.periodic(2)) runtimeErrorMsg() << "Stokesian Dynamics requires periodicity " << "(False, False, False)\n"; @@ -297,7 +299,8 @@ void on_periodicity_change() { } void on_skin_change() { - cells_re_init(cell_structure.decomposition_type()); + auto const &system = System::get_system(); + cells_re_init(*system.cell_structure); on_coulomb_and_dipoles_change(); } @@ -313,8 +316,9 @@ void on_timestep_change() { void on_forcecap_change() { recalc_forces = true; } void on_node_grid_change() { - grid_changed_n_nodes(); auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + update_local_geo(system); system.lb.on_node_grid_change(); system.ek.on_node_grid_change(); #ifdef ELECTROSTATICS @@ -323,7 +327,7 @@ void on_node_grid_change() { #ifdef DIPOLES system.dipoles.on_node_grid_change(); #endif - cells_re_init(cell_structure.decomposition_type()); + cells_re_init(cell_structure); } /** @@ -356,6 +360,8 @@ unsigned global_ghost_flags() { } void update_dependent_particles() { + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; #ifdef VIRTUAL_SITES virtual_sites()->update(); cells_update_ghosts(global_ghost_flags()); diff --git a/src/core/forces.cpp b/src/core/forces.cpp index b83b55b4dc0..fa6a783ec13 100644 --- a/src/core/forces.cpp +++ b/src/core/forces.cpp @@ -24,6 +24,7 @@ * The corresponding header file is forces.hpp. */ +#include "BoxGeometry.hpp" #include "bond_breakage/bond_breakage.hpp" #include "cell_system/CellStructure.hpp" #include "cells.hpp" @@ -152,12 +153,14 @@ void force_calc(CellStructure &cell_structure, double time_step, double kT) { CALI_CXX_MARK_FUNCTION; #endif - auto &espresso_system = System::get_system(); + auto &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const n_nodes = ::communicator.size; #ifdef CUDA #ifdef CALIPER CALI_MARK_BEGIN("copy_particles_to_GPU"); #endif - espresso_system.gpu.update(); + system.gpu.update(); #ifdef CALIPER CALI_MARK_END("copy_particles_to_GPU"); #endif @@ -170,9 +173,9 @@ void force_calc(CellStructure &cell_structure, double time_step, double kT) { auto particles = cell_structure.local_particles(); auto ghost_particles = cell_structure.ghost_particles(); #ifdef ELECTROSTATICS - if (espresso_system.coulomb.impl->extension) { + if (system.coulomb.impl->extension) { if (auto icc = std::get_if>( - get_ptr(espresso_system.coulomb.impl->extension))) { + get_ptr(system.coulomb.impl->extension))) { (**icc).iteration(cell_structure, particles, ghost_particles); } } @@ -181,26 +184,27 @@ void force_calc(CellStructure &cell_structure, double time_step, double kT) { calc_long_range_forces(particles); - auto const elc_kernel = espresso_system.coulomb.pair_force_elc_kernel(); - auto const coulomb_kernel = espresso_system.coulomb.pair_force_kernel(); - auto const dipoles_kernel = espresso_system.dipoles.pair_force_kernel(); + auto const elc_kernel = system.coulomb.pair_force_elc_kernel(); + auto const coulomb_kernel = system.coulomb.pair_force_kernel(); + auto const dipoles_kernel = system.dipoles.pair_force_kernel(); #ifdef ELECTROSTATICS - auto const coulomb_cutoff = espresso_system.coulomb.cutoff(); + auto const coulomb_cutoff = system.coulomb.cutoff(); #else auto const coulomb_cutoff = INACTIVE_CUTOFF; #endif #ifdef DIPOLES - auto const dipole_cutoff = espresso_system.dipoles.cutoff(); + auto const dipole_cutoff = system.dipoles.cutoff(); #else auto const dipole_cutoff = INACTIVE_CUTOFF; #endif short_range_loop( - [coulomb_kernel_ptr = get_ptr(coulomb_kernel)]( - Particle &p1, int bond_id, Utils::Span partners) { - return add_bonded_force(p1, bond_id, partners, coulomb_kernel_ptr); + [coulomb_kernel_ptr = get_ptr(coulomb_kernel), + &box_geo](Particle &p1, int bond_id, Utils::Span partners) { + return add_bonded_force(p1, bond_id, partners, box_geo, + coulomb_kernel_ptr); }, [coulomb_kernel_ptr = get_ptr(coulomb_kernel), dipoles_kernel_ptr = get_ptr(dipoles_kernel), @@ -214,31 +218,32 @@ void force_calc(CellStructure &cell_structure, double time_step, double kT) { detect_collision(p1, p2, d.dist2); #endif }, - maximal_cutoff(n_nodes), maximal_cutoff_bonded(), + cell_structure, maximal_cutoff(n_nodes), maximal_cutoff_bonded(), VerletCriterion<>{skin, interaction_range(), coulomb_cutoff, dipole_cutoff, collision_detection_cutoff()}); - Constraints::constraints.add_forces(particles, get_sim_time()); + Constraints::constraints.add_forces(box_geo, particles, get_sim_time()); if (max_oif_objects) { // There are two global quantities that need to be evaluated: // object's surface and object's volume. for (int i = 0; i < max_oif_objects; i++) { auto const area_volume = boost::mpi::all_reduce( - comm_cart, calc_oif_global(i, cell_structure), std::plus<>()); + comm_cart, calc_oif_global(i, box_geo, cell_structure), + std::plus<>()); auto const oif_part_area = std::abs(area_volume[0]); auto const oif_part_vol = std::abs(area_volume[1]); if (oif_part_area < 1e-100 and oif_part_vol < 1e-100) { break; } - add_oif_global_forces(area_volume, i, cell_structure); + add_oif_global_forces(area_volume, i, box_geo, cell_structure); } } // Must be done here. Forces need to be ghost-communicated immersed_boundaries.volume_conservation(cell_structure); - if (System::get_system().lb.is_solver_set()) { + if (system.lb.is_solver_set()) { LB::couple_particles(thermo_virtual, particles, ghost_particles, time_step); } @@ -246,7 +251,7 @@ void force_calc(CellStructure &cell_structure, double time_step, double kT) { #ifdef CALIPER CALI_MARK_BEGIN("copy_forces_from_GPU"); #endif - espresso_system.gpu.copy_forces_to_host(particles, this_node); + system.gpu.copy_forces_to_host(particles, this_node); #ifdef CALIPER CALI_MARK_END("copy_forces_from_GPU"); #endif diff --git a/src/core/forces_inline.hpp b/src/core/forces_inline.hpp index e18a18c7868..2d21f2483be 100644 --- a/src/core/forces_inline.hpp +++ b/src/core/forces_inline.hpp @@ -28,6 +28,7 @@ #include "forces.hpp" +#include "BoxGeometry.hpp" #include "actor/visitors.hpp" #include "bond_breakage/bond_breakage.hpp" #include "bonded_interactions/bonded_interaction_data.hpp" @@ -324,6 +325,7 @@ inline boost::optional calc_bond_pair_force( inline bool add_bonded_two_body_force( Bonded_IA_Parameters const &iaparams, Particle &p1, Particle &p2, + BoxGeometry const &box_geo, Coulomb::ShortRangeForceKernel::kernel_type const *kernel) { auto const dx = box_geo.get_mi_vector(p1.pos(), p2.pos()); @@ -355,35 +357,39 @@ inline bool add_bonded_two_body_force( inline boost::optional< std::tuple> calc_bonded_three_body_force(Bonded_IA_Parameters const &iaparams, - Particle const &p1, Particle const &p2, - Particle const &p3) { + BoxGeometry const &box_geo, Particle const &p1, + Particle const &p2, Particle const &p3) { + auto const vec1 = box_geo.get_mi_vector(p2.pos(), p1.pos()); + auto const vec2 = box_geo.get_mi_vector(p3.pos(), p1.pos()); if (auto const *iap = boost::get(&iaparams)) { - return iap->forces(p1.pos(), p2.pos(), p3.pos()); + return iap->forces(vec1, vec2); } if (auto const *iap = boost::get(&iaparams)) { - return iap->forces(p1.pos(), p2.pos(), p3.pos()); + return iap->forces(vec1, vec2); } if (auto const *iap = boost::get(&iaparams)) { - return iap->forces(p1.pos(), p2.pos(), p3.pos()); + return iap->forces(vec1, vec2); } #ifdef TABULATED if (auto const *iap = boost::get(&iaparams)) { - return iap->forces(p1.pos(), p2.pos(), p3.pos()); + return iap->forces(vec1, vec2); } #endif if (auto const *iap = boost::get(&iaparams)) { - return iap->calc_forces(p1, p2, p3); + return iap->calc_forces(vec1, vec2); } throw BondUnknownTypeError(); } inline bool add_bonded_three_body_force(Bonded_IA_Parameters const &iaparams, + BoxGeometry const &box_geo, Particle &p1, Particle &p2, Particle &p3) { if (boost::get(&iaparams)) { return false; } - auto const result = calc_bonded_three_body_force(iaparams, p1, p2, p3); + auto const result = + calc_bonded_three_body_force(iaparams, box_geo, p1, p2, p3); if (result) { auto const &forces = result.get(); @@ -399,29 +405,36 @@ inline bool add_bonded_three_body_force(Bonded_IA_Parameters const &iaparams, inline boost::optional> calc_bonded_four_body_force(Bonded_IA_Parameters const &iaparams, - Particle const &p1, Particle const &p2, - Particle const &p3, Particle const &p4) { + BoxGeometry const &box_geo, Particle const &p1, + Particle const &p2, Particle const &p3, + Particle const &p4) { if (auto const *iap = boost::get(&iaparams)) { - return iap->calc_forces(p1, p2, p3, p4); + return iap->calc_forces(box_geo, p1, p2, p3, p4); } if (auto const *iap = boost::get(&iaparams)) { - return iap->calc_forces(p1, p2, p3, p4); + return iap->calc_forces(box_geo, p1, p2, p3, p4); } + // note: particles in a dihedral bond are ordered as p2-p1-p3-p4 + auto const v12 = box_geo.get_mi_vector(p1.pos(), p2.pos()); + auto const v23 = box_geo.get_mi_vector(p3.pos(), p1.pos()); + auto const v34 = box_geo.get_mi_vector(p4.pos(), p3.pos()); if (auto const *iap = boost::get(&iaparams)) { - return iap->forces(p2.pos(), p1.pos(), p3.pos(), p4.pos()); + return iap->forces(v12, v23, v34); } #ifdef TABULATED if (auto const *iap = boost::get(&iaparams)) { - return iap->forces(p2.pos(), p1.pos(), p3.pos(), p4.pos()); + return iap->forces(v12, v23, v34); } #endif throw BondUnknownTypeError(); } inline bool add_bonded_four_body_force(Bonded_IA_Parameters const &iaparams, - Particle &p1, Particle &p2, Particle &p3, + BoxGeometry const &box_geo, Particle &p1, + Particle &p2, Particle &p3, Particle &p4) { - auto const result = calc_bonded_four_body_force(iaparams, p1, p2, p3, p4); + auto const result = + calc_bonded_four_body_force(iaparams, box_geo, p1, p2, p3, p4); if (result) { auto const &forces = result.get(); @@ -438,6 +451,7 @@ inline bool add_bonded_four_body_force(Bonded_IA_Parameters const &iaparams, inline bool add_bonded_force(Particle &p1, int bond_id, Utils::Span partners, + BoxGeometry const &box_geo, Coulomb::ShortRangeForceKernel::kernel_type const *kernel) { // Consider for bond breakage @@ -463,13 +477,14 @@ add_bonded_force(Particle &p1, int bond_id, Utils::Span partners, case 0: return false; case 1: - return add_bonded_two_body_force(iaparams, p1, *partners[0], kernel); + return add_bonded_two_body_force(iaparams, p1, *partners[0], box_geo, + kernel); case 2: - return add_bonded_three_body_force(iaparams, p1, *partners[0], + return add_bonded_three_body_force(iaparams, box_geo, p1, *partners[0], *partners[1]); case 3: - return add_bonded_four_body_force(iaparams, p1, *partners[0], *partners[1], - *partners[2]); + return add_bonded_four_body_force(iaparams, box_geo, p1, *partners[0], + *partners[1], *partners[2]); default: throw BondInvalidSizeError{number_of_partners(iaparams)}; } diff --git a/src/core/galilei/Galilei.cpp b/src/core/galilei/Galilei.cpp index fba6b2b9d10..79a21325611 100644 --- a/src/core/galilei/Galilei.cpp +++ b/src/core/galilei/Galilei.cpp @@ -21,13 +21,14 @@ #include "galilei/Galilei.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "config/config.hpp" #include "event.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include @@ -39,6 +40,7 @@ void Galilei::kill_particle_motion(bool omega) const { #ifndef ROTATION std::ignore = omega; #endif // not ROTATION + auto &cell_structure = *System::get_system().cell_structure; for (auto &p : cell_structure.local_particles()) { p.v() = {}; #ifdef ROTATION @@ -54,6 +56,7 @@ void Galilei::kill_particle_forces(bool torque) const { #ifndef ROTATION std::ignore = torque; #endif // not ROTATION + auto &cell_structure = *System::get_system().cell_structure; for (auto &p : cell_structure.local_particles()) { p.force() = {}; #ifdef ROTATION @@ -66,13 +69,15 @@ void Galilei::kill_particle_forces(bool torque) const { } Utils::Vector3d Galilei::calc_system_cms_position() const { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; auto total_mass = 0.; auto cms_pos = Utils::Vector3d{}; for (auto const &p : cell_structure.local_particles()) { if (not p.is_virtual()) { total_mass += p.mass(); - cms_pos += p.mass() * - unfolded_position(p.pos(), p.image_box(), box_geo.length()); + cms_pos += p.mass() * box_geo.unfolded_position(p.pos(), p.image_box()); } } total_mass = boost::mpi::all_reduce(comm_cart, total_mass, std::plus<>()); @@ -82,6 +87,7 @@ Utils::Vector3d Galilei::calc_system_cms_position() const { } Utils::Vector3d Galilei::calc_system_cms_velocity() const { + auto &cell_structure = *System::get_system().cell_structure; auto total_mass = 0.; auto cms_vel = Utils::Vector3d{}; for (auto const &p : cell_structure.local_particles()) { @@ -97,6 +103,7 @@ Utils::Vector3d Galilei::calc_system_cms_velocity() const { } void Galilei::galilei_transform() const { + auto &cell_structure = *System::get_system().cell_structure; auto const cms_vel = calc_system_cms_velocity(); for (auto &p : cell_structure.local_particles()) { p.v() -= cms_vel; diff --git a/src/core/ghosts.cpp b/src/core/ghosts.cpp index 6a22941130b..4655c09ae86 100644 --- a/src/core/ghosts.cpp +++ b/src/core/ghosts.cpp @@ -30,8 +30,9 @@ */ #include "ghosts.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -122,6 +123,7 @@ template static void serialize_and_reduce(Archive &ar, Particle &p, unsigned int data_parts, ReductionPolicy policy, SerializationDirection direction, + BoxGeometry const &box_geo, Utils::Vector3d const *ghost_shift) { if (data_parts & GHOSTTRANS_PROPRTS) { ar &p.id() & p.mol_id() & p.type(); @@ -171,7 +173,7 @@ serialize_and_reduce(Archive &ar, Particle &p, unsigned int data_parts, /* ok, this is not nice, but perhaps fast */ auto pos = p.pos() + *ghost_shift; auto img = p.image_box(); - fold_position(pos, img, ::box_geo); + box_geo.fold_position(pos, img); ar &pos; ar &img; } else { @@ -225,16 +227,18 @@ serialize_and_reduce(Archive &ar, Particle &p, unsigned int data_parts, #endif } -static std::size_t calc_transmit_size(unsigned data_parts) { +static auto calc_transmit_size(BoxGeometry const &box_geo, + unsigned data_parts) { SerializationSizeCalculator sizeof_archive; Particle p{}; serialize_and_reduce(sizeof_archive, p, data_parts, ReductionPolicy::MOVE, - SerializationDirection::SAVE, nullptr); + SerializationDirection::SAVE, box_geo, nullptr); return sizeof_archive.size(); } -static std::size_t calc_transmit_size(const GhostCommunication &ghost_comm, - unsigned int data_parts) { +static auto calc_transmit_size(GhostCommunication const &ghost_comm, + BoxGeometry const &box_geo, + unsigned int data_parts) { if (data_parts & GHOSTTRANS_PARTNUM) return sizeof(unsigned int) * ghost_comm.part_lists.size(); @@ -242,14 +246,16 @@ static std::size_t calc_transmit_size(const GhostCommunication &ghost_comm, ghost_comm.part_lists, std::size_t{0}, [](std::size_t sum, auto part_list) { return sum + part_list->size(); }); - return n_part * calc_transmit_size(data_parts); + return n_part * calc_transmit_size(box_geo, data_parts); } static void prepare_send_buffer(CommBuf &send_buffer, const GhostCommunication &ghost_comm, unsigned int data_parts) { + auto const &box_geo = *System::get_system().box_geo; + /* reallocate send buffer */ - send_buffer.resize(calc_transmit_size(ghost_comm, data_parts)); + send_buffer.resize(calc_transmit_size(ghost_comm, box_geo, data_parts)); send_buffer.bonds().clear(); auto archiver = Utils::MemcpyOArchive{Utils::make_span(send_buffer)}; @@ -269,7 +275,8 @@ static void prepare_send_buffer(CommBuf &send_buffer, } else { for (auto &p : *part_list) { serialize_and_reduce(archiver, p, data_parts, ReductionPolicy::MOVE, - SerializationDirection::SAVE, &ghost_comm.shift); + SerializationDirection::SAVE, box_geo, + &ghost_comm.shift); if (data_parts & GHOSTTRANS_BONDS) { bond_archiver << p.bonds(); } @@ -293,8 +300,9 @@ static void prepare_ghost_cell(ParticleList *cell, std::size_t size) { static void prepare_recv_buffer(CommBuf &recv_buffer, const GhostCommunication &ghost_comm, unsigned int data_parts) { + auto const &box_geo = *System::get_system().box_geo; /* reallocate recv buffer */ - recv_buffer.resize(calc_transmit_size(ghost_comm, data_parts)); + recv_buffer.resize(calc_transmit_size(ghost_comm, box_geo, data_parts)); /* clear bond buffer */ recv_buffer.bonds().clear(); } @@ -304,6 +312,7 @@ static void put_recv_buffer(CommBuf &recv_buffer, unsigned int data_parts) { /* put back data */ auto archiver = Utils::MemcpyIArchive{Utils::make_span(recv_buffer)}; + auto const &box_geo = *System::get_system().box_geo; if (data_parts & GHOSTTRANS_PARTNUM) { for (auto part_list : ghost_comm.part_lists) { @@ -315,7 +324,7 @@ static void put_recv_buffer(CommBuf &recv_buffer, for (auto part_list : ghost_comm.part_lists) { for (auto &p : *part_list) { serialize_and_reduce(archiver, p, data_parts, ReductionPolicy::MOVE, - SerializationDirection::LOAD, nullptr); + SerializationDirection::LOAD, box_geo, nullptr); } } if (data_parts & GHOSTTRANS_BONDS) { @@ -368,9 +377,10 @@ static void add_forces_from_recv_buffer(CommBuf &recv_buffer, static void cell_cell_transfer(const GhostCommunication &ghost_comm, unsigned int data_parts) { + auto const &box_geo = *System::get_system().box_geo; CommBuf buffer; if (!(data_parts & GHOSTTRANS_PARTNUM)) { - buffer.resize(calc_transmit_size(data_parts)); + buffer.resize(calc_transmit_size(box_geo, data_parts)); } /* transfer data */ auto const offset = ghost_comm.part_lists.size() / 2; @@ -391,9 +401,10 @@ static void cell_cell_transfer(const GhostCommunication &ghost_comm, auto &p1 = src_part.begin()[i]; auto &p2 = dst_part.begin()[i]; serialize_and_reduce(ar_out, p1, data_parts, ReductionPolicy::UPDATE, - SerializationDirection::SAVE, &ghost_comm.shift); + SerializationDirection::SAVE, box_geo, + &ghost_comm.shift); serialize_and_reduce(ar_in, p2, data_parts, ReductionPolicy::UPDATE, - SerializationDirection::LOAD, nullptr); + SerializationDirection::LOAD, box_geo, nullptr); if (data_parts & GHOSTTRANS_BONDS) { p2.bonds() = p1.bonds(); } @@ -435,6 +446,9 @@ void ghost_communicator(const GhostCommunicator &gcr, unsigned int data_parts) { static CommBuf send_buffer, recv_buffer; +#ifndef NDEBUG + auto const &box_geo = *System::get_system().box_geo; +#endif auto const &comm = gcr.mpi_comm; for (auto it = gcr.communications.begin(); it != gcr.communications.end(); @@ -459,7 +473,8 @@ void ghost_communicator(const GhostCommunicator &gcr, unsigned int data_parts) { } // Check prefetched send buffers (must also hold for buffers allocated // in the previous lines.) - assert(send_buffer.size() == calc_transmit_size(ghost_comm, data_parts)); + assert(send_buffer.size() == + calc_transmit_size(ghost_comm, box_geo, data_parts)); } else if (prefetch) { /* we do not send this time, let's look for a prefetch */ auto prefetch_ghost_comm = std::find_if( @@ -542,7 +557,7 @@ void ghost_communicator(const GhostCommunicator &gcr, unsigned int data_parts) { if (poststore_ghost_comm != gcr.communications.rend()) { assert(recv_buffer.size() == - calc_transmit_size(*poststore_ghost_comm, data_parts)); + calc_transmit_size(*poststore_ghost_comm, box_geo, data_parts)); /* as above */ if (data_parts == GHOSTTRANS_FORCE && comm_type != GHOST_RDCE) add_forces_from_recv_buffer(recv_buffer, *poststore_ghost_comm); diff --git a/src/core/grid.cpp b/src/core/grid.cpp deleted file mode 100644 index 5f8aca36b72..00000000000 --- a/src/core/grid.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2010-2022 The ESPResSo project - * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - * Max-Planck-Institute for Polymer Research, Theory Group - * - * This file is part of ESPResSo. - * - * ESPResSo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ESPResSo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -/** \file - * Domain decomposition for parallel computing. - * - * The corresponding header file is grid.hpp. - */ - -#include "grid.hpp" - -#include "communication.hpp" -#include "event.hpp" - -#include -#include - -#include - -#include -#include - -BoxGeometry box_geo; -LocalBox local_geo; - -Utils::Vector3i node_grid{}; - -void init_node_grid() { grid_changed_n_nodes(); } - -Utils::Vector3i calc_node_pos(const boost::mpi::communicator &comm) { - return Utils::Mpi::cart_coords<3>(comm, comm.rank()); -} - -Utils::Vector -calc_node_neighbors(const boost::mpi::communicator &comm) { - return Utils::Mpi::cart_neighbors<3>(comm); -} - -LocalBox regular_decomposition(const BoxGeometry &box, - Utils::Vector3i const &node_pos, - Utils::Vector3i const &node_grid_par) { - Utils::Vector3d local_length; - Utils::Vector3d my_left; - - for (unsigned int i = 0; i < 3; i++) { - local_length[i] = box.length()[i] / node_grid_par[i]; - my_left[i] = node_pos[i] * local_length[i]; - } - - Utils::Array boundaries; - for (unsigned int dir = 0; dir < 3; dir++) { - /* left boundary ? */ - boundaries[2 * dir] = (node_pos[dir] == 0); - /* right boundary ? */ - boundaries[2 * dir + 1] = -(node_pos[dir] == node_grid_par[dir] - 1); - } - - return {my_left, local_length, boundaries, - CellStructureType::CELL_STRUCTURE_REGULAR}; -} - -void grid_changed_box_l(const BoxGeometry &box) { - local_geo = regular_decomposition(box, calc_node_pos(comm_cart), node_grid); -} - -void grid_changed_n_nodes() { - comm_cart = - Utils::Mpi::cart_create(comm_cart, node_grid, /* reorder */ false); - - this_node = comm_cart.rank(); - - calc_node_neighbors(comm_cart); - - grid_changed_box_l(box_geo); -} - -void set_node_grid(Utils::Vector3i const &value) { - ::node_grid = value; - on_node_grid_change(); -} - -void set_box_length(Utils::Vector3d const &value) { - ::box_geo.set_length(value); - on_boxl_change(); -} diff --git a/src/core/grid.hpp b/src/core/grid.hpp deleted file mode 100644 index 2b8a17693e6..00000000000 --- a/src/core/grid.hpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2010-2022 The ESPResSo project - * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 - * Max-Planck-Institute for Polymer Research, Theory Group - * - * This file is part of ESPResSo. - * - * ESPResSo is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * ESPResSo is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef CORE_GRID_HPP -#define CORE_GRID_HPP -/** @file - * Domain decomposition for parallel computing. - * - * The primary simulation box is divided into orthogonal rectangular - * subboxes which are assigned to the different nodes (or processes - * or threads if you want). This grid is described in @ref node_grid. - * - * Implementation in grid.cpp. - */ - -#include "BoxGeometry.hpp" - -#include "LocalBox.hpp" - -#include - -#include - -extern BoxGeometry box_geo; -extern LocalBox local_geo; - -/** The number of nodes in each spatial dimension. */ -extern Utils::Vector3i node_grid; - -/** Make sure that the node grid is set, eventually - * determine one automatically. - */ -void init_node_grid(); - -/** @brief Fill neighbor lists of node. - * - * Calculates the numbers of the nearest neighbors for a node. - * - * @return Ranks of neighbors - */ -Utils::Vector calc_node_neighbors(const boost::mpi::communicator &comm); - -/** - * @brief Calculate the position of node in topology. - * - * @param comm Cartesian communicator - * @return Index of node in grid. - */ -Utils::Vector3i calc_node_pos(const boost::mpi::communicator &comm); - -void grid_changed_n_nodes(); - -void grid_changed_box_l(const BoxGeometry &box); - -/** @brief Calculate image box shift vector. - * @param image_box image box offset - * @param box box parameters (side lengths) - * @return Image box coordinates. - */ -inline Utils::Vector3d image_shift(const Utils::Vector3i &image_box, - const Utils::Vector3d &box) { - return hadamard_product(image_box, box); -} - -/** @brief Unfold particle coordinates to image box. - * @param pos coordinate to unfold - * @param image_box image box offset - * @param box box parameters (side lengths, periodicity) - * @return Unfolded coordinates. - */ -inline Utils::Vector3d unfolded_position(const Utils::Vector3d &pos, - const Utils::Vector3i &image_box, - const Utils::Vector3d &box) { - return pos + image_shift(image_box, box); -} - -/** - * @brief Composition of the simulation box into equal parts for each node. - * - * @param box Geometry of the simulation box - * @param node_pos Position of node in the node grid - * @param node_grid Nodes in each direction - * @return Geometry for the node - */ -LocalBox regular_decomposition(const BoxGeometry &box, - Utils::Vector3i const &node_pos, - Utils::Vector3i const &node_grid); - -void set_node_grid(Utils::Vector3i const &value); -void set_box_length(Utils::Vector3d const &value); - -#endif diff --git a/src/core/immersed_boundary/ImmersedBoundaries.cpp b/src/core/immersed_boundary/ImmersedBoundaries.cpp index c90cf431e21..2b59bbefb8d 100644 --- a/src/core/immersed_boundary/ImmersedBoundaries.cpp +++ b/src/core/immersed_boundary/ImmersedBoundaries.cpp @@ -23,8 +23,8 @@ #include "Particle.hpp" #include "cell_system/CellStructure.hpp" #include "communication.hpp" -#include "grid.hpp" #include "ibm_volcons.hpp" +#include "system/System.hpp" #include "bonded_interactions/bonded_interaction_data.hpp" @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -98,12 +99,14 @@ void ImmersedBoundaries::calc_volumes(CellStructure &cs) { if (!BoundariesFound) return; + auto const &box_geo = *System::get_system().box_geo; + // Partial volumes for each soft particle, to be summed up std::vector tempVol(VolumesCurrent.size()); // Loop over all particles on local node - cs.bond_loop([&tempVol](Particle &p1, int bond_id, - Utils::Span partners) { + cs.bond_loop([&tempVol, &box_geo](Particle &p1, int bond_id, + Utils::Span partners) { auto const vol_cons_params = vol_cons_parameters(p1); if (vol_cons_params && @@ -116,8 +119,7 @@ void ImmersedBoundaries::calc_volumes(CellStructure &cs) { // Unfold position of first node. // This is to get a continuous trajectory with no jumps when box // boundaries are crossed. - auto const x1 = - unfolded_position(p1.pos(), p1.image_box(), box_geo.length()); + auto const x1 = box_geo.unfolded_position(p1.pos(), p1.image_box()); auto const x2 = x1 + box_geo.get_mi_vector(p2.pos(), x1); auto const x3 = x1 + box_geo.get_mi_vector(p3.pos(), x1); @@ -155,8 +157,10 @@ void ImmersedBoundaries::calc_volume_force(CellStructure &cs) { if (!BoundariesFound) return; - cs.bond_loop([this](Particle &p1, int bond_id, - Utils::Span partners) { + auto const &box_geo = *System::get_system().box_geo; + + cs.bond_loop([this, &box_geo](Particle &p1, int bond_id, + Utils::Span partners) { if (boost::get(bonded_ia_params.at(bond_id).get()) != nullptr) { // Check if particle has an IBM Triel bonded interaction and an // IBM VolCons bonded interaction. Basically this loops over all @@ -177,8 +181,7 @@ void ImmersedBoundaries::calc_volume_force(CellStructure &cs) { // Unfold position of first node. // This is to get a continuous trajectory with no jumps when box // boundaries are crossed. - auto const x1 = - unfolded_position(p1.pos(), p1.image_box(), box_geo.length()); + auto const x1 = box_geo.unfolded_position(p1.pos(), p1.image_box()); // Unfolding seems to work only for the first particle of a triel // so get the others from relative vectors considering PBC diff --git a/src/core/immersed_boundary/ibm_common.cpp b/src/core/immersed_boundary/ibm_common.cpp index d2fe972ecd4..176950a4d99 100644 --- a/src/core/immersed_boundary/ibm_common.cpp +++ b/src/core/immersed_boundary/ibm_common.cpp @@ -19,8 +19,9 @@ #include "ibm_common.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" +#include "system/System.hpp" #include @@ -31,6 +32,7 @@ #include Utils::Vector3d get_ibm_particle_position(int pid) { + auto &cell_structure = *System::get_system().cell_structure; auto *p = cell_structure.get_local_particle(pid); boost::optional opt_part{boost::none}; diff --git a/src/core/immersed_boundary/ibm_tribend.cpp b/src/core/immersed_boundary/ibm_tribend.cpp index 4d627ed9373..35b922dd5fe 100644 --- a/src/core/immersed_boundary/ibm_tribend.cpp +++ b/src/core/immersed_boundary/ibm_tribend.cpp @@ -20,8 +20,8 @@ #include "immersed_boundary/ibm_tribend.hpp" #include "BoxGeometry.hpp" -#include "grid.hpp" #include "ibm_common.hpp" +#include "system/System.hpp" #include @@ -30,8 +30,9 @@ #include std::tuple -IBMTribend::calc_forces(Particle const &p1, Particle const &p2, - Particle const &p3, Particle const &p4) const { +IBMTribend::calc_forces(BoxGeometry const &box_geo, Particle const &p1, + Particle const &p2, Particle const &p3, + Particle const &p4) const { // Get vectors making up the two triangles auto const dx1 = box_geo.get_mi_vector(p1.pos(), p3.pos()); @@ -94,6 +95,8 @@ IBMTribend::calc_forces(Particle const &p1, Particle const &p2, IBMTribend::IBMTribend(const int ind1, const int ind2, const int ind3, const int ind4, const double kb, const bool flat) { + auto const &box_geo = *System::get_system().box_geo; + // Compute theta0 if (flat) { theta0 = 0; diff --git a/src/core/immersed_boundary/ibm_tribend.hpp b/src/core/immersed_boundary/ibm_tribend.hpp index 1445f84702b..3a013d040db 100644 --- a/src/core/immersed_boundary/ibm_tribend.hpp +++ b/src/core/immersed_boundary/ibm_tribend.hpp @@ -22,6 +22,7 @@ #include "config/config.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" #include @@ -52,8 +53,8 @@ struct IBMTribend { * @return forces on @p p1, @p p2, @p p3, @p p4 */ std::tuple - calc_forces(Particle const &p1, Particle const &p2, Particle const &p3, - Particle const &p4) const; + calc_forces(BoxGeometry const &box_geo, Particle const &p1, + Particle const &p2, Particle const &p3, Particle const &p4) const; private: friend boost::serialization::access; diff --git a/src/core/immersed_boundary/ibm_triel.cpp b/src/core/immersed_boundary/ibm_triel.cpp index 63426c01875..b5c80cb4c07 100644 --- a/src/core/immersed_boundary/ibm_triel.cpp +++ b/src/core/immersed_boundary/ibm_triel.cpp @@ -20,9 +20,8 @@ #include "immersed_boundary/ibm_triel.hpp" #include "BoxGeometry.hpp" -#include "Particle.hpp" -#include "grid.hpp" #include "ibm_common.hpp" +#include "system/System.hpp" #include #include @@ -73,17 +72,15 @@ RotateForces(Utils::Vector2d const &f1_rot, Utils::Vector2d const &f2_rot, } // namespace boost::optional> -IBMTriel::calc_forces(Particle const &p1, Particle const &p2, - Particle const &p3) const { +IBMTriel::calc_forces(Utils::Vector3d const &vec1, + Utils::Vector3d const &vec2) const { // Calculate the current shape of the triangle (l,lp,cos(phi),sin(phi)); // l = length between 1 and 3 // get_mi_vector is an ESPResSo function which considers PBC - auto const vec2 = box_geo.get_mi_vector(p3.pos(), p1.pos()); auto const l = vec2.norm(); // lp = length between 1 and 2 - auto const vec1 = box_geo.get_mi_vector(p2.pos(), p1.pos()); auto const lp = vec1.norm(); // Check for sanity @@ -93,7 +90,7 @@ IBMTriel::calc_forces(Particle const &p1, Particle const &p2, // angles between these vectors; calculated directly via the products auto const cosPhi = (vec1 * vec2) / (lp * l); - auto const vecpro = vector_product(vec1, vec2); + auto const vecpro = Utils::vector_product(vec1, vec2); auto const sinPhi = vecpro.norm() / (l * lp); // Displacement gradient tensor D: eq. (C.9) in @cite kruger12a @@ -199,6 +196,8 @@ IBMTriel::IBMTriel(const int ind1, const int ind2, const int ind3, const double maxDist, const tElasticLaw elasticLaw, const double k1, const double k2) { + auto const &box_geo = *System::get_system().box_geo; + // collect particles from nodes auto const pos1 = get_ibm_particle_position(ind1); auto const pos2 = get_ibm_particle_position(ind2); @@ -215,7 +214,7 @@ IBMTriel::IBMTriel(const int ind1, const int ind2, const int ind3, // cospo / sinpo angle functions between these vectors; calculated directly // via the products cosPhi0 = (temp_l0 * temp_lp0) / (l0 * lp0); - auto const vecpro = vector_product(temp_l0, temp_lp0); + auto const vecpro = Utils::vector_product(temp_l0, temp_lp0); sinPhi0 = vecpro.norm() / (l0 * lp0); // Use the values determined above for further constants of the stretch-force diff --git a/src/core/immersed_boundary/ibm_triel.hpp b/src/core/immersed_boundary/ibm_triel.hpp index 9039f094890..429ce876a44 100644 --- a/src/core/immersed_boundary/ibm_triel.hpp +++ b/src/core/immersed_boundary/ibm_triel.hpp @@ -20,7 +20,6 @@ #ifndef IBM_TRIEL_H #define IBM_TRIEL_H -#include "Particle.hpp" #include "config/config.hpp" #include @@ -69,7 +68,7 @@ struct IBMTriel { * @return the forces on @p p1, @p p2, @p p3 */ boost::optional> - calc_forces(Particle const &p1, Particle const &p2, Particle const &p3) const; + calc_forces(Utils::Vector3d const &vec1, Utils::Vector3d const &vec2) const; private: friend boost::serialization::access; diff --git a/src/core/integrate.cpp b/src/core/integrate.cpp index 8d779d3ccde..ed8b0b20503 100644 --- a/src/core/integrate.cpp +++ b/src/core/integrate.cpp @@ -33,17 +33,18 @@ #include "integrators/velocity_verlet_inline.hpp" #include "integrators/velocity_verlet_npt.hpp" +#include "BoxGeometry.hpp" #include "ParticleRange.hpp" #include "accumulators.hpp" #include "bond_breakage/bond_breakage.hpp" #include "bonded_interactions/rigid_bond.hpp" +#include "cell_system/CellStructure.hpp" #include "cells.hpp" #include "collision.hpp" #include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" #include "forces.hpp" -#include "grid.hpp" #include "interactions.hpp" #include "lb/particle_coupling.hpp" #include "lb/utils.hpp" @@ -120,7 +121,7 @@ std::weak_ptr get_protocol() { return protocol; } * @brief Update the Lees-Edwards parameters of the box geometry * for the current simulation time. */ -static void update_box_params() { +static void update_box_params(BoxGeometry &box_geo) { if (box_geo.type() == BoxType::LEES_EDWARDS) { assert(protocol != nullptr); box_geo.lees_edwards_update(get_pos_offset(sim_time, *protocol), @@ -129,22 +130,30 @@ static void update_box_params() { } void set_protocol(std::shared_ptr new_protocol) { + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + auto &box_geo = *system.box_geo; box_geo.set_type(BoxType::LEES_EDWARDS); protocol = std::move(new_protocol); - LeesEdwards::update_box_params(); + LeesEdwards::update_box_params(box_geo); ::recalc_forces = true; cell_structure.set_resort_particles(Cells::RESORT_LOCAL); } void unset_protocol() { + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + auto &box_geo = *system.box_geo; protocol = nullptr; box_geo.set_type(BoxType::CUBOID); ::recalc_forces = true; cell_structure.set_resort_particles(Cells::RESORT_LOCAL); } -template void run_kernel() { +template void run_kernel(BoxGeometry const &box_geo) { if (box_geo.type() == BoxType::LEES_EDWARDS) { + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; auto const kernel = Kernel{box_geo}; auto const particles = cell_structure.local_particles(); std::for_each(particles.begin(), particles.end(), @@ -172,7 +181,7 @@ void integrator_sanity_checks() { case INTEG_METHOD_NPT_ISO: if (thermo_switch != THERMO_OFF and thermo_switch != THERMO_NPT_ISO) runtimeErrorMsg() << "The NpT integrator requires the NpT thermostat"; - if (box_geo.type() == BoxType::LEES_EDWARDS) + if (System::get_system().box_geo->type() == BoxType::LEES_EDWARDS) runtimeErrorMsg() << "The NpT integrator cannot use Lees-Edwards"; break; #endif @@ -221,8 +230,9 @@ void walberla_agrid_sanity_checks(std::string method, Utils::Vector3d const &lattice_right, double agrid) { // waLBerla and ESPResSo must agree on domain decomposition - auto const &my_left = ::local_geo.my_left(); - auto const &my_right = ::local_geo.my_right(); + auto const &system = System::get_system(); + auto const &my_left = system.local_geo->my_left(); + auto const &my_right = system.local_geo->my_right(); auto const tol = agrid / 1E6; if ((lattice_left - my_left).norm2() > tol or (lattice_right - my_right).norm2() > tol) { @@ -243,8 +253,10 @@ static auto calc_md_steps_per_tau(double tau) { } static void resort_particles_if_needed(ParticleRange const &particles) { + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; auto const offset = LeesEdwards::verlet_list_offset( - box_geo, cell_structure.get_le_pos_offset_at_last_resort()); + *system.box_geo, cell_structure.get_le_pos_offset_at_last_resort()); if (cell_structure.check_resort_required(particles, skin, offset)) { cell_structure.set_resort_particles(Cells::RESORT_LOCAL); } @@ -317,6 +329,8 @@ int integrate(int n_steps, int reuse_forces) { #endif auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + auto &box_geo = *system.box_geo; // Prepare particle structure and run sanity checks of all active algorithms on_integration_start(time_step); @@ -394,12 +408,12 @@ int integrate(int n_steps, int reuse_forces) { save_old_position(particles, cell_structure.ghost_particles()); #endif - LeesEdwards::update_box_params(); + LeesEdwards::update_box_params(box_geo); bool early_exit = integrator_step_1(particles); if (early_exit) break; - LeesEdwards::run_kernel(); + LeesEdwards::run_kernel(box_geo); #ifdef NPT if (integ_switch != INTEG_METHOD_NPT_ISO) @@ -414,7 +428,7 @@ int integrate(int n_steps, int reuse_forces) { #ifdef BOND_CONSTRAINT // Correct particle positions that participate in a rigid/constrained bond if (n_rigidbonds) { - correct_position_shake(cell_structure); + correct_position_shake(cell_structure, box_geo); } #endif @@ -436,11 +450,11 @@ int integrate(int n_steps, int reuse_forces) { virtual_sites()->after_force_calc(time_step); #endif integrator_step_2(particles, temperature); - LeesEdwards::run_kernel(); + LeesEdwards::run_kernel(box_geo); #ifdef BOND_CONSTRAINT // SHAKE velocity updates if (n_rigidbonds) { - correct_velocity_shake(cell_structure); + correct_velocity_shake(cell_structure, box_geo); } #endif @@ -493,7 +507,7 @@ int integrate(int n_steps, int reuse_forces) { #endif #ifdef COLLISION_DETECTION - handle_collisions(); + handle_collisions(cell_structure); #endif BondBreakage::process_queue(); } @@ -512,7 +526,7 @@ int integrate(int n_steps, int reuse_forces) { } } // for-loop over integration steps - LeesEdwards::update_box_params(); + LeesEdwards::update_box_params(box_geo); #ifdef CALIPER CALI_CXX_MARK_LOOP_END(integration_loop); #endif @@ -550,6 +564,8 @@ int integrate_with_signal_handler(int n_steps, int reuse_forces, bool update_accumulators) { assert(n_steps >= 0); + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; // Override the signal handler so that the integrator obeys Ctrl+C SignalHandler sa(SIGINT, [](int) { ctrl_C = 1; }); @@ -562,7 +578,7 @@ int integrate_with_signal_handler(int n_steps, int reuse_forces, /* if skin wasn't set, do an educated guess now */ if (!skin_set) { - auto const max_cut = maximal_cutoff(n_nodes); + auto const max_cut = maximal_cutoff(::comm_cart.size()); if (max_cut <= 0.0) { if (is_head_node) { throw std::runtime_error( @@ -572,7 +588,7 @@ int integrate_with_signal_handler(int n_steps, int reuse_forces, } /* maximal skin that can be used without resorting is the maximal * range of the cell system minus what is needed for interactions. */ - auto const max_range = *boost::min_element(::cell_structure.max_cutoff()); + auto const max_range = *boost::min_element(cell_structure.max_cutoff()); auto const new_skin = std::min(0.4 * max_cut, max_range - max_cut); ::set_skin(new_skin); } @@ -607,7 +623,7 @@ int integrate_with_signal_handler(int n_steps, int reuse_forces, double interaction_range() { /* Consider skin only if there are actually interactions */ - auto const max_cut = maximal_cutoff(n_nodes == 1); + auto const max_cut = maximal_cutoff(::communicator.size == 1); return (max_cut > 0.) ? max_cut + skin : INACTIVE_CUTOFF; } @@ -642,7 +658,9 @@ void set_skin(double value) { void set_time(double value) { ::sim_time = value; ::recalc_forces = true; - LeesEdwards::update_box_params(); + auto &system = System::get_system(); + auto &box_geo = *system.box_geo; + LeesEdwards::update_box_params(box_geo); } void set_integ_switch(int value) { diff --git a/src/core/integrators/steepest_descent.cpp b/src/core/integrators/steepest_descent.cpp index fa5e1e4e9dd..2370da4b02e 100644 --- a/src/core/integrators/steepest_descent.cpp +++ b/src/core/integrators/steepest_descent.cpp @@ -23,10 +23,11 @@ #include "Particle.hpp" #include "ParticleRange.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "config/config.hpp" #include "rotation.hpp" +#include "system/System.hpp" #include #include @@ -93,6 +94,7 @@ bool steepest_descent_step(const ParticleRange &particles) { f_max = std::max(f_max, f); } + auto &cell_structure = *System::get_system().cell_structure; cell_structure.set_resort_particles(Cells::RESORT_LOCAL); // Synchronize maximum force/torque encountered diff --git a/src/core/integrators/velocity_verlet_npt.cpp b/src/core/integrators/velocity_verlet_npt.cpp index 1d37b62c978..3e65e9485a4 100644 --- a/src/core/integrators/velocity_verlet_npt.cpp +++ b/src/core/integrators/velocity_verlet_npt.cpp @@ -22,16 +22,17 @@ #ifdef NPT #include "velocity_verlet_npt.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "npt.hpp" #include "rotation.hpp" +#include "system/System.hpp" #include "thermostat.hpp" #include "thermostats/npt_inline.hpp" @@ -90,6 +91,10 @@ void velocity_verlet_npt_finalize_p_inst(double time_step) { void velocity_verlet_npt_propagate_pos(const ParticleRange &particles, double time_step) { + + auto const &system = System::get_system(); + auto &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; Utils::Vector3d scal{}; double L_new = 0.0; diff --git a/src/core/io/mpiio/mpiio.cpp b/src/core/io/mpiio/mpiio.cpp index 789094d80ca..2dca7309762 100644 --- a/src/core/io/mpiio/mpiio.cpp +++ b/src/core/io/mpiio/mpiio.cpp @@ -52,8 +52,9 @@ #include "Particle.hpp" #include "bonded_interactions/bonded_interaction_data.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "errorhandling.hpp" +#include "system/System.hpp" #include @@ -401,6 +402,7 @@ read_prefs(const std::string &fn, int rank, int size, } void mpi_mpiio_common_read(const std::string &prefix, unsigned fields) { + auto &cell_structure = *System::get_system().cell_structure; cell_structure.remove_all_particles(); int size, rank; diff --git a/src/core/io/writer/h5md_core.cpp b/src/core/io/writer/h5md_core.cpp index 73a83366dcd..175ae92636c 100644 --- a/src/core/io/writer/h5md_core.cpp +++ b/src/core/io/writer/h5md_core.cpp @@ -323,10 +323,10 @@ void write_td_particle_property(hsize_t prefix, hsize_t n_part_global, } } -static void write_box(BoxGeometry const &geometry, h5xx::dataset &dataset) { +static void write_box(BoxGeometry const &box_geo, h5xx::dataset &dataset) { auto const extents = static_cast(dataset).extents(); extend_dataset(dataset, Vector2hs{1, 0}); - h5xx::write_dataset(dataset, geometry.length(), + h5xx::write_dataset(dataset, box_geo.length(), h5xx::slice(Vector2hs{extents[0], 0}, Vector2hs{1, 3})); } @@ -354,11 +354,11 @@ static void write_le_normal(LeesEdwardsBC const &lebc, h5xx::dataset &dataset) { } void File::write(const ParticleRange &particles, double time, int step, - BoxGeometry const &geometry) { + BoxGeometry const &box_geo) { if (m_fields & H5MD_OUT_BOX_L) { - write_box(geometry, datasets["particles/atoms/box/edges/value"]); + write_box(box_geo, datasets["particles/atoms/box/edges/value"]); } - auto const &lebc = geometry.lees_edwards_bc(); + auto const &lebc = box_geo.lees_edwards_bc(); if (m_fields & H5MD_OUT_LE_OFF) { write_le_off(lebc, datasets["particles/atoms/lees_edwards/offset/value"]); } @@ -412,7 +412,7 @@ void File::write(const ParticleRange &particles, double time, int step, write_td_particle_property<3>( prefix, n_part_global, particles, datasets["particles/atoms/position/value"], - [&](auto const &p) { return folded_position(p.pos(), geometry); }); + [&](auto const &p) { return box_geo.folded_position(p.pos()); }); } if (m_fields & H5MD_OUT_IMG) { write_td_particle_property<3>(prefix, n_part_global, particles, diff --git a/src/core/lb/LBWalberla.cpp b/src/core/lb/LBWalberla.cpp index 9aad8f4635e..2abbce492a0 100644 --- a/src/core/lb/LBWalberla.cpp +++ b/src/core/lb/LBWalberla.cpp @@ -24,7 +24,6 @@ #include "communication.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "system/System.hpp" diff --git a/src/core/lb/Solver.cpp b/src/core/lb/Solver.cpp index 5e7e7c9fce6..7fd1f1a3833 100644 --- a/src/core/lb/Solver.cpp +++ b/src/core/lb/Solver.cpp @@ -27,7 +27,6 @@ #include "lb/LBWalberla.hpp" #include "BoxGeometry.hpp" -#include "grid.hpp" #include "system/System.hpp" #ifdef WALBERLA @@ -153,7 +152,8 @@ Solver::get_interpolated_velocity(Utils::Vector3d const &pos) const { return std::visit( [&](auto &ptr) { auto const agrid = ptr->get_agrid(); - auto const lb_pos = folded_position(pos, ::box_geo) / agrid; + auto const &box_geo = *System::get_system().box_geo; + auto const lb_pos = box_geo.folded_position(pos) / agrid; return ptr->get_velocity_at_pos(lb_pos, false); }, *impl->solver); @@ -164,7 +164,8 @@ Solver::get_interpolated_density(Utils::Vector3d const &pos) const { return std::visit( [&](auto &ptr) { auto const agrid = ptr->get_agrid(); - auto const lb_pos = folded_position(pos, ::box_geo) / agrid; + auto const &box_geo = *System::get_system().box_geo; + auto const lb_pos = box_geo.folded_position(pos) / agrid; return ptr->get_density_at_pos(lb_pos, false); }, *impl->solver); @@ -213,7 +214,8 @@ void Solver::set(std::shared_ptr lb_fluid, assert(not impl->solver.has_value()); auto lb_instance = std::make_shared(lb_fluid, lb_params); lb_instance->sanity_checks(); - auto const &lebc = ::box_geo.lees_edwards_bc(); + auto const &box_geo = *System::get_system().box_geo; + auto const &lebc = box_geo.lees_edwards_bc(); lb_fluid->check_lebc(lebc.shear_direction, lebc.shear_plane_normal); impl->solver = lb_instance; } diff --git a/src/core/lb/particle_coupling.cpp b/src/core/lb/particle_coupling.cpp index 8604ac04d61..63fa308d26c 100644 --- a/src/core/lb/particle_coupling.cpp +++ b/src/core/lb/particle_coupling.cpp @@ -19,12 +19,12 @@ #include "lb/particle_coupling.hpp" #include "BoxGeometry.hpp" +#include "LocalBox.hpp" #include "Particle.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "config/config.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "random.hpp" #include "system/System.hpp" #include "thermostat.hpp" @@ -151,6 +151,7 @@ Utils::Vector3d lb_drag_force(LB::Solver const &lb, Particle const &p, */ static bool in_local_domain(Utils::Vector3d const &pos, double halo = 0.) { auto const halo_vec = Utils::Vector3d::broadcast(halo); + auto const &local_geo = *System::get_system().local_geo; auto const lower_corner = local_geo.my_left() - halo_vec; auto const upper_corner = local_geo.my_right() + halo_vec; @@ -179,6 +180,9 @@ bool in_local_halo(Utils::Vector3d const &pos) { std::vector positions_in_halo(Utils::Vector3d const &pos, BoxGeometry const &box, double agrid) { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &local_geo = *system.local_geo; auto const halo = 0.5 * agrid; auto const halo_vec = Utils::Vector3d::broadcast(halo); auto const fully_inside_lower = local_geo.my_left() + 2. * halo_vec; @@ -241,6 +245,7 @@ void ParticleCoupling::kernel(Particle &p) { return; auto const agrid = m_lb.get_agrid(); + auto const &box_geo = *System::get_system().box_geo; // Calculate coupling force Utils::Vector3d force_on_particle = {}; @@ -278,7 +283,9 @@ void ParticleCoupling::kernel(Particle &p) { } bool CouplingBookkeeping::is_ghost_for_local_particle(Particle const &p) const { - return not ::cell_structure.get_local_particle(p.id())->is_ghost(); + auto const &system = System::get_system(); + auto const &cell_structure = *system.cell_structure; + return not cell_structure.get_local_particle(p.id())->is_ghost(); } #if defined(THERMOSTAT_PER_PARTICLE) and defined(PARTICLE_ANISOTROPY) diff --git a/src/core/lees_edwards/lees_edwards.hpp b/src/core/lees_edwards/lees_edwards.hpp index 629fd4cfed9..631c945a3f7 100644 --- a/src/core/lees_edwards/lees_edwards.hpp +++ b/src/core/lees_edwards/lees_edwards.hpp @@ -65,7 +65,7 @@ class Push : public UpdateOffset { p.v()[m_le.shear_direction] += dir * m_le.shear_velocity; p.pos()[m_le.shear_direction] += pos_prefactor * dir * m_le.pos_offset; p.lees_edwards_offset() -= pos_prefactor * dir * m_le.pos_offset; - fold_position(p.pos(), p.image_box(), m_box); + m_box.fold_position(p.pos(), p.image_box()); // UpdateOffset::operator()(p,pos_prefactor); } }; diff --git a/src/core/magnetostatics/dipolar_direct_sum.cpp b/src/core/magnetostatics/dipolar_direct_sum.cpp index ab3f6ba37cd..b112aa570be 100644 --- a/src/core/magnetostatics/dipolar_direct_sum.cpp +++ b/src/core/magnetostatics/dipolar_direct_sum.cpp @@ -25,10 +25,11 @@ #include "magnetostatics/dipolar_direct_sum.hpp" +#include "BoxGeometry.hpp" #include "cells.hpp" #include "communication.hpp" #include "errorhandling.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -50,7 +51,6 @@ #include #include -namespace { /** * @brief Pair force of two interacting dipoles. * @@ -60,8 +60,8 @@ namespace { * * @return Resulting force. */ -auto pair_force(Utils::Vector3d const &d, Utils::Vector3d const &m1, - Utils::Vector3d const &m2) { +static auto pair_force(Utils::Vector3d const &d, Utils::Vector3d const &m1, + Utils::Vector3d const &m2) { auto const pe2 = m1 * d; auto const pe3 = m2 * d; @@ -90,8 +90,8 @@ auto pair_force(Utils::Vector3d const &d, Utils::Vector3d const &m1, * * @return Interaction energy. */ -auto pair_potential(Utils::Vector3d const &d, Utils::Vector3d const &m1, - Utils::Vector3d const &m2) { +static auto pair_potential(Utils::Vector3d const &d, Utils::Vector3d const &m1, + Utils::Vector3d const &m2) { auto const r2 = d * d; auto const r = sqrt(r2); auto const r3 = r2 * r; @@ -113,7 +113,7 @@ auto pair_potential(Utils::Vector3d const &d, Utils::Vector3d const &m1, * * @return Utils::Vector3d containing dipole field components. */ -auto dipole_field(Utils::Vector3d const &d, Utils::Vector3d const &m1) { +static auto dipole_field(Utils::Vector3d const &d, Utils::Vector3d const &m1) { auto const r2 = d * d; auto const r = sqrt(r2); auto const r3 = r2 * r; @@ -185,7 +185,7 @@ struct PosMom { * at all. If false, distances are calculated as Euclidean * distances, and not using minimum image convention. * @param ncut Number of replicas in each direction. - * @param box_l Box dimensions. + * @param box_geo Box geometry. * @param init Initial value of the sum. * @param f Binary operation mapping distance and moment of the * interaction partner to the value to be summed up for this pair. @@ -195,13 +195,14 @@ struct PosMom { template T image_sum(InputIterator begin, InputIterator end, InputIterator it, bool with_replicas, Utils::Vector3i const &ncut, - Utils::Vector3d const &box_l, T init, F f) { + BoxGeometry const &box_geo, T init, F f) { + auto const &box_l = box_geo.length(); for (auto jt = begin; jt != end; ++jt) { auto const exclude_primary = (it == jt); - auto const primary_distance = - (with_replicas) ? (it->pos - jt->pos) - : ::box_geo.get_mi_vector(it->pos, jt->pos); + auto const primary_distance = (with_replicas) + ? (it->pos - jt->pos) + : box_geo.get_mi_vector(it->pos, jt->pos); for_each_image(ncut, [&](int nx, int ny, int nz) { if (!(exclude_primary && nx == 0 && ny == 0 && nz == 0)) { @@ -216,7 +217,9 @@ T image_sum(InputIterator begin, InputIterator end, InputIterator it, return init; } -auto gather_particle_data(ParticleRange const &particles, int n_replicas) { +static auto gather_particle_data(BoxGeometry const &box_geo, + ParticleRange const &particles, + int n_replicas) { auto const &comm = ::comm_cart; std::vector local_particles; std::vector local_posmom; @@ -230,7 +233,7 @@ auto gather_particle_data(ParticleRange const &particles, int n_replicas) { if (p.dipm() != 0.0) { local_particles.emplace_back(&p); local_posmom.emplace_back( - PosMom{folded_position(p.pos(), ::box_geo), p.calc_dip()}); + PosMom{box_geo.folded_position(p.pos()), p.calc_dip()}); } } @@ -255,14 +258,12 @@ auto gather_particle_data(ParticleRange const &particles, int n_replicas) { std::move(reqs), offset); } -auto get_n_cut(int n_replicas) { - return n_replicas * Utils::Vector3i{static_cast(::box_geo.periodic(0)), - static_cast(::box_geo.periodic(1)), - static_cast(::box_geo.periodic(2))}; +static auto get_n_cut(BoxGeometry const &box_geo, int n_replicas) { + return n_replicas * Utils::Vector3i{static_cast(box_geo.periodic(0)), + static_cast(box_geo.periodic(1)), + static_cast(box_geo.periodic(2))}; } -} // namespace - /** * @brief Calculate and add the interaction forces/torques to the particles. * @@ -287,12 +288,13 @@ auto get_n_cut(int n_replicas) { */ void DipolarDirectSum::add_long_range_forces( ParticleRange const &particles) const { - auto const &box_l = ::box_geo.length(); + auto const &box_geo = *System::get_system().box_geo; + auto const &box_l = box_geo.length(); auto [local_particles, all_posmom, reqs, offset] = - gather_particle_data(particles, n_replicas); + gather_particle_data(box_geo, particles, n_replicas); /* Number of image boxes considered */ - auto const ncut = get_n_cut(n_replicas); + auto const ncut = get_n_cut(box_geo, n_replicas); auto const with_replicas = (ncut.norm2() > 0); /* Range of particles we calculate the ia for on this node */ @@ -307,7 +309,7 @@ void DipolarDirectSum::add_long_range_forces( for (auto it = local_posmom_begin; it != local_posmom_end; ++it, ++p) { /* IA with own images */ auto fi = image_sum( - it, std::next(it), it, with_replicas, ncut, box_l, ParticleForce{}, + it, std::next(it), it, with_replicas, ncut, box_geo, ParticleForce{}, [it](Utils::Vector3d const &rn, Utils::Vector3d const &mj) { return pair_force(rn, it->m, mj); }); @@ -315,9 +317,8 @@ void DipolarDirectSum::add_long_range_forces( /* IA with other local particles */ auto q = std::next(p); for (auto jt = std::next(it); jt != local_posmom_end; ++jt, ++q) { - auto const d = (with_replicas) - ? (it->pos - jt->pos) - : ::box_geo.get_mi_vector(it->pos, jt->pos); + auto const d = (with_replicas) ? (it->pos - jt->pos) + : box_geo.get_mi_vector(it->pos, jt->pos); ParticleForce fij{}; ParticleForce fji{}; @@ -352,14 +353,14 @@ void DipolarDirectSum::add_long_range_forces( // red particles auto fi = image_sum(all_posmom.begin(), local_posmom_begin, it, with_replicas, - ncut, box_l, ParticleForce{}, + ncut, box_geo, ParticleForce{}, [it](Utils::Vector3d const &rn, Utils::Vector3d const &mj) { return pair_force(rn, it->m, mj); }); // black particles fi += image_sum(local_posmom_end, all_posmom.end(), it, with_replicas, ncut, - box_l, ParticleForce{}, + box_geo, ParticleForce{}, [it](Utils::Vector3d const &rn, Utils::Vector3d const &mj) { return pair_force(rn, it->m, mj); }); @@ -376,12 +377,12 @@ void DipolarDirectSum::add_long_range_forces( */ double DipolarDirectSum::long_range_energy(ParticleRange const &particles) const { - auto const &box_l = ::box_geo.length(); + auto const &box_geo = *System::get_system().box_geo; auto [local_particles, all_posmom, reqs, offset] = - gather_particle_data(particles, n_replicas); + gather_particle_data(box_geo, particles, n_replicas); /* Number of image boxes considered */ - auto const ncut = get_n_cut(n_replicas); + auto const ncut = get_n_cut(box_geo, n_replicas); auto const with_replicas = (ncut.norm2() > 0); /* Wait for the rest of the data to arrive */ @@ -394,7 +395,7 @@ DipolarDirectSum::long_range_energy(ParticleRange const &particles) const { auto u = 0.; for (auto it = local_posmom_begin; it != local_posmom_end; ++it) { - u = image_sum(it, all_posmom.end(), it, with_replicas, ncut, box_l, u, + u = image_sum(it, all_posmom.end(), it, with_replicas, ncut, box_geo, u, [it](Utils::Vector3d const &rn, Utils::Vector3d const &mj) { return pair_potential(rn, it->m, mj); }); @@ -415,12 +416,12 @@ DipolarDirectSum::long_range_energy(ParticleRange const &particles) const { #ifdef DIPOLE_FIELD_TRACKING void DipolarDirectSum::dipole_field_at_part( ParticleRange const &particles) const { - auto const &box_l = ::box_geo.length(); + auto const &box_geo = *System::get_system().box_geo; /* collect particle data */ auto [local_particles, all_posmom, reqs, offset] = - gather_particle_data(particles, n_replicas); + gather_particle_data(box_geo, particles, n_replicas); - auto const ncut = get_n_cut(n_replicas); + auto const ncut = get_n_cut(box_geo, n_replicas); auto const with_replicas = (ncut.norm2() > 0); boost::mpi::wait_all(reqs.begin(), reqs.end()); @@ -433,7 +434,7 @@ void DipolarDirectSum::dipole_field_at_part( auto p = local_particles.begin(); for (auto pi = local_posmom_begin; pi != local_posmom_end; ++pi, ++p) { auto const u = image_sum( - all_posmom.begin(), all_posmom.end(), pi, with_replicas, ncut, box_l, + all_posmom.begin(), all_posmom.end(), pi, with_replicas, ncut, box_geo, u_init, [](Utils::Vector3d const &rn, Utils::Vector3d const &mj) { return dipole_field(rn, mj); }); diff --git a/src/core/magnetostatics/dipolar_direct_sum_gpu.cpp b/src/core/magnetostatics/dipolar_direct_sum_gpu.cpp index d2603adc95a..91398f57eb8 100644 --- a/src/core/magnetostatics/dipolar_direct_sum_gpu.cpp +++ b/src/core/magnetostatics/dipolar_direct_sum_gpu.cpp @@ -24,13 +24,14 @@ #include "magnetostatics/dipolar_direct_sum_gpu.hpp" #include "magnetostatics/dipolar_direct_sum_gpu_cuda.cuh" +#include "BoxGeometry.hpp" #include "communication.hpp" -#include "grid.hpp" #include "system/GpuParticleData.hpp" #include "system/System.hpp" -static void get_simulation_box(float *box, int *per) { - for (int i = 0; i < 3; i++) { +static void get_simulation_box(BoxGeometry const &box_geo, float *box, + int *per) { + for (unsigned int i = 0u; i < 3u; i++) { box[i] = static_cast(box_geo.length()[i]); per[i] = box_geo.periodic(i); } @@ -46,14 +47,15 @@ DipolarDirectSumGpu::DipolarDirectSumGpu(double prefactor) } void DipolarDirectSumGpu::add_long_range_forces() const { - auto &gpu = System::get_system().gpu; + auto &system = System::get_system(); + auto &gpu = system.gpu; gpu.update(); if (this_node != 0) { return; } float box[3]; int periodicity[3]; - get_simulation_box(box, periodicity); + get_simulation_box(*system.box_geo, box, periodicity); auto const npart = static_cast(gpu.n_particles()); auto const forces_device = gpu.get_particle_forces_device(); auto const torques_device = gpu.get_particle_torques_device(); @@ -65,14 +67,15 @@ void DipolarDirectSumGpu::add_long_range_forces() const { } void DipolarDirectSumGpu::long_range_energy() const { - auto &gpu = System::get_system().gpu; + auto &system = System::get_system(); + auto &gpu = system.gpu; gpu.update(); if (this_node != 0) { return; } float box[3]; int periodicity[3]; - get_simulation_box(box, periodicity); + get_simulation_box(*system.box_geo, box, periodicity); auto const npart = static_cast(gpu.n_particles()); auto const energy_device = &(gpu.get_energy_device()->dipolar); auto const positions_device = gpu.get_particle_positions_device(); diff --git a/src/core/magnetostatics/dipoles.cpp b/src/core/magnetostatics/dipoles.cpp index 5739c7e32e4..18f6eedcdeb 100644 --- a/src/core/magnetostatics/dipoles.cpp +++ b/src/core/magnetostatics/dipoles.cpp @@ -31,7 +31,6 @@ #include "actor/visitors.hpp" #include "communication.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "npt.hpp" #include "system/System.hpp" diff --git a/src/core/magnetostatics/dlc.cpp b/src/core/magnetostatics/dlc.cpp index ecd9a238724..0a42853f7b4 100644 --- a/src/core/magnetostatics/dlc.cpp +++ b/src/core/magnetostatics/dlc.cpp @@ -30,11 +30,12 @@ #include "magnetostatics/dp3m.hpp" #include "p3m/common.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "errorhandling.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -67,7 +68,8 @@ void DipolarLayerCorrection::check_gap(Particle const &p) const { /** Calculate the maximal dipole moment in the system */ static double calc_mu_max() { - auto const local_particles = cell_structure.local_particles(); + auto const &system = System::get_system(); + auto const local_particles = system.cell_structure->local_particles(); auto const mu_max_local = std::accumulate( local_particles.begin(), local_particles.end(), 0., [](double mu, Particle const &p) { return std::max(mu, p.dipm()); }); @@ -111,6 +113,7 @@ static void dipolar_force_corrections(int kcut, std::vector &fs, std::vector &ts, ParticleRange const &particles) { + auto const &box_geo = *System::get_system().box_geo; auto const facux = 2. * Utils::pi() * box_geo.length_inv()[0]; auto const facuy = 2. * Utils::pi() * box_geo.length_inv()[1]; @@ -244,6 +247,7 @@ static void dipolar_force_corrections(int kcut, */ static double dipolar_energy_correction(int kcut, ParticleRange const &particles) { + auto const &box_geo = *System::get_system().box_geo; auto const facux = 2. * Utils::pi() * box_geo.length_inv()[0]; auto const facuy = 2. * Utils::pi() * box_geo.length_inv()[1]; @@ -301,6 +305,7 @@ static double dipolar_energy_correction(int kcut, void DipolarLayerCorrection::add_force_corrections( ParticleRange const &particles) const { assert(dlc.far_cut > 0.); + auto const &box_geo = *System::get_system().box_geo; auto const volume = box_geo.volume(); auto const correc = 4. * Utils::pi() / volume; @@ -352,6 +357,7 @@ void DipolarLayerCorrection::add_force_corrections( double DipolarLayerCorrection::energy_correction( ParticleRange const &particles) const { assert(dlc.far_cut > 0.); + auto const &box_geo = *System::get_system().box_geo; auto const volume = box_geo.volume(); auto const pref = prefactor * 2. * Utils::pi() / volume; @@ -390,6 +396,7 @@ double DipolarLayerCorrection::energy_correction( } static int count_magnetic_particles() { + auto &cell_structure = *System::get_system().cell_structure; int local_n = 0; for (auto const &p : cell_structure.local_particles()) { @@ -411,6 +418,7 @@ double DipolarLayerCorrection::tune_far_cut() const { /* we take the maximum dipole in the system, to be sure that the errors * in the other case will be equal or less than for this one */ auto const mu_max_sq = Utils::sqr(calc_mu_max()); + auto const &box_geo = *System::get_system().box_geo; auto const lx = box_geo.length()[0]; auto const ly = box_geo.length()[1]; auto const lz = box_geo.length()[2]; @@ -473,14 +481,15 @@ void DipolarLayerCorrection::adapt_solver() { } void DipolarLayerCorrection::sanity_checks_node_grid() const { + auto const &box_geo = *System::get_system().box_geo; if (!box_geo.periodic(0) || !box_geo.periodic(1) || !box_geo.periodic(2)) { throw std::runtime_error("DLC: requires periodicity (True, True, True)"); } } dlc_data::dlc_data(double maxPWerror, double gap_size, double far_cut) - : maxPWerror{maxPWerror}, gap_size{gap_size}, box_h{box_geo.length()[2] - - gap_size}, + : maxPWerror{maxPWerror}, gap_size{gap_size}, + box_h{System::get_system().box_geo->length()[2] - gap_size}, far_cut{far_cut}, far_calculated{far_cut == -1.} { if (far_cut <= 0. and not far_calculated) { throw std::domain_error("Parameter 'far_cut' must be > 0"); @@ -494,11 +503,12 @@ dlc_data::dlc_data(double maxPWerror, double gap_size, double far_cut) } void DipolarLayerCorrection::recalc_box_h() { - auto const new_box_h = box_geo.length()[2] - dlc.gap_size; + auto const lz = System::get_system().box_geo->length()[2]; + auto const new_box_h = lz - dlc.gap_size; if (new_box_h < 0.) { throw std::runtime_error("DLC gap size (" + std::to_string(dlc.gap_size) + ") larger than box length in z-direction (" + - std::to_string(box_geo.length()[2]) + ")"); + std::to_string(lz) + ")"); } dlc.box_h = new_box_h; } diff --git a/src/core/magnetostatics/dp3m.cpp b/src/core/magnetostatics/dp3m.cpp index 90538004629..5f448a84fbf 100644 --- a/src/core/magnetostatics/dp3m.cpp +++ b/src/core/magnetostatics/dp3m.cpp @@ -39,16 +39,18 @@ #include "p3m/interpolation.hpp" #include "p3m/send_mesh.hpp" +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" +#include "cell_system/CellStructure.hpp" #include "cell_system/CellStructureType.hpp" -#include "cells.hpp" #include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "npt.hpp" +#include "system/System.hpp" #include "tuning.hpp" #include @@ -70,10 +72,11 @@ #include void DipolarP3M::count_magnetic_particles() { + auto const &system = System::get_system(); int local_n = 0; double local_mu2 = 0.; - for (auto const &p : cell_structure.local_particles()) { + for (auto const &p : system.cell_structure->local_particles()) { if (p.dipm() != 0.) { local_mu2 += p.calc_dip().norm2(); local_n++; @@ -105,6 +108,7 @@ double DipolarP3M::calc_average_self_energy_k_space() const { auto const start = Utils::Vector3i{dp3m.fft.plan[3].start}; auto const size = Utils::Vector3i{dp3m.fft.plan[3].new_mesh}; + auto const &box_geo = *System::get_system().box_geo; auto const node_phi = grid_influence_function_self_energy( dp3m.params, start, start + size, dp3m.g_energy); @@ -119,15 +123,20 @@ void DipolarP3M::init() { assert(dp3m.params.cao >= 1 and dp3m.params.cao <= 7); assert(dp3m.params.alpha > 0.); + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &local_geo = *system.local_geo; + dp3m.params.cao3 = Utils::int_pow<3>(dp3m.params.cao); dp3m.params.recalc_a_ai_cao_cut(box_geo.length()); dp3m.local_mesh.calc_local_ca_mesh(dp3m.params, local_geo, skin, 0.); dp3m.sm.resize(comm_cart, dp3m.local_mesh); - int ca_mesh_size = fft_init(dp3m.local_mesh.dim, dp3m.local_mesh.margin, - dp3m.params.mesh, dp3m.params.mesh_off, - dp3m.ks_pnum, dp3m.fft, node_grid, comm_cart); + int ca_mesh_size = + fft_init(dp3m.local_mesh.dim, dp3m.local_mesh.margin, dp3m.params.mesh, + dp3m.params.mesh_off, dp3m.ks_pnum, dp3m.fft, + ::communicator.node_grid, comm_cart); dp3m.rs_mesh.resize(ca_mesh_size); dp3m.ks_mesh.resize(ca_mesh_size); @@ -255,6 +264,7 @@ double DipolarP3M::kernel(bool force_flag, bool energy_flag, double k_space_energy_dip = 0.; double tmp0, tmp1; + auto const &box_geo = *System::get_system().box_geo; auto const dipole_prefac = prefactor / Utils::int_pow<3>(dp3m.params.mesh[0]); if (dp3m.sum_mu2 > 0) { @@ -503,6 +513,7 @@ double DipolarP3M::kernel(bool force_flag, bool energy_flag, double DipolarP3M::calc_surface_term(bool force_flag, bool energy_flag, ParticleRange const &particles) { + auto const &box_geo = *System::get_system().box_geo; auto const pref = prefactor * 4. * Utils::pi() / box_geo.volume() / (2. * dp3m.params.epsilon + 1.); auto const n_local_part = particles.size(); @@ -570,6 +581,7 @@ double DipolarP3M::calc_surface_term(bool force_flag, bool energy_flag, void DipolarP3M::calc_influence_function_force() { auto const start = Utils::Vector3i{dp3m.fft.plan[3].start}; auto const size = Utils::Vector3i{dp3m.fft.plan[3].new_mesh}; + auto const &box_geo = *System::get_system().box_geo; dp3m.g_force = grid_influence_function<3>(dp3m.params, start, start + size, box_geo.length()); @@ -578,6 +590,7 @@ void DipolarP3M::calc_influence_function_force() { void DipolarP3M::calc_influence_function_energy() { auto const start = Utils::Vector3i{dp3m.fft.plan[3].start}; auto const size = Utils::Vector3i{dp3m.fft.plan[3].new_mesh}; + auto const &box_geo = *System::get_system().box_geo; dp3m.g_energy = grid_influence_function<2>(dp3m.params, start, start + size, box_geo.length()); @@ -602,6 +615,7 @@ class DipolarTuningAlgorithm : public TuningAlgorithm { } void setup_logger(bool verbose) override { + auto const &box_geo = *System::get_system().box_geo; m_logger = std::make_unique( verbose and this_node == 0, "DipolarP3M", TuningLogger::Mode::Dipolar); m_logger->tuning_goals(dp3m.params.accuracy, m_prefactor, @@ -615,6 +629,7 @@ class DipolarTuningAlgorithm : public TuningAlgorithm { double r_cut_iL) const override { double alpha_L, rs_err, ks_err; + auto const &box_geo = *System::get_system().box_geo; /* calc maximal real space error for setting */ rs_err = dp3m_real_space_error(box_geo.length()[0], r_cut_iL, @@ -695,6 +710,7 @@ class DipolarTuningAlgorithm : public TuningAlgorithm { }; void DipolarP3M::tune() { + auto const &box_geo = *System::get_system().box_geo; if (dp3m.params.alpha_L == 0. and dp3m.params.alpha != 0.) { dp3m.params.alpha_L = dp3m.params.alpha * box_geo.length()[0]; } @@ -858,7 +874,10 @@ double dp3m_rtbisection(double box_size, double r_cut_iL, int n_c_part, } void DipolarP3M::sanity_checks_boxl() const { - for (unsigned int i = 0; i < 3; i++) { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &local_geo = *system.local_geo; + for (unsigned int i = 0u; i < 3u; i++) { /* check k-space cutoff */ if (dp3m.params.cao_cut[i] >= box_geo.length_half()[i]) { std::stringstream msg; @@ -881,6 +900,7 @@ void DipolarP3M::sanity_checks_boxl() const { } void DipolarP3M::sanity_checks_periodicity() const { + auto const &box_geo = *System::get_system().box_geo; if (!box_geo.periodic(0) or !box_geo.periodic(1) or !box_geo.periodic(2)) { throw std::runtime_error( "DipolarP3M: requires periodicity (True, True, True)"); @@ -888,6 +908,7 @@ void DipolarP3M::sanity_checks_periodicity() const { } void DipolarP3M::sanity_checks_cell_structure() const { + auto const &local_geo = *System::get_system().local_geo; if (local_geo.cell_structure_type() != CellStructureType::CELL_STRUCTURE_REGULAR && local_geo.cell_structure_type() != @@ -895,8 +916,8 @@ void DipolarP3M::sanity_checks_cell_structure() const { throw std::runtime_error( "DipolarP3M: requires the regular or hybrid decomposition cell system"); } - if (n_nodes > 1 && local_geo.cell_structure_type() == - CellStructureType::CELL_STRUCTURE_HYBRID) { + if (::communicator.size > 1 && local_geo.cell_structure_type() == + CellStructureType::CELL_STRUCTURE_HYBRID) { throw std::runtime_error( "DipolarP3M: does not work with the hybrid decomposition cell system, " "if using more than one MPI node"); @@ -904,6 +925,7 @@ void DipolarP3M::sanity_checks_cell_structure() const { } void DipolarP3M::sanity_checks_node_grid() const { + auto const &node_grid = ::communicator.node_grid; if (node_grid[0] < node_grid[1] || node_grid[1] < node_grid[2]) { throw std::runtime_error( "DipolarP3M: node grid must be sorted, largest first"); @@ -911,6 +933,7 @@ void DipolarP3M::sanity_checks_node_grid() const { } void DipolarP3M::scaleby_box_l() { + auto const &box_geo = *System::get_system().box_geo; dp3m.params.r_cut = dp3m.params.r_cut_iL * box_geo.length()[0]; dp3m.params.alpha = dp3m.params.alpha_L * box_geo.length_inv()[0]; dp3m.params.recalc_a_ai_cao_cut(box_geo.length()); @@ -922,6 +945,7 @@ void DipolarP3M::scaleby_box_l() { } void DipolarP3M::calc_energy_correction() { + auto const &box_geo = *System::get_system().box_geo; auto const Ukp3m = calc_average_self_energy_k_space() * box_geo.volume(); auto const Ewald_volume = Utils::int_pow<3>(dp3m.params.alpha_L); auto const Eself = -2. * Ewald_volume * Utils::sqrt_pi_i() / 3.; diff --git a/src/core/magnetostatics/scafacos_impl.cpp b/src/core/magnetostatics/scafacos_impl.cpp index 21bdf3ba540..47adf6e3ff4 100644 --- a/src/core/magnetostatics/scafacos_impl.cpp +++ b/src/core/magnetostatics/scafacos_impl.cpp @@ -26,9 +26,10 @@ #include "magnetostatics/scafacos.hpp" #include "magnetostatics/scafacos_impl.hpp" -#include "cells.hpp" +#include "BoxGeometry.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -45,11 +46,15 @@ make_dipolar_scafacos(std::string const &method, } void DipolarScafacosImpl::update_particle_data() { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; + positions.clear(); dipoles.clear(); for (auto const &p : cell_structure.local_particles()) { - auto const pos = folded_position(p.pos(), box_geo); + auto const pos = box_geo.folded_position(p.pos()); positions.push_back(pos[0]); positions.push_back(pos[1]); positions.push_back(pos[2]); @@ -64,6 +69,8 @@ void DipolarScafacosImpl::update_particle_forces() const { if (positions.empty()) return; + auto &cell_structure = *System::get_system().cell_structure; + auto it_potentials = potentials.begin(); auto it_f = std::size_t{0ul}; for (auto &p : cell_structure.local_particles()) { diff --git a/src/core/object-in-fluid/oif_global_forces.cpp b/src/core/object-in-fluid/oif_global_forces.cpp index 6cdc35d3a13..14296433318 100644 --- a/src/core/object-in-fluid/oif_global_forces.cpp +++ b/src/core/object-in-fluid/oif_global_forces.cpp @@ -22,7 +22,6 @@ #include "BoxGeometry.hpp" #include "Particle.hpp" #include "cell_system/CellStructure.hpp" -#include "grid.hpp" #include "bonded_interactions/bonded_interaction_data.hpp" @@ -33,13 +32,14 @@ int max_oif_objects = 0; -Utils::Vector2d calc_oif_global(int molType, CellStructure &cs) { +Utils::Vector2d calc_oif_global(int molType, BoxGeometry const &box_geo, + CellStructure &cs) { // first-fold-then-the-same approach double partArea = 0.0; // z volume double VOL_partVol = 0.; - cs.bond_loop([&partArea, &VOL_partVol, + cs.bond_loop([&partArea, &VOL_partVol, &box_geo, molType](Particle &p1, int bond_id, Utils::Span partners) { if (p1.mol_id() != molType) @@ -48,8 +48,7 @@ Utils::Vector2d calc_oif_global(int molType, CellStructure &cs) { if (boost::get(bonded_ia_params.at(bond_id).get()) != nullptr) { // remaining neighbors fetched - auto const p11 = - unfolded_position(p1.pos(), p1.image_box(), box_geo.length()); + auto const p11 = box_geo.unfolded_position(p1.pos(), p1.image_box()); auto const p22 = p11 + box_geo.get_mi_vector(partners[0]->pos(), p11); auto const p33 = p11 + box_geo.get_mi_vector(partners[1]->pos(), p11); @@ -70,20 +69,20 @@ Utils::Vector2d calc_oif_global(int molType, CellStructure &cs) { } void add_oif_global_forces(Utils::Vector2d const &area_volume, int molType, - CellStructure &cs) { + BoxGeometry const &box_geo, CellStructure &cs) { // first-fold-then-the-same approach double area = area_volume[0]; double VOL_volume = area_volume[1]; - cs.bond_loop([area, VOL_volume, molType](Particle &p1, int bond_id, - Utils::Span partners) { + cs.bond_loop([&box_geo, area, VOL_volume, + molType](Particle &p1, int bond_id, + Utils::Span partners) { if (p1.mol_id() != molType) return false; if (auto const *iaparams = boost::get( bonded_ia_params.at(bond_id).get())) { - auto const p11 = - unfolded_position(p1.pos(), p1.image_box(), box_geo.length()); + auto const p11 = box_geo.unfolded_position(p1.pos(), p1.image_box()); auto const p22 = p11 + box_geo.get_mi_vector(partners[0]->pos(), p11); auto const p33 = p11 + box_geo.get_mi_vector(partners[1]->pos(), p11); diff --git a/src/core/object-in-fluid/oif_global_forces.hpp b/src/core/object-in-fluid/oif_global_forces.hpp index a0bd8924350..908a349e136 100644 --- a/src/core/object-in-fluid/oif_global_forces.hpp +++ b/src/core/object-in-fluid/oif_global_forces.hpp @@ -23,6 +23,7 @@ * for a particle triple (triangle from mesh). See @cite dupin07a. */ +#include "BoxGeometry.hpp" #include "cell_system/CellStructure.hpp" #include "oif_global_forces_params.hpp" @@ -35,11 +36,12 @@ * - MPI synchronization with all reduce * - !!! loop over particles from regular_decomposition !!! */ -Utils::Vector2d calc_oif_global(int molType, CellStructure &cs); +Utils::Vector2d calc_oif_global(int molType, BoxGeometry const &box_geo, + CellStructure &cs); /** Distribute the OIF global forces to all particles in the mesh. */ void add_oif_global_forces(Utils::Vector2d const &area_volume, int molType, - CellStructure &cs); + BoxGeometry const &box_geo, CellStructure &cs); extern int max_oif_objects; diff --git a/src/core/object-in-fluid/oif_local_forces.hpp b/src/core/object-in-fluid/oif_local_forces.hpp index 3a07c67595e..cc3d63371bd 100644 --- a/src/core/object-in-fluid/oif_local_forces.hpp +++ b/src/core/object-in-fluid/oif_local_forces.hpp @@ -29,7 +29,6 @@ #include "BoxGeometry.hpp" #include "Particle.hpp" -#include "grid.hpp" #include #include @@ -79,8 +78,8 @@ struct OifLocalForcesBond { } std::tuple - calc_forces(Particle const &p2, Particle const &p1, Particle const &p3, - Particle const &p4) const; + calc_forces(BoxGeometry const &box_geo, Particle const &p2, + Particle const &p1, Particle const &p3, Particle const &p4) const; private: friend boost::serialization::access; @@ -100,6 +99,7 @@ struct OifLocalForcesBond { /** Compute the OIF local forces. * See @cite dupin07a, @cite jancigova16a. + * @param box_geo Box geometry. * @param p2 %Particle of triangle 1. * @param p1 , p3 Particles common to triangle 1 and triangle 2. * @param p4 %Particle of triangle 2. @@ -107,12 +107,12 @@ struct OifLocalForcesBond { */ inline std::tuple -OifLocalForcesBond::calc_forces(Particle const &p2, Particle const &p1, - Particle const &p3, Particle const &p4) const { +OifLocalForcesBond::calc_forces(BoxGeometry const &box_geo, Particle const &p2, + Particle const &p1, Particle const &p3, + Particle const &p4) const { // first-fold-then-the-same approach - auto const fp2 = - unfolded_position(p2.pos(), p2.image_box(), box_geo.length()); + auto const fp2 = box_geo.unfolded_position(p2.pos(), p2.image_box()); auto const fp1 = fp2 + box_geo.get_mi_vector(p1.pos(), fp2); auto const fp3 = fp2 + box_geo.get_mi_vector(p3.pos(), fp2); auto const fp4 = fp2 + box_geo.get_mi_vector(p4.pos(), fp2); diff --git a/src/core/observables/BondAngles.hpp b/src/core/observables/BondAngles.hpp index 56500e1a378..981e68ff570 100644 --- a/src/core/observables/BondAngles.hpp +++ b/src/core/observables/BondAngles.hpp @@ -21,7 +21,7 @@ #include "BoxGeometry.hpp" #include "PidObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include @@ -58,6 +58,7 @@ class BondAngles : public PidObservable { return {}; } + auto const &box_geo = *System::get_system().box_geo; std::vector res(n_values()); auto v1 = box_geo.get_mi_vector(positions_sorted[1], positions_sorted[0]); auto n1 = v1.norm(); diff --git a/src/core/observables/BondDihedrals.hpp b/src/core/observables/BondDihedrals.hpp index 864628cd915..0d246313509 100644 --- a/src/core/observables/BondDihedrals.hpp +++ b/src/core/observables/BondDihedrals.hpp @@ -21,7 +21,7 @@ #include "BoxGeometry.hpp" #include "PidObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include @@ -62,6 +62,7 @@ class BondDihedrals : public PidObservable { return {}; } + auto const &box_geo = *System::get_system().box_geo; std::vector res(n_values()); auto v1 = box_geo.get_mi_vector(positions_sorted[1], positions_sorted[0]); auto v2 = box_geo.get_mi_vector(positions_sorted[2], positions_sorted[1]); diff --git a/src/core/observables/CosPersistenceAngles.hpp b/src/core/observables/CosPersistenceAngles.hpp index 10c7f892c1d..84b75d878ae 100644 --- a/src/core/observables/CosPersistenceAngles.hpp +++ b/src/core/observables/CosPersistenceAngles.hpp @@ -21,7 +21,7 @@ #include "BoxGeometry.hpp" #include "PidObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include @@ -59,6 +59,7 @@ class CosPersistenceAngles : public PidObservable { return {}; } + auto const &box_geo = *System::get_system().box_geo; auto const no_of_angles = n_values(); auto const no_of_bonds = no_of_angles + 1; std::vector angles(no_of_angles); diff --git a/src/core/observables/CylindricalDensityProfile.hpp b/src/core/observables/CylindricalDensityProfile.hpp index 4b0c18f7871..834ec653c53 100644 --- a/src/core/observables/CylindricalDensityProfile.hpp +++ b/src/core/observables/CylindricalDensityProfile.hpp @@ -22,7 +22,7 @@ #include "CylindricalPidProfileObservable.hpp" #include "BoxGeometry.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include "utils_histogram.hpp" #include @@ -40,12 +40,13 @@ class CylindricalDensityProfile : public CylindricalPidProfileObservable { ParticleReferenceRange const &local_particles, const ParticleObservables::traits &traits) const override { using pos_type = Utils::Vector3d; + auto const &box_geo = *System::get_system().box_geo; std::vector local_folded_positions{}; local_folded_positions.reserve(local_particles.size()); for (auto const &p : local_particles) { - auto const pos = folded_position(traits.position(p), box_geo); + auto const pos = box_geo.folded_position(traits.position(p)); auto const pos_shifted = pos - transform_params->center(); local_folded_positions.emplace_back( diff --git a/src/core/observables/CylindricalFluxDensityProfile.hpp b/src/core/observables/CylindricalFluxDensityProfile.hpp index 9e27a6c3394..20f7d979922 100644 --- a/src/core/observables/CylindricalFluxDensityProfile.hpp +++ b/src/core/observables/CylindricalFluxDensityProfile.hpp @@ -21,7 +21,7 @@ #include "BoxGeometry.hpp" #include "CylindricalPidProfileObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include "utils_histogram.hpp" #include @@ -42,6 +42,7 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { const ParticleObservables::traits &traits) const override { using pos_type = decltype(traits.position(std::declval())); using vel_type = decltype(traits.velocity(std::declval())); + auto const &box_geo = *System::get_system().box_geo; std::vector local_folded_positions{}; local_folded_positions.reserve(local_particles.size()); @@ -49,7 +50,7 @@ class CylindricalFluxDensityProfile : public CylindricalPidProfileObservable { local_velocities.reserve(local_particles.size()); for (auto const &p : local_particles) { - auto const pos = folded_position(traits.position(p), box_geo) - + auto const pos = box_geo.folded_position(traits.position(p)) - transform_params->center(); local_folded_positions.emplace_back( diff --git a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp index 9c4b06e8ed5..b5d0736dfb6 100644 --- a/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBFluxDensityProfileAtParticlePositions.cpp @@ -19,7 +19,6 @@ #include "CylindricalLBFluxDensityProfileAtParticlePositions.hpp" #include "BoxGeometry.hpp" -#include "grid.hpp" #include "system/System.hpp" #include "utils_histogram.hpp" @@ -46,11 +45,13 @@ CylindricalLBFluxDensityProfileAtParticlePositions::evaluate( local_folded_positions.reserve(local_particles.size()); local_flux_densities.reserve(local_particles.size()); - auto const &lb = System::get_system().lb; + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &lb = system.lb; auto const vel_conv = lb.get_lattice_speed(); for (auto const &p : local_particles) { - auto const pos = folded_position(traits.position(p), box_geo); + auto const pos = box_geo.folded_position(traits.position(p)); auto const pos_shifted = pos - transform_params->center(); auto const vel = *lb.get_interpolated_velocity(pos); auto const dens = *lb.get_interpolated_density(pos); diff --git a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp index cce02d6f13e..4d30e53d88a 100644 --- a/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp +++ b/src/core/observables/CylindricalLBVelocityProfileAtParticlePositions.cpp @@ -19,7 +19,6 @@ #include "CylindricalLBVelocityProfileAtParticlePositions.hpp" #include "BoxGeometry.hpp" -#include "grid.hpp" #include "system/System.hpp" #include "utils_histogram.hpp" @@ -42,11 +41,13 @@ std::vector CylindricalLBVelocityProfileAtParticlePositions::evaluate( local_folded_positions.reserve(local_particles.size()); local_velocities.reserve(local_particles.size()); - auto const &lb = System::get_system().lb; + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &lb = system.lb; auto const vel_conv = lb.get_lattice_speed(); for (auto const &p : local_particles) { - auto const pos = folded_position(traits.position(p), box_geo); + auto const pos = box_geo.folded_position(traits.position(p)); auto const pos_shifted = pos - transform_params->center(); auto const vel = *lb.get_interpolated_velocity(pos); auto const pos_cyl = Utils::transform_coordinate_cartesian_to_cylinder( diff --git a/src/core/observables/CylindricalVelocityProfile.hpp b/src/core/observables/CylindricalVelocityProfile.hpp index 394df7cb034..c4728e78ce1 100644 --- a/src/core/observables/CylindricalVelocityProfile.hpp +++ b/src/core/observables/CylindricalVelocityProfile.hpp @@ -21,7 +21,7 @@ #include "BoxGeometry.hpp" #include "CylindricalPidProfileObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include "utils_histogram.hpp" #include @@ -41,6 +41,7 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { const ParticleObservables::traits &traits) const override { using pos_type = Utils::Vector3d; using vel_type = Utils::Vector3d; + auto const &box_geo = *System::get_system().box_geo; std::vector local_folded_positions{}; std::vector local_velocities{}; @@ -48,7 +49,7 @@ class CylindricalVelocityProfile : public CylindricalPidProfileObservable { local_velocities.reserve(local_particles.size()); for (auto const &p : local_particles) { - auto const pos = folded_position(traits.position(p), box_geo) - + auto const pos = box_geo.folded_position(traits.position(p)) - transform_params->center(); local_folded_positions.emplace_back( Utils::transform_coordinate_cartesian_to_cylinder( diff --git a/src/core/observables/DensityProfile.hpp b/src/core/observables/DensityProfile.hpp index 4ebad035dca..0de2f5c1c2f 100644 --- a/src/core/observables/DensityProfile.hpp +++ b/src/core/observables/DensityProfile.hpp @@ -22,7 +22,7 @@ #include "BoxGeometry.hpp" #include "Particle.hpp" #include "PidProfileObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include "utils_histogram.hpp" #include @@ -41,13 +41,14 @@ class DensityProfile : public PidProfileObservable { ParticleReferenceRange const &local_particles, const ParticleObservables::traits &traits) const override { using pos_type = decltype(traits.position(std::declval())); + auto const &box_geo = *System::get_system().box_geo; std::vector local_folded_positions{}; local_folded_positions.reserve(local_particles.size()); for (auto const &p : local_particles) { local_folded_positions.emplace_back( - folded_position(traits.position(p), box_geo)); + box_geo.folded_position(traits.position(p))); } auto const global_folded_positions = diff --git a/src/core/observables/FluxDensityProfile.hpp b/src/core/observables/FluxDensityProfile.hpp index 1887c8d8c61..a2d8cad0077 100644 --- a/src/core/observables/FluxDensityProfile.hpp +++ b/src/core/observables/FluxDensityProfile.hpp @@ -22,7 +22,7 @@ #include "BoxGeometry.hpp" #include "Particle.hpp" #include "PidProfileObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include "utils_histogram.hpp" #include @@ -46,6 +46,7 @@ class FluxDensityProfile : public PidProfileObservable { const ParticleObservables::traits &traits) const override { using pos_type = decltype(traits.position(std::declval())); using vel_type = decltype(traits.velocity(std::declval())); + auto const &box_geo = *System::get_system().box_geo; std::vector local_folded_positions{}; std::vector local_velocities{}; @@ -54,7 +55,7 @@ class FluxDensityProfile : public PidProfileObservable { for (auto const &p : local_particles) { local_folded_positions.emplace_back( - folded_position(traits.position(p), box_geo)); + box_geo.folded_position(traits.position(p))); local_velocities.emplace_back(traits.velocity(p)); } diff --git a/src/core/observables/ForceDensityProfile.hpp b/src/core/observables/ForceDensityProfile.hpp index bd3ded0f03e..be6c6b31e3a 100644 --- a/src/core/observables/ForceDensityProfile.hpp +++ b/src/core/observables/ForceDensityProfile.hpp @@ -22,7 +22,7 @@ #include "BoxGeometry.hpp" #include "Particle.hpp" #include "PidProfileObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include "utils_histogram.hpp" #include @@ -50,6 +50,7 @@ class ForceDensityProfile : public PidProfileObservable { const ParticleObservables::traits &traits) const override { using pos_type = decltype(traits.position(std::declval())); using force_type = decltype(traits.force(std::declval())); + auto const &box_geo = *System::get_system().box_geo; std::vector local_folded_positions{}; local_folded_positions.reserve(local_particles.size()); @@ -58,7 +59,7 @@ class ForceDensityProfile : public PidProfileObservable { for (auto const &p : local_particles) { local_folded_positions.emplace_back( - folded_position(traits.position(p), box_geo)); + box_geo.folded_position(traits.position(p))); local_forces.emplace_back(traits.force(p)); } diff --git a/src/core/observables/LBProfileObservable.hpp b/src/core/observables/LBProfileObservable.hpp index c27d88a6c6c..77956a05fe2 100644 --- a/src/core/observables/LBProfileObservable.hpp +++ b/src/core/observables/LBProfileObservable.hpp @@ -20,7 +20,6 @@ #define OBSERVABLES_LBPROFILEOBSERVABLE_HPP #include "ProfileObservable.hpp" -#include "grid.hpp" #include diff --git a/src/core/observables/ParticleDistances.hpp b/src/core/observables/ParticleDistances.hpp index 1db61a1a690..5329244ce09 100644 --- a/src/core/observables/ParticleDistances.hpp +++ b/src/core/observables/ParticleDistances.hpp @@ -21,7 +21,7 @@ #include "BoxGeometry.hpp" #include "PidObservable.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -55,6 +55,7 @@ class ParticleDistances : public PidObservable { return {}; } + auto const &box_geo = *System::get_system().box_geo; std::vector res(n_values()); for (std::size_t i = 0, end = n_values(); i < end; i++) { diff --git a/src/core/observables/ParticleTraits.hpp b/src/core/observables/ParticleTraits.hpp index fe57ed0d419..0a06fef6b30 100644 --- a/src/core/observables/ParticleTraits.hpp +++ b/src/core/observables/ParticleTraits.hpp @@ -22,8 +22,8 @@ #include "BoxGeometry.hpp" #include "Particle.hpp" #include "config/config.hpp" -#include "grid.hpp" #include "rotation.hpp" +#include "system/System.hpp" namespace ParticleObservables { /** @@ -34,7 +34,8 @@ namespace ParticleObservables { template <> struct traits { auto id(Particle const &p) const { return p.id(); } auto position(Particle const &p) const { - return unfolded_position(p.pos(), p.image_box(), box_geo.length()); + auto const &box_geo = *System::get_system().box_geo; + return box_geo.unfolded_position(p.pos(), p.image_box()); } auto position_folded(Particle const &p) const { return p.pos(); } auto velocity(Particle const &p) const { return p.v(); } diff --git a/src/core/observables/RDF.cpp b/src/core/observables/RDF.cpp index c4975ca4e66..e631fefc783 100644 --- a/src/core/observables/RDF.cpp +++ b/src/core/observables/RDF.cpp @@ -20,7 +20,7 @@ #include "BoxGeometry.hpp" #include "fetch_particles.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -61,12 +61,13 @@ RDF::evaluate(boost::mpi::communicator const &comm, return {}; } + auto const &box_geo = *System::get_system().box_geo; auto const bin_width = (max_r - min_r) / static_cast(n_r_bins); auto const inv_bin_width = 1.0 / bin_width; std::vector res(n_values(), 0.0); long int cnt = 0; - auto op = [this, inv_bin_width, &cnt, &res](auto const &pos1, - auto const &pos2) { + auto op = [this, inv_bin_width, &cnt, &res, &box_geo](auto const &pos1, + auto const &pos2) { auto const dist = box_geo.get_mi_vector(pos1, pos2).norm(); if (dist > min_r && dist < max_r) { auto const ind = diff --git a/src/core/observables/fetch_particles.hpp b/src/core/observables/fetch_particles.hpp index af33a133df5..44d1c75e4bb 100644 --- a/src/core/observables/fetch_particles.hpp +++ b/src/core/observables/fetch_particles.hpp @@ -21,7 +21,8 @@ #define FETCH_PARTICLES_HPP #include "PidObservable.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" +#include "system/System.hpp" #include #include @@ -34,8 +35,9 @@ * @return array of particle copies, with positions in the current box. */ inline auto fetch_particles(std::vector const &ids) { + auto const &system = System::get_system(); auto const ids_set = std::set{ids.begin(), ids.end()}; - auto const local_particles = ::cell_structure.local_particles(); + auto const local_particles = system.cell_structure->local_particles(); Observables::ParticleReferenceRange local_particle_refs; std::copy_if(local_particles.begin(), local_particles.end(), std::back_inserter(local_particle_refs), diff --git a/src/core/p3m/TuningAlgorithm.cpp b/src/core/p3m/TuningAlgorithm.cpp index 9fa852e36ed..8e7fdfbb062 100644 --- a/src/core/p3m/TuningAlgorithm.cpp +++ b/src/core/p3m/TuningAlgorithm.cpp @@ -28,9 +28,11 @@ #include "tuning.hpp" +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" #include "communication.hpp" -#include "grid.hpp" #include "integrate.hpp" +#include "system/System.hpp" #include @@ -55,6 +57,9 @@ static auto constexpr P3M_TUNE_ACCURACY_TOO_LARGE = 3.; static auto constexpr P3M_RCUT_PREC = 1e-3; void TuningAlgorithm::determine_r_cut_limits() { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &local_geo = *system.local_geo; auto const r_cut_iL = get_params().r_cut_iL; if (r_cut_iL == 0.) { auto const min_box_l = *boost::min_element(box_geo.length()); @@ -84,6 +89,7 @@ void TuningAlgorithm::determine_cao_limits(int initial_cao) { void TuningAlgorithm::commit(Utils::Vector3i const &mesh, int cao, double r_cut_iL, double alpha_L) { + auto const &box_geo = *System::get_system().box_geo; auto &p3m_params = get_params(); p3m_params.r_cut = r_cut_iL * box_geo.length()[0]; p3m_params.r_cut_iL = r_cut_iL; @@ -113,6 +119,9 @@ double TuningAlgorithm::get_mc_time(Utils::Vector3i const &mesh, int cao, double &tuned_r_cut_iL, double &tuned_alpha_L, double &tuned_accuracy) { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto const &local_geo = *system.local_geo; auto const target_accuracy = get_params().accuracy; double rs_err, ks_err; double r_cut_iL_min = m_r_cut_iL_min; diff --git a/src/core/p3m/common.cpp b/src/core/p3m/common.cpp index bf5bdf4f4b4..c2a9a60ac6c 100644 --- a/src/core/p3m/common.cpp +++ b/src/core/p3m/common.cpp @@ -76,8 +76,8 @@ double p3m_analytic_cotangent_sum(int n, double mesh_i, int cao) { } void P3MLocalMesh::calc_local_ca_mesh(P3MParameters const ¶ms, - LocalBox const &local_geo, - double skin, double space_layer) { + LocalBox const &local_geo, double skin, + double space_layer) { int i; int ind[3]; // total skin size diff --git a/src/core/p3m/common.hpp b/src/core/p3m/common.hpp index 247a23c1bfe..13b0379468c 100644 --- a/src/core/p3m/common.hpp +++ b/src/core/p3m/common.hpp @@ -215,7 +215,7 @@ struct P3MLocalMesh { * for the charge assignment process. */ void calc_local_ca_mesh(P3MParameters const ¶ms, - LocalBox const &local_geo, double skin, + LocalBox const &local_geo, double skin, double space_layer); }; diff --git a/src/core/pair_criteria/DistanceCriterion.hpp b/src/core/pair_criteria/DistanceCriterion.hpp index 2cf2ee72378..2d0a935b56b 100644 --- a/src/core/pair_criteria/DistanceCriterion.hpp +++ b/src/core/pair_criteria/DistanceCriterion.hpp @@ -21,7 +21,8 @@ #include "pair_criteria/PairCriterion.hpp" -#include "grid.hpp" +#include "BoxGeometry.hpp" +#include "system/System.hpp" namespace PairCriteria { /** @@ -31,6 +32,7 @@ namespace PairCriteria { class DistanceCriterion : public PairCriterion { public: bool decide(const Particle &p1, const Particle &p2) const override { + auto const &box_geo = *System::get_system().box_geo; return box_geo.get_mi_vector(p1.pos(), p2.pos()).norm() <= m_cut_off; } double get_cut_off() { return m_cut_off; } diff --git a/src/core/pair_criteria/EnergyCriterion.hpp b/src/core/pair_criteria/EnergyCriterion.hpp index af331e4e8ed..e5a09dae382 100644 --- a/src/core/pair_criteria/EnergyCriterion.hpp +++ b/src/core/pair_criteria/EnergyCriterion.hpp @@ -21,9 +21,9 @@ #include "pair_criteria/PairCriterion.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "energy_inline.hpp" -#include "grid.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" #include "system/System.hpp" @@ -34,6 +34,8 @@ namespace PairCriteria { class EnergyCriterion : public PairCriterion { public: bool decide(Particle const &p1, Particle const &p2) const override { + auto const &box_geo = *System::get_system().box_geo; + // Distance between particles auto const d = box_geo.get_mi_vector(p1.pos(), p2.pos()); diff --git a/src/core/particle_node.cpp b/src/core/particle_node.cpp index ef66de66b84..8e144e8e94f 100644 --- a/src/core/particle_node.cpp +++ b/src/core/particle_node.cpp @@ -21,13 +21,15 @@ #include "particle_node.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" +#include "cell_system/CellStructure.hpp" #include "cells.hpp" #include "communication.hpp" #include "event.hpp" -#include "grid.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" #include "partCfg_global.hpp" +#include "system/System.hpp" #include #include @@ -66,6 +68,10 @@ static std::unordered_map> particle_type_map; /** @brief Mapping particle ids to MPI ranks. */ static std::unordered_map particle_node; +static auto &get_cell_structure() { + return *System::get_system().cell_structure; +} + /** * @brief Keep track of the largest particle id. * This book-keeping variable is necessary to make particle insertion run @@ -95,7 +101,7 @@ void init_type_map(int type) { make_particle_type_exist(type); std::vector local_pids; - for (auto const &p : ::cell_structure.local_particles()) { + for (auto const &p : get_cell_structure().local_particles()) { if (p.type() == type) { local_pids.emplace_back(p.id()); } @@ -131,7 +137,7 @@ void on_particle_type_change(int p_id, int old_type, int new_type) { if (it != kv.second.end()) { kv.second.erase(it); #ifndef NDEBUG - if (auto p = ::cell_structure.get_local_particle(p_id)) { + if (auto p = get_cell_structure().get_local_particle(p_id)) { assert(p->type() == kv.first); } #endif @@ -157,7 +163,7 @@ void invalidate_fetch_cache() { particle_fetch_cache.invalidate(); } std::size_t fetch_cache_max_size() { return particle_fetch_cache.max_size(); } static void mpi_send_particle_data_local(int p_id) { - auto const p = cell_structure.get_local_particle(p_id); + auto const p = get_cell_structure().get_local_particle(p_id); auto const found = p and not p->is_ghost(); assert(1 == boost::mpi::all_reduce(::comm_cart, static_cast(found), std::plus<>()) && @@ -173,8 +179,9 @@ const Particle &get_particle_data(int p_id) { auto const pnode = get_particle_node(p_id); if (pnode == this_node) { - assert(cell_structure.get_local_particle(p_id)); - return *cell_structure.get_local_particle(p_id); + auto const p = get_cell_structure().get_local_particle(p_id); + assert(p != nullptr); + return *p; } /* Query the cache */ @@ -196,9 +203,10 @@ static void mpi_get_particles_local() { boost::mpi::scatter(comm_cart, ids, 0); std::vector parts(ids.size()); - std::transform(ids.begin(), ids.end(), parts.begin(), [](int id) { - assert(cell_structure.get_local_particle(id)); - return *cell_structure.get_local_particle(id); + std::transform(ids.begin(), ids.end(), parts.begin(), [](int p_id) { + auto const p = get_cell_structure().get_local_particle(p_id); + assert(p != nullptr); + return *p; }); Utils::Mpi::gatherv(comm_cart, parts.data(), static_cast(parts.size()), @@ -243,8 +251,9 @@ static std::vector mpi_get_particles(Utils::Span ids) { /* Copy local particles */ std::transform(node_ids[this_node].cbegin(), node_ids[this_node].cend(), parts.begin(), [](int p_id) { - assert(cell_structure.get_local_particle(p_id)); - return *cell_structure.get_local_particle(p_id); + auto const p = get_cell_structure().get_local_particle(p_id); + assert(p != nullptr); + return *p; }); static std::vector node_sizes(comm_cart.size()); @@ -286,7 +295,7 @@ void prefetch_particle_data(Utils::Span in_ids) { static void mpi_who_has_local() { static std::vector sendbuf; - auto local_particles = cell_structure.local_particles(); + auto local_particles = get_cell_structure().local_particles(); auto const n_part = static_cast(local_particles.size()); boost::mpi::gather(comm_cart, n_part, 0); @@ -307,13 +316,14 @@ static void mpi_who_has_local() { REGISTER_CALLBACK(mpi_who_has_local) static void mpi_who_has_head() { - auto local_particles = cell_structure.local_particles(); + auto local_particles = get_cell_structure().local_particles(); static std::vector n_parts; boost::mpi::gather(comm_cart, static_cast(local_particles.size()), n_parts, 0); static std::vector pdata; + auto const n_nodes = ::comm_cart.size(); max_seen_pid = -1; /* then fetch particle locations */ @@ -428,16 +438,18 @@ static int calculate_max_seen_id() { * @return Whether the particle was created on that node. */ static bool maybe_insert_particle(int p_id, Utils::Vector3d const &pos) { + auto const &box_geo = *System::get_system().box_geo; auto folded_pos = pos; auto image_box = Utils::Vector3i{}; - fold_position(folded_pos, image_box, box_geo); + box_geo.fold_position(folded_pos, image_box); Particle new_part; new_part.id() = p_id; new_part.pos() = folded_pos; new_part.image_box() = image_box; - return ::cell_structure.add_local_particle(std::move(new_part)) != nullptr; + return get_cell_structure().add_local_particle(std::move(new_part)) != + nullptr; } /** @@ -447,20 +459,22 @@ static bool maybe_insert_particle(int p_id, Utils::Vector3d const &pos) { * @return Whether the particle was moved from that node. */ static bool maybe_move_particle(int p_id, Utils::Vector3d const &pos) { - auto pt = ::cell_structure.get_local_particle(p_id); - if (pt == nullptr) { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto p = system.cell_structure->get_local_particle(p_id); + if (p == nullptr) { return false; } auto folded_pos = pos; auto image_box = Utils::Vector3i{}; - fold_position(folded_pos, image_box, box_geo); - pt->pos() = folded_pos; - pt->image_box() = image_box; + box_geo.fold_position(folded_pos, image_box); + p->pos() = folded_pos; + p->image_box() = image_box; return true; } void remove_all_particles() { - ::cell_structure.remove_all_particles(); + get_cell_structure().remove_all_particles(); on_particle_change(); clear_particle_node(); clear_particle_type_map(); @@ -468,7 +482,7 @@ void remove_all_particles() { void remove_particle(int p_id) { if (::type_list_enable) { - auto p = ::cell_structure.get_local_particle(p_id); + auto p = get_cell_structure().get_local_particle(p_id); auto p_type = -1; if (p != nullptr and not p->is_ghost()) { if (this_node == 0) { @@ -487,7 +501,7 @@ void remove_particle(int p_id) { if (this_node == 0) { particle_node[p_id] = -1; } - ::cell_structure.remove_particle(p_id); + get_cell_structure().remove_particle(p_id); on_particle_change(); mpi_synchronize_max_seen_pid_local(); if (this_node == 0) { @@ -525,7 +539,7 @@ void make_new_particle(int p_id, Utils::Vector3d const &pos) { void set_particle_pos(int p_id, Utils::Vector3d const &pos) { auto const has_moved = maybe_move_particle(p_id, pos); - ::cell_structure.set_resort_particles(Cells::RESORT_GLOBAL); + get_cell_structure().set_resort_particles(Cells::RESORT_GLOBAL); on_particle_change(); auto success = false; diff --git a/src/core/polymer.cpp b/src/core/polymer.cpp index d17e2f5ea5c..052f2fdb9a9 100644 --- a/src/core/polymer.cpp +++ b/src/core/polymer.cpp @@ -33,8 +33,8 @@ #include "constraints.hpp" #include "constraints/Constraints.hpp" #include "constraints/ShapeBasedConstraint.hpp" -#include "grid.hpp" #include "random.hpp" +#include "system/System.hpp" #include #include @@ -48,7 +48,8 @@ #include #include -template static Utils::Vector3d random_position(RNG &rng) { +template +static Utils::Vector3d random_position(BoxGeometry const &box_geo, RNG &rng) { Utils::Vector3d v; for (int i = 0; i < 3; ++i) v[i] = box_geo.length()[i] * rng(); @@ -73,6 +74,7 @@ template static Utils::Vector3d random_unit_vector(RNG &rng) { * @return the minimal distance of a particle to coordinates @p pos */ static double distto(PartCfg &partCfg, Utils::Vector3d const &pos) { + auto const &box_geo = *System::get_system().box_geo; auto mindist_sq = std::numeric_limits::infinity(); for (auto const &p : partCfg) { @@ -89,6 +91,7 @@ static double distto(PartCfg &partCfg, Utils::Vector3d const &pos) { * @param pos the trial position in question * @param positions buffered positions to respect * @param partCfg existing particles to respect + * @param box_geo Box geometry * @param min_distance threshold for the minimum distance between * trial position and buffered/existing particles * @param respect_constraints whether to respect constraints @@ -97,11 +100,11 @@ static double distto(PartCfg &partCfg, Utils::Vector3d const &pos) { static bool is_valid_position(Utils::Vector3d const &pos, std::vector> const &positions, - PartCfg &partCfg, double const min_distance, - int const respect_constraints) { + PartCfg &partCfg, BoxGeometry const &box_geo, + double const min_distance, int const respect_constraints) { // check if constraint is violated if (respect_constraints) { - Utils::Vector3d const folded_pos = folded_position(pos, box_geo); + Utils::Vector3d const folded_pos = box_geo.folded_position(pos); for (auto &c : Constraints::constraints) { auto cs = @@ -144,6 +147,8 @@ draw_polymer_positions(PartCfg &partCfg, int const n_polymers, double const min_distance, int const max_tries, int const use_bond_angle, double const bond_angle, int const respect_constraints, int const seed) { + + auto const &box_geo = *System::get_system().box_geo; auto rng = [mt = Random::mt19937(static_cast(seed)), dist = std::uniform_real_distribution( 0.0, 1.0)]() mutable { return dist(mt); }; @@ -153,9 +158,9 @@ draw_polymer_positions(PartCfg &partCfg, int const n_polymers, p.reserve(beads_per_chain); } - auto is_valid_pos = [&positions, &partCfg, min_distance, + auto is_valid_pos = [&positions, &partCfg, min_distance, &box_geo, respect_constraints](Utils::Vector3d const &v) { - return is_valid_position(v, positions, partCfg, min_distance, + return is_valid_position(v, positions, partCfg, box_geo, min_distance, respect_constraints); }; @@ -172,7 +177,7 @@ draw_polymer_positions(PartCfg &partCfg, int const n_polymers, auto draw_monomer_position = [&](int p, int m) { if (m == 0) { return (p < start_positions.size()) ? start_positions[p] - : random_position(rng); + : random_position(box_geo, rng); } if (not use_bond_angle or m < 2) { diff --git a/src/core/pressure.cpp b/src/core/pressure.cpp index d8b8ab8f734..816d7418462 100644 --- a/src/core/pressure.cpp +++ b/src/core/pressure.cpp @@ -23,15 +23,14 @@ */ #include "pressure.hpp" +#include "BoxGeometry.hpp" #include "Observable_stat.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" #include "bonded_interactions/bonded_interaction_data.hpp" -#include "cells.hpp" #include "communication.hpp" #include "electrostatics/coulomb.hpp" #include "event.hpp" -#include "grid.hpp" #include "interactions.hpp" #include "magnetostatics/dipoles.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" @@ -61,23 +60,27 @@ std::shared_ptr calculate_pressure() { on_observable_calc(); - auto const volume = box_geo.volume(); + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + auto const volume = system.box_geo->volume(); auto const local_parts = cell_structure.local_particles(); + auto const n_nodes = ::communicator.size; for (auto const &p : local_parts) { add_kinetic_virials(p, obs_pressure); } - auto const &coulomb = System::get_system().coulomb; + auto const &coulomb = system.coulomb; auto const coulomb_force_kernel = coulomb.pair_force_kernel(); auto const coulomb_pressure_kernel = coulomb.pair_pressure_kernel(); short_range_loop( - [&obs_pressure, coulomb_force_kernel_ptr = get_ptr(coulomb_force_kernel)]( - Particle const &p1, int bond_id, Utils::Span partners) { + [&obs_pressure, coulomb_force_kernel_ptr = get_ptr(coulomb_force_kernel), + box_geo = system.box_geo](Particle const &p1, int bond_id, + Utils::Span partners) { auto const &iaparams = *bonded_ia_params.at(bond_id); auto const result = calc_bonded_pressure_tensor( - iaparams, p1, partners, coulomb_force_kernel_ptr); + iaparams, p1, partners, *box_geo, coulomb_force_kernel_ptr); if (result) { auto const &tensor = result.get(); /* pressure tensor part */ @@ -97,7 +100,7 @@ std::shared_ptr calculate_pressure() { obs_pressure, coulomb_force_kernel_ptr, coulomb_pressure_kernel_ptr); }, - maximal_cutoff(n_nodes), maximal_cutoff_bonded()); + cell_structure, maximal_cutoff(n_nodes), maximal_cutoff_bonded()); #ifdef ELECTROSTATICS /* calculate k-space part of electrostatic interaction. */ diff --git a/src/core/pressure_inline.hpp b/src/core/pressure_inline.hpp index 7a6ef6589aa..319872fc633 100644 --- a/src/core/pressure_inline.hpp +++ b/src/core/pressure_inline.hpp @@ -29,6 +29,7 @@ #include "magnetostatics/dipoles.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" +#include "BoxGeometry.hpp" #include "Observable_stat.hpp" #include "Particle.hpp" #include "errorhandling.hpp" @@ -98,7 +99,7 @@ inline void add_non_bonded_pair_virials( boost::optional> calc_bonded_virial_pressure_tensor( Bonded_IA_Parameters const &iaparams, Particle const &p1, - Particle const &p2, + Particle const &p2, BoxGeometry const &box_geo, Coulomb::ShortRangeForceKernel::kernel_type const *kernel) { auto const dx = box_geo.get_mi_vector(p1.pos(), p2.pos()); auto const result = calc_bond_pair_force(p1, p2, iaparams, dx, kernel); @@ -114,7 +115,8 @@ boost::optional> calc_bonded_virial_pressure_tensor( boost::optional> calc_bonded_three_body_pressure_tensor(Bonded_IA_Parameters const &iaparams, Particle const &p1, Particle const &p2, - Particle const &p3) { + Particle const &p3, + BoxGeometry const &box_geo) { if ((boost::get(&iaparams) != nullptr) || (boost::get(&iaparams) != nullptr) || #ifdef TABULATED @@ -124,7 +126,8 @@ calc_bonded_three_body_pressure_tensor(Bonded_IA_Parameters const &iaparams, auto const dx21 = -box_geo.get_mi_vector(p1.pos(), p2.pos()); auto const dx31 = box_geo.get_mi_vector(p3.pos(), p1.pos()); - auto const result = calc_bonded_three_body_force(iaparams, p1, p2, p3); + auto const result = + calc_bonded_three_body_force(iaparams, box_geo, p1, p2, p3); if (result) { Utils::Vector3d force2, force3; std::tie(std::ignore, force2, force3) = result.get(); @@ -144,15 +147,15 @@ calc_bonded_three_body_pressure_tensor(Bonded_IA_Parameters const &iaparams, inline boost::optional> calc_bonded_pressure_tensor( Bonded_IA_Parameters const &iaparams, Particle const &p1, - Utils::Span partners, + Utils::Span partners, BoxGeometry const &box_geo, Coulomb::ShortRangeForceKernel::kernel_type const *kernel) { switch (number_of_partners(iaparams)) { case 1: return calc_bonded_virial_pressure_tensor(iaparams, p1, *partners[0], - kernel); + box_geo, kernel); case 2: return calc_bonded_three_body_pressure_tensor(iaparams, p1, *partners[0], - *partners[1]); + *partners[1], box_geo); default: runtimeWarningMsg() << "Unsupported bond type " + std::to_string(iaparams.which()) + diff --git a/src/core/rattle.cpp b/src/core/rattle.cpp index b1e3c8cf64a..b906667923a 100644 --- a/src/core/rattle.cpp +++ b/src/core/rattle.cpp @@ -23,6 +23,7 @@ #ifdef BOND_CONSTRAINT +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" #include "bonded_interactions/bonded_interaction_data.hpp" @@ -31,7 +32,6 @@ #include "cells.hpp" #include "communication.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include #include @@ -68,11 +68,13 @@ static void init_correction_vector(const ParticleRange &particles, * @brief Calculate the positional correction for the particles. * * @param ia_params Parameters + * @param box_geo Box geometry. * @param p1 First particle. * @param p2 Second particle. * @return True if there was a correction. */ static bool calculate_positional_correction(RigidBond const &ia_params, + BoxGeometry const &box_geo, Particle &p1, Particle &p2) { auto const r_ij = box_geo.get_mi_vector(p1.pos(), p2.pos()); auto const r_ij2 = r_ij.norm2(); @@ -98,25 +100,29 @@ static bool calculate_positional_correction(RigidBond const &ia_params, * @brief Compute the correction vectors using given kernel. * * @param cs cell structure + * @param box_geo Box geometry * @param kernel kernel function * @return True if correction is necessary */ template -static bool compute_correction_vector(CellStructure &cs, Kernel kernel) { +static bool compute_correction_vector(CellStructure &cs, + BoxGeometry const &box_geo, + Kernel kernel) { bool correction = false; - cs.bond_loop([&correction, &kernel](Particle &p1, int bond_id, - Utils::Span partners) { - auto const &iaparams = *bonded_ia_params.at(bond_id); - - if (auto const *bond = boost::get(&iaparams)) { - auto const corrected = kernel(*bond, p1, *partners[0]); - if (corrected) - correction = true; - } - - /* Rigid bonds cannot break */ - return false; - }); + cs.bond_loop( + [&correction, &kernel, &box_geo](Particle &p1, int bond_id, + Utils::Span partners) { + auto const &iaparams = *bonded_ia_params.at(bond_id); + + if (auto const *bond = boost::get(&iaparams)) { + auto const corrected = kernel(*bond, box_geo, p1, *partners[0]); + if (corrected) + correction = true; + } + + /* Rigid bonds cannot break */ + return false; + }); return correction; } @@ -133,7 +139,7 @@ static void apply_positional_correction(const ParticleRange &particles) { }); } -void correct_position_shake(CellStructure &cs) { +void correct_position_shake(CellStructure &cs, BoxGeometry const &box_geo) { cells_update_ghosts(Cells::DATA_PART_POSITION | Cells::DATA_PART_PROPERTIES); auto particles = cs.local_particles(); @@ -143,7 +149,7 @@ void correct_position_shake(CellStructure &cs) { for (cnt = 0; cnt < SHAKE_MAX_ITERATIONS; ++cnt) { init_correction_vector(particles, ghost_particles); bool const repeat_ = - compute_correction_vector(cs, calculate_positional_correction); + compute_correction_vector(cs, box_geo, calculate_positional_correction); bool const repeat = boost::mpi::all_reduce(comm_cart, repeat_, std::logical_or()); @@ -151,7 +157,7 @@ void correct_position_shake(CellStructure &cs) { if (!repeat) break; - cell_structure.ghosts_reduce_rattle_correction(); + cs.ghosts_reduce_rattle_correction(); apply_positional_correction(particles); cs.ghosts_update(Cells::DATA_PART_POSITION | Cells::DATA_PART_MOMENTUM); @@ -171,11 +177,13 @@ void correct_position_shake(CellStructure &cs) { * of the particles so that it can be reduced over the ghosts. * * @param ia_params Parameters + * @param box_geo Box geometry. * @param p1 First particle. * @param p2 Second particle. * @return True if there was a correction. */ static bool calculate_velocity_correction(RigidBond const &ia_params, + BoxGeometry const &box_geo, Particle &p1, Particle &p2) { auto const v_ij = p1.v() - p2.v(); auto const r_ij = box_geo.get_mi_vector(p1.pos(), p2.pos()); @@ -199,13 +207,15 @@ static bool calculate_velocity_correction(RigidBond const &ia_params, * @brief Apply velocity corrections * * @param particles particle range + * @param box_geo Box geometry */ -static void apply_velocity_correction(const ParticleRange &particles) { +static void apply_velocity_correction(ParticleRange const &particles, + BoxGeometry const &box_geo) { boost::for_each(particles, [](Particle &p) { p.v() += p.rattle_params().correction; }); } -void correct_velocity_shake(CellStructure &cs) { +void correct_velocity_shake(CellStructure &cs, BoxGeometry const &box_geo) { cs.ghosts_update(Cells::DATA_PART_POSITION | Cells::DATA_PART_MOMENTUM); auto particles = cs.local_particles(); @@ -215,7 +225,7 @@ void correct_velocity_shake(CellStructure &cs) { for (cnt = 0; cnt < SHAKE_MAX_ITERATIONS; ++cnt) { init_correction_vector(particles, ghost_particles); bool const repeat_ = - compute_correction_vector(cs, calculate_velocity_correction); + compute_correction_vector(cs, box_geo, calculate_velocity_correction); bool const repeat = boost::mpi::all_reduce(comm_cart, repeat_, std::logical_or()); @@ -223,9 +233,9 @@ void correct_velocity_shake(CellStructure &cs) { if (!repeat) break; - cell_structure.ghosts_reduce_rattle_correction(); + cs.ghosts_reduce_rattle_correction(); - apply_velocity_correction(particles); + apply_velocity_correction(particles, box_geo); cs.ghosts_update(Cells::DATA_PART_MOMENTUM); } diff --git a/src/core/rattle.hpp b/src/core/rattle.hpp index 41ceb8cb037..5502bd62558 100644 --- a/src/core/rattle.hpp +++ b/src/core/rattle.hpp @@ -31,6 +31,7 @@ #ifdef BOND_CONSTRAINT +#include "BoxGeometry.hpp" #include "cell_system/CellStructure.hpp" /** Transfer the current particle positions from @ref Particle::pos @@ -43,17 +44,13 @@ void save_old_position(const ParticleRange &particles, /** * @brief Propagate velocity and position while using SHAKE algorithm for bond * constraint. - * - * @param cs cell structure */ -void correct_position_shake(CellStructure &cs); +void correct_position_shake(CellStructure &cs, BoxGeometry const &box_geo); /** * @brief Correction of current velocities using RATTLE algorithm. - * - * @param cs cell structure */ -void correct_velocity_shake(CellStructure &cs); +void correct_velocity_shake(CellStructure &cs, BoxGeometry const &box_geo); #endif #endif diff --git a/src/core/reaction_methods/ReactionAlgorithm.cpp b/src/core/reaction_methods/ReactionAlgorithm.cpp index d2e10732aae..f1f2e6c7c01 100644 --- a/src/core/reaction_methods/ReactionAlgorithm.cpp +++ b/src/core/reaction_methods/ReactionAlgorithm.cpp @@ -21,11 +21,13 @@ #include "reaction_methods/ReactionAlgorithm.hpp" +#include "BoxGeometry.hpp" +#include "cell_system/CellStructure.hpp" #include "cells.hpp" #include "energy.hpp" #include "event.hpp" -#include "grid.hpp" #include "particle_node.hpp" +#include "system/System.hpp" #include #include @@ -83,6 +85,7 @@ void ReactionAlgorithm::add_reaction( */ void ReactionAlgorithm::restore_old_system_state() { auto const &old_state = get_old_system_state(); + auto const &box_geo = *System::get_system().box_geo; // restore the properties of changed and hidden particles for (auto const &state : {old_state.changed, old_state.hidden}) { for (auto const &[p_id, p_type] : state) { @@ -105,13 +108,15 @@ void ReactionAlgorithm::restore_old_system_state() { p->v() = vel; auto folded_pos = pos; auto image_box = Utils::Vector3i{}; - fold_position(folded_pos, image_box, box_geo); + box_geo.fold_position(folded_pos, image_box); p->pos() = folded_pos; p->image_box() = image_box; } } if (not old_state.moved.empty()) { - ::cell_structure.set_resort_particles(Cells::RESORT_GLOBAL); + auto const &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + cell_structure.set_resort_particles(Cells::RESORT_GLOBAL); } on_particle_change(); clear_old_system_state(); @@ -121,7 +126,10 @@ void ReactionAlgorithm::restore_old_system_state() { * Automatically sets the volume which is used by the reaction ensemble to the * volume of a cuboid box. */ -void ReactionAlgorithm::update_volume() { volume = box_geo.volume(); } +void ReactionAlgorithm::update_volume() { + auto const &box_geo = *System::get_system().box_geo; + volume = box_geo.volume(); +} /** * Checks whether all particles exist for the provided reaction. @@ -343,11 +351,14 @@ void ReactionAlgorithm::check_exclusion_range(int p_id, int p_type) { if (p1_ptr != nullptr) { auto &p1 = *p1_ptr; + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; /* Check if the inserted particle within the exclusion radius of any other * particle */ for (auto const p2_id : particle_ids) { - if (auto const p2_ptr = ::cell_structure.get_local_particle(p2_id)) { + if (auto const p2_ptr = cell_structure.get_local_particle(p2_id)) { auto const &p2 = *p2_ptr; double excluded_distance; if (exclusion_radius_per_type.count(p_type) == 0 || @@ -360,7 +371,7 @@ void ReactionAlgorithm::check_exclusion_range(int p_id, int p_type) { exclusion_radius_per_type[p2.type()]; } - auto const d_min = ::box_geo.get_mi_vector(p2.pos(), p1.pos()).norm(); + auto const d_min = box_geo.get_mi_vector(p2.pos(), p1.pos()).norm(); if (d_min < excluded_distance) { particle_inside_exclusion_range_touched = true; @@ -413,6 +424,7 @@ void ReactionAlgorithm::delete_particle(int p_id) { void ReactionAlgorithm::set_cyl_constraint(double center_x, double center_y, double radius) { + auto const &box_geo = *System::get_system().box_geo; if (center_x < 0. or center_x > box_geo.length()[0]) throw std::domain_error("center_x is outside the box"); if (center_y < 0. or center_y > box_geo.length()[1]) @@ -427,6 +439,7 @@ void ReactionAlgorithm::set_cyl_constraint(double center_x, double center_y, void ReactionAlgorithm::set_slab_constraint(double slab_start_z, double slab_end_z) { + auto const &box_geo = *System::get_system().box_geo; if (slab_start_z < 0. or slab_start_z > box_geo.length()[2]) throw std::domain_error("slab_start_z is outside the box"); if (slab_end_z < 0. or slab_end_z > box_geo.length()[2]) @@ -442,6 +455,7 @@ void ReactionAlgorithm::set_slab_constraint(double slab_start_z, * Writes a random position inside the central box into the provided array. */ Utils::Vector3d ReactionAlgorithm::get_random_position_in_box() { + auto const &box_geo = *System::get_system().box_geo; Utils::Vector3d out_pos{}; if (m_reaction_constraint == ReactionConstraint::CYL_Z) { @@ -618,7 +632,8 @@ double ReactionAlgorithm::calculate_potential_energy() const { Particle *ReactionAlgorithm::get_real_particle(int p_id) const { assert(p_id >= 0); - auto ptr = ::cell_structure.get_local_particle(p_id); + auto const &system = System::get_system(); + auto ptr = system.cell_structure->get_local_particle(p_id); if (ptr != nullptr and ptr->is_ghost()) { ptr = nullptr; } @@ -629,7 +644,8 @@ Particle *ReactionAlgorithm::get_real_particle(int p_id) const { Particle *ReactionAlgorithm::get_local_particle(int p_id) const { assert(p_id >= 0); - auto ptr = ::cell_structure.get_local_particle(p_id); + auto const &system = System::get_system(); + auto ptr = system.cell_structure->get_local_particle(p_id); assert(boost::mpi::all_reduce( m_comm, static_cast(ptr != nullptr and not ptr->is_ghost()), std::plus<>()) == 1); diff --git a/src/core/reaction_methods/tests/ReactionAlgorithm_test.cpp b/src/core/reaction_methods/tests/ReactionAlgorithm_test.cpp index 180577afa6e..23667947d9d 100644 --- a/src/core/reaction_methods/tests/ReactionAlgorithm_test.cpp +++ b/src/core/reaction_methods/tests/ReactionAlgorithm_test.cpp @@ -70,6 +70,7 @@ BOOST_FIXTURE_TEST_CASE(ReactionAlgorithm_test, ParticleFactory) { using ReactionMethods::SingleReaction; auto constexpr tol = 8. * 100. * std::numeric_limits::epsilon(); auto const comm = boost::mpi::communicator(); + auto const &cell_structure = *System::get_system().cell_structure; // check acceptance rate auto r_algo = Testing::ReactionAlgorithm(comm, 42, 1., 0., {}); @@ -153,7 +154,7 @@ BOOST_FIXTURE_TEST_CASE(ReactionAlgorithm_test, ParticleFactory) { BOOST_REQUIRE(pid == 0 or pid == 1); auto const ref_old_pos = ref_positions[pid].first; auto const ref_old_vel = ref_positions[pid].second; - if (auto const p = ::cell_structure.get_local_particle(pid)) { + if (auto const p = cell_structure.get_local_particle(pid)) { auto const &new_pos = p->pos(); auto const &new_vel = p->v(); BOOST_CHECK_EQUAL(old_pos, ref_old_pos); @@ -196,7 +197,7 @@ BOOST_FIXTURE_TEST_CASE(ReactionAlgorithm_test, ParticleFactory) { // check none of the particles moved for (auto const pid : {0, 1}) { auto const ref_old_pos = ref_positions[pid]; - if (auto const p = ::cell_structure.get_local_particle(pid)) { + if (auto const p = cell_structure.get_local_particle(pid)) { auto const &new_pos = p->pos(); BOOST_CHECK_LE((new_pos - ref_old_pos).norm(), tol); } @@ -207,7 +208,7 @@ BOOST_FIXTURE_TEST_CASE(ReactionAlgorithm_test, ParticleFactory) { std::vector distances(2); // check that only one particle moved for (auto const pid : {0, 1}) { - if (auto const p = ::cell_structure.get_local_particle(pid)) { + if (auto const p = cell_structure.get_local_particle(pid)) { distances[pid] = (ref_positions[pid] - p->pos()).norm(); } } diff --git a/src/core/reaction_methods/tests/particle_tracking_test.cpp b/src/core/reaction_methods/tests/particle_tracking_test.cpp index 7d19a401e3b..ee662608d80 100644 --- a/src/core/reaction_methods/tests/particle_tracking_test.cpp +++ b/src/core/reaction_methods/tests/particle_tracking_test.cpp @@ -25,8 +25,12 @@ #include "unit_tests/ParticleFactory.hpp" +#include "cell_system/CellStructure.hpp" +#include "cell_system/CellStructureType.hpp" +#include "cells.hpp" #include "communication.hpp" #include "particle_node.hpp" +#include "system/System.hpp" #include @@ -66,5 +70,8 @@ int main(int argc, char **argv) { auto mpi_env = std::make_shared(argc, argv); Communication::init(mpi_env); + auto &cell_structure = *System::get_system().cell_structure; + cells_re_init(cell_structure, CellStructureType::CELL_STRUCTURE_REGULAR); + return boost::unit_test::unit_test_main(init_unit_test, argc, argv); } diff --git a/src/core/rotate_system.cpp b/src/core/rotate_system.cpp index aa57cc579f6..49c26fe43b9 100644 --- a/src/core/rotate_system.cpp +++ b/src/core/rotate_system.cpp @@ -21,7 +21,7 @@ #include "Particle.hpp" #include "ParticleRange.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "config/config.hpp" #include "event.hpp" @@ -37,7 +37,8 @@ #include #include -void rotate_system(double phi, double theta, double alpha) { +void rotate_system(CellStructure &cell_structure, double phi, double theta, + double alpha) { auto const particles = cell_structure.local_particles(); // Calculate center of mass diff --git a/src/core/rotate_system.hpp b/src/core/rotate_system.hpp index d126342bf77..4ce22382ed3 100644 --- a/src/core/rotate_system.hpp +++ b/src/core/rotate_system.hpp @@ -16,12 +16,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef ESPRESSO_SRC_CORE_ROTATE_SYSTEM_HPP -#define ESPRESSO_SRC_CORE_ROTATE_SYSTEM_HPP + +#pragma once + +#include "cell_system/CellStructure.hpp" /** Rotate all particle coordinates around an axis given by phi,theta through * the center of mass by an angle alpha. */ -void rotate_system(double phi, double theta, double alpha); - -#endif +void rotate_system(CellStructure &cell_structure, double phi, double theta, + double alpha); diff --git a/src/core/scafacos/ScafacosContext.cpp b/src/core/scafacos/ScafacosContext.cpp index eb9d1ae9f9d..fc4fa1937d5 100644 --- a/src/core/scafacos/ScafacosContext.cpp +++ b/src/core/scafacos/ScafacosContext.cpp @@ -25,9 +25,10 @@ #include "scafacos/ScafacosContext.hpp" -#include "cells.hpp" +#include "BoxGeometry.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include @@ -39,6 +40,9 @@ namespace detail { std::tuple get_system_params() { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; auto periodicity = Utils::Vector3i{static_cast(box_geo.periodic(0)), static_cast(box_geo.periodic(1)), static_cast(box_geo.periodic(2))}; diff --git a/src/core/short_range_loop.hpp b/src/core/short_range_loop.hpp index 7688881cb61..97fe08fcda1 100644 --- a/src/core/short_range_loop.hpp +++ b/src/core/short_range_loop.hpp @@ -21,7 +21,7 @@ #include "config/config.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #ifdef CALIPER #include @@ -42,8 +42,9 @@ struct True { template void short_range_loop(BondKernel bond_kernel, PairKernel pair_kernel, - double pair_cutoff, double bond_cutoff, - const VerletCriterion &verlet_criterion = {}) { + CellStructure &cell_structure, double pair_cutoff, + double bond_cutoff, + VerletCriterion const &verlet_criterion = {}) { #ifdef CALIPER CALI_CXX_MARK_FUNCTION; #endif diff --git a/src/core/stokesian_dynamics/sd_interface.cpp b/src/core/stokesian_dynamics/sd_interface.cpp index aaee5dbf88a..656e5833cd8 100644 --- a/src/core/stokesian_dynamics/sd_interface.cpp +++ b/src/core/stokesian_dynamics/sd_interface.cpp @@ -24,9 +24,10 @@ #include "stokesian_dynamics/sd_cpu.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "ParticleRange.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include "thermostat.hpp" #include @@ -77,7 +78,8 @@ static double sd_kT = 0.0; static std::vector v_sd{}; void register_integrator(StokesianDynamicsParameters const &obj) { - if (::box_geo.periodic(0) or ::box_geo.periodic(1) or ::box_geo.periodic(2)) { + auto const &box_geo = *System::get_system().box_geo; + if (box_geo.periodic(0) or box_geo.periodic(1) or box_geo.periodic(2)) { throw std::runtime_error( "Stokesian Dynamics requires periodicity (False, False, False)"); } diff --git a/src/core/system/GpuParticleData.cpp b/src/core/system/GpuParticleData.cpp index d27bfc53b66..a2da0a94755 100644 --- a/src/core/system/GpuParticleData.cpp +++ b/src/core/system/GpuParticleData.cpp @@ -23,10 +23,10 @@ #include "GpuParticleData.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "cuda/CudaHostAllocator.hpp" -#include "grid.hpp" +#include "system/System.hpp" #include #include @@ -49,7 +49,8 @@ void GpuParticleData::enable_particle_transfer() { } void GpuParticleData::copy_particles_to_device() { - copy_particles_to_device(::cell_structure.local_particles(), ::this_node); + auto &cell_structure = *System::get_system().cell_structure; + copy_particles_to_device(cell_structure.local_particles(), ::this_node); } bool GpuParticleData::has_compatible_device() const { @@ -82,10 +83,10 @@ BOOST_SERIALIZATION_SPLIT_FREE(GpuParticleData::GpuParticle) static void pack_particles(ParticleRange const &particles, GpuParticleData::GpuParticle *buffer) { - auto const &box_l = ::box_geo; + auto const &box = *System::get_system().box_geo; unsigned long int i = 0u; for (auto const &p : particles) { - buffer[i].p = static_cast(folded_position(p.pos(), box_l)); + buffer[i].p = static_cast(box.folded_position(p.pos())); #ifdef DIPOLES buffer[i].dip = static_cast(p.calc_dip()); #endif diff --git a/src/core/system/System.cpp b/src/core/system/System.cpp index bce32a9c795..cbb462559e3 100644 --- a/src/core/system/System.cpp +++ b/src/core/system/System.cpp @@ -17,9 +17,10 @@ * along with this program. If not, see . */ +#include "config/config.hpp" + #include "System.hpp" #include "System.impl.hpp" -#include "grid.hpp" #include @@ -29,6 +30,12 @@ namespace System { static std::shared_ptr instance = std::make_shared(); +System::System() { + box_geo = std::make_shared(); + local_geo = std::make_shared(); + cell_structure = std::make_shared(*box_geo); +} + bool is_system_set() { return instance != nullptr; } void reset_system() { instance.reset(); } @@ -39,6 +46,12 @@ void set_system(std::shared_ptr new_instance) { System &get_system() { return *instance; } -Utils::Vector3d System::box() const { return ::box_geo.length(); } +Utils::Vector3d System::box() const { return box_geo->length(); } + +void System::init() { +#ifdef CUDA + gpu.init(); +#endif +} } // namespace System diff --git a/src/core/system/System.hpp b/src/core/system/System.hpp index 0b4ad5bcb14..afae6c3807d 100644 --- a/src/core/system/System.hpp +++ b/src/core/system/System.hpp @@ -34,25 +34,30 @@ #include +class BoxGeometry; +class LocalBox; +struct CellStructure; + namespace System { class System { public: + System(); #ifdef CUDA GpuParticleData gpu; #endif ResourceCleanup cleanup_queue; Utils::Vector3d box() const; - void init() { -#ifdef CUDA - gpu.init(); -#endif - } + void init(); + Coulomb::Solver coulomb; Dipoles::Solver dipoles; LB::Solver lb; EK::Solver ek; + std::shared_ptr box_geo; + std::shared_ptr local_geo; + std::shared_ptr cell_structure; }; System &get_system(); diff --git a/src/core/system/System.impl.hpp b/src/core/system/System.impl.hpp index 03b364d525d..4bf2d44044f 100644 --- a/src/core/system/System.impl.hpp +++ b/src/core/system/System.impl.hpp @@ -24,3 +24,8 @@ #include "ek/Implementation.hpp" #include "lb/Implementation.hpp" + +#include "cell_system/CellStructure.hpp" + +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" diff --git a/src/core/tuning.cpp b/src/core/tuning.cpp index 7f84be0497a..392a15d86b4 100644 --- a/src/core/tuning.cpp +++ b/src/core/tuning.cpp @@ -21,13 +21,13 @@ #include "tuning.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "interactions.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" +#include "system/System.hpp" #include @@ -128,14 +128,16 @@ void tune_skin(double min_skin, double max_skin, double tol, int int_steps, double a = min_skin; double b = max_skin; + auto const &system = System::get_system(); + auto const &cell_structure = *system.cell_structure; /* The maximal skin is the remainder from the required cutoff to * the maximal range that can be supported by the cell system, but * never larger than half the box size. */ double const max_permissible_skin = std::min(*boost::min_element(cell_structure.max_cutoff()) - - maximal_cutoff(n_nodes), - 0.5 * *boost::max_element(box_geo.length())); + maximal_cutoff(::communicator.size), + 0.5 * *boost::max_element(system.box_geo->length())); if (adjust_max_skin and max_skin > max_permissible_skin) b = max_permissible_skin; diff --git a/src/core/unit_tests/EspressoSystemStandAlone_test.cpp b/src/core/unit_tests/EspressoSystemStandAlone_test.cpp index d5d23a38574..2739b0cceb8 100644 --- a/src/core/unit_tests/EspressoSystemStandAlone_test.cpp +++ b/src/core/unit_tests/EspressoSystemStandAlone_test.cpp @@ -34,7 +34,7 @@ namespace utf = boost::unit_test; #include "bonded_interactions/bonded_interaction_utils.hpp" #include "bonded_interactions/fene.hpp" #include "bonded_interactions/harmonic.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "communication.hpp" #include "electrostatics/coulomb.hpp" #include "electrostatics/p3m.hpp" @@ -126,11 +126,12 @@ BOOST_FIXTURE_TEST_CASE(espresso_system_stand_alone, ParticleFactory) { // check observables { + auto const &cell_structure = *System::get_system().cell_structure; auto const pid4 = 10; auto const pids = std::vector{pid2, pid3, pid1, pid4}; Observables::ParticleReferenceRange particle_range{}; for (int pid : pids) { - if (auto const p = ::cell_structure.get_local_particle(pid)) { + if (auto const p = cell_structure.get_local_particle(pid)) { particle_range.emplace_back(*p); } } diff --git a/src/core/unit_tests/EspressoSystem_test.cpp b/src/core/unit_tests/EspressoSystem_test.cpp index cf494041ec6..ede72ae98c3 100644 --- a/src/core/unit_tests/EspressoSystem_test.cpp +++ b/src/core/unit_tests/EspressoSystem_test.cpp @@ -30,6 +30,8 @@ #include "ParticleFactory.hpp" #include "Particle.hpp" +#include "cell_system/CellStructure.hpp" +#include "cell_system/CellStructureType.hpp" #include "cells.hpp" #include "communication.hpp" #include "particle_node.hpp" @@ -64,6 +66,8 @@ BOOST_FIXTURE_TEST_CASE(check_with_gpu, ParticleFactory, System::set_system(system); system->init(); auto &gpu = system->gpu; + auto &cell_structure = *system->cell_structure; + cells_re_init(cell_structure, CellStructureType::CELL_STRUCTURE_REGULAR); // check uninitialized device pointers BOOST_CHECK_EQUAL(gpu.get_energy_device(), nullptr); @@ -144,6 +148,7 @@ BOOST_FIXTURE_TEST_CASE(check_with_gpu, ParticleFactory, gpu.update(); BOOST_CHECK_EQUAL(gpu.n_particles(), 0); + clear_particles(); System::reset_system(); } diff --git a/src/core/unit_tests/LocalBox_test.cpp b/src/core/unit_tests/LocalBox_test.cpp index 5a992d19efc..33d8774f601 100644 --- a/src/core/unit_tests/LocalBox_test.cpp +++ b/src/core/unit_tests/LocalBox_test.cpp @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -#define BOOST_TEST_MODULE tests +#define BOOST_TEST_MODULE LocalBox #define BOOST_TEST_DYN_LINK #include @@ -29,23 +29,22 @@ #include -#include #include /* Check that the box corners and side length agree. */ -template void check_length(LocalBox box) { +void check_length(LocalBox const &box) { auto const expected = box.my_right() - box.my_left(); auto const result = box.length(); BOOST_CHECK_SMALL((result - expected).norm2(), - std::numeric_limits::epsilon()); + std::numeric_limits::epsilon()); } BOOST_AUTO_TEST_CASE(constructors) { /* default */ { - auto const box = LocalBox(); - BOOST_CHECK_EQUAL(box.my_left().norm2(), 0.f); + LocalBox const box{}; + BOOST_CHECK_EQUAL(box.my_left().norm2(), 0.); check_length(box); } @@ -56,8 +55,7 @@ BOOST_AUTO_TEST_CASE(constructors) { Utils::Array const boundaries = {{{-1, 0, 1, 1, 0, -1}}}; CellStructureType const type = CellStructureType::CELL_STRUCTURE_REGULAR; - auto const box = - LocalBox(lower_corner, local_box_length, boundaries, type); + auto const box = LocalBox(lower_corner, local_box_length, boundaries, type); BOOST_CHECK(box.my_left() == lower_corner); BOOST_CHECK(box.length() == local_box_length); diff --git a/src/core/unit_tests/ParticleFactory.hpp b/src/core/unit_tests/ParticleFactory.hpp index 697d8d3d7cf..5449c7b25e0 100644 --- a/src/core/unit_tests/ParticleFactory.hpp +++ b/src/core/unit_tests/ParticleFactory.hpp @@ -16,13 +16,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#ifndef REACTION_ENSEMBLE_TESTS_PARTICLE_FACTORY_HPP -#define REACTION_ENSEMBLE_TESTS_PARTICLE_FACTORY_HPP + +#pragma once #include "BondList.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" #include "event.hpp" #include "particle_node.hpp" +#include "system/System.hpp" #include @@ -32,11 +33,7 @@ struct ParticleFactory { ParticleFactory() = default; - ~ParticleFactory() { - for (auto pid : particle_cache) { - remove_particle(pid); - } - } + ~ParticleFactory() { clear_particles(); } void create_particle(Utils::Vector3d const &pos, int p_id, int type) { ::make_new_particle(p_id, pos); @@ -56,7 +53,7 @@ struct ParticleFactory { void insert_particle_bond(int p_id, int bond_id, std::vector const &partner_ids) const { - auto p = ::cell_structure.get_local_particle(p_id); + auto p = System::get_system().cell_structure->get_local_particle(p_id); if (p != nullptr and not p->is_ghost()) { p->bonds().insert(BondView(bond_id, partner_ids)); } @@ -66,13 +63,19 @@ struct ParticleFactory { template void set_particle_property(int p_id, T &(Particle::*setter)(), T const &value) const { - if (auto p = ::cell_structure.get_local_particle(p_id)) { + auto p = System::get_system().cell_structure->get_local_particle(p_id); + if (p != nullptr) { (p->*setter)() = value; } } + void clear_particles() { + for (auto pid : particle_cache) { + remove_particle(pid); + } + particle_cache.clear(); + } + private: std::vector particle_cache; }; - -#endif diff --git a/src/core/unit_tests/ek_interface_test.cpp b/src/core/unit_tests/ek_interface_test.cpp index 56685b03200..9ded44377f0 100644 --- a/src/core/unit_tests/ek_interface_test.cpp +++ b/src/core/unit_tests/ek_interface_test.cpp @@ -25,12 +25,12 @@ #include "ParticleFactory.hpp" #include "EspressoSystemStandAlone.hpp" +#include "communication.hpp" #include "config/config.hpp" #include "ek/EKReactions.hpp" #include "ek/EKWalberla.hpp" #include "ek/Implementation.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "system/System.hpp" #ifdef WALBERLA @@ -82,8 +82,8 @@ static auto make_ek_actor() { #ifdef WALBERLA auto constexpr n_ghost_layers = 1u; auto constexpr single_precision = true; - ek_lattice = std::make_shared(params.grid_dimensions, - ::node_grid, n_ghost_layers); + ek_lattice = std::make_shared( + params.grid_dimensions, ::communicator.node_grid, n_ghost_layers); ek_container = std::make_shared( params.tau, new_ek_poisson_none(ek_lattice, single_precision)); ek_reactions = std::make_shared(); diff --git a/src/core/unit_tests/grid_test.cpp b/src/core/unit_tests/grid_test.cpp index 65a4fb4e8fd..1694ba57784 100644 --- a/src/core/unit_tests/grid_test.cpp +++ b/src/core/unit_tests/grid_test.cpp @@ -21,7 +21,8 @@ #define BOOST_TEST_DYN_LINK #include -#include "grid.hpp" +#include "BoxGeometry.hpp" +#include "LocalBox.hpp" #include @@ -211,7 +212,7 @@ BOOST_AUTO_TEST_CASE(image_shift_test) { Utils::Vector3i img{1, -2, 3}; Utils::Vector3d box{1., 2., 3.}; - auto const result = image_shift(img, box); + auto const result = detail::image_shift(img, box); auto const expected = Utils::Vector3d{img[0] * box[0], img[1] * box[1], img[2] * box[2]}; @@ -223,17 +224,24 @@ BOOST_AUTO_TEST_CASE(unfolded_position_test) { Utils::Vector3i img{1, -2, 3}; Utils::Vector3d box{1., 2., 3.}; - auto expected = pos + image_shift(img, box); - auto result = unfolded_position(pos, img, box); + auto expected = pos + detail::image_shift(img, box); + auto result = detail::unfolded_position(pos, img, box); BOOST_CHECK_SMALL((result - expected).norm(), epsilon); } -BOOST_AUTO_TEST_CASE(fold_coordinate_test) { - BOOST_CHECK_THROW(fold_coordinate(0., std::numeric_limits::max(), 1.), - std::runtime_error); - BOOST_CHECK_THROW(fold_coordinate(0., std::numeric_limits::min(), 1.), - std::runtime_error); +BOOST_AUTO_TEST_CASE(fold_position_exceptions_test) { + auto const box = BoxGeometry(); + { + auto pos = Utils::Vector3d::broadcast(0.); + auto img = Utils::Vector3i::broadcast(std::numeric_limits::max()); + BOOST_CHECK_THROW(box.fold_position(pos, img), std::runtime_error); + } + { + auto pos = Utils::Vector3d::broadcast(0.); + auto img = Utils::Vector3i::broadcast(std::numeric_limits::min()); + BOOST_CHECK_THROW(box.fold_position(pos, img), std::runtime_error); + } } BOOST_AUTO_TEST_CASE(fold_position_test) { @@ -251,7 +259,7 @@ BOOST_AUTO_TEST_CASE(fold_position_test) { Utils::Vector3d const expected_pos{0.1, 0.1, 7.}; Utils::Vector3i const expected_img{-1, 2, 1}; - fold_position(pos, img, box); + box.fold_position(pos, img); BOOST_CHECK_SMALL((pos - expected_pos).norm(), 3 * epsilon); BOOST_CHECK_EQUAL((img - expected_img).norm2(), 0); @@ -264,7 +272,7 @@ BOOST_AUTO_TEST_CASE(fold_position_test) { Utils::Vector3d const expected_pos{1., 3., 7.}; Utils::Vector3i const expected_img{0, -1, -1}; - fold_position(pos, img, box); + box.fold_position(pos, img); BOOST_CHECK_SMALL((pos - expected_pos).norm(), 3 * epsilon); BOOST_CHECK_EQUAL((img - expected_img).norm2(), 0); @@ -275,13 +283,12 @@ BOOST_AUTO_TEST_CASE(regular_decomposition_test) { auto const eps = std::numeric_limits::epsilon(); auto const box_l = Utils::Vector3d{10, 20, 30}; - auto box = BoxGeometry(); - box.set_length(box_l); auto const node_grid = Utils::Vector3i{1, 2, 3}; /* check length */ { - auto const result = regular_decomposition(box, {0, 0, 0}, node_grid); + auto const result = + LocalBox::make_regular_decomposition(box_l, {0, 0, 0}, node_grid); auto const local_box_l = result.length(); BOOST_CHECK_CLOSE(box_l[0], local_box_l[0] * node_grid[0], 100. * eps); @@ -295,7 +302,8 @@ BOOST_AUTO_TEST_CASE(regular_decomposition_test) { for (node_pos[0] = 0; node_pos[0] < node_grid[0]; node_pos[0]++) for (node_pos[1] = 0; node_pos[1] < node_grid[1]; node_pos[1]++) for (node_pos[2] = 0; node_pos[2] < node_grid[2]; node_pos[2]++) { - auto const result = regular_decomposition(box, node_pos, node_grid); + auto const result = + LocalBox::make_regular_decomposition(box_l, node_pos, node_grid); auto const local_box_l = result.length(); auto const lower_corner = result.my_left(); diff --git a/src/core/unit_tests/lb_particle_coupling_test.cpp b/src/core/unit_tests/lb_particle_coupling_test.cpp index 1f5d2456295..86ef04d9918 100644 --- a/src/core/unit_tests/lb_particle_coupling_test.cpp +++ b/src/core/unit_tests/lb_particle_coupling_test.cpp @@ -35,10 +35,10 @@ namespace utf = boost::unit_test; #include "EspressoSystemStandAlone.hpp" #include "Particle.hpp" -#include "cells.hpp" +#include "cell_system/CellStructure.hpp" +#include "communication.hpp" #include "errorhandling.hpp" #include "event.hpp" -#include "grid.hpp" #include "lb/LBNone.hpp" #include "lb/LBWalberla.hpp" #include "lb/particle_coupling.hpp" @@ -101,8 +101,8 @@ static auto make_lb_actor() { auto constexpr n_ghost_layers = 1u; auto constexpr single_precision = false; lb_params = std::make_shared(params.agrid, params.tau); - lb_lattice = std::make_shared(params.grid_dimensions, - ::node_grid, n_ghost_layers); + lb_lattice = std::make_shared( + params.grid_dimensions, ::communicator.node_grid, n_ghost_layers); lb_fluid = new_lb_walberla(lb_lattice, params.viscosity, params.density, single_precision); lb_fluid->set_collision_model(params.kT, params.seed); @@ -346,7 +346,9 @@ BOOST_DATA_TEST_CASE_F(CleanupActorLB, coupling_particle_lattice_ia, auto const rank = comm.rank(); espresso::set_lb_kT(kT); lb_lbcoupling_set_rng_state(17); - auto &lb = System::get_system().lb; + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + auto &lb = system.lb; auto const first_lb_node = espresso::lb_fluid->get_lattice().get_local_domain().first; auto const gamma = 0.2; @@ -389,8 +391,8 @@ BOOST_DATA_TEST_CASE_F(CleanupActorLB, coupling_particle_lattice_ia, cells_update_ghosts(global_ghost_flags()); } if (rank == 0) { - auto const particles = ::cell_structure.local_particles(); - auto const ghost_particles = ::cell_structure.ghost_particles(); + auto const particles = cell_structure.local_particles(); + auto const ghost_particles = cell_structure.ghost_particles(); BOOST_REQUIRE_GE(particles.size(), 1); BOOST_REQUIRE_GE(ghost_particles.size(), static_cast(with_ghosts)); } @@ -398,6 +400,7 @@ BOOST_DATA_TEST_CASE_F(CleanupActorLB, coupling_particle_lattice_ia, // check box shifts if (rank == 0) { + auto const &box_geo = *system.box_geo; auto constexpr reference_shifts = std::array{{{{0, 0, 0}}, {{0, 0, 8}}, @@ -438,8 +441,8 @@ BOOST_DATA_TEST_CASE_F(CleanupActorLB, coupling_particle_lattice_ia, { lb_lbcoupling_deactivate(); lb_lbcoupling_broadcast(); - auto const particles = ::cell_structure.local_particles(); - auto const ghost_particles = ::cell_structure.ghost_particles(); + auto const particles = cell_structure.local_particles(); + auto const ghost_particles = cell_structure.ghost_particles(); LB::couple_particles(thermo_virtual, particles, ghost_particles, params.time_step); auto const p_opt = copy_particle_to_head_node(comm, pid); @@ -453,8 +456,8 @@ BOOST_DATA_TEST_CASE_F(CleanupActorLB, coupling_particle_lattice_ia, { lb_lbcoupling_activate(); lb_lbcoupling_broadcast(); - auto const particles = ::cell_structure.local_particles(); - auto const ghost_particles = ::cell_structure.ghost_particles(); + auto const particles = cell_structure.local_particles(); + auto const ghost_particles = cell_structure.ghost_particles(); Utils::Vector3d lb_before{}; { auto const p_opt = copy_particle_to_head_node(comm, pid); @@ -532,17 +535,18 @@ BOOST_AUTO_TEST_SUITE_END() bool test_lb_domain_mismatch_local() { boost::mpi::communicator world; - auto const node_grid_original = ::node_grid; + auto const node_grid_original = ::communicator.node_grid; auto const node_grid_reversed = - Utils::Vector3i{{::node_grid[2], ::node_grid[1], ::node_grid[0]}}; + Utils::Vector3i{{::communicator.node_grid[2], ::communicator.node_grid[1], + ::communicator.node_grid[0]}}; auto const n_ghost_layers = 1u; auto const params = std::make_shared(0.5, 0.01); - ::node_grid = node_grid_reversed; + ::communicator.node_grid = node_grid_reversed; auto const lattice = std::make_shared( Utils::Vector3i{12, 12, 12}, node_grid_original, n_ghost_layers); auto const ptr = new_lb_walberla(lattice, 1.0, 1.0, false); ptr->set_collision_model(0.0, 0); - ::node_grid = node_grid_original; + ::communicator.node_grid = node_grid_original; auto lb_instance = std::make_shared(ptr, params); if (world.rank() == 0) { try { diff --git a/src/core/unit_tests/lees_edwards_test.cpp b/src/core/unit_tests/lees_edwards_test.cpp index 74424f78983..c82c74c1e06 100644 --- a/src/core/unit_tests/lees_edwards_test.cpp +++ b/src/core/unit_tests/lees_edwards_test.cpp @@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(test_push) { old_pos - prefactor * shear_direction(box) * le.pos_offset; auto expected_vel = old_vel - shear_direction(box) * le.shear_velocity; auto expected_offset = old_offset + prefactor * le.pos_offset; - fold_position(expected_pos, p.image_box(), box); + box.fold_position(expected_pos, p.image_box()); BOOST_CHECK_SMALL((p.pos() - expected_pos).norm(), eps); BOOST_CHECK_SMALL((p.v() - expected_vel).norm(), eps); BOOST_CHECK_CLOSE(p.lees_edwards_offset(), expected_offset, tol); @@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(test_push) { p.pos()[le.shear_plane_normal] = -1; Push{box}(p, prefactor); expected_pos = {old_pos[0], -1., old_pos[2]}; - fold_position(expected_pos, p.image_box(), box); + box.fold_position(expected_pos, p.image_box()); expected_vel = old_vel; expected_offset = old_offset; BOOST_CHECK_SMALL((p.pos() - expected_pos).norm(), eps); diff --git a/src/core/unit_tests/particle_management.hpp b/src/core/unit_tests/particle_management.hpp index faf3d9565db..6c847c02dde 100644 --- a/src/core/unit_tests/particle_management.hpp +++ b/src/core/unit_tests/particle_management.hpp @@ -17,11 +17,12 @@ * along with this program. If not, see . */ -#ifndef ESPRESSO_SRC_CORE_UNIT_TESTS_PARTICLE_MANAGEMENT_HPP -#define ESPRESSO_SRC_CORE_UNIT_TESTS_PARTICLE_MANAGEMENT_HPP +#pragma once #include "Particle.hpp" +#include "cell_system/CellStructure.hpp" #include "cells.hpp" +#include "system/System.hpp" #include #include @@ -29,7 +30,7 @@ inline auto copy_particle_to_head_node(boost::mpi::communicator const &comm, int p_id) { boost::optional result{}; - auto p = ::cell_structure.get_local_particle(p_id); + auto p = System::get_system().cell_structure->get_local_particle(p_id); if (p and not p->is_ghost()) { if (comm.rank() == 0) { result = *p; @@ -44,5 +45,3 @@ inline auto copy_particle_to_head_node(boost::mpi::communicator const &comm, } return result; } - -#endif // ESPRESSO_SRC_CORE_UNIT_TESTS_PARTICLE_MANAGEMENT_HPP diff --git a/src/core/virtual_sites.cpp b/src/core/virtual_sites.cpp index cb973e5a7fb..bb70b6ae925 100644 --- a/src/core/virtual_sites.cpp +++ b/src/core/virtual_sites.cpp @@ -25,10 +25,10 @@ #include "virtual_sites.hpp" +#include "BoxGeometry.hpp" #include "Particle.hpp" #include "communication.hpp" #include "errorhandling.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "nonbonded_interactions/nonbonded_interaction_data.hpp" @@ -55,16 +55,16 @@ void set_virtual_sites(std::shared_ptr const &v) { /** Calculate the rotation quaternion and distance between two particles */ std::tuple, double> -calculate_vs_relate_to_params(Particle const &p_vs, - Particle const &p_relate_to) { +calculate_vs_relate_to_params(Particle const &p_vs, Particle const &p_relate_to, + BoxGeometry const &box_geo) { // get the distance between the particles - auto d = ::box_geo.get_mi_vector(p_vs.pos(), p_relate_to.pos()); + auto d = box_geo.get_mi_vector(p_vs.pos(), p_relate_to.pos()); // Check if the distance between virtual and non-virtual particles is larger // than minimum global cutoff. If so, warn user. auto const dist = d.norm(); auto const min_global_cut = get_min_global_cut(); - if (dist > min_global_cut && n_nodes > 1 && + if (dist > min_global_cut and ::communicator.size > 1 and not virtual_sites()->get_override_cutoff_check()) { runtimeErrorMsg() << "Warning: The distance between virtual and non-virtual particle (" diff --git a/src/core/virtual_sites.hpp b/src/core/virtual_sites.hpp index bf540b3beef..3682cb0e3fb 100644 --- a/src/core/virtual_sites.hpp +++ b/src/core/virtual_sites.hpp @@ -36,26 +36,31 @@ void set_virtual_sites(std::shared_ptr const &v); #ifdef VIRTUAL_SITES_RELATIVE +#include "BoxGeometry.hpp" + #include #include std::tuple, double> calculate_vs_relate_to_params(Particle const &p_current, - Particle const &p_relate_to); + Particle const &p_relate_to, + BoxGeometry const &box_geo); /** * @brief Setup a virtual site to track a real particle. + * @param[in] box_geo Box geometry. * @param[in,out] p_vs Virtual site. * @param[in] p_relate_to Real particle to follow. */ -inline void vs_relate_to(Particle &p_vs, Particle const &p_relate_to) { +inline void vs_relate_to(Particle &p_vs, Particle const &p_relate_to, + BoxGeometry const &box_geo) { // Set the particle id of the particle we want to relate to, the distance // and the relative orientation auto &vs_relative = p_vs.vs_relative(); vs_relative.to_particle_id = p_relate_to.id(); std::tie(vs_relative.rel_orientation, vs_relative.distance) = - calculate_vs_relate_to_params(p_vs, p_relate_to); + calculate_vs_relate_to_params(p_vs, p_relate_to, box_geo); } #endif // VIRTUAL_SITES_RELATIVE diff --git a/src/core/virtual_sites/VirtualSitesInertialessTracers.cpp b/src/core/virtual_sites/VirtualSitesInertialessTracers.cpp index ab54e7b0530..a27268b95e1 100644 --- a/src/core/virtual_sites/VirtualSitesInertialessTracers.cpp +++ b/src/core/virtual_sites/VirtualSitesInertialessTracers.cpp @@ -22,10 +22,11 @@ #include "VirtualSitesInertialessTracers.hpp" +#include "BoxGeometry.hpp" +#include "cell_system/CellStructure.hpp" #include "cells.hpp" #include "errorhandling.hpp" #include "forces.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "lb/particle_coupling.hpp" #include "system/System.hpp" @@ -50,6 +51,8 @@ static bool lb_active_check(DeferredActiveLBChecks const &check) { void VirtualSitesInertialessTracers::after_force_calc(double time_step) { DeferredActiveLBChecks check_lb_solver_set{}; auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + auto const &box_geo = *system.box_geo; auto const agrid = (check_lb_solver_set()) ? system.lb.get_agrid() : 0.; auto const to_lb_units = (check_lb_solver_set()) ? 1. / agrid : 0.; @@ -70,7 +73,7 @@ void VirtualSitesInertialessTracers::after_force_calc(double time_step) { return; } if (bookkeeping.should_be_coupled(p)) { - for (auto pos : positions_in_halo(p.pos(), ::box_geo, agrid)) { + for (auto pos : positions_in_halo(p.pos(), box_geo, agrid)) { add_md_force(system.lb, pos * to_lb_units, p.force(), time_step); } } @@ -83,7 +86,9 @@ void VirtualSitesInertialessTracers::after_force_calc(double time_step) { void VirtualSitesInertialessTracers::after_lb_propagation(double time_step) { DeferredActiveLBChecks check_lb_solver_set{}; - auto const &lb = System::get_system().lb; + auto &system = System::get_system(); + auto &cell_structure = *system.cell_structure; + auto const &lb = system.lb; // Advect particles for (auto &p : cell_structure.local_particles()) { diff --git a/src/core/virtual_sites/VirtualSitesRelative.cpp b/src/core/virtual_sites/VirtualSitesRelative.cpp index 7da96d1221b..92b1d02ae84 100644 --- a/src/core/virtual_sites/VirtualSitesRelative.cpp +++ b/src/core/virtual_sites/VirtualSitesRelative.cpp @@ -21,13 +21,15 @@ #ifdef VIRTUAL_SITES_RELATIVE +#include "BoxGeometry.hpp" #include "Particle.hpp" +#include "cell_system/CellStructure.hpp" #include "cells.hpp" #include "errorhandling.hpp" #include "forces.hpp" -#include "grid.hpp" #include "integrate.hpp" #include "rotation.hpp" +#include "system/System.hpp" #include #include @@ -87,6 +89,7 @@ static Particle *get_reference_particle(Particle const &p) { << " is a dangling virtual site"; return nullptr; } + auto &cell_structure = *System::get_system().cell_structure; auto p_ref_ptr = cell_structure.get_local_particle(vs_rel.to_particle_id); if (!p_ref_ptr) { runtimeErrorMsg() << "No real particle with id " << vs_rel.to_particle_id @@ -110,6 +113,9 @@ static auto constraint_stress(Particle const &p_ref, Particle const &p_vs) { } void VirtualSitesRelative::update() const { + auto const &system = System::get_system(); + auto const &box_geo = *system.box_geo; + auto &cell_structure = *system.cell_structure; cell_structure.ghosts_update(Cells::DATA_PART_POSITION | Cells::DATA_PART_MOMENTUM); @@ -128,7 +134,7 @@ void VirtualSitesRelative::update() const { auto push = LeesEdwards::Push(box_geo); push(p, -1); // includes a position fold } else { - fold_position(p.pos(), p.image_box(), box_geo); + box_geo.fold_position(p.pos(), p.image_box()); } if (have_quaternions()) @@ -143,6 +149,7 @@ void VirtualSitesRelative::update() const { // Distribute forces that have accumulated on virtual particles to the // associated real particles void VirtualSitesRelative::back_transfer_forces_and_torques() const { + auto &cell_structure = *System::get_system().cell_structure; cell_structure.ghosts_reduce_forces(); init_forces_ghosts(cell_structure.ghost_particles()); @@ -163,6 +170,8 @@ void VirtualSitesRelative::back_transfer_forces_and_torques() const { // Rigid body contribution to scalar pressure and pressure tensor Utils::Matrix VirtualSitesRelative::pressure_tensor() const { + auto &cell_structure = *System::get_system().cell_structure; + Utils::Matrix pressure_tensor = {}; for (auto const &p : cell_structure.local_particles()) { diff --git a/src/script_interface/analysis/Analysis.cpp b/src/script_interface/analysis/Analysis.cpp index d7f9f20f530..3152e946a21 100644 --- a/src/script_interface/analysis/Analysis.cpp +++ b/src/script_interface/analysis/Analysis.cpp @@ -19,16 +19,17 @@ #include "Analysis.hpp" +#include "core/BoxGeometry.hpp" #include "core/analysis/statistics.hpp" #include "core/analysis/statistics_chain.hpp" #include "core/cells.hpp" #include "core/dpd.hpp" #include "core/energy.hpp" #include "core/event.hpp" -#include "core/grid.hpp" #include "core/nonbonded_interactions/nonbonded_interaction_data.hpp" #include "core/partCfg_global.hpp" #include "core/particle_node.hpp" +#include "core/system/System.hpp" #include "script_interface/communication.hpp" @@ -217,9 +218,9 @@ Variant Analysis::do_call_method(std::string const &name, return make_vector_of_variants(result); } if (name == "distribution") { + auto const &box_l = System::get_system().box_geo->length(); auto const r_max_limit = - 0.5 * std::min(std::min(::box_geo.length()[0], ::box_geo.length()[1]), - ::box_geo.length()[2]); + 0.5 * std::min(std::min(box_l[0], box_l[1]), box_l[2]); auto const r_min = get_value_or(parameters, "r_min", 0.); auto const r_max = get_value_or(parameters, "r_max", r_max_limit); auto const r_bins = get_value_or(parameters, "r_bins", 100); diff --git a/src/script_interface/cell_system/CellSystem.cpp b/src/script_interface/cell_system/CellSystem.cpp index db39a9ad81b..9223f8c29a2 100644 --- a/src/script_interface/cell_system/CellSystem.cpp +++ b/src/script_interface/cell_system/CellSystem.cpp @@ -21,15 +21,18 @@ #include "script_interface/ScriptInterface.hpp" +#include "core/BoxGeometry.hpp" #include "core/bonded_interactions/bonded_interaction_data.hpp" +#include "core/cell_system/CellStructure.hpp" #include "core/cell_system/HybridDecomposition.hpp" #include "core/cell_system/RegularDecomposition.hpp" #include "core/cells.hpp" +#include "core/communication.hpp" #include "core/event.hpp" -#include "core/grid.hpp" #include "core/integrate.hpp" #include "core/nonbonded_interactions/nonbonded_interaction_data.hpp" #include "core/particle_node.hpp" +#include "core/system/System.hpp" #include "core/tuning.hpp" #include @@ -51,24 +54,28 @@ namespace ScriptInterface { namespace CellSystem { +static auto &get_cell_structure() { + return *::System::get_system().cell_structure; +} + static auto const &get_regular_decomposition() { return dynamic_cast( - std::as_const(::cell_structure).decomposition()); + std::as_const(get_cell_structure()).decomposition()); } static auto const &get_hybrid_decomposition() { return dynamic_cast( - std::as_const(::cell_structure).decomposition()); + std::as_const(get_cell_structure()).decomposition()); } CellSystem::CellSystem() { add_parameters({ - {"use_verlet_lists", ::cell_structure.use_verlet_list}, + {"use_verlet_lists", get_cell_structure().use_verlet_list}, {"node_grid", [this](Variant const &v) { context()->parallel_try_catch([&v]() { auto const error_msg = std::string("Parameter 'node_grid'"); - auto const old_node_grid = ::node_grid; + auto const old_node_grid = ::communicator.node_grid; auto const new_node_grid = get_value(v); auto const n_nodes_old = Utils::product(old_node_grid); auto const n_nodes_new = Utils::product(new_node_grid); @@ -79,14 +86,14 @@ CellSystem::CellSystem() { throw std::invalid_argument(error_msg + reason.str()); } try { - set_node_grid(new_node_grid); + ::communicator.set_node_grid(new_node_grid); } catch (...) { - set_node_grid(old_node_grid); + ::communicator.set_node_grid(old_node_grid); throw; } }); }, - []() { return ::node_grid; }}, + []() { return ::communicator.node_grid; }}, {"skin", [this](Variant const &v) { auto const new_skin = get_value(v); @@ -101,11 +108,11 @@ CellSystem::CellSystem() { []() { return ::skin; }}, {"decomposition_type", AutoParameter::read_only, [this]() { - return cs_type_to_name.at(::cell_structure.decomposition_type()); + return cs_type_to_name.at(get_cell_structure().decomposition_type()); }}, {"n_square_types", AutoParameter::read_only, []() { - if (::cell_structure.decomposition_type() != + if (get_cell_structure().decomposition_type() != CellStructureType::CELL_STRUCTURE_HYBRID) { return Variant{none}; } @@ -115,7 +122,7 @@ CellSystem::CellSystem() { }}, {"cutoff_regular", AutoParameter::read_only, []() { - if (::cell_structure.decomposition_type() != + if (get_cell_structure().decomposition_type() != CellStructureType::CELL_STRUCTURE_HYBRID) { return Variant{none}; } @@ -142,7 +149,7 @@ Variant CellSystem::do_call_method(std::string const &name, } if (name == "get_state") { auto state = get_parameters(); - auto const cs_type = ::cell_structure.decomposition_type(); + auto const cs_type = get_cell_structure().decomposition_type(); if (cs_type == CellStructureType::CELL_STRUCTURE_REGULAR) { auto const rd = get_regular_decomposition(); state["cell_grid"] = Variant{rd.cell_grid}; @@ -231,15 +238,16 @@ Variant CellSystem::do_call_method(std::string const &name, return ::skin; } if (name == "get_max_range") { - return ::cell_structure.max_range(); + return get_cell_structure().max_range(); } return {}; } std::vector CellSystem::mpi_resort_particles(bool global_flag) const { - ::cell_structure.resort_particles(global_flag, box_geo); + auto &cell_structure = get_cell_structure(); + cell_structure.resort_particles(global_flag, *::System::get_system().box_geo); clear_particle_node(); - auto const size = static_cast(::cell_structure.local_particles().size()); + auto const size = static_cast(cell_structure.local_particles().size()); std::vector n_part_per_node; boost::mpi::gather(context()->get_comm(), size, n_part_per_node, 0); return n_part_per_node; @@ -248,7 +256,8 @@ std::vector CellSystem::mpi_resort_particles(bool global_flag) const { void CellSystem::initialize(CellStructureType const &cs_type, VariantMap const ¶ms) const { auto const verlet = get_value_or(params, "use_verlet_lists", true); - ::cell_structure.use_verlet_list = verlet; + auto &cell_structure = get_cell_structure(); + cell_structure.use_verlet_list = verlet; if (cs_type == CellStructureType::CELL_STRUCTURE_HYBRID) { auto const cutoff_regular = get_value(params, "cutoff_regular"); auto const ns_types = @@ -256,7 +265,7 @@ void CellSystem::initialize(CellStructureType const &cs_type, auto n_square_types = std::set{ns_types.begin(), ns_types.end()}; set_hybrid_decomposition(std::move(n_square_types), cutoff_regular); } else { - cells_re_init(cs_type); + cells_re_init(cell_structure, cs_type); } } diff --git a/src/script_interface/constraints/ExternalField.hpp b/src/script_interface/constraints/ExternalField.hpp index 391975747ba..1e3299ee0eb 100644 --- a/src/script_interface/constraints/ExternalField.hpp +++ b/src/script_interface/constraints/ExternalField.hpp @@ -30,7 +30,6 @@ #include "core/constraints/Constraint.hpp" #include "core/constraints/ExternalField.hpp" -#include "core/grid.hpp" #include diff --git a/src/script_interface/constraints/ShapeBasedConstraint.hpp b/src/script_interface/constraints/ShapeBasedConstraint.hpp index 4f4d4d8ff7e..49aeb63a606 100644 --- a/src/script_interface/constraints/ShapeBasedConstraint.hpp +++ b/src/script_interface/constraints/ShapeBasedConstraint.hpp @@ -23,9 +23,10 @@ #define SCRIPT_INTERFACE_CONSTRAINTS_SHAPEBASEDCONSTRAINT_HPP #include "Constraint.hpp" -#include "core/cells.hpp" +#include "core/cell_system/CellStructure.hpp" #include "core/constraints/Constraint.hpp" #include "core/constraints/ShapeBasedConstraint.hpp" +#include "core/system/System.hpp" #include "script_interface/shapes/Shape.hpp" @@ -64,6 +65,8 @@ class ShapeBasedConstraint : public Constraint { return shape_based_constraint()->total_force(); } if (name == "min_dist") { + auto const &system = ::System::get_system(); + auto &cell_structure = *system.cell_structure; return shape_based_constraint()->min_dist( cell_structure.local_particles()); } diff --git a/src/script_interface/h5md/h5md.cpp b/src/script_interface/h5md/h5md.cpp index 5efadfc7ae1..2bace3a2e82 100644 --- a/src/script_interface/h5md/h5md.cpp +++ b/src/script_interface/h5md/h5md.cpp @@ -25,9 +25,9 @@ #include "h5md.hpp" -#include "core/cells.hpp" -#include "core/grid.hpp" +#include "cell_system/CellStructure.hpp" #include "core/integrate.hpp" +#include "core/system/System.hpp" #include #include @@ -37,17 +37,20 @@ namespace Writer { Variant H5md::do_call_method(const std::string &name, const VariantMap ¶meters) { - if (name == "write") + if (name == "write") { + auto const &system = System::get_system(); + auto &cell_structure = *system.cell_structure; m_h5md->write( cell_structure.local_particles(), get_sim_time(), static_cast(std::round(get_sim_time() / get_time_step())), - box_geo); - else if (name == "flush") + *system.box_geo); + } else if (name == "flush") { m_h5md->flush(); - else if (name == "close") + } else if (name == "close") { m_h5md->close(); - else if (name == "valid_fields") + } else if (name == "valid_fields") { return make_vector_of_variants(m_h5md->valid_fields()); + } return {}; } diff --git a/src/script_interface/integrators/StokesianDynamics.cpp b/src/script_interface/integrators/StokesianDynamics.cpp index 27bd7962b6e..c7dfa3569d0 100644 --- a/src/script_interface/integrators/StokesianDynamics.cpp +++ b/src/script_interface/integrators/StokesianDynamics.cpp @@ -25,7 +25,6 @@ #include "script_interface/ScriptInterface.hpp" -#include "core/grid.hpp" #include "core/integrate.hpp" #include "core/stokesian_dynamics/sd_interface.hpp" diff --git a/src/script_interface/lees_edwards/LeesEdwards.hpp b/src/script_interface/lees_edwards/LeesEdwards.hpp index 92a030cf4ca..579b4493f6f 100644 --- a/src/script_interface/lees_edwards/LeesEdwards.hpp +++ b/src/script_interface/lees_edwards/LeesEdwards.hpp @@ -21,7 +21,7 @@ #include "Protocol.hpp" -#include "core/grid.hpp" +#include "core/BoxGeometry.hpp" #include "core/lees_edwards/LeesEdwardsBC.hpp" #include "core/lees_edwards/lees_edwards.hpp" #include "core/system/System.hpp" @@ -37,21 +37,23 @@ namespace LeesEdwards { class LeesEdwards : public AutoParameters { std::shared_ptr m_protocol; - LeesEdwardsBC const &m_lebc = ::box_geo.lees_edwards_bc(); + LeesEdwardsBC const &m_lebc; public: - LeesEdwards() : m_protocol{nullptr} { + LeesEdwards() + : m_protocol{nullptr}, + m_lebc{System::get_system().box_geo->lees_edwards_bc()} { add_parameters( {{"protocol", [this](Variant const &value) { if (is_none(value)) { - context()->parallel_try_catch([]() { + auto const &system = System::get_system(); + context()->parallel_try_catch([&system]() { auto constexpr invalid_dir = LeesEdwardsBC::invalid_dir; - auto const &system = System::get_system(); system.lb.lebc_sanity_checks(invalid_dir, invalid_dir); }); m_protocol = nullptr; - ::box_geo.set_lees_edwards_bc(LeesEdwardsBC{}); + system.box_geo->set_lees_edwards_bc(LeesEdwardsBC{}); ::LeesEdwards::unset_protocol(); return; } @@ -104,7 +106,7 @@ class LeesEdwards : public AutoParameters { auto const &system = System::get_system(); system.lb.lebc_sanity_checks(shear_direction, shear_plane_normal); // update box geometry and cell structure - ::box_geo.set_lees_edwards_bc( + system.box_geo->set_lees_edwards_bc( LeesEdwardsBC{0., 0., shear_direction, shear_plane_normal}); ::LeesEdwards::set_protocol(m_protocol->protocol()); }); diff --git a/src/script_interface/mpiio/mpiio.hpp b/src/script_interface/mpiio/mpiio.hpp index ab04e5eff4a..fd37189ee67 100644 --- a/src/script_interface/mpiio/mpiio.hpp +++ b/src/script_interface/mpiio/mpiio.hpp @@ -26,8 +26,9 @@ #include "script_interface/auto_parameters/AutoParameters.hpp" #include "script_interface/get_value.hpp" -#include "core/cells.hpp" +#include "core/cell_system/CellStructure.hpp" #include "core/io/mpiio/mpiio.hpp" +#include "core/system/System.hpp" #include @@ -52,11 +53,14 @@ class MPIIOScript : public AutoParameters { ((typ) ? Mpiio::MPIIO_OUT_TYP : Mpiio::MPIIO_OUT_NON) | ((bnd) ? Mpiio::MPIIO_OUT_BND : Mpiio::MPIIO_OUT_NON); - if (name == "write") + if (name == "write") { + auto const &system = ::System::get_system(); + auto &cell_structure = *system.cell_structure; Mpiio::mpi_mpiio_common_write(prefix, fields, cell_structure.local_particles()); - else if (name == "read") + } else if (name == "read") { Mpiio::mpi_mpiio_common_read(prefix, fields); + } return {}; } diff --git a/src/script_interface/particle_data/ParticleHandle.cpp b/src/script_interface/particle_data/ParticleHandle.cpp index e0c6e6f99d5..a26c444891f 100644 --- a/src/script_interface/particle_data/ParticleHandle.cpp +++ b/src/script_interface/particle_data/ParticleHandle.cpp @@ -24,14 +24,15 @@ #include "script_interface/Variant.hpp" #include "script_interface/get_value.hpp" +#include "core/BoxGeometry.hpp" #include "core/bonded_interactions/bonded_interaction_data.hpp" -#include "core/cells.hpp" +#include "core/cell_system/CellStructure.hpp" #include "core/event.hpp" #include "core/exclusions.hpp" -#include "core/grid.hpp" #include "core/nonbonded_interactions/nonbonded_interaction_data.hpp" #include "core/particle_node.hpp" #include "core/rotation.hpp" +#include "core/system/System.hpp" #include "core/virtual_sites.hpp" #include @@ -118,7 +119,9 @@ static auto get_real_particle(boost::mpi::communicator const &comm, int p_id) { if (p_id < 0) { throw std::domain_error("Invalid particle id: " + std::to_string(p_id)); } - auto ptr = ::cell_structure.get_local_particle(p_id); + auto const &system = ::System::get_system(); + auto &cell_structure = *system.cell_structure; + auto ptr = cell_structure.get_local_particle(p_id); if (ptr != nullptr and ptr->is_ghost()) { ptr = nullptr; } @@ -194,7 +197,7 @@ ParticleHandle::ParticleHandle() { auto const p = get_particle_data(m_pid); auto const pos = p.pos(); auto const image_box = p.image_box(); - return unfolded_position(pos, image_box, ::box_geo.length()); + return System::get_system().box_geo->unfolded_position(pos, image_box); }}, {"v", [this](Variant const &value) { @@ -391,7 +394,8 @@ ParticleHandle::ParticleHandle() { #endif // THERMOSTAT_PER_PARTICLE {"pos_folded", AutoParameter::read_only, [this]() { - return folded_position(get_particle_data(m_pid).pos(), ::box_geo); + auto const &box_geo = *System::get_system().box_geo; + return box_geo.folded_position(get_particle_data(m_pid).pos()); }}, {"lees_edwards_offset", @@ -488,10 +492,12 @@ ParticleHandle::ParticleHandle() { * @param pid2 the identity of the second exclusion partner */ static void local_add_exclusion(int pid1, int pid2) { - if (auto p1 = ::cell_structure.get_local_particle(pid1)) { + auto const &system = ::System::get_system(); + auto &cell_structure = *system.cell_structure; + if (auto p1 = cell_structure.get_local_particle(pid1)) { add_exclusion(*p1, pid2); } - if (auto p2 = ::cell_structure.get_local_particle(pid2)) { + if (auto p2 = cell_structure.get_local_particle(pid2)) { add_exclusion(*p2, pid1); } } @@ -502,10 +508,12 @@ static void local_add_exclusion(int pid1, int pid2) { * @param pid2 the identity of the second exclusion partner */ static void local_remove_exclusion(int pid1, int pid2) { - if (auto p1 = ::cell_structure.get_local_particle(pid1)) { + auto const &system = ::System::get_system(); + auto &cell_structure = *system.cell_structure; + if (auto p1 = cell_structure.get_local_particle(pid1)) { delete_exclusion(*p1, pid2); } - if (auto p2 = ::cell_structure.get_local_particle(pid2)) { + if (auto p2 = cell_structure.get_local_particle(pid2)) { delete_exclusion(*p2, pid1); } } @@ -604,8 +612,8 @@ Variant ParticleHandle::do_call_method(std::string const &name, */ auto const &p_current = get_particle_data(m_pid); auto const &p_relate_to = get_particle_data(other_pid); - auto const [quat, dist] = - calculate_vs_relate_to_params(p_current, p_relate_to); + auto const [quat, dist] = calculate_vs_relate_to_params( + p_current, p_relate_to, *::System::get_system().box_geo); set_parameter("vs_relative", Variant{std::vector{ {other_pid, dist, quat2vector(quat)}}}); set_parameter("virtual", true); @@ -726,7 +734,9 @@ void ParticleHandle::do_construct(VariantMap const ¶ms) { auto const pos = get_value(params, "pos"); context()->parallel_try_catch([&]() { particle_checks(m_pid, pos); - auto ptr = ::cell_structure.get_local_particle(m_pid); + auto const &system = ::System::get_system(); + auto const &cell_structure = *system.cell_structure; + auto ptr = cell_structure.get_local_particle(m_pid); if (ptr != nullptr) { throw std::invalid_argument("Particle " + std::to_string(m_pid) + " already exists"); diff --git a/src/script_interface/particle_data/ParticleList.cpp b/src/script_interface/particle_data/ParticleList.cpp index e2f2c7ab961..6d3620050b0 100644 --- a/src/script_interface/particle_data/ParticleList.cpp +++ b/src/script_interface/particle_data/ParticleList.cpp @@ -23,10 +23,11 @@ #include "script_interface/ObjectState.hpp" #include "script_interface/ScriptInterface.hpp" -#include "core/cells.hpp" +#include "core/cell_system/CellStructure.hpp" #include "core/event.hpp" #include "core/exclusions.hpp" #include "core/particle_node.hpp" +#include "core/system/System.hpp" #include #include @@ -131,8 +132,11 @@ static void auto_exclusions(boost::mpi::communicator const &comm, std::unordered_map>> partners; std::vector bonded_pairs; + auto const &system = ::System::get_system(); + auto &cell_structure = *system.cell_structure; + // determine initial connectivity - for (auto const &p : ::cell_structure.local_particles()) { + for (auto const &p : cell_structure.local_particles()) { auto const pid1 = p.id(); for (auto const bond : p.bonds()) { if (bond.partner_ids().size() == 1) { @@ -196,10 +200,10 @@ static void auto_exclusions(boost::mpi::communicator const &comm, auto const &partner_list = kv.second; for (auto const &partner : partner_list) { auto const pid2 = partner.first; - if (auto p1 = ::cell_structure.get_local_particle(pid1)) { + if (auto p1 = cell_structure.get_local_particle(pid1)) { add_exclusion(*p1, pid2); } - if (auto p2 = ::cell_structure.get_local_particle(pid2)) { + if (auto p2 = cell_structure.get_local_particle(pid2)) { add_exclusion(*p2, pid1); } } diff --git a/src/script_interface/reaction_methods/ReactionAlgorithm.cpp b/src/script_interface/reaction_methods/ReactionAlgorithm.cpp index d11c875a4bf..790f46a8919 100644 --- a/src/script_interface/reaction_methods/ReactionAlgorithm.cpp +++ b/src/script_interface/reaction_methods/ReactionAlgorithm.cpp @@ -25,13 +25,14 @@ #include "config/config.hpp" -#include "core/cells.hpp" +#include "core/cell_system/CellStructure.hpp" #include "core/communication.hpp" #include "core/energy.hpp" #include "core/event.hpp" #include "core/particle_node.hpp" #include "core/reaction_methods/ReactionAlgorithm.hpp" #include "core/reaction_methods/utils.hpp" +#include "core/system/System.hpp" #include @@ -104,7 +105,9 @@ ReactionAlgorithm::ReactionAlgorithm() { static auto get_real_particle(boost::mpi::communicator const &comm, int p_id) { assert(p_id >= 0); - auto ptr = ::cell_structure.get_local_particle(p_id); + auto const &system = ::System::get_system(); + auto &cell_structure = *system.cell_structure; + auto ptr = cell_structure.get_local_particle(p_id); if (ptr != nullptr and ptr->is_ghost()) { ptr = nullptr; } diff --git a/src/script_interface/system/System.cpp b/src/script_interface/system/System.cpp index d0029030269..2aee8982ce1 100644 --- a/src/script_interface/system/System.cpp +++ b/src/script_interface/system/System.cpp @@ -19,9 +19,11 @@ #include "System.hpp" +#include "core/BoxGeometry.hpp" +#include "core/cell_system/CellStructure.hpp" +#include "core/cell_system/CellStructureType.hpp" #include "core/cells.hpp" #include "core/event.hpp" -#include "core/grid.hpp" #include "core/nonbonded_interactions/nonbonded_interaction_data.hpp" #include "core/object-in-fluid/oif_global_forces.hpp" #include "core/particle_node.hpp" @@ -43,12 +45,14 @@ namespace System { static bool system_created = false; static Utils::Vector3b get_periodicity() { - return {::box_geo.periodic(0), ::box_geo.periodic(1), ::box_geo.periodic(2)}; + auto const &box_geo = *::System::get_system().box_geo; + return {box_geo.periodic(0), box_geo.periodic(1), box_geo.periodic(2)}; } static void set_periodicity(Utils::Vector3b const &value) { + auto &box_geo = *::System::get_system().box_geo; for (int i = 0; i < 3; ++i) { - ::box_geo.set_periodic(i, value[i]); + box_geo.set_periodic(i, value[i]); } on_periodicity_change(); } @@ -62,11 +66,11 @@ System::System() { if (not(new_value > Utils::Vector3d::broadcast(0.))) { throw std::domain_error("Attribute 'box_l' must be > 0"); } - box_geo.set_length(new_value); + m_instance->box_geo->set_length(new_value); on_boxl_change(); }); }, - []() { return ::box_geo.length(); }}, + []() { return ::System::get_system().box_geo->length(); }}, {"min_global_cut", [this](Variant const &v) { context()->parallel_try_catch([&]() { @@ -106,7 +110,12 @@ void System::do_construct(VariantMap const ¶ms) { ::System::set_system(m_instance); m_instance->init(); + // domain decomposition can only be set after box_l is set + auto &cell_structure = *m_instance->cell_structure; + cells_re_init(cell_structure, CellStructureType::CELL_STRUCTURE_NSQUARE); do_set_parameter("box_l", params.at("box_l")); + cells_re_init(cell_structure, CellStructureType::CELL_STRUCTURE_REGULAR); + if (params.count("periodicity")) { do_set_parameter("periodicity", params.at("periodicity")); } @@ -121,11 +130,13 @@ void System::do_construct(VariantMap const ¶ms) { } /** Rescale all particle positions in direction @p dir by a factor @p scale. + * @param cell_structure cell structure * @param dir direction to scale (0/1/2 = x/y/z, 3 = x+y+z isotropically) * @param scale factor by which to rescale (>1: stretch, <1: contract) */ -static void rescale_particles(int dir, double scale) { - for (auto &p : ::cell_structure.local_particles()) { +static void rescale_particles(CellStructure &cell_structure, int dir, + double scale) { + for (auto &p : cell_structure.local_particles()) { if (dir < 3) p.pos()[dir] *= scale; else { @@ -145,10 +156,11 @@ Variant System::do_call_method(std::string const &name, return {}; } if (name == "rescale_boxl") { + auto &box_geo = *::System::get_system().box_geo; auto const coord = get_value(parameters, "coord"); auto const length = get_value(parameters, "length"); - auto const scale = (coord == 3) ? length * ::box_geo.length_inv()[0] - : length * ::box_geo.length_inv()[coord]; + auto const scale = (coord == 3) ? length * box_geo.length_inv()[0] + : length * box_geo.length_inv()[coord]; context()->parallel_try_catch([&]() { if (length <= 0.) { throw std::domain_error("Parameter 'd_new' be > 0"); @@ -158,16 +170,17 @@ Variant System::do_call_method(std::string const &name, if (coord == 3) { new_value = Utils::Vector3d::broadcast(length); } else { - new_value = ::box_geo.length(); + new_value = box_geo.length(); new_value[coord] = length; } // when shrinking, rescale the particles first if (scale <= 1.) { - rescale_particles(coord, scale); + rescale_particles(*m_instance->cell_structure, coord, scale); } - set_box_length(new_value); + m_instance->box_geo->set_length(new_value); + on_boxl_change(); if (scale > 1.) { - rescale_particles(coord, scale); + rescale_particles(*m_instance->cell_structure, coord, scale); } return {}; } @@ -183,19 +196,22 @@ Variant System::do_call_method(std::string const &name, return ::number_of_particles_with_type(type); } if (name == "velocity_difference") { + auto const &box_geo = *::System::get_system().box_geo; auto const pos1 = get_value(parameters, "pos1"); auto const pos2 = get_value(parameters, "pos2"); auto const v1 = get_value(parameters, "v1"); auto const v2 = get_value(parameters, "v2"); - return ::box_geo.velocity_difference(pos2, pos1, v2, v1); + return box_geo.velocity_difference(pos2, pos1, v2, v1); } if (name == "distance_vec") { + auto const &box_geo = *::System::get_system().box_geo; auto const pos1 = get_value(parameters, "pos1"); auto const pos2 = get_value(parameters, "pos2"); - return ::box_geo.get_mi_vector(pos2, pos1); + return box_geo.get_mi_vector(pos2, pos1); } if (name == "rotate_system") { - rotate_system(get_value(parameters, "phi"), + rotate_system(*m_instance->cell_structure, + get_value(parameters, "phi"), get_value(parameters, "theta"), get_value(parameters, "alpha")); return {}; diff --git a/src/script_interface/tests/Actors_test.cpp b/src/script_interface/tests/Actors_test.cpp index bda702f2a60..591864587f8 100644 --- a/src/script_interface/tests/Actors_test.cpp +++ b/src/script_interface/tests/Actors_test.cpp @@ -108,7 +108,6 @@ BOOST_AUTO_TEST_CASE(coulomb_actor) { #ifdef DIPOLES BOOST_AUTO_TEST_CASE(dipoles_actor) { auto constexpr tol = 100. * std::numeric_limits::epsilon(); - n_nodes = 1; ScriptInterface::Dipoles::MockDipolarDirectSum actor; actor.do_construct({{"prefactor", 2.}, {"n_replicas", 3}}); // check const and non-const access diff --git a/src/script_interface/walberla/LBFluid.cpp b/src/script_interface/walberla/LBFluid.cpp index 7c1a5a93a44..c3a7d9932c8 100644 --- a/src/script_interface/walberla/LBFluid.cpp +++ b/src/script_interface/walberla/LBFluid.cpp @@ -26,7 +26,6 @@ #include "core/BoxGeometry.hpp" #include "core/event.hpp" -#include "core/grid.hpp" #include "core/integrate.hpp" #include "core/lb/LBWalberla.hpp" #include "core/lees_edwards/lees_edwards.hpp" @@ -83,9 +82,10 @@ Variant LBFluid::do_call_method(std::string const &name, return {}; } if (name == "add_force_at_pos") { + auto const &box_geo = *::System::get_system().box_geo; auto const pos = get_value(params, "pos"); auto const f = get_value(params, "force"); - auto const folded_pos = folded_position(pos, box_geo); + auto const folded_pos = box_geo.folded_position(pos); m_instance->add_force_at_pos(folded_pos * m_conv_dist, f * m_conv_force); return {}; } @@ -177,7 +177,7 @@ void LBFluid::do_construct(VariantMap const ¶ms) { throw std::runtime_error( "Lees-Edwards LB doesn't support thermalization"); } - auto const &le_bc = ::box_geo.lees_edwards_bc(); + auto const &le_bc = ::System::get_system().box_geo->lees_edwards_bc(); auto lees_edwards_object = std::make_unique( le_bc.shear_direction, le_bc.shear_plane_normal, [this, le_protocol]() { @@ -211,7 +211,8 @@ std::vector LBFluid::get_average_pressure_tensor() const { } Variant LBFluid::get_interpolated_velocity(Utils::Vector3d const &pos) const { - auto const lb_pos = folded_position(pos, box_geo) * m_conv_dist; + auto const &box_geo = *::System::get_system().box_geo; + auto const lb_pos = box_geo.folded_position(pos) * m_conv_dist; auto const result = m_instance->get_velocity_at_pos(lb_pos); return Utils::Mpi::reduce_optional(context()->get_comm(), result) / m_conv_speed; diff --git a/src/script_interface/walberla/LatticeWalberla.hpp b/src/script_interface/walberla/LatticeWalberla.hpp index c20fab5fffd..6c9c99a9de8 100644 --- a/src/script_interface/walberla/LatticeWalberla.hpp +++ b/src/script_interface/walberla/LatticeWalberla.hpp @@ -23,7 +23,9 @@ #ifdef WALBERLA -#include "core/grid.hpp" +#include "core/BoxGeometry.hpp" +#include "core/communication.hpp" +#include "core/system/System.hpp" #include @@ -55,8 +57,9 @@ class LatticeWalberla : public AutoParameters { } void do_construct(VariantMap const &args) override { + auto const &box_geo = *System::get_system().box_geo; m_agrid = get_value(args, "agrid"); - m_box_l = get_value_or(args, "_box_l", ::box_geo.length()); + m_box_l = get_value_or(args, "_box_l", box_geo.length()); auto const n_ghost_layers = get_value(args, "n_ghost_layers"); context()->parallel_try_catch([&]() { @@ -69,7 +72,8 @@ class LatticeWalberla : public AutoParameters { auto const grid_dim = ::LatticeWalberla::calc_grid_dimensions(m_box_l, m_agrid); m_lattice = std::make_shared<::LatticeWalberla>( - grid_dim, node_grid, static_cast(n_ghost_layers)); + grid_dim, ::communicator.node_grid, + static_cast(n_ghost_layers)); }); } diff --git a/testsuite/python/collision_detection.py b/testsuite/python/collision_detection.py index bd621630994..336e1debd48 100644 --- a/testsuite/python/collision_detection.py +++ b/testsuite/python/collision_detection.py @@ -35,10 +35,15 @@ class CollisionDetection(ut.TestCase): if espressomd.has_features("VIRTUAL_SITES_RELATIVE"): system.virtual_sites = espressomd.virtual_sites.VirtualSitesRelative() - H = espressomd.interactions.HarmonicBond(k=5000, r_0=0.1) - H2 = espressomd.interactions.HarmonicBond(k=25000, r_0=0.02) - system.bonded_inter.add(H) - system.bonded_inter.add(H2) + bond_center = espressomd.interactions.HarmonicBond(k=5000, r_0=0.1) + bond_vs = espressomd.interactions.HarmonicBond(k=25000, r_0=0.02) + bond_pair = espressomd.interactions.HarmonicBond(k=100, r_0=0.1) + bond_angle_vs = espressomd.interactions.AngleHarmonic( + bend=0., phi0=np.pi / 3.) + system.bonded_inter.add(bond_center) + system.bonded_inter.add(bond_vs) + system.bonded_inter.add(bond_pair) + system.bonded_inter.add(bond_angle_vs) time_step = 0.001 system.time_step = time_step system.cell_system.skin = 0.05 @@ -74,7 +79,7 @@ def test_bind_centers(self): # Check that it cannot be activated system.collision_detection.set_params( - mode="bind_centers", distance=0.11, bond_centers=self.H) + mode="bind_centers", distance=0.11, bond_centers=self.bond_center) self.get_state_set_state_consistency() system.integrator.run(1, recalc_forces=True) bond0 = ((system.bonded_inter[0], 1),) @@ -100,10 +105,10 @@ def run_test_bind_at_point_of_collision_for_pos(self, *positions): random.shuffle(positions) system.part.clear() # Place particle which should not take part in collisions - p = system.part.add(pos=(0.1, 0.3, 0)) + p = system.part.add(pos=(0.1, 0.3, 0.)) for pos in positions: - p1 = system.part.add(pos=pos + (0, 0, 0)) - p2 = system.part.add(pos=pos + (0.1, 0, 0)) + p1 = system.part.add(pos=pos + (0., 0., 0.)) + p2 = system.part.add(pos=pos + (0.1, 0., 0.)) assert system.distance(p1, p) >= 0.12 and system.distance( p2, p) >= 0.12, "Test particles too close to particle, which should not take part in collision" @@ -111,8 +116,8 @@ def run_test_bind_at_point_of_collision_for_pos(self, *positions): expected_np = 4 * len(positions) + 1 system.collision_detection.set_params( - mode="bind_at_point_of_collision", bond_centers=self.H, - bond_vs=self.H2, part_type_vs=1, vs_placement=0.4, distance=0.11) + mode="bind_at_point_of_collision", bond_centers=self.bond_center, + bond_vs=self.bond_vs, part_type_vs=1, vs_placement=0.4, distance=0.11) self.get_state_set_state_consistency() system.integrator.run(1, recalc_forces=True) self.verify_state_after_bind_at_poc(expected_np) @@ -129,6 +134,12 @@ def run_test_bind_at_point_of_collision_for_pos(self, *positions): self.verify_state_after_bind_at_poc(expected_np) def verify_state_after_bind_at_poc(self, expected_np): + if self.system.collision_detection.bond_vs == self.bond_angle_vs: + self.verify_state_after_bind_at_poc_triplet(expected_np) + else: + self.verify_state_after_bind_at_poc_pair(expected_np) + + def verify_state_after_bind_at_poc_pair(self, expected_np): system = self.system self.assertEqual(len(system.part), expected_np) @@ -147,7 +158,7 @@ def verify_state_after_bind_at_poc(self, expected_np): # Parse the bond self.assertEqual(len(p.bonds), 1) # Bond type - self.assertEqual(p.bonds[0][0], self.H2) + self.assertEqual(p.bonds[0][0], self.bond_vs) # get partner p2 = system.part.by_id(p.bonds[0][1]) # Is that really a vs @@ -156,9 +167,9 @@ def verify_state_after_bind_at_poc(self, expected_np): base_p1 = system.part.by_id(p.vs_relative[0]) base_p2 = system.part.by_id(p2.vs_relative[0]) # Take note of accounted-for particles - for _p in p, p2, base_p1, base_p2: + for _p in (p, p2, base_p1, base_p2): parts_not_accounted_for.remove(_p.id) - self.verify_bind_at_poc_pair(base_p1, base_p2, p, p2) + self.verify_bind_at_poc(base_p1, base_p2, p, p2) # Check particle that did not take part in collision. self.assertEqual(len(parts_not_accounted_for), 1) p = system.part.by_id(parts_not_accounted_for[0]) @@ -167,17 +178,71 @@ def verify_state_after_bind_at_poc(self, expected_np): parts_not_accounted_for.remove(p.id) self.assertEqual(parts_not_accounted_for, []) - def verify_bind_at_poc_pair(self, p1, p2, vs1, vs2): + def verify_state_after_bind_at_poc_triplet(self, expected_np): system = self.system - bond_p1 = ((system.bonded_inter[0], p2.id),) - bond_p2 = ((system.bonded_inter[0], p1.id),) - self.assertTrue(p1.bonds == bond_p1 or p2.bonds == bond_p2) + self.assertEqual(len(system.part), expected_np) + + # At the end of test, this list should be empty + parts_not_accounted_for = list(range(expected_np)) + + # We traverse particles. We look for a vs with a bond to find the other vs. + # From the two vs we find the two non-virtual particles + for p in system.part: + # Skip non-virtual + if not p.virtual: + continue + # Skip vs that doesn't have a bond + if p.bonds == (): + continue + if p.id == 1: + # Parse the bond + self.assertEqual(len(p.bonds), 2) + # Bond type + self.assertEqual(p.bonds[0][0], self.bond_pair) + self.assertEqual(p.bonds[1][0], self.bond_vs) + else: + # Parse the bond + self.assertEqual(len(p.bonds), 1) + # Bond type + self.assertEqual(p.bonds[0][0], self.bond_angle_vs) + # Is that really a vs + self.assertTrue(p.virtual) + # Get base particles + base_p1 = system.part.by_id(p.bonds[0][1]) + base_p2 = system.part.by_id(p.bonds[0][2]) + # Take note of accounted-for particles + for _p in (p, base_p1, base_p2): + if _p.id in parts_not_accounted_for: + parts_not_accounted_for.remove(_p.id) + self.verify_bind_at_poc(system.part.by_id(1), system.part.by_id(2), + system.part.by_id(3), system.part.by_id(4)) + # Check particle that did not take part in collision. + self.assertEqual(len(parts_not_accounted_for), 1) + p = system.part.by_id(parts_not_accounted_for[0]) + self.assertFalse(p.virtual) + self.assertEqual(p.bonds, ()) + parts_not_accounted_for.remove(p.id) + self.assertEqual(parts_not_accounted_for, []) + def verify_bind_at_poc(self, p1, p2, vs1, vs2): + system = self.system # Check for presence of vs # Check for bond between vs - bond_vs1 = ((system.bonded_inter[1], vs2.id),) - bond_vs2 = ((system.bonded_inter[1], vs1.id),) - self.assertTrue(vs1.bonds == bond_vs1 or vs2.bonds == bond_vs2) + if self.system.collision_detection.bond_vs == self.bond_angle_vs: + bond_p1 = ((self.bond_pair, p2.id), (self.bond_center, p2.id),) + bond_p2 = ((self.bond_pair, p1.id), (self.bond_center, p1.id),) + self.assertTrue(p1.bonds == bond_p1 or p2.bonds == bond_p2) + bond_vs1 = ((self.bond_angle_vs, p1.id, p2.id),) + bond_vs2 = ((self.bond_angle_vs, p2.id, p1.id),) + self.assertTrue(vs1.bonds == bond_vs1 or vs1.bonds == bond_vs2) + self.assertTrue(vs2.bonds == bond_vs1 or vs2.bonds == bond_vs2) + else: + bond_p1 = ((self.bond_center, p2.id),) + bond_p2 = ((self.bond_center, p1.id),) + self.assertTrue(p1.bonds == bond_p1 or p2.bonds == bond_p2) + bond_vs1 = ((self.bond_vs, vs2.id),) + bond_vs2 = ((self.bond_vs, vs1.id),) + self.assertTrue(vs1.bonds == bond_vs1 or vs2.bonds == bond_vs2) # Vs properties self.assertTrue(vs1.virtual) @@ -229,6 +294,42 @@ def test_bind_at_point_of_collision(self): self.run_test_bind_at_point_of_collision_for_pos( np.array((0.2, 0, 0)), np.array((0.95, 0, 0)), np.array((0.7, 0, 0))) + @utx.skipIfMissingFeatures("VIRTUAL_SITES_RELATIVE") + def test_bind_at_point_of_collision_triplet(self): + system = self.system + positions = [np.array((0, 0, 0))] + random.shuffle(positions) + system.part.clear() + # Place particle which should not take part in collisions + p = system.part.add(pos=(0.1, 0.3, 0.)) + for pos in positions: + p1 = system.part.add(pos=pos + (0., 0., 0.)) + p2 = system.part.add(pos=pos + (0.1, 0., 0.)) + p1.add_bond((self.bond_pair, p2)) + assert system.distance(p1, p) >= 0.12 and system.distance( + p2, p) >= 0.12, "Test particles too close to particle, which should not take part in collision" + + # 2 non-virtual + 2 virtual + one that doesn't take part + expected_np = 4 * len(positions) + 1 + + system.collision_detection.set_params( + mode="bind_at_point_of_collision", bond_centers=self.bond_center, + bond_vs=self.bond_angle_vs, part_type_vs=1, vs_placement=0.4, distance=0.11) + self.get_state_set_state_consistency() + system.integrator.run(1, recalc_forces=True) + self.verify_state_after_bind_at_poc(expected_np) + + # Integrate again and check that nothing has changed + system.integrator.run(1, recalc_forces=True) + self.verify_state_after_bind_at_poc(expected_np) + + # Check that nothing explodes when the particles are moved. + # In particular for parallel simulations + system.thermostat.set_langevin(kT=0, gamma=0.01, seed=42) + system.part.all().v = [0.05, 0.01, 0.15] + system.integrator.run(3000) + self.verify_state_after_bind_at_poc(expected_np) + @utx.skipIfMissingFeatures(["LENNARD_JONES", "VIRTUAL_SITES_RELATIVE"]) def test_bind_at_point_of_collision_random(self): """Integrate lj liquid and check that no double bonds are formed @@ -258,8 +359,8 @@ def test_bind_at_point_of_collision_random(self): system.collision_detection.set_params( mode="bind_at_point_of_collision", distance=0.11, - bond_centers=self.H, - bond_vs=self.H2, + bond_centers=self.bond_center, + bond_vs=self.bond_vs, part_type_vs=1, vs_placement=0.4) self.get_state_set_state_consistency() @@ -338,8 +439,8 @@ def run_test_glue_to_surface_for_pos(self, *positions): system.collision_detection.set_params( mode="glue_to_surface", distance=0.11, - distance_glued_particle_to_vs=0.02, bond_centers=self.H, - bond_vs=self.H2, part_type_vs=self.part_type_vs, + distance_glued_particle_to_vs=0.02, bond_centers=self.bond_center, + bond_vs=self.bond_vs, part_type_vs=self.part_type_vs, part_type_to_attach_vs_to=self.part_type_to_attach_vs_to, part_type_to_be_glued=self.part_type_to_be_glued, part_type_after_glueing=self.part_type_after_glueing) @@ -383,7 +484,7 @@ def verify_state_after_glue_to_surface(self, expected_np): # 1. On the base particle of the vs p2 = None if len(base_p.bonds) == 1: - self.assertEqual(base_p.bonds[0][0], self.H) + self.assertEqual(base_p.bonds[0][0], self.bond_center) p2 = system.part.by_id(base_p.bonds[0][1]) else: # We need to go through all particles to find it @@ -392,7 +493,7 @@ def verify_state_after_glue_to_surface(self, expected_np): continue if len(candidate.bonds) >= 1: for b in candidate.bonds: - if b[0] == self.H and b[1] == base_p.id: + if b[0] == self.bond_center and b[1] == base_p.id: p2 = candidate assert p2 is not None, "Bound particle not found" # Take note of accounted-for particles @@ -420,9 +521,9 @@ def verify_glue_to_surface_pair(self, base_p, vs, bound_p): # to the base particle bond_to_vs_found = 0 for b in bound_p.bonds: - if b[0] == self.H2: + if b[0] == self.bond_vs: # bond to vs - self.assertEqual(b, (self.H2, vs.id)) + self.assertEqual(b, (self.bond_vs, vs.id)) bond_to_vs_found += 1 self.assertEqual(bond_to_vs_found, 1) # Vs should not have a bond @@ -494,8 +595,8 @@ def test_glue_to_surface_random(self): # Collision detection system.collision_detection.set_params( mode="glue_to_surface", distance=0.11, - distance_glued_particle_to_vs=0.02, bond_centers=self.H, - bond_vs=self.H2, part_type_vs=self.part_type_vs, + distance_glued_particle_to_vs=0.02, bond_centers=self.bond_center, + bond_vs=self.bond_vs, part_type_vs=self.part_type_vs, part_type_to_attach_vs_to=self.part_type_to_attach_vs_to, part_type_to_be_glued=self.part_type_to_be_glued, part_type_after_glueing=self.part_type_after_glueing) @@ -536,9 +637,9 @@ def test_glue_to_surface_random(self): allowed_types, msg=f"Particle {p.id} of type {p.type} should not have bonds, yet has {p.bonds}.") if p.type == self.part_type_after_glueing: - self.assertIn(bond[0], (self.H, self.H2)) + self.assertIn(bond[0], (self.bond_center, self.bond_vs)) # Bonds to virtual sites: - if bond[0] == self.H2: + if bond[0] == self.bond_vs: self.assertEqual( system.part.by_id(bond[1]).type, self.part_type_vs) @@ -547,7 +648,7 @@ def test_glue_to_surface_random(self): system.part.by_id(bond[1]).type, self.part_type_to_attach_vs_to) elif p.type == self.part_type_to_attach_vs_to: - self.assertEqual(bond[0], self.H) + self.assertEqual(bond[0], self.bond_center) self.assertEqual( system.part.by_id(bond[1]).type, self.part_type_after_glueing) @@ -555,7 +656,7 @@ def test_glue_to_surface_random(self): # Collect bonds # Sort bond partners to make them unique independently of # which particle got the bond - if bond[0] == self.H: + if bond[0] == self.bond_center: bonds_centers.append(tuple(sorted([p.id, bond[1]]))) else: bonds_virtual.append(tuple(sorted([p.id, bond[1]]))) @@ -600,20 +701,20 @@ def test_bind_three_particles(self): # Setup bonds res = 181 for i in range(res): - system.bonded_inter[i + 2] = espressomd.interactions.AngleHarmonic( + system.bonded_inter[i + 4] = espressomd.interactions.AngleHarmonic( bend=1, phi0=float(i) / (res - 1) * np.pi) cutoff = 0.11 system.collision_detection.set_params( - mode="bind_three_particles", bond_centers=self.H, - bond_three_particles=2, three_particle_binding_angle_resolution=res, distance=cutoff) + mode="bind_three_particles", bond_centers=self.bond_center, + bond_three_particles=4, three_particle_binding_angle_resolution=res, distance=cutoff) self.get_state_set_state_consistency() system.time_step = 1E-6 system.integrator.run(1, recalc_forces=True) - self.verify_triangle_binding(cutoff, system.bonded_inter[2], res) + self.verify_triangle_binding(cutoff, system.bonded_inter[4], res) # Make sure no extra bonds appear system.integrator.run(1, recalc_forces=True) - self.verify_triangle_binding(cutoff, system.bonded_inter[2], res) + self.verify_triangle_binding(cutoff, system.bonded_inter[4], res) # Place the particles in two steps and make sure, the bonds are the # same @@ -627,11 +728,11 @@ def test_bind_three_particles(self): system.part.add(id=1, pos=b) system.cell_system.set_regular_decomposition() system.integrator.run(1, recalc_forces=True) - self.verify_triangle_binding(cutoff, system.bonded_inter[2], res) + self.verify_triangle_binding(cutoff, system.bonded_inter[4], res) system.cell_system.set_n_square() system.part.all().bonds = () system.integrator.run(1, recalc_forces=True) - self.verify_triangle_binding(cutoff, system.bonded_inter[2], res) + self.verify_triangle_binding(cutoff, system.bonded_inter[4], res) system.time_step = self.time_step def verify_triangle_binding(self, distance, first_bond, angle_res): @@ -693,7 +794,7 @@ def verify_triangle_binding(self, distance, first_bond, angle_res): self.assertIn( len(b), (2, 3), msg="There should only be 2- and 3-particle bonds") if len(b) == 2: - self.assertEqual(b[0]._bond_id, self.H._bond_id) + self.assertEqual(b[0]._bond_id, self.bond_center._bond_id) found_pairs.append(tuple(sorted((i, b[1])))) elif len(b) == 3: partners = sorted(b[1:]) diff --git a/testsuite/python/interactions_bond_angle.py b/testsuite/python/interactions_bond_angle.py index b21d3043bca..ff94dad18f4 100644 --- a/testsuite/python/interactions_bond_angle.py +++ b/testsuite/python/interactions_bond_angle.py @@ -93,17 +93,18 @@ def run_test(self, bond_instance, force_func, energy_func, phi0): d_phi = np.pi / self.N for i in range(1, self.N): # avoid corner cases at phi = 0 or phi = pi + phi = i * d_phi self.p2.pos = self.start_pos + \ - self.rotate_vector(self.rel_pos, self.axis, i * d_phi) + self.rotate_vector(self.rel_pos, self.axis, phi) self.system.integrator.run(recalc_forces=True, steps=0) # Calculate energies E_sim = self.system.analysis.energy()["bonded"] - E_ref = energy_func(i * d_phi) + E_ref = energy_func(phi) # Check that energies match np.testing.assert_almost_equal(E_sim, E_ref, decimal=4) - f_ref = force_func(i * d_phi) + f_ref = force_func(phi) phi_diff = i * d_phi - phi0 for p, sign in [[self.p1, -1], [self.p2, +1]]: # Check that force is perpendicular @@ -123,6 +124,18 @@ def run_test(self, bond_instance, force_func, energy_func, phi0): np.sign(sign * np.dot(force_axis, self.axis)), msg="The force moves particles in the wrong direction") + # Check that force vectors are correct + v1 = np.copy(self.system.distance_vec(self.p1, self.p0)) + v2 = np.copy(self.system.distance_vec(self.p2, self.p0)) + d1 = np.linalg.norm(v1) + d2 = np.linalg.norm(v2) + v1 /= d1 + v2 /= d2 + ref_f1 = (f_ref / d1 / np.sin(phi)) * (v1 * np.cos(phi) - v2) + ref_f2 = (f_ref / d2 / np.sin(phi)) * (v2 * np.cos(phi) - v1) + np.testing.assert_allclose(np.copy(self.p1.f), ref_f1, atol=1E-8) + np.testing.assert_allclose(np.copy(self.p2.f), ref_f2, atol=1E-8) + # Total force =0? np.testing.assert_allclose( np.sum(np.copy(self.system.part.all().f), 0), [0, 0, 0], atol=1E-12) diff --git a/testsuite/scripts/samples/test_electrophoresis.py b/testsuite/scripts/samples/test_electrophoresis.py index c8a2e79dea3..b057a843dc5 100644 --- a/testsuite/scripts/samples/test_electrophoresis.py +++ b/testsuite/scripts/samples/test_electrophoresis.py @@ -19,28 +19,12 @@ import importlib_wrapper import numpy as np - -def set_seed(code): - np_seed = "np.random.seed()" - assert np_seed in code - return code.replace(np_seed, "np.random.seed(42)") - - -def set_p3m_params(code): - p3m = "electrostatics.P3M(prefactor=1.0, accuracy=1e-2)" - assert p3m in code - return code.replace( - p3m, "electrostatics.P3M(prefactor=1, mesh=[16, 16, 16], cao=1, accuracy=1e-2, r_cut=3.7, alpha=0.2, tune=False)") - - -def make_deterministic(code): - code = set_seed(code) - code = set_p3m_params(code) - return code - +np.random.seed(seed=42) sample, skipIfMissingFeatures = importlib_wrapper.configure_and_import( - "@SAMPLES_DIR@/electrophoresis.py", N_SAMPLES=400, substitutions=make_deterministic) + "@SAMPLES_DIR@/electrophoresis.py", N_SAMPLES=400, + p3m_params={"prefactor": 1., "mesh": [14, 14, 14], "cao": 1, "tune": False, + "accuracy": 1e-2, "r_cut": 5.3, "alpha": 0.16}) @skipIfMissingFeatures @@ -51,7 +35,7 @@ def test_persistence_length(self): # These two values differ due to undersampling, they converge # to the same value around N_SAMPLES=1000 self.assertAlmostEqual(sample.persistence_length, 38.2, delta=1) - self.assertAlmostEqual(sample.persistence_length_obs, 48.3, delta=1) + self.assertAlmostEqual(sample.persistence_length_obs, 48.6, delta=1) def test_mobility(self): self.assertAlmostEqual(sample.mu, 1.05, delta=0.02)