diff --git a/doc/sphinx/analysis.rst b/doc/sphinx/analysis.rst
index 2fdb4576f1c..e30e32f8687 100644
--- a/doc/sphinx/analysis.rst
+++ b/doc/sphinx/analysis.rst
@@ -787,7 +787,7 @@ To obtain the cluster structure of a system, an instance of
To to create a cluster structure with above criterion::
import espressomd.cluster_analysis
- cs = espressomd.cluster_analysis.ClusterStructure(distance_criterion=dc)
+ cs = espressomd.cluster_analysis.ClusterStructure(distance_criterion=dc, system=system)
In most cases, the cluster analysis is carried out by calling the
:any:`espressomd.cluster_analysis.ClusterStructure.run_for_all_pairs` method.
diff --git a/doc/sphinx/io.rst b/doc/sphinx/io.rst
index 1e8a0fbb11a..e47388753c8 100644
--- a/doc/sphinx/io.rst
+++ b/doc/sphinx/io.rst
@@ -337,7 +337,7 @@ capabilities. The usage is quite simple:
import espressomd.io
system = espressomd.System(box_l=[1, 1, 1])
# ... add particles here
- mpiio = espressomd.io.mpiio.Mpiio()
+ mpiio = espressomd.io.mpiio.Mpiio(system=system)
mpiio.write("/tmp/mydata", positions=True, velocities=True, types=True, bonds=True)
Here, :file:`/tmp/mydata` is the prefix used to generate several files.
diff --git a/doc/tutorials/ferrofluid/ferrofluid_part1.ipynb b/doc/tutorials/ferrofluid/ferrofluid_part1.ipynb
index 82b8012552a..d65111cce28 100644
--- a/doc/tutorials/ferrofluid/ferrofluid_part1.ipynb
+++ b/doc/tutorials/ferrofluid/ferrofluid_part1.ipynb
@@ -802,7 +802,9 @@
"source": [
"# SOLUTION CELL\n",
"# Setup cluster analysis\n",
- "cluster_structure = espressomd.cluster_analysis.ClusterStructure(pair_criterion=espressomd.pair_criteria.DistanceCriterion(cut_off=1.3 * LJ_SIGMA))"
+ "cluster_structure = espressomd.cluster_analysis.ClusterStructure(\n",
+ " system=system,\n",
+ " pair_criterion=espressomd.pair_criteria.DistanceCriterion(cut_off=1.3 * LJ_SIGMA))"
]
},
{
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 0e7b82024d1..ce441674492 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -21,18 +21,15 @@
add_library(
espresso_core SHARED
- accumulators.cpp
bond_error.cpp
cells.cpp
collision.cpp
communication.cpp
- constraints.cpp
dpd.cpp
energy.cpp
errorhandling.cpp
forces.cpp
ghosts.cpp
- immersed_boundaries.cpp
integrate.cpp
npt.cpp
particle_node.cpp
diff --git a/src/core/accumulators.cpp b/src/core/accumulators.cpp
deleted file mode 100644
index db1bcee9a5f..00000000000
--- a/src/core/accumulators.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2016-2022 The ESPResSo project
- *
- * 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 .
- */
-#include "accumulators.hpp"
-
-#include
-
-#include
-#include
-#include
-#include
-
-namespace Accumulators {
-namespace {
-struct AutoUpdateAccumulator {
- explicit AutoUpdateAccumulator(AccumulatorBase *acc)
- : frequency(acc->delta_N()), counter(1), acc(acc) {}
- int frequency;
- int counter;
- AccumulatorBase *acc;
-};
-
-std::vector auto_update_accumulators;
-} // namespace
-
-void auto_update(boost::mpi::communicator const &comm, int steps) {
- for (auto &acc : auto_update_accumulators) {
- assert(steps <= acc.frequency);
- acc.counter -= steps;
- if (acc.counter <= 0) {
- acc.acc->update(comm);
- acc.counter = acc.frequency;
- }
-
- assert(acc.counter > 0);
- }
-}
-
-int auto_update_next_update() {
- return boost::accumulate(auto_update_accumulators,
- std::numeric_limits::max(),
- [](int a, AutoUpdateAccumulator const &acc) {
- return std::min(a, acc.counter);
- });
-}
-
-namespace detail {
-struct MatchPredicate {
- AccumulatorBase const *m_acc;
- template bool operator()(T const &a) const {
- return a.acc == m_acc;
- }
-};
-} // namespace detail
-
-void auto_update_add(AccumulatorBase *acc) {
- assert(not auto_update_contains(acc));
- auto_update_accumulators.emplace_back(acc);
-}
-
-void auto_update_remove(AccumulatorBase *acc) {
- assert(auto_update_contains(acc));
- std::erase_if(auto_update_accumulators, detail::MatchPredicate{acc});
-}
-
-bool auto_update_contains(AccumulatorBase const *acc) noexcept {
- assert(acc);
- return std::ranges::any_of(auto_update_accumulators,
- detail::MatchPredicate{acc});
-}
-
-} // namespace Accumulators
diff --git a/src/core/accumulators.hpp b/src/core/accumulators.hpp
deleted file mode 100644
index bc8199b05d6..00000000000
--- a/src/core/accumulators.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016-2022 The ESPResSo project
- *
- * 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 ESPRESSO_ACCUMULATORS_HPP
-#define ESPRESSO_ACCUMULATORS_HPP
-
-#include "accumulators/AccumulatorBase.hpp"
-
-namespace Accumulators {
-/**
- * @brief Update accumulators.
- *
- * Checks for all auto update accumulators if
- * they need to be updated and if so does.
- *
- */
-void auto_update(boost::mpi::communicator const &comm, int steps);
-int auto_update_next_update();
-bool auto_update_contains(AccumulatorBase const *) noexcept;
-void auto_update_add(AccumulatorBase *);
-void auto_update_remove(AccumulatorBase *);
-
-} // namespace Accumulators
-
-#endif // ESPRESSO_ACCUMULATORS_HPP
diff --git a/src/core/accumulators/AccumulatorBase.hpp b/src/core/accumulators/AccumulatorBase.hpp
index 7bf17d4a799..98a01deff82 100644
--- a/src/core/accumulators/AccumulatorBase.hpp
+++ b/src/core/accumulators/AccumulatorBase.hpp
@@ -16,34 +16,50 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifndef CORE_ACCUMULATORS_ACCUMULATOR_BASE_HPP
-#define CORE_ACCUMULATORS_ACCUMULATOR_BASE_HPP
+#pragma once
+
+#include
#include
+#include
#include
-// Forward declaration
+// Forward declarations
namespace boost::mpi {
class communicator;
}
+namespace System {
+class System;
+}
namespace Accumulators {
class AccumulatorBase {
public:
- explicit AccumulatorBase(int delta_N = 1) : m_delta_N(delta_N) {}
+ AccumulatorBase(::System::System const *system, int delta_N)
+ : m_system(reinterpret_cast(system)), m_delta_N(delta_N) {}
virtual ~AccumulatorBase() = default;
int &delta_N() { return m_delta_N; }
+ bool has_same_system_handle(::System::System const *system) const {
+ return reinterpret_cast(system) == m_system;
+ }
+ void override_system_handle(::System::System const *system) {
+ assert(m_system == nullptr);
+ m_system = reinterpret_cast(system);
+ }
virtual void update(boost::mpi::communicator const &comm) = 0;
/** Dimensions needed to reshape the flat array returned by the accumulator */
virtual std::vector shape() const = 0;
+ /** Serialization of private members. */
+ virtual std::string get_internal_state() const = 0;
+ virtual void set_internal_state(std::string const &) = 0;
+protected:
+ void const *m_system; ///< for bookkeeping purposes
private:
- // Number of timesteps between automatic updates.
+ /// Number of time steps between automatic updates.
int m_delta_N;
};
} // namespace Accumulators
-
-#endif
diff --git a/src/core/accumulators/AutoUpdateAccumulators.cpp b/src/core/accumulators/AutoUpdateAccumulators.cpp
new file mode 100644
index 00000000000..8151b25e161
--- /dev/null
+++ b/src/core/accumulators/AutoUpdateAccumulators.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016-2024 The ESPResSo project
+ *
+ * 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 .
+ */
+
+#include "AutoUpdateAccumulators.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+namespace Accumulators {
+
+void AutoUpdateAccumulators::operator()(boost::mpi::communicator const &comm,
+ int steps) {
+ for (auto &acc : m_accumulators) {
+ assert(steps <= acc.frequency);
+ acc.counter -= steps;
+ if (acc.counter <= 0) {
+ acc.acc->update(comm);
+ acc.counter = acc.frequency;
+ }
+
+ assert(acc.counter > 0);
+ }
+}
+
+int AutoUpdateAccumulators::next_update() const {
+ return std::accumulate(m_accumulators.begin(), m_accumulators.end(),
+ std::numeric_limits::max(),
+ [](int a, AutoUpdateAccumulator const &acc) {
+ return std::min(a, acc.counter);
+ });
+}
+
+namespace detail {
+struct MatchPredicate {
+ AccumulatorBase const *m_acc;
+ template bool operator()(T const &a) const {
+ return a.acc == m_acc;
+ }
+};
+} // namespace detail
+
+void AutoUpdateAccumulators::add(AccumulatorBase *acc) {
+ assert(not contains(acc));
+ auto const *this_system = &get_system();
+ if (acc->has_same_system_handle(nullptr)) {
+ acc->override_system_handle(this_system);
+ } else if (not acc->has_same_system_handle(this_system)) {
+ throw std::runtime_error("This accumulator is bound to another system");
+ }
+ m_accumulators.emplace_back(acc);
+}
+
+void AutoUpdateAccumulators::remove(AccumulatorBase *acc) {
+ assert(contains(acc));
+ std::erase_if(m_accumulators, detail::MatchPredicate{acc});
+}
+
+bool AutoUpdateAccumulators::contains(AccumulatorBase const *acc) const {
+ assert(acc);
+ return std::ranges::any_of(m_accumulators, detail::MatchPredicate{acc});
+}
+
+} // namespace Accumulators
diff --git a/src/core/accumulators/AutoUpdateAccumulators.hpp b/src/core/accumulators/AutoUpdateAccumulators.hpp
new file mode 100644
index 00000000000..f41556def9b
--- /dev/null
+++ b/src/core/accumulators/AutoUpdateAccumulators.hpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016-2024 The ESPResSo project
+ *
+ * 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 .
+ */
+
+#pragma once
+
+#include "AccumulatorBase.hpp"
+
+#include "system/Leaf.hpp"
+
+namespace Accumulators {
+
+class AutoUpdateAccumulators : public System::Leaf {
+public:
+ /**
+ * @brief Update accumulators.
+ *
+ * Checks for all auto update accumulators if
+ * they need to be updated and if so does.
+ *
+ */
+ void operator()(boost::mpi::communicator const &comm, int steps);
+ int next_update() const;
+ bool contains(AccumulatorBase const *) const;
+ void add(AccumulatorBase *);
+ void remove(AccumulatorBase *);
+
+private:
+ struct AutoUpdateAccumulator {
+ explicit AutoUpdateAccumulator(AccumulatorBase *acc)
+ : frequency(acc->delta_N()), counter(1), acc(acc) {}
+ int frequency;
+ int counter;
+ AccumulatorBase *acc;
+ };
+
+ std::vector m_accumulators;
+};
+
+} // namespace Accumulators
diff --git a/src/core/accumulators/CMakeLists.txt b/src/core/accumulators/CMakeLists.txt
index 8dee6ffcc1f..2fe79a3e220 100644
--- a/src/core/accumulators/CMakeLists.txt
+++ b/src/core/accumulators/CMakeLists.txt
@@ -20,5 +20,6 @@
target_sources(
espresso_core
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Correlator.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/AutoUpdateAccumulators.cpp
${CMAKE_CURRENT_SOURCE_DIR}/MeanVarianceCalculator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TimeSeries.cpp)
diff --git a/src/core/accumulators/Correlator.cpp b/src/core/accumulators/Correlator.cpp
index 430b8656805..1be32a7d31d 100644
--- a/src/core/accumulators/Correlator.cpp
+++ b/src/core/accumulators/Correlator.cpp
@@ -163,13 +163,12 @@ std::vector fcs_acf(std::vector const &A,
return C;
}
-void Correlator::initialize() {
+void Correlator::initialize_operations() {
// Class members are assigned via the initializer list
if (m_tau_lin == 1) { // use the default
- m_tau_lin = static_cast(ceil(m_tau_max / m_dt));
- if (m_tau_lin % 2)
- m_tau_lin += 1;
+ m_tau_lin = static_cast(std::ceil(m_tau_max / m_dt));
+ m_tau_lin += m_tau_lin % 2;
}
if (m_tau_lin < 2) {
@@ -187,8 +186,9 @@ void Correlator::initialize() {
if ((m_tau_max / m_dt) < m_tau_lin) {
m_hierarchy_depth = 1;
} else {
- m_hierarchy_depth = static_cast(
- ceil(1 + log((m_tau_max / m_dt) / (m_tau_lin - 1)) / log(2.0)));
+ auto const operand = (m_tau_max / m_dt) / double(m_tau_lin - 1);
+ assert(operand > 0.);
+ m_hierarchy_depth = static_cast(std::ceil(1. + std::log2(operand)));
}
assert(A_obs);
@@ -224,12 +224,11 @@ void Correlator::initialize() {
} else if (corr_operation_name == "fcs_acf") {
// note: user provides w=(wx,wy,wz) but we want to use
// wsquare=(wx^2,wy^2,wz^2)
- if (m_correlation_args[0] <= 0 || m_correlation_args[1] <= 0 ||
- m_correlation_args[2] <= 0) {
+ if (not(m_correlation_args_input > Utils::Vector3d::broadcast(0.))) {
throw std::runtime_error("missing parameter for fcs_acf: w_x w_y w_z");
}
- m_correlation_args =
- Utils::hadamard_product(m_correlation_args, m_correlation_args);
+ m_correlation_args = Utils::hadamard_product(m_correlation_args_input,
+ m_correlation_args_input);
if (dim_A % 3u)
throw std::runtime_error("dimA must be divisible by 3 for fcs_acf");
m_dim_corr = dim_A / 3u;
@@ -272,7 +271,9 @@ void Correlator::initialize() {
throw std::invalid_argument("unknown compression method '" +
compressB_name + "' for second observable");
}
+}
+void Correlator::initialize_buffers() {
using index_type = decltype(result)::index;
A.resize(std::array{{m_hierarchy_depth, m_tau_lin + 1}});
@@ -536,7 +537,9 @@ std::string Correlator::get_internal_state() const {
boost::archive::binary_oarchive oa(ss);
oa << t;
+ oa << m_dt;
oa << m_shape;
+ oa << m_correlation_args_input;
oa << A;
oa << B;
oa << result;
@@ -557,7 +560,9 @@ void Correlator::set_internal_state(std::string const &state) {
boost::archive::binary_iarchive ia(ss);
ia >> t;
+ ia >> m_dt;
ia >> m_shape;
+ ia >> m_correlation_args_input;
ia >> A;
ia >> B;
ia >> result;
@@ -567,6 +572,8 @@ void Correlator::set_internal_state(std::string const &state) {
ia >> A_accumulated_average;
ia >> B_accumulated_average;
ia >> n_data;
+ initialize_operations();
+ m_system = nullptr;
}
} // namespace Accumulators
diff --git a/src/core/accumulators/Correlator.hpp b/src/core/accumulators/Correlator.hpp
index e60fa27d40b..6d0047c65f2 100644
--- a/src/core/accumulators/Correlator.hpp
+++ b/src/core/accumulators/Correlator.hpp
@@ -16,8 +16,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifndef CORE_ACCUMULATORS_CORRELATOR_HPP
-#define CORE_ACCUMULATORS_CORRELATOR_HPP
+
+#pragma once
+
/** @file
*
* This module computes correlations (and other two time averages) on
@@ -128,6 +129,12 @@ namespace Accumulators {
*/
class Correlator : public AccumulatorBase {
using obs_ptr = std::shared_ptr;
+ void initialize_operations();
+ void initialize_buffers();
+ void initialize() {
+ initialize_operations();
+ initialize_buffers();
+ }
public:
/** The initialization procedure for the correlation object. All important
@@ -135,6 +142,7 @@ class Correlator : public AccumulatorBase {
* later, so every instance of the correlation class has to be fed with
* correct data from the very beginning.
*
+ * @param system The system attached to this correlator
* @param delta_N The number of time steps between subsequent updates
* @param tau_lin The linear part of the correlation function.
* @param tau_max maximal time delay tau to sample
@@ -150,23 +158,21 @@ class Correlator : public AccumulatorBase {
* (currently only used when @p corr_operation is "fcs_acf")
*
*/
- Correlator(int tau_lin, double tau_max, int delta_N, std::string compress1_,
- std::string compress2_, std::string corr_operation, obs_ptr obs1,
- obs_ptr obs2, Utils::Vector3d correlation_args_ = {})
- : AccumulatorBase(delta_N), finalized(false), t(0),
+ Correlator(::System::System const *system, int delta_N, int tau_lin,
+ double tau_max, std::string compress1_, std::string compress2_,
+ std::string corr_operation, obs_ptr obs1, obs_ptr obs2,
+ Utils::Vector3d correlation_args_ = {})
+ : AccumulatorBase(system, delta_N), finalized(false), t(0),
+ m_correlation_args_input(correlation_args_),
m_correlation_args(correlation_args_), m_tau_lin(tau_lin),
- m_dt(::System::get_system().get_time_step()), m_tau_max(tau_max),
- compressA_name(std::move(compress1_)),
+ m_dt(system->get_time_step() * static_cast(delta_N)),
+ m_tau_max(tau_max), compressA_name(std::move(compress1_)),
compressB_name(std::move(compress2_)),
corr_operation_name(std::move(corr_operation)), A_obs(std::move(obs1)),
B_obs(std::move(obs2)) {
- m_dt *= static_cast(delta_N);
initialize();
}
-private:
- void initialize();
-
public:
/** The function to process a new datapoint of A and B
*
@@ -215,15 +221,14 @@ class Correlator : public AccumulatorBase {
return corr_operation_name;
}
- /** Partial serialization of state that is not accessible via the interface.
- */
- std::string get_internal_state() const;
- void set_internal_state(std::string const &);
+ std::string get_internal_state() const final;
+ void set_internal_state(std::string const &) final;
private:
bool finalized; ///< whether the correlation is finalized
unsigned int t; ///< global time in number of frames
+ Utils::Vector3d m_correlation_args_input;
Utils::Vector3d m_correlation_args; ///< additional arguments, which the
///< correlation may need (currently
///< only used by fcs_acf)
@@ -280,4 +285,3 @@ class Correlator : public AccumulatorBase {
};
} // namespace Accumulators
-#endif
diff --git a/src/core/accumulators/MeanVarianceCalculator.cpp b/src/core/accumulators/MeanVarianceCalculator.cpp
index 06373928ed7..0e67276be11 100644
--- a/src/core/accumulators/MeanVarianceCalculator.cpp
+++ b/src/core/accumulators/MeanVarianceCalculator.cpp
@@ -66,5 +66,6 @@ void MeanVarianceCalculator::set_internal_state(std::string const &state) {
boost::archive::binary_iarchive ia(ss);
ia >> m_acc;
+ m_system = nullptr;
}
} // namespace Accumulators
diff --git a/src/core/accumulators/MeanVarianceCalculator.hpp b/src/core/accumulators/MeanVarianceCalculator.hpp
index f2aa5ec6852..f8fa39f0664 100644
--- a/src/core/accumulators/MeanVarianceCalculator.hpp
+++ b/src/core/accumulators/MeanVarianceCalculator.hpp
@@ -16,11 +16,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifndef CORE_ACCUMULATORS_MEAN_VARIANCE_CALCULATOR_HPP
-#define CORE_ACCUMULATORS_MEAN_VARIANCE_CALCULATOR_HPP
+
+#pragma once
#include "AccumulatorBase.hpp"
#include "observables/Observable.hpp"
+
#include
#include
@@ -34,25 +35,21 @@ class MeanVarianceCalculator : public AccumulatorBase {
public:
// The accumulator struct has to be initialized with the correct vector size,
// therefore the order of init is important.
- MeanVarianceCalculator(std::shared_ptr obs,
- int delta_N)
- : AccumulatorBase(delta_N), m_obs(obs), m_acc(obs->n_values()) {}
+ MeanVarianceCalculator(::System::System const *system, int delta_N,
+ std::shared_ptr obs)
+ : AccumulatorBase(system, delta_N), m_obs(obs), m_acc(obs->n_values()) {}
void update(boost::mpi::communicator const &comm) override;
std::vector mean();
std::vector variance();
std::vector std_error();
- /* Partial serialization of state that is not accessible
- via the interface. */
- std::string get_internal_state() const;
- void set_internal_state(std::string const &);
+ std::string get_internal_state() const final;
+ void set_internal_state(std::string const &) final;
std::vector shape() const override { return m_obs->shape(); }
private:
std::shared_ptr m_obs;
- ::Utils::Accumulator m_acc;
+ Utils::Accumulator m_acc;
};
} // namespace Accumulators
-
-#endif
diff --git a/src/core/accumulators/TimeSeries.cpp b/src/core/accumulators/TimeSeries.cpp
index 206b6a0160d..14d32ff9794 100644
--- a/src/core/accumulators/TimeSeries.cpp
+++ b/src/core/accumulators/TimeSeries.cpp
@@ -52,5 +52,6 @@ void TimeSeries::set_internal_state(std::string const &state) {
boost::archive::binary_iarchive ia(ss);
ia >> m_data;
+ m_system = nullptr;
}
} // namespace Accumulators
diff --git a/src/core/accumulators/TimeSeries.hpp b/src/core/accumulators/TimeSeries.hpp
index e7d78c49de6..ce1906fb23f 100644
--- a/src/core/accumulators/TimeSeries.hpp
+++ b/src/core/accumulators/TimeSeries.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 CORE_ACCUMULATORS_TIMESERIES_HPP
-#define CORE_ACCUMULATORS_TIMESERIES_HPP
+
+#pragma once
#include "AccumulatorBase.hpp"
#include "observables/Observable.hpp"
@@ -40,12 +40,13 @@ namespace Accumulators {
*/
class TimeSeries : public AccumulatorBase {
public:
- TimeSeries(std::shared_ptr obs, int delta_N)
- : AccumulatorBase(delta_N), m_obs(std::move(obs)) {}
+ TimeSeries(::System::System const *system, int delta_N,
+ std::shared_ptr obs)
+ : AccumulatorBase(system, delta_N), m_obs(std::move(obs)) {}
void update(boost::mpi::communicator const &comm) override;
- std::string get_internal_state() const;
- void set_internal_state(std::string const &);
+ std::string get_internal_state() const final;
+ void set_internal_state(std::string const &) final;
const std::vector> &time_series() const { return m_data; }
std::vector shape() const override {
@@ -62,5 +63,3 @@ class TimeSeries : public AccumulatorBase {
};
} // namespace Accumulators
-
-#endif
diff --git a/src/core/bonded_interactions/angle_cosine.hpp b/src/core/bonded_interactions/angle_cosine.hpp
index 681e7388a94..7df19c90afa 100644
--- a/src/core/bonded_interactions/angle_cosine.hpp
+++ b/src/core/bonded_interactions/angle_cosine.hpp
@@ -61,16 +61,6 @@ struct AngleCosineBond {
std::tuple
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;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & bend;
- ar & phi0;
- ar & cos_phi0;
- ar & sin_phi0;
- }
};
/** Compute the three-body angle interaction force.
diff --git a/src/core/bonded_interactions/angle_cossquare.hpp b/src/core/bonded_interactions/angle_cossquare.hpp
index 0b1a45136d4..5cf0b1f666b 100644
--- a/src/core/bonded_interactions/angle_cossquare.hpp
+++ b/src/core/bonded_interactions/angle_cossquare.hpp
@@ -57,15 +57,6 @@ struct AngleCossquareBond {
std::tuple
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;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & bend;
- ar & phi0;
- ar & cos_phi0;
- }
};
/** Compute the three-body angle interaction force.
diff --git a/src/core/bonded_interactions/angle_harmonic.hpp b/src/core/bonded_interactions/angle_harmonic.hpp
index 5aa1d77e04d..fd97b0ccf14 100644
--- a/src/core/bonded_interactions/angle_harmonic.hpp
+++ b/src/core/bonded_interactions/angle_harmonic.hpp
@@ -54,14 +54,6 @@ struct AngleHarmonicBond {
std::tuple
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;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & bend;
- ar & phi0;
- }
};
/** Compute the three-body angle interaction force.
diff --git a/src/core/bonded_interactions/bonded_coulomb.hpp b/src/core/bonded_interactions/bonded_coulomb.hpp
index bb51b8483c1..bb854ab4e63 100644
--- a/src/core/bonded_interactions/bonded_coulomb.hpp
+++ b/src/core/bonded_interactions/bonded_coulomb.hpp
@@ -47,13 +47,6 @@ struct BondedCoulomb {
std::optional force(double q1q2,
Utils::Vector3d const &dx) const;
std::optional energy(double q1q2, Utils::Vector3d const &dx) const;
-
-private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & prefactor;
- }
};
/** Compute the bonded Coulomb pair force.
diff --git a/src/core/bonded_interactions/bonded_coulomb_sr.hpp b/src/core/bonded_interactions/bonded_coulomb_sr.hpp
index fa7fbb8e3b2..11fdd606b28 100644
--- a/src/core/bonded_interactions/bonded_coulomb_sr.hpp
+++ b/src/core/bonded_interactions/bonded_coulomb_sr.hpp
@@ -57,13 +57,6 @@ struct BondedCoulombSR {
std::function const &kernel)
const;
-
-private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & q1q2;
- }
};
/** Compute the short-range bonded Coulomb pair force.
diff --git a/src/core/bonded_interactions/bonded_interaction_data.cpp b/src/core/bonded_interactions/bonded_interaction_data.cpp
index cbb4441f4d9..8d5c2a631ae 100644
--- a/src/core/bonded_interactions/bonded_interaction_data.cpp
+++ b/src/core/bonded_interactions/bonded_interaction_data.cpp
@@ -16,18 +16,21 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
#include "bonded_interaction_data.hpp"
+
+#include "BoxGeometry.hpp"
+#include "cell_system/CellStructure.hpp"
+#include "immersed_boundary/ImmersedBoundaries.hpp"
#include "rigid_bond.hpp"
#include "system/System.hpp"
#include "thermalized_bond.hpp"
+#include "thermostat.hpp"
#include
#include
-#include
-#include
-
-BondedInteractionsMap bonded_ia_params;
+#include
/** Visitor to get the bond cutoff from the bond parameter variant */
class BondCutoff : public boost::static_visitor {
@@ -37,20 +40,18 @@ class BondCutoff : public boost::static_visitor {
}
};
-double maximal_cutoff_bonded() {
+double BondedInteractionsMap::maximal_cutoff() const {
auto const max_cut_bonded = std::accumulate(
- bonded_ia_params.begin(), bonded_ia_params.end(), BONDED_INACTIVE_CUTOFF,
- [](auto max_cut, auto const &kv) {
+ begin(), end(), BONDED_INACTIVE_CUTOFF, [](auto max_cut, auto const &kv) {
return std::max(max_cut,
boost::apply_visitor(BondCutoff(), *kv.second));
});
/* Check if there are dihedrals */
- auto const any_dihedrals = std::any_of(
- bonded_ia_params.begin(), bonded_ia_params.end(), [](auto const &kv) {
- return (boost::get(&(*kv.second)) ||
- boost::get(&(*kv.second)));
- });
+ auto const any_dihedrals = std::any_of(begin(), end(), [](auto const &kv) {
+ return (boost::get(&(*kv.second)) ||
+ boost::get(&(*kv.second)));
+ });
/* dihedrals: the central particle is indirectly connected to the fourth
* particle via the third particle, so we have to double the cutoff */
@@ -72,9 +73,33 @@ void BondedInteractionsMap::on_ia_change() {
}
#endif
}
- if (System::is_system_set()) {
- auto &system = System::get_system();
- system.on_short_range_ia_change();
- system.on_thermostat_param_change(); // thermalized bonds
+ if (auto system = m_system.lock()) {
+ system->on_short_range_ia_change();
+ system->on_thermostat_param_change(); // thermalized bonds
+ }
+}
+
+void BondedInteractionsMap::activate_bond(mapped_type const &ptr) {
+ auto &system = get_system();
+ if (auto bond = boost::get(ptr.get())) {
+ bond->set_thermostat_view(system.thermostat);
+ }
+ if (auto bond = boost::get(ptr.get())) {
+ system.immersed_boundaries->register_softID(*bond);
+ }
+ if (auto bond = boost::get(ptr.get())) {
+ bond->initialize(*system.box_geo, *system.cell_structure);
+ }
+ if (auto bond = boost::get(ptr.get())) {
+ bond->initialize(*system.box_geo, *system.cell_structure);
+ }
+}
+
+void BondedInteractionsMap::deactivate_bond(mapped_type const &ptr) {
+ if (auto bond = boost::get(ptr.get())) {
+ bond->unset_thermostat_view();
+ }
+ if (auto bond = boost::get(ptr.get())) {
+ bond->unset_volumes_view();
}
}
diff --git a/src/core/bonded_interactions/bonded_interaction_data.hpp b/src/core/bonded_interactions/bonded_interaction_data.hpp
index 77e3ccd2f0c..c2e877b8876 100644
--- a/src/core/bonded_interactions/bonded_interaction_data.hpp
+++ b/src/core/bonded_interactions/bonded_interaction_data.hpp
@@ -43,15 +43,16 @@
#include "rigid_bond.hpp"
#include "thermalized_bond.hpp"
+#include "BondList.hpp"
#include "TabulatedPotential.hpp"
+#include "system/Leaf.hpp"
-#include
-#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -65,20 +66,12 @@ static constexpr double BONDED_INACTIVE_CUTOFF = -1.;
struct NoneBond {
static constexpr int num = 0;
double cutoff() const { return BONDED_INACTIVE_CUTOFF; }
-
-private:
- friend boost::serialization::access;
- template void serialize(Archive &, long int) {}
};
/** Interaction type for virtual bonds */
struct VirtualBond {
static constexpr int num = 1;
double cutoff() const { return BONDED_INACTIVE_CUTOFF; }
-
-private:
- friend boost::serialization::access;
- template void serialize(Archive &, long int) {}
};
/** Visitor to get the number of bound partners from the bond parameter
@@ -100,7 +93,10 @@ using Bonded_IA_Parameters =
RigidBond, IBMTriel, IBMVolCons, IBMTribend,
OifGlobalForcesBond, OifLocalForcesBond, VirtualBond>;
-class BondedInteractionsMap {
+/**
+ * @brief container for bonded interactions.
+ */
+class BondedInteractionsMap : public System::Leaf {
using container_type =
std::unordered_map>;
@@ -111,7 +107,8 @@ class BondedInteractionsMap {
using iterator = typename container_type::iterator;
using const_iterator = typename container_type::const_iterator;
- explicit BondedInteractionsMap() = default;
+ BondedInteractionsMap() = default;
+ virtual ~BondedInteractionsMap() = default;
iterator begin() { return m_params.begin(); }
iterator end() { return m_params.end(); }
@@ -119,24 +116,34 @@ class BondedInteractionsMap {
const_iterator end() const { return m_params.end(); }
void insert(key_type const &key, mapped_type const &ptr) {
+ if (m_params.contains(key)) {
+ deactivate_bond(m_params.at(key));
+ }
+ activate_bond(ptr);
next_key = std::max(next_key, key + 1);
m_params[key] = ptr;
on_ia_change();
}
key_type insert(mapped_type const &ptr) {
+ activate_bond(ptr);
auto const key = next_key++;
m_params[key] = ptr;
on_ia_change();
return key;
}
auto erase(key_type const &key) {
+ if (m_params.contains(key)) {
+ deactivate_bond(m_params.at(key));
+ }
auto &&obj = m_params.erase(key);
on_ia_change();
return obj;
}
+ virtual void activate_bond(mapped_type const &ptr);
+ virtual void deactivate_bond(mapped_type const &ptr);
mapped_type at(key_type const &key) const { return m_params.at(key); }
auto count(key_type const &key) const { return m_params.count(key); }
- bool contains(key_type const &key) const { return m_params.count(key); }
+ bool contains(key_type const &key) const { return m_params.contains(key); }
bool empty() const { return m_params.empty(); }
auto size() const { return m_params.size(); }
auto get_next_key() const { return next_key; }
@@ -147,6 +154,69 @@ class BondedInteractionsMap {
#ifdef BOND_CONSTRAINT
auto get_n_rigid_bonds() const { return n_rigid_bonds; }
#endif
+ std::optional find_bond_id(mapped_type const &bond) const {
+ for (auto const &kv : m_params) {
+ if (kv.second == bond) {
+ return kv.first;
+ }
+ }
+ return std::nullopt;
+ }
+
+ /**
+ * @brief Calculate the maximal cutoff of bonded interactions, required to
+ * determine the cell size for communication.
+ *
+ * Bond angle and dihedral potentials do not contain a cutoff intrinsically.
+ * The cutoff for these potentials depends on the bond length potentials
+ * (it is assumed that particles participating in a bond angle or dihedral
+ * potential are bound to each other by some bond length potential). For bond
+ * angle potentials nothing has to be done. For dihedral potentials the cutoff
+ * is set to twice the maximal cutoff because the particle in which the bond
+ * is stored is only bonded to the first two partners, one of which has an
+ * additional bond to the third partner.
+ */
+ double maximal_cutoff() const;
+
+ /**
+ * @brief Checks both particles for a specific bond, even on ghost particles.
+ *
+ * @param p particle to check for the bond
+ * @param p_partner possible bond partner
+ * @tparam BondType Bond type to check for. Must be of one of the types in
+ * @ref Bonded_IA_Parameters.
+ */
+ template
+ bool pair_bond_exists_on(Particle const &p, Particle const &p_partner) const {
+ auto const &bonds = p.bonds();
+ return std::any_of(
+ bonds.begin(), bonds.end(),
+ [this, partner_id = p_partner.id()](BondView const &bond) {
+ auto const &bond_ptr = at(bond.bond_id());
+ return (boost::get(bond_ptr.get()) != nullptr) and
+ (bond.partner_ids()[0] == partner_id);
+ });
+ }
+
+ /**
+ * @brief Checks both particles for a specific bond, even on ghost particles.
+ *
+ * @param p1 particle on which the bond may be stored
+ * @param p2 particle on which the bond may be stored
+ * @tparam BondType Bond type to check for.
+ */
+ template
+ bool pair_bond_exists_between(Particle const &p1, Particle const &p2) const {
+ if (&p1 == &p2)
+ return false;
+
+ // Check if particles have bonds and search for the bond of interest.
+ // Could be saved on either particle, so we need to check both.
+ return pair_bond_exists_on(p1, p2) or
+ pair_bond_exists_on(p2, p1);
+ }
+
+ void on_ia_change();
private:
container_type m_params = {};
@@ -155,27 +225,9 @@ class BondedInteractionsMap {
#ifdef BOND_CONSTRAINT
int n_rigid_bonds = 0;
#endif
- void on_ia_change();
};
-/** Field containing the parameters of the bonded ia types */
-extern BondedInteractionsMap bonded_ia_params;
-
-/** Calculate the maximal cutoff of bonded interactions, required to
- * determine the cell size for communication.
- *
- * Bond angle and dihedral potentials do not contain a cutoff intrinsically.
- * The cutoff for these potentials depends on the bond length potentials
- * (it is assumed that particles participating in a bond angle or dihedral
- * potential are bound to each other by some bond length potential). For bond
- * angle potentials nothing has to be done. For dihedral potentials the cutoff
- * is set to twice the maximal cutoff because the particle in which the bond
- * is stored is only bonded to the first two partners, one of which has an
- * additional bond to the third partner.
- */
-double maximal_cutoff_bonded();
-
-/** Return the number of bonded partners for the specified bond */
+/** @brief Get the number of bonded partners for the specified bond. */
inline int number_of_partners(Bonded_IA_Parameters const &iaparams) {
return boost::apply_visitor(BondNumPartners(), iaparams);
}
diff --git a/src/core/bonded_interactions/bonded_interaction_utils.hpp b/src/core/bonded_interactions/bonded_interaction_utils.hpp
deleted file mode 100644
index 9f0f60c9a30..00000000000
--- a/src/core/bonded_interactions/bonded_interaction_utils.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010-2022 The ESPResSo project
- *
- * 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 .
- */
-
-#pragma once
-
-#include "bonded_interaction_data.hpp"
-
-#include "BondList.hpp"
-#include "Particle.hpp"
-
-#include
-
-#include
-
-/** @brief Checks both particles for a specific bond, even on ghost particles.
- *
- * @param p particle to check for the bond
- * @param p_partner possible bond partner
- * @tparam BondType Bond type to check for. Must be of one of the types in
- * @ref Bonded_IA_Parameters.
- */
-template
-inline bool pair_bond_enum_exists_on(Particle const &p,
- Particle const &p_partner) {
- auto const &bonds = p.bonds();
- return std::any_of(
- bonds.begin(), bonds.end(),
- [partner_id = p_partner.id()](BondView const &bond) {
- auto const &bond_ptr = bonded_ia_params.at(bond.bond_id());
- return (boost::get(bond_ptr.get()) != nullptr) and
- (bond.partner_ids()[0] == partner_id);
- });
-}
-
-/** @brief Checks both particles for a specific bond, even on ghost particles.
- *
- * @param p1 particle on which the bond may be stored
- * @param p2 particle on which the bond may be stored
- * @tparam BondType Bond type to check for. Must be of one of the types in
- * @ref Bonded_IA_Parameters.
- */
-template
-inline bool pair_bond_enum_exists_between(Particle const &p1,
- Particle const &p2) {
- if (&p1 == &p2)
- return false;
-
- // Check if particles have bonds and search for the bond of interest.
- // Could be saved on both sides (and both could have other bonds), so
- // we need to check both.
- return pair_bond_enum_exists_on(p1, p2) or
- pair_bond_enum_exists_on(p2, p1);
-}
diff --git a/src/core/bonded_interactions/bonded_interactions.dox b/src/core/bonded_interactions/bonded_interactions.dox
index 251d7711e2f..7883f96be6a 100644
--- a/src/core/bonded_interactions/bonded_interactions.dox
+++ b/src/core/bonded_interactions/bonded_interactions.dox
@@ -95,24 +95,6 @@
* @endcode
* All values the bond needs to function properly should be passed as
* arguments to this constructor.
- * * A template function for serialization called @c serialize. This is for
- * communication between nodes in parallel computations.
- * The following function can serve as a starting point.
- * @code{.cpp}
- * private:
- * friend boost::serialization::access;
- * template
- * void serialize(Archive &ar, long int) {
- * ar &k;
- * ar &drmax;
- * ar &r0;
- * ar &drmax2;
- * ar &drmax2i;
- * }
- * @endcode
- * Replace all the ar& commands with the new bond's parameters.
- * Every data member of your struct needs to be transmitted. This template
- * function is private.
*
* @subsection bondedIA_new_integration Integrating the new bond type into the C++ core
*
diff --git a/src/core/bonded_interactions/bonded_tab.hpp b/src/core/bonded_interactions/bonded_tab.hpp
index 346f004dd9d..64238e84c58 100644
--- a/src/core/bonded_interactions/bonded_tab.hpp
+++ b/src/core/bonded_interactions/bonded_tab.hpp
@@ -35,8 +35,6 @@
#include
#include
-#include
-
#include
#include
#include
@@ -61,13 +59,6 @@ struct TabulatedBond {
std::vector const &force) {
pot = std::make_shared(min, max, force, energy);
}
-
-private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & pot;
- }
};
/** Parameters for 2-body tabulated potential. */
diff --git a/src/core/bonded_interactions/dihedral.hpp b/src/core/bonded_interactions/dihedral.hpp
index ff57332c912..434172f2a3a 100644
--- a/src/core/bonded_interactions/dihedral.hpp
+++ b/src/core/bonded_interactions/dihedral.hpp
@@ -61,15 +61,6 @@ struct DihedralBond {
std::optional energy(Utils::Vector3d const &v12,
Utils::Vector3d const &v23,
Utils::Vector3d const &v34) const;
-
-private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & mult;
- ar & bend;
- ar & phase;
- }
};
/**
diff --git a/src/core/bonded_interactions/fene.hpp b/src/core/bonded_interactions/fene.hpp
index 82d2ec8c43c..0156399a088 100644
--- a/src/core/bonded_interactions/fene.hpp
+++ b/src/core/bonded_interactions/fene.hpp
@@ -62,17 +62,6 @@ struct FeneBond {
std::optional force(Utils::Vector3d const &dx) const;
std::optional energy(Utils::Vector3d const &dx) const;
-
-private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & k;
- ar & drmax;
- ar & r0;
- ar & drmax2;
- ar & drmax2i;
- }
};
/** Compute the FENE bond force.
diff --git a/src/core/bonded_interactions/harmonic.hpp b/src/core/bonded_interactions/harmonic.hpp
index 1c9cde00bf8..bb8c7e2ee50 100644
--- a/src/core/bonded_interactions/harmonic.hpp
+++ b/src/core/bonded_interactions/harmonic.hpp
@@ -54,15 +54,6 @@ struct HarmonicBond {
std::optional force(Utils::Vector3d const &dx) const;
std::optional energy(Utils::Vector3d const &dx) const;
-
-private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & k;
- ar & r;
- ar & r_cut;
- }
};
/** Compute the harmonic bond force.
diff --git a/src/core/bonded_interactions/quartic.hpp b/src/core/bonded_interactions/quartic.hpp
index eb37ccce7ad..68231c0e3ff 100644
--- a/src/core/bonded_interactions/quartic.hpp
+++ b/src/core/bonded_interactions/quartic.hpp
@@ -51,16 +51,6 @@ struct QuarticBond {
std::optional force(Utils::Vector3d const &dx) const;
std::optional energy(Utils::Vector3d const &dx) const;
-
-private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & k0;
- ar & k1;
- ar & r;
- ar & r_cut;
- }
};
/** Compute the quartic bond force.
diff --git a/src/core/bonded_interactions/rigid_bond.hpp b/src/core/bonded_interactions/rigid_bond.hpp
index 3b0fbb7d4cc..75597610117 100644
--- a/src/core/bonded_interactions/rigid_bond.hpp
+++ b/src/core/bonded_interactions/rigid_bond.hpp
@@ -51,13 +51,4 @@ struct RigidBond {
this->p_tol = 2.0 * p_tol;
this->v_tol = v_tol;
}
-
-private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & d2;
- ar & p_tol;
- ar & v_tol;
- }
};
diff --git a/src/core/bonded_interactions/thermalized_bond.hpp b/src/core/bonded_interactions/thermalized_bond.hpp
index 7cf9e9a0bf2..badd981d086 100644
--- a/src/core/bonded_interactions/thermalized_bond.hpp
+++ b/src/core/bonded_interactions/thermalized_bond.hpp
@@ -29,10 +29,16 @@
#include
+#include
#include
+#include
#include
#include
+namespace Thermostat {
+class Thermostat;
+}
+
/** Parameters for Thermalized bond */
struct ThermalizedBond {
double temp_com;
@@ -70,22 +76,17 @@ struct ThermalizedBond {
pref2_dist = std::sqrt(24. * gamma_distance / time_step * temp_distance);
}
+ void set_thermostat_view(
+ std::weak_ptr const &thermostat) {
+ m_thermostat = thermostat;
+ }
+
+ void unset_thermostat_view() { m_thermostat.reset(); }
+
std::optional>
forces(Particle const &p1, Particle const &p2,
Utils::Vector3d const &dx) const;
private:
- friend boost::serialization::access;
- template
- void serialize(Archive &ar, long int /* version */) {
- ar & temp_com;
- ar & gamma_com;
- ar & temp_distance;
- ar & gamma_distance;
- ar & r_cut;
- ar & pref1_com;
- ar & pref2_com;
- ar & pref1_dist;
- ar & pref2_dist;
- }
+ std::weak_ptr m_thermostat;
};
diff --git a/src/core/bonded_interactions/thermalized_bond_kernel.hpp b/src/core/bonded_interactions/thermalized_bond_kernel.hpp
index 2b13b08a8d6..90b378dbd1d 100644
--- a/src/core/bonded_interactions/thermalized_bond_kernel.hpp
+++ b/src/core/bonded_interactions/thermalized_bond_kernel.hpp
@@ -25,7 +25,6 @@
#include "Particle.hpp"
#include "random.hpp"
-#include "system/System.hpp"
#include "thermostat.hpp"
#include
@@ -54,8 +53,9 @@ ThermalizedBond::forces(Particle const &p1, Particle const &p2,
auto const sqrt_mass_red = sqrt(p1.mass() * p2.mass() / mass_tot);
auto const com_vel = mass_tot_inv * (p1.mass() * p1.v() + p2.mass() * p2.v());
auto const dist_vel = p2.v() - p1.v();
- auto const &thermalized_bond =
- *::System::get_system().thermostat->thermalized_bond;
+ auto const thermostat_view = m_thermostat.lock();
+ assert(thermostat_view);
+ auto const &thermalized_bond = *thermostat_view->thermalized_bond;
Utils::Vector3d force1{};
Utils::Vector3d force2{};
diff --git a/src/core/cluster_analysis/Cluster.cpp b/src/core/cluster_analysis/Cluster.cpp
index 841b056f1d2..36665e96aa3 100644
--- a/src/core/cluster_analysis/Cluster.cpp
+++ b/src/core/cluster_analysis/Cluster.cpp
@@ -29,7 +29,6 @@
#include "Particle.hpp"
#include "errorhandling.hpp"
#include "particle_node.hpp"
-#include "system/System.hpp"
#include
@@ -52,7 +51,8 @@ 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;
+ auto const box_geo_handle = get_box_geo();
+ auto const &box_geo = *box_geo_handle;
Utils::Vector3d com{};
// The distances between the particles are "folded", such that all distances
@@ -83,7 +83,8 @@ Cluster::center_of_mass_subcluster(std::vector const &particle_ids) {
double Cluster::longest_distance() {
sanity_checks();
- auto const &box_geo = *System::get_system().box_geo;
+ auto const box_geo_handle = get_box_geo();
+ auto const &box_geo = *box_geo_handle;
double ld = 0.;
for (auto a = particles.begin(); a != particles.end(); a++) {
for (auto b = a; ++b != particles.end();) {
@@ -107,7 +108,8 @@ 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;
+ auto const box_geo_handle = get_box_geo();
+ auto const &box_geo = *box_geo_handle;
// Center of mass
Utils::Vector3d com = center_of_mass_subcluster(particle_ids);
double sum_sq_dist = 0.;
@@ -136,7 +138,8 @@ 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;
+ auto const box_geo_handle = get_box_geo();
+ auto const &box_geo = *box_geo_handle;
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
@@ -186,7 +189,8 @@ std::pair Cluster::fractal_dimension(double dr) {
}
void Cluster::sanity_checks() const {
- auto const &box_geo = *System::get_system().box_geo;
+ auto const box_geo_handle = get_box_geo();
+ auto const &box_geo = *box_geo_handle;
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/Cluster.hpp b/src/core/cluster_analysis/Cluster.hpp
index 85bed84cd8d..b76d279c60b 100644
--- a/src/core/cluster_analysis/Cluster.hpp
+++ b/src/core/cluster_analysis/Cluster.hpp
@@ -16,14 +16,17 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifndef CLUSTER_ANALYSIS_CLUSTER_HPP
-#define CLUSTER_ANALYSIS_CLUSTER_HPP
+#pragma once
+
+#include "BoxGeometry.hpp"
#include "Particle.hpp"
#include
#include
+#include
+#include
#include
#include
@@ -32,6 +35,8 @@ namespace ClusterAnalysis {
/** @brief Represents a single cluster of particles */
class Cluster {
public:
+ explicit Cluster(std::weak_ptr const &box_geo)
+ : m_box_geo{box_geo} {}
/** @brief Ids of the particles in the cluster */
std::vector particles;
/** @brief add a particle to the cluster */
@@ -56,8 +61,12 @@ class Cluster {
private:
void sanity_checks() const;
+ auto get_box_geo() const {
+ auto ptr = m_box_geo.lock();
+ assert(ptr);
+ return ptr;
+ }
+ mutable std::weak_ptr m_box_geo;
};
} // namespace ClusterAnalysis
-
-#endif
diff --git a/src/core/cluster_analysis/ClusterStructure.cpp b/src/core/cluster_analysis/ClusterStructure.cpp
index e53acae9dc1..b8b0f833845 100644
--- a/src/core/cluster_analysis/ClusterStructure.cpp
+++ b/src/core/cluster_analysis/ClusterStructure.cpp
@@ -23,7 +23,6 @@
#include "PartCfg.hpp"
#include "errorhandling.hpp"
#include "particle_node.hpp"
-#include "system/System.hpp"
#include
@@ -54,7 +53,9 @@ void ClusterStructure::run_for_all_pairs() {
sanity_checks();
// Iterate over pairs
- PartCfg partCfg{*System::get_system().box_geo};
+ auto const box_geo_handle = get_box_geo();
+ auto const &box_geo = *box_geo_handle;
+ PartCfg partCfg{box_geo};
Utils::for_each_pair(partCfg.begin(), partCfg.end(),
[this](const Particle &p1, const Particle &p2) {
this->add_pair(p1, p2);
@@ -65,7 +66,9 @@ void ClusterStructure::run_for_all_pairs() {
void ClusterStructure::run_for_bonded_particles() {
clear();
sanity_checks();
- PartCfg partCfg{*System::get_system().box_geo};
+ auto const box_geo_handle = get_box_geo();
+ auto const &box_geo = *box_geo_handle;
+ PartCfg partCfg{box_geo};
for (const auto &p : partCfg) {
for (auto const bond : p.bonds()) {
if (bond.partner_ids().size() == 1) {
@@ -148,7 +151,7 @@ void ClusterStructure::merge_clusters() {
to_be_changed.emplace_back(it.first, cid);
// Empty cluster object
if (clusters.find(cid) == clusters.end()) {
- clusters[cid] = std::make_shared();
+ clusters[cid] = std::make_shared(m_box_geo);
}
}
@@ -164,7 +167,7 @@ void ClusterStructure::merge_clusters() {
// If this is the first particle in this cluster, instance a new cluster
// object
if (clusters.find(it.second) == clusters.end()) {
- clusters[it.second] = std::make_shared();
+ clusters[it.second] = std::make_shared(m_box_geo);
}
clusters[it.second]->particles.push_back(it.first);
}
@@ -196,7 +199,7 @@ int ClusterStructure::get_next_free_cluster_id() {
}
void ClusterStructure::sanity_checks() const {
- if (System::get_system().box_geo->type() != BoxType::CUBOID) {
+ if (get_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.hpp b/src/core/cluster_analysis/ClusterStructure.hpp
index a0b18fb0704..20d0e379d5a 100644
--- a/src/core/cluster_analysis/ClusterStructure.hpp
+++ b/src/core/cluster_analysis/ClusterStructure.hpp
@@ -17,9 +17,9 @@
* along with this program. If not, see .
*/
-#ifndef CLUSTER_ANALYSIS_CLUSTER_STRUCTURE_HPP
-#define CLUSTER_ANALYSIS_CLUSTER_STRUCTURE_HPP
+#pragma once
+#include "BoxGeometry.hpp"
#include "pair_criteria/PairCriterion.hpp"
#include "Cluster.hpp"
@@ -58,6 +58,10 @@ class ClusterStructure {
return *m_pair_criterion;
}
+ void attach(std::weak_ptr const &box_geo) {
+ m_box_geo = box_geo;
+ }
+
private:
/** @brief Clusters that turn out to be the same during the analysis process
* (i.e., if two particles are neighbors that already belong to different
@@ -77,7 +81,12 @@ class ClusterStructure {
/** @brief Get next free cluster id */
inline int get_next_free_cluster_id();
void sanity_checks() const;
+ auto get_box_geo() const {
+ auto ptr = m_box_geo.lock();
+ assert(ptr);
+ return ptr;
+ }
+ mutable std::weak_ptr m_box_geo;
};
} // namespace ClusterAnalysis
-#endif
diff --git a/src/core/collision.cpp b/src/core/collision.cpp
index 62b4d6b3a4f..0070d90100b 100644
--- a/src/core/collision.cpp
+++ b/src/core/collision.cpp
@@ -17,9 +17,12 @@
* along with this program. If not, see .
*/
-#include "collision.hpp"
+#include "config/config.hpp"
#ifdef COLLISION_DETECTION
+
+#include "collision.hpp"
+
#include "BoxGeometry.hpp"
#include "Particle.hpp"
#include "bonded_interactions/bonded_interaction_data.hpp"
@@ -41,6 +44,7 @@
#include
#include
+#include
#include
#include
#include
@@ -48,12 +52,6 @@
#include
#include
-/// Data type holding the info about a single collision
-struct CollisionPair {
- int pp1; // 1st particle id
- int pp2; // 2nd particle id
-};
-
namespace boost {
namespace serialization {
template
@@ -64,14 +62,6 @@ void serialize(Archive &ar, CollisionPair &c, const unsigned int) {
} // namespace serialization
} // namespace boost
-/// During force calculation, colliding particles are recorded in the queue.
-/// The queue is processed after force calculation, when it is safe to add
-/// particles.
-static std::vector local_collision_queue;
-
-/// Parameters for collision detection
-Collision_parameters collision_params;
-
namespace {
Particle &get_part(CellStructure &cell_structure, int id) {
auto const p = cell_structure.get_local_particle(id);
@@ -85,43 +75,27 @@ Particle &get_part(CellStructure &cell_structure, int id) {
}
} // namespace
-/** @brief Return true if a bond between the centers of the colliding
- * particles needs to be placed. At this point, all modes need this.
- */
-static bool bind_centers() {
- // 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
- // time step
- return collision_params.mode != CollisionModeType::OFF and
- collision_params.mode != CollisionModeType::GLUE_TO_SURF;
-}
-
-static int get_bond_num_partners(int bond_id) {
- return number_of_partners(*bonded_ia_params.at(bond_id));
-}
-
-void Collision_parameters::initialize() {
+void CollisionDetection::initialize() {
// If mode is OFF, no further checks
- if (collision_params.mode == CollisionModeType::OFF) {
+ if (mode == CollisionModeType::OFF) {
return;
}
// Validate distance
- if (collision_params.mode != CollisionModeType::OFF) {
- if (collision_params.distance <= 0.) {
+ if (mode != CollisionModeType::OFF) {
+ if (distance <= 0.) {
throw std::domain_error("Parameter 'distance' must be > 0");
}
// Cache square of cutoff
- collision_params.distance2 = Utils::sqr(collision_params.distance);
+ distance_sq = Utils::sqr(distance);
}
#ifndef VIRTUAL_SITES_RELATIVE
// The collision modes involving virtual sites also require the creation of a
// bond between the colliding
// If we don't have virtual sites, virtual site binding isn't possible.
- if ((collision_params.mode == CollisionModeType::BIND_VS) ||
- (collision_params.mode == CollisionModeType::GLUE_TO_SURF)) {
+ if ((mode == CollisionModeType::BIND_VS) or
+ (mode == CollisionModeType::GLUE_TO_SURF)) {
throw std::runtime_error("collision modes based on virtual sites require "
"the VIRTUAL_SITES_RELATIVE feature");
}
@@ -129,140 +103,119 @@ void Collision_parameters::initialize() {
#ifdef VIRTUAL_SITES
// Check vs placement parameter
- if (collision_params.mode == CollisionModeType::BIND_VS) {
- if ((collision_params.vs_placement < 0.) or
- (collision_params.vs_placement > 1.)) {
+ if (mode == CollisionModeType::BIND_VS) {
+ if (vs_placement < 0. or vs_placement > 1.) {
throw std::domain_error(
"Parameter 'vs_placement' must be between 0 and 1");
}
}
#endif
- auto &system = System::get_system();
+ auto &system = get_system();
+ auto &bonded_ias = *system.bonded_ias;
auto &nonbonded_ias = *system.nonbonded_ias;
- // Check if bonded ia exist
- if ((collision_params.mode == CollisionModeType::BIND_CENTERS) and
- !bonded_ia_params.contains(collision_params.bond_centers)) {
- throw std::runtime_error(
- "Bond in parameter 'bond_centers' was not added to the system");
- }
-
- if ((collision_params.mode == CollisionModeType::BIND_VS) and
- !bonded_ia_params.contains(collision_params.bond_vs)) {
- throw std::runtime_error(
- "Bond in parameter 'bond_vs' was not added to the system");
- }
+ // Check if bond exists
+ assert(mode != CollisionModeType::BIND_CENTERS or
+ bonded_ias.contains(bond_centers));
+ assert(mode != CollisionModeType::BIND_VS or bonded_ias.contains(bond_vs));
// If the bond type to bind particle centers is not a pair bond...
// Check that the bonds have the right number of partners
- if ((collision_params.mode == CollisionModeType::BIND_CENTERS) and
- (get_bond_num_partners(collision_params.bond_centers) != 1)) {
+ if ((mode == CollisionModeType::BIND_CENTERS) and
+ (number_of_partners(*bonded_ias.at(bond_centers)) != 1)) {
throw std::runtime_error("The bond type to be used for binding particle "
"centers needs to be a pair bond");
}
// The bond between the virtual sites can be pair or triple
- if ((collision_params.mode == CollisionModeType::BIND_VS) and
- (get_bond_num_partners(collision_params.bond_vs) != 1 and
- get_bond_num_partners(collision_params.bond_vs) != 2)) {
+ if ((mode == CollisionModeType::BIND_VS) and
+ (number_of_partners(*bonded_ias.at(bond_vs)) != 1 and
+ number_of_partners(*bonded_ias.at(bond_vs)) != 2)) {
throw std::runtime_error("The bond type to be used for binding virtual "
"sites needs to be a pair bond");
}
// Create particle types
- if (collision_params.mode == CollisionModeType::BIND_VS) {
- if (collision_params.vs_particle_type < 0) {
+ if (mode == CollisionModeType::BIND_VS) {
+ if (vs_particle_type < 0) {
throw std::domain_error("Collision detection particle type for virtual "
"sites needs to be >=0");
}
- nonbonded_ias.make_particle_type_exist(collision_params.vs_particle_type);
+ nonbonded_ias.make_particle_type_exist(vs_particle_type);
}
- if (collision_params.mode == CollisionModeType::GLUE_TO_SURF) {
- if (collision_params.vs_particle_type < 0) {
+ if (mode == CollisionModeType::GLUE_TO_SURF) {
+ if (vs_particle_type < 0) {
throw std::domain_error("Collision detection particle type for virtual "
"sites needs to be >=0");
}
- nonbonded_ias.make_particle_type_exist(collision_params.vs_particle_type);
+ nonbonded_ias.make_particle_type_exist(vs_particle_type);
- if (collision_params.part_type_to_be_glued < 0) {
+ if (part_type_to_be_glued < 0) {
throw std::domain_error("Collision detection particle type to be glued "
"needs to be >=0");
}
- nonbonded_ias.make_particle_type_exist(
- collision_params.part_type_to_be_glued);
+ nonbonded_ias.make_particle_type_exist(part_type_to_be_glued);
- if (collision_params.part_type_to_attach_vs_to < 0) {
+ if (part_type_to_attach_vs_to < 0) {
throw std::domain_error("Collision detection particle type to attach "
"the virtual site to needs to be >=0");
}
- nonbonded_ias.make_particle_type_exist(
- collision_params.part_type_to_attach_vs_to);
+ nonbonded_ias.make_particle_type_exist(part_type_to_attach_vs_to);
- if (collision_params.part_type_after_glueing < 0) {
+ if (part_type_after_glueing < 0) {
throw std::domain_error("Collision detection particle type after gluing "
"needs to be >=0");
}
- nonbonded_ias.make_particle_type_exist(
- collision_params.part_type_after_glueing);
+ nonbonded_ias.make_particle_type_exist(part_type_after_glueing);
}
system.on_short_range_ia_change();
}
-void prepare_local_collision_queue() { local_collision_queue.clear(); }
-
-void queue_collision(const int part1, const int part2) {
- local_collision_queue.push_back({part1, part2});
-}
-
/** @brief Calculate position of vs for GLUE_TO_SURFACE mode.
* Returns id of particle to bind vs to.
*/
-static auto const &glue_to_surface_calc_vs_pos(Particle const &p1,
- Particle const &p2,
- BoxGeometry const &box_geo,
- Utils::Vector3d &pos) {
- double c;
+static auto const &glue_to_surface_calc_vs_pos(
+ Particle const &p1, Particle const &p2, BoxGeometry const &box_geo,
+ CollisionDetection const &collision_params, Utils::Vector3d &pos) {
+ double ratio;
auto const vec21 = box_geo.get_mi_vector(p1.pos(), p2.pos());
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;
+ ratio = 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;
+ ratio = collision_params.dist_glued_part_to_vs / dist;
} else {
throw std::runtime_error("This should never be thrown. Bug.");
}
- pos = p2.pos() + vec21 * c;
+ pos = p2.pos() + vec21 * ratio;
if (p1.type() == collision_params.part_type_to_attach_vs_to)
return p1;
return p2;
}
-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) {
+static void bind_at_point_of_collision_calc_vs_pos(
+ Particle const &p1, Particle const &p2, BoxGeometry const &box_geo,
+ CollisionDetection const &collision_params, Utils::Vector3d &pos1,
+ 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);
}
#ifdef VIRTUAL_SITES_RELATIVE
-static void place_vs_and_relate_to_particle(CellStructure &cell_structure,
- BoxGeometry const &box_geo,
- double const min_global_cut,
- int const current_vs_pid,
- Utils::Vector3d const &pos,
- int const relate_to) {
+static void place_vs_and_relate_to_particle(
+ CellStructure &cell_structure, BoxGeometry const &box_geo,
+ CollisionDetection const &collision_params, double const min_global_cut,
+ int const current_vs_pid, Utils::Vector3d const &pos, int const relate_to) {
Particle new_part;
new_part.id() = current_vs_pid;
new_part.pos() = pos;
@@ -272,10 +225,11 @@ static void place_vs_and_relate_to_particle(CellStructure &cell_structure,
p_vs->type() = collision_params.vs_particle_type;
}
-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)) {
+static void bind_at_poc_create_bond_between_vs(
+ CellStructure &cell_structure, BondedInteractionsMap const &bonded_ias,
+ CollisionDetection const &collision_params, int const current_vs_pid,
+ CollisionPair const &c) {
+ switch (number_of_partners(*bonded_ias.at(collision_params.bond_vs))) {
case 1: {
// Create bond between the virtual particles
const int bondG[] = {current_vs_pid - 2};
@@ -297,11 +251,10 @@ static void bind_at_poc_create_bond_between_vs(CellStructure &cell_structure,
}
}
-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) {
+static void glue_to_surface_bind_part_to_vs(
+ Particle const *const p1, Particle const *const p2,
+ int const vs_pid_plus_one, CollisionDetection const &collision_params,
+ CellStructure &cell_structure) {
// Create bond between the virtual particles
const int bondG[] = {vs_pid_plus_one - 1};
@@ -318,22 +271,23 @@ static void glue_to_surface_bind_part_to_vs(Particle const *const p1,
#endif // VIRTUAL_SITES_RELATIVE
-std::vector gather_global_collision_queue() {
- std::vector res = local_collision_queue;
+static auto gather_collision_queue(std::vector const &local) {
+ auto global = local;
if (comm_cart.size() > 1) {
- Utils::Mpi::gather_buffer(res, comm_cart);
- boost::mpi::broadcast(comm_cart, res, 0);
+ Utils::Mpi::gather_buffer(global, ::comm_cart);
+ boost::mpi::broadcast(::comm_cart, global, 0);
}
- return res;
+ return global;
}
-// Handle the collisions stored in the queue
-void handle_collisions(CellStructure &cell_structure) {
+void CollisionDetection::handle_collisions(CellStructure &cell_structure) {
// 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
// time step
- if (bind_centers()) {
+ auto const bind_centers = mode != CollisionModeType::OFF and
+ mode != CollisionModeType::GLUE_TO_SURF;
+ if (bind_centers) {
for (auto &c : local_collision_queue) {
// put the bond to the non-ghost particle; at least one partner always is
if (cell_structure.get_local_particle(c.pp1)->is_ghost()) {
@@ -342,34 +296,31 @@ void handle_collisions(CellStructure &cell_structure) {
const int bondG[] = {c.pp2};
- get_part(cell_structure, c.pp1)
- .bonds()
- .insert({collision_params.bond_centers, bondG});
+ get_part(cell_structure, c.pp1).bonds().insert({bond_centers, bondG});
}
}
-// Virtual sites based collision schemes
#ifdef VIRTUAL_SITES_RELATIVE
- auto &system = System::get_system();
+ auto &system = get_system();
auto const &box_geo = *system.box_geo;
auto const min_global_cut = system.get_min_global_cut();
- if ((collision_params.mode == CollisionModeType::BIND_VS) ||
- (collision_params.mode == CollisionModeType::GLUE_TO_SURF)) {
+ if ((mode == CollisionModeType::BIND_VS) ||
+ (mode == CollisionModeType::GLUE_TO_SURF)) {
// Gather the global collision queue, because only one node has a collision
// across node boundaries in its queue.
// The other node might still have to change particle properties on its
// non-ghost particle
- auto gathered_queue = gather_global_collision_queue();
+ auto global_collision_queue = gather_collision_queue(local_collision_queue);
// Sync max_seen_part
auto const global_max_seen_particle = boost::mpi::all_reduce(
- comm_cart, cell_structure.get_max_local_particle_id(),
+ ::comm_cart, cell_structure.get_max_local_particle_id(),
boost::mpi::maximum());
int current_vs_pid = global_max_seen_particle + 1;
// Iterate over global collision queue
- for (auto &c : gathered_queue) {
+ for (auto &c : global_collision_queue) {
// Get particle pointers
Particle *p1 = cell_structure.get_local_particle(c.pp1);
@@ -384,27 +335,25 @@ void handle_collisions(CellStructure &cell_structure) {
// number of particles created by other nodes
if (((!p1 or p1->is_ghost()) and (!p2 or p2->is_ghost())) or !p1 or !p2) {
// Increase local counters
- if (collision_params.mode == CollisionModeType::BIND_VS) {
+ if (mode == CollisionModeType::BIND_VS) {
current_vs_pid++;
}
// For glue to surface, we have only one vs
current_vs_pid++;
- if (collision_params.mode == CollisionModeType::GLUE_TO_SURF) {
- if (p1)
- if (p1->type() == collision_params.part_type_to_be_glued) {
- p1->type() = collision_params.part_type_after_glueing;
- }
- if (p2)
- if (p2->type() == collision_params.part_type_to_be_glued) {
- p2->type() = collision_params.part_type_after_glueing;
- }
+ if (mode == CollisionModeType::GLUE_TO_SURF) {
+ if (p1 and p1->type() == part_type_to_be_glued) {
+ p1->type() = part_type_after_glueing;
+ }
+ if (p2 and p2->type() == part_type_to_be_glued) {
+ p2->type() = part_type_after_glueing;
+ }
} // mode glue to surface
} else { // We consider the pair because one particle
// is local to the node and the other is local or ghost
// If we are in the two vs mode
// Virtual site related to first particle in the collision
- if (collision_params.mode == CollisionModeType::BIND_VS) {
+ if (mode == CollisionModeType::BIND_VS) {
Utils::Vector3d pos1, pos2;
// Enable rotation on the particles to which vs will be attached
@@ -412,11 +361,12 @@ void handle_collisions(CellStructure &cell_structure) {
p2->set_can_rotate_all_axes();
// Positions of the virtual sites
- bind_at_point_of_collision_calc_vs_pos(*p1, *p2, box_geo, pos1, pos2);
+ bind_at_point_of_collision_calc_vs_pos(*p1, *p2, box_geo, *this, pos1,
+ pos2);
auto handle_particle = [&](Particle *p, Utils::Vector3d const &pos) {
if (not p->is_ghost()) {
- place_vs_and_relate_to_particle(cell_structure, box_geo,
+ place_vs_and_relate_to_particle(cell_structure, box_geo, *this,
min_global_cut, current_vs_pid,
pos, p->id());
// Particle storage locations may have changed due to
@@ -437,18 +387,18 @@ void handle_collisions(CellStructure &cell_structure) {
current_vs_pid++;
// Create bonds between the vs.
- bind_at_poc_create_bond_between_vs(cell_structure, current_vs_pid, c);
+ bind_at_poc_create_bond_between_vs(cell_structure, *system.bonded_ias,
+ *this, current_vs_pid, c);
} // mode VS
- if (collision_params.mode == CollisionModeType::GLUE_TO_SURF) {
+ if (mode == CollisionModeType::GLUE_TO_SURF) {
// If particles are made inert by a type change on collision:
// We skip the pair if one of the particles has already reacted
// but we still increase the particle counters, as other nodes
// can not always know whether or not a vs is placed
- if (collision_params.part_type_after_glueing !=
- collision_params.part_type_to_be_glued) {
- if ((p1->type() == collision_params.part_type_after_glueing) ||
- (p2->type() == collision_params.part_type_after_glueing)) {
+ if (part_type_after_glueing != part_type_to_be_glued) {
+ if ((p1->type() == part_type_after_glueing) ||
+ (p2->type() == part_type_after_glueing)) {
current_vs_pid++;
continue;
}
@@ -456,7 +406,7 @@ void handle_collisions(CellStructure &cell_structure) {
Utils::Vector3d pos;
Particle const &attach_vs_to =
- glue_to_surface_calc_vs_pos(*p1, *p2, box_geo, pos);
+ glue_to_surface_calc_vs_pos(*p1, *p2, box_geo, *this, pos);
// Add a bond between the centers of the colliding particles
// The bond is placed on the node that has p1
@@ -464,20 +414,20 @@ void handle_collisions(CellStructure &cell_structure) {
const int bondG[] = {c.pp2};
get_part(cell_structure, c.pp1)
.bonds()
- .insert({collision_params.bond_centers, bondG});
+ .insert({bond_centers, bondG});
}
// Change type of particle being attached, to make it inert
- if (p1->type() == collision_params.part_type_to_be_glued) {
- p1->type() = collision_params.part_type_after_glueing;
+ if (p1->type() == part_type_to_be_glued) {
+ p1->type() = part_type_after_glueing;
}
- if (p2->type() == collision_params.part_type_to_be_glued) {
- p2->type() = collision_params.part_type_after_glueing;
+ if (p2->type() == part_type_to_be_glued) {
+ p2->type() = part_type_after_glueing;
}
// Vs placement happens on the node that has p1
if (!attach_vs_to.is_ghost()) {
- place_vs_and_relate_to_particle(cell_structure, box_geo,
+ place_vs_and_relate_to_particle(cell_structure, box_geo, *this,
min_global_cut, current_vs_pid, pos,
attach_vs_to.id());
// Particle storage locations may have changed due to
@@ -488,7 +438,7 @@ void handle_collisions(CellStructure &cell_structure) {
} 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, *this,
cell_structure);
}
} // we considered the pair
@@ -500,7 +450,7 @@ void handle_collisions(CellStructure &cell_structure) {
#endif
// If any node had a collision, all nodes need to resort
- if (!gathered_queue.empty()) {
+ if (not global_collision_queue.empty()) {
cell_structure.set_resort_particles(Cells::RESORT_GLOBAL);
cell_structure.update_ghosts_and_resort_particle(
Cells::DATA_PART_PROPERTIES | Cells::DATA_PART_BONDS);
@@ -509,7 +459,7 @@ void handle_collisions(CellStructure &cell_structure) {
} // are we in one of the vs_based methods
#endif // defined VIRTUAL_SITES_RELATIVE
- local_collision_queue.clear();
+ clear_queue();
}
#endif // COLLISION_DETECTION
diff --git a/src/core/collision.hpp b/src/core/collision.hpp
index 29c0bfe9bd1..0a5545c16e5 100644
--- a/src/core/collision.hpp
+++ b/src/core/collision.hpp
@@ -21,10 +21,11 @@
#include "config/config.hpp"
-#include "cell_system/CellStructure.hpp"
-
#include "BondList.hpp"
#include "Particle.hpp"
+#include "cell_system/CellStructure.hpp"
+#include "nonbonded_interactions/nonbonded_interaction_data.hpp"
+#include "system/Leaf.hpp"
/** @brief Protocols for collision handling. */
enum class CollisionModeType : int {
@@ -43,10 +44,16 @@ enum class CollisionModeType : int {
GLUE_TO_SURF = 3,
};
-class Collision_parameters {
+/// Data type holding the info about a single collision
+struct CollisionPair {
+ int pp1; // 1st particle id
+ int pp2; // 2nd particle id
+};
+
+class CollisionDetection : public System::Leaf {
public:
- Collision_parameters()
- : mode(CollisionModeType::OFF), distance(0.), distance2(0.),
+ CollisionDetection()
+ : mode(CollisionModeType::OFF), distance(0.), distance_sq(0.),
bond_centers(-1), bond_vs(-1) {}
/// collision protocol
@@ -54,7 +61,7 @@ class Collision_parameters {
/// distance at which particles are bound
double distance;
// Square of distance at which particle are bound
- double distance2;
+ double distance_sq;
/// bond type used between centers of colliding particles
int bond_centers;
@@ -82,70 +89,63 @@ class Collision_parameters {
/** @brief Validates parameters and creates particle types if needed. */
void initialize();
-};
-/// Parameters for collision detection
-extern Collision_parameters collision_params;
+ auto cutoff() const {
+ if (mode != CollisionModeType::OFF) {
+ return distance;
+ }
+ return INACTIVE_CUTOFF;
+ }
-#ifdef COLLISION_DETECTION
+ /// Handle queued collisions
+ void handle_collisions(CellStructure &cell_structure);
-void prepare_local_collision_queue();
+ void clear_queue() { local_collision_queue.clear(); }
-/// Handle the collisions recorded in the queue
-void handle_collisions(CellStructure &cell_structure);
+ /** @brief Detect (and queue) a collision between the given particles. */
+ void detect_collision(Particle const &p1, Particle const &p2,
+ double const dist_sq) {
+ if (dist_sq > distance_sq)
+ return;
-/** @brief Add the collision between the given particle ids to the collision
- * queue
- */
-void queue_collision(int part1, int part2);
-
-/** @brief Check additional criteria for the glue_to_surface collision mode */
-inline bool glue_to_surface_criterion(Particle const &p1, Particle const &p2) {
- return (((p1.type() == collision_params.part_type_to_be_glued) &&
- (p2.type() == collision_params.part_type_to_attach_vs_to)) ||
- ((p2.type() == collision_params.part_type_to_be_glued) &&
- (p1.type() == collision_params.part_type_to_attach_vs_to)));
-}
-
-/** @brief Detect (and queue) a collision between the given particles. */
-inline void detect_collision(Particle const &p1, Particle const &p2,
- double const dist2) {
- if (dist2 > collision_params.distance2)
- return;
-
- // If we are in the glue to surface mode, check that the particles
- // are of the right type
- if (collision_params.mode == CollisionModeType::GLUE_TO_SURF)
- if (!glue_to_surface_criterion(p1, p2))
+ // If we are in the glue to surface mode, check that the particles
+ // are of the right type
+ if (mode == CollisionModeType::GLUE_TO_SURF)
+ if (!glue_to_surface_criterion(p1, p2))
+ return;
+
+ // Ignore virtual particles
+ if (p1.is_virtual() or p2.is_virtual())
return;
- // Ignore virtual particles
- if (p1.is_virtual() or p2.is_virtual())
- return;
+ // Check, if there's already a bond between the particles
+ if (pair_bond_exists_on(p1.bonds(), p2.id(), bond_centers))
+ return;
- // Check, if there's already a bond between the particles
- if (pair_bond_exists_on(p1.bonds(), p2.id(), collision_params.bond_centers))
- return;
+ if (pair_bond_exists_on(p2.bonds(), p1.id(), bond_centers))
+ return;
- if (pair_bond_exists_on(p2.bonds(), p1.id(), collision_params.bond_centers))
- return;
+ /* If we're still here, there is no previous bond between the particles,
+ we have a new collision */
- /* If we're still here, there is no previous bond between the particles,
- we have a new collision */
+ // do not create bond between ghost particles
+ if (p1.is_ghost() and p2.is_ghost()) {
+ return;
+ }
+ local_collision_queue.push_back({p1.id(), p2.id()});
+ }
- // do not create bond between ghost particles
- if (p1.is_ghost() and p2.is_ghost()) {
- return;
+ // private:
+ /// During force calculation, colliding particles are recorded in the queue.
+ /// The queue is processed after force calculation, when it is safe to add
+ /// particles.
+ std::vector local_collision_queue;
+
+ /** @brief Check additional criteria for the glue_to_surface collision mode */
+ bool glue_to_surface_criterion(Particle const &p1, Particle const &p2) const {
+ return (((p1.type() == part_type_to_be_glued) and
+ (p2.type() == part_type_to_attach_vs_to)) or
+ ((p2.type() == part_type_to_be_glued) and
+ (p1.type() == part_type_to_attach_vs_to)));
}
- queue_collision(p1.id(), p2.id());
-}
-
-#endif // COLLISION_DETECTION
-
-inline double collision_detection_cutoff() {
-#ifdef COLLISION_DETECTION
- if (collision_params.mode != CollisionModeType::OFF)
- return collision_params.distance;
-#endif
- return -1.;
-}
+};
diff --git a/src/core/constraints.cpp b/src/core/constraints.cpp
deleted file mode 100644
index d5bbe12dd35..00000000000
--- a/src/core/constraints.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2010-2022 The ESPResSo project
- *
- * 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 .
- */
-#include "constraints.hpp"
-
-namespace Constraints {
-Constraints constraints;
-}
diff --git a/src/core/constraints.hpp b/src/core/constraints.hpp
deleted file mode 100644
index 6e74937d60f..00000000000
--- a/src/core/constraints.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2010-2022 The ESPResSo project
- *
- * 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 CONSTRAINTS_HPP
-#define CONSTRAINTS_HPP
-
-#include "ParticleRange.hpp"
-#include "constraints/Constraint.hpp"
-#include "constraints/Constraints.hpp"
-
-namespace Constraints {
-extern Constraints constraints;
-}
-#endif
diff --git a/src/core/constraints/CMakeLists.txt b/src/core/constraints/CMakeLists.txt
index f9648321f48..9f9752d31f6 100644
--- a/src/core/constraints/CMakeLists.txt
+++ b/src/core/constraints/CMakeLists.txt
@@ -18,5 +18,7 @@
#
target_sources(
- espresso_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/HomogeneousMagneticField.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/ShapeBasedConstraint.cpp)
+ espresso_core
+ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/HomogeneousMagneticField.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/Constraints.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/ShapeBasedConstraint.cpp)
diff --git a/src/core/constraints/Constraint.hpp b/src/core/constraints/Constraint.hpp
index 875834b636f..9aa13a23d1e 100644
--- a/src/core/constraints/Constraint.hpp
+++ b/src/core/constraints/Constraint.hpp
@@ -16,14 +16,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifndef CONSTRAINTS_CONSTRAINT_HPP
-#define CONSTRAINTS_CONSTRAINT_HPP
+
+#pragma once
#include "Observable_stat.hpp"
-#include "Particle.hpp"
#include
+struct Particle;
+struct ParticleForce;
+
namespace Constraints {
class Constraint {
public:
@@ -58,6 +60,4 @@ class Constraint {
virtual ~Constraint() = default;
};
-} /* namespace Constraints */
-
-#endif
+} // namespace Constraints
diff --git a/src/core/constraints/Constraints.cpp b/src/core/constraints/Constraints.cpp
new file mode 100644
index 00000000000..ef1eb35f633
--- /dev/null
+++ b/src/core/constraints/Constraints.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010-2024 The ESPResSo project
+ *
+ * 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 .
+ */
+
+#include "Constraints.hpp"
+#include "BoxGeometry.hpp"
+#include "Constraint.hpp"
+#include "Observable_stat.hpp"
+#include "system/System.hpp"
+
+#include
+#include
+#include
+#include
+
+namespace Constraints {
+
+void Constraints::add(std::shared_ptr const &constraint) {
+ auto &system = get_system();
+ if (not constraint->fits_in_box(system.box_geo->length())) {
+ throw std::runtime_error("Constraint not compatible with box size.");
+ }
+ assert(not contains(constraint));
+ m_constraints.emplace_back(constraint);
+ system.on_constraint_change();
+}
+void Constraints::remove(std::shared_ptr const &constraint) {
+ auto &system = get_system();
+ assert(contains(constraint));
+ std::erase(m_constraints, constraint);
+ system.on_constraint_change();
+}
+void Constraints::add_forces(ParticleRange &particles, double time) const {
+ if (m_constraints.empty())
+ return;
+
+ reset_forces();
+ auto const &box_geo = *get_system().box_geo;
+
+ for (auto &p : particles) {
+ auto const pos = box_geo.folded_position(p.pos());
+ ParticleForce force{};
+ for (auto const &constraint : *this) {
+ force += constraint->force(p, pos, time);
+ }
+
+ p.force_and_torque() += force;
+ }
+}
+
+void Constraints::add_energy(ParticleRange const &particles, double time,
+ Observable_stat &obs_energy) const {
+ if (m_constraints.empty())
+ return;
+
+ auto const &box_geo = *get_system().box_geo;
+
+ 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);
+ }
+ }
+}
+
+} // namespace Constraints
diff --git a/src/core/constraints/Constraints.hpp b/src/core/constraints/Constraints.hpp
index 89076a26b68..0609023553b 100644
--- a/src/core/constraints/Constraints.hpp
+++ b/src/core/constraints/Constraints.hpp
@@ -16,21 +16,22 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifndef CORE_CONSTRAINTS_CONSTRAINTS_HPP
-#define CORE_CONSTRAINTS_CONSTRAINTS_HPP
-#include "BoxGeometry.hpp"
-#include "Observable_stat.hpp"
-#include "system/System.hpp"
+#pragma once
+
+#include "Constraint.hpp"
+#include "system/Leaf.hpp"
#include
-#include
#include
#include
#include
+class ParticleRange;
+class Observable_stat;
+
namespace Constraints {
-template class Constraints {
+class Constraints : public System::Leaf {
using container_type = std::vector>;
public:
@@ -51,59 +52,18 @@ template class Constraints {
bool contains(std::shared_ptr const &constraint) const noexcept {
return std::find(begin(), end(), constraint) != end();
}
- void add(std::shared_ptr const &constraint) {
- auto &system = System::get_system();
- auto const &box_geo = *system.box_geo;
- if (not constraint->fits_in_box(box_geo.length())) {
- throw std::runtime_error("Constraint not compatible with box size.");
- }
- assert(not contains(constraint));
- m_constraints.emplace_back(constraint);
- system.on_constraint_change();
- }
- void remove(std::shared_ptr const &constraint) {
- auto &system = System::get_system();
- assert(contains(constraint));
- std::erase(m_constraints, constraint);
- system.on_constraint_change();
- }
+ void add(std::shared_ptr const &constraint);
+ void remove(std::shared_ptr const &constraint);
iterator begin() { return m_constraints.begin(); }
iterator end() { return m_constraints.end(); }
const_iterator begin() const { return m_constraints.begin(); }
const_iterator end() const { return m_constraints.end(); }
- void add_forces(BoxGeometry const &box_geo, ParticleRange &particles,
- double time) const {
- if (m_constraints.empty())
- return;
-
- reset_forces();
+ void add_forces(ParticleRange &particles, double time) const;
- for (auto &p : particles) {
- auto const pos = box_geo.folded_position(p.pos());
- ParticleForce force{};
- for (auto const &constraint : *this) {
- force += constraint->force(p, pos, time);
- }
-
- p.force_and_torque() += force;
- }
- }
-
- void add_energy(BoxGeometry const &box_geo, ParticleRange const &particles,
- double time, Observable_stat &obs_energy) const {
- if (m_constraints.empty())
- return;
-
- 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);
- }
- }
- }
+ void add_energy(ParticleRange const &particles, double time,
+ Observable_stat &obs_energy) const;
void veto_boxl_change() const {
if (not m_constraints.empty()) {
@@ -115,5 +75,3 @@ template class Constraints {
void on_boxl_change() const { veto_boxl_change(); }
};
} // namespace Constraints
-
-#endif
diff --git a/src/core/constraints/ExternalField.hpp b/src/core/constraints/ExternalField.hpp
index f8a85a2c02d..f5c1c07ed53 100644
--- a/src/core/constraints/ExternalField.hpp
+++ b/src/core/constraints/ExternalField.hpp
@@ -16,10 +16,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifndef CONSTRAINTS_EXTERNAL_FIELD_HPP
-#define CONSTRAINTS_EXTERNAL_FIELD_HPP
+
+#pragma once
#include "Constraint.hpp"
+#include "Particle.hpp"
#include "field_coupling/ForceField.hpp"
namespace Constraints {
@@ -49,6 +50,4 @@ class ExternalField : public Constraint {
return impl.field().fits_in_box(box);
}
};
-} /* namespace Constraints */
-
-#endif
+} // namespace Constraints
diff --git a/src/core/constraints/ExternalPotential.hpp b/src/core/constraints/ExternalPotential.hpp
index f2a68b00e89..6f0b659dfe0 100644
--- a/src/core/constraints/ExternalPotential.hpp
+++ b/src/core/constraints/ExternalPotential.hpp
@@ -16,10 +16,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#ifndef CONSTRAINTS_EXTERNAL_POTENTIAL_HPP
-#define CONSTRAINTS_EXTERNAL_POTENTIAL_HPP
+
+#pragma once
#include "Constraint.hpp"
+#include "Particle.hpp"
#include "field_coupling/PotentialField.hpp"
namespace Constraints {
@@ -51,5 +52,4 @@ class ExternalPotential : public Constraint {
return impl.field().fits_in_box(box);
}
};
-} /* namespace Constraints */
-#endif
+} // namespace Constraints
diff --git a/src/core/constraints/HomogeneousMagneticField.hpp b/src/core/constraints/HomogeneousMagneticField.hpp
index 3ac8940419c..dc8ba2ba043 100644
--- a/src/core/constraints/HomogeneousMagneticField.hpp
+++ b/src/core/constraints/HomogeneousMagneticField.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 CONSTRAINTS_HOMOGENEOUSMAGNETICFIELD_HPP
-#define CONSTRAINTS_HOMOGENEOUSMAGNETICFIELD_HPP
+
+#pragma once
#include "Constraint.hpp"
#include "Observable_stat.hpp"
@@ -47,6 +47,4 @@ class HomogeneousMagneticField : public Constraint {
Utils::Vector3d m_field;
};
-} /* namespace Constraints */
-
-#endif
+} // namespace Constraints
diff --git a/src/core/constraints/ShapeBasedConstraint.cpp b/src/core/constraints/ShapeBasedConstraint.cpp
index ad25f7b5924..e97237725d7 100644
--- a/src/core/constraints/ShapeBasedConstraint.cpp
+++ b/src/core/constraints/ShapeBasedConstraint.cpp
@@ -21,6 +21,7 @@
#include "BoxGeometry.hpp"
#include "Observable_stat.hpp"
+#include "bonded_interactions/bonded_interaction_data.hpp"
#include "communication.hpp"
#include "config/config.hpp"
#include "dpd.hpp"
@@ -46,6 +47,15 @@ static bool is_active(IA_parameters const &data) {
return data.max_cut != INACTIVE_CUTOFF;
}
+void ShapeBasedConstraint::set_type(int type) {
+ part_rep.type() = type;
+ m_system.lock()->nonbonded_ias->make_particle_type_exist(type);
+}
+
+IA_parameters const &ShapeBasedConstraint::get_ia_param(int type) const {
+ return m_system.lock()->nonbonded_ias->get_ia_param(type, part_rep.type());
+}
+
Utils::Vector3d ShapeBasedConstraint::total_force() const {
return all_reduce(comm_cart, m_local_force, std::plus<>());
}
@@ -86,7 +96,8 @@ ParticleForce ShapeBasedConstraint::force(Particle const &p,
double dist = 0.;
Utils::Vector3d dist_vec;
m_shape->calculate_dist(folded_pos, dist, dist_vec);
- auto const coulomb_kernel = m_system.coulomb.pair_force_kernel();
+ auto &system = *m_system.lock();
+ auto const coulomb_kernel = system.coulomb.pair_force_kernel();
#ifdef DPD
Utils::Vector3d dpd_force{};
@@ -96,33 +107,37 @@ ParticleForce ShapeBasedConstraint::force(Particle const &p,
if (dist > 0) {
outer_normal_vec = -dist_vec / dist;
pf = calc_central_radial_force(ia_params, dist_vec, dist) +
- calc_central_radial_charge_force(p, part_rep, ia_params, dist_vec,
- dist, get_ptr(coulomb_kernel)) +
+#ifdef THOLE
+ thole_pair_force(p, part_rep, ia_params, dist_vec, dist,
+ *system.bonded_ias, get_ptr(coulomb_kernel)) +
+#endif
calc_non_central_force(p, part_rep, ia_params, dist_vec, dist);
#ifdef DPD
- if (m_system.thermostat->thermo_switch & THERMO_DPD) {
- dpd_force = dpd_pair_force(p, part_rep, *m_system.thermostat->dpd,
- *m_system.box_geo, ia_params, dist_vec, dist,
+ if (system.thermostat->thermo_switch & THERMO_DPD) {
+ dpd_force = dpd_pair_force(p, part_rep, *system.thermostat->dpd,
+ *system.box_geo, ia_params, dist_vec, dist,
dist * dist);
// Additional use of DPD here requires counter increase
- m_system.thermostat->dpd->rng_increment();
+ system.thermostat->dpd->rng_increment();
}
#endif
} else if (m_penetrable && (dist <= 0)) {
if ((!m_only_positive) && (dist < 0)) {
pf = calc_central_radial_force(ia_params, dist_vec, -dist) +
- calc_central_radial_charge_force(p, part_rep, ia_params, dist_vec,
- -dist, get_ptr(coulomb_kernel)) +
+#ifdef THOLE
+ thole_pair_force(p, part_rep, ia_params, dist_vec, -dist,
+ *system.bonded_ias, get_ptr(coulomb_kernel)) +
+#endif
calc_non_central_force(p, part_rep, ia_params, dist_vec, -dist);
#ifdef DPD
- if (m_system.thermostat->thermo_switch & THERMO_DPD) {
- dpd_force = dpd_pair_force(p, part_rep, *m_system.thermostat->dpd,
- *m_system.box_geo, ia_params, dist_vec,
- dist, dist * dist);
+ if (system.thermostat->thermo_switch & THERMO_DPD) {
+ dpd_force = dpd_pair_force(p, part_rep, *system.thermostat->dpd,
+ *system.box_geo, ia_params, dist_vec, dist,
+ dist * dist);
// Additional use of DPD here requires counter increase
- m_system.thermostat->dpd->rng_increment();
+ system.thermostat->dpd->rng_increment();
}
#endif
}
@@ -150,16 +165,19 @@ void ShapeBasedConstraint::add_energy(const Particle &p,
auto const &ia_params = get_ia_param(p.type());
if (is_active(ia_params)) {
- auto const coulomb_kernel = m_system.coulomb.pair_energy_kernel();
+ auto &system = *m_system.lock();
+ auto const coulomb_kernel = system.coulomb.pair_energy_kernel();
double dist = 0.0;
Utils::Vector3d vec;
m_shape->calculate_dist(folded_pos, dist, vec);
- if (dist > 0) {
+ if (dist > 0.) {
energy = calc_non_bonded_pair_energy(p, part_rep, ia_params, vec, dist,
+ *system.bonded_ias,
get_ptr(coulomb_kernel));
- } else if ((dist <= 0) && m_penetrable) {
- if (!m_only_positive && (dist < 0)) {
+ } else if (dist <= 0. and m_penetrable) {
+ if (!m_only_positive and dist < 0.) {
energy = calc_non_bonded_pair_energy(p, part_rep, ia_params, vec, -dist,
+ *system.bonded_ias,
get_ptr(coulomb_kernel));
}
} else {
diff --git a/src/core/constraints/ShapeBasedConstraint.hpp b/src/core/constraints/ShapeBasedConstraint.hpp
index 13b87500e2a..7bae22055b5 100644
--- a/src/core/constraints/ShapeBasedConstraint.hpp
+++ b/src/core/constraints/ShapeBasedConstraint.hpp
@@ -25,7 +25,6 @@
#include "Particle.hpp"
#include "ParticleRange.hpp"
#include "nonbonded_interactions/nonbonded_interaction_data.hpp"
-#include "system/System.hpp"
#include
#include
@@ -35,14 +34,18 @@
#include
#include
+namespace System {
+class System;
+}
+
namespace Constraints {
class ShapeBasedConstraint : public Constraint {
public:
- ShapeBasedConstraint(System::System const &system)
+ ShapeBasedConstraint()
: part_rep{}, m_shape{std::make_shared()},
m_penetrable{false}, m_only_positive{false}, m_local_force{},
- m_outer_normal_force{}, m_system{system} {}
+ m_outer_normal_force{}, m_system{} {}
void add_energy(const Particle &p, const Utils::Vector3d &folded_pos,
double time, Observable_stat &energy) const override;
@@ -78,13 +81,13 @@ class ShapeBasedConstraint : public Constraint {
int &type() { return part_rep.type(); }
Utils::Vector3d &velocity() { return part_rep.v(); }
- void set_type(int type) {
- part_rep.type() = type;
- m_system.nonbonded_ias->make_particle_type_exist(type);
- }
+ void set_type(int type);
Utils::Vector3d total_force() const;
double total_normal_force() const;
+ void bind_system(std::shared_ptr const &system) {
+ m_system = system;
+ }
private:
Particle part_rep;
@@ -93,11 +96,9 @@ class ShapeBasedConstraint : public Constraint {
bool m_only_positive;
Utils::Vector3d m_local_force;
double m_outer_normal_force;
- System::System const &m_system;
+ std::weak_ptr m_system;
- auto const &get_ia_param(int type) const {
- return m_system.nonbonded_ias->get_ia_param(type, part_rep.type());
- }
+ IA_parameters const &get_ia_param(int type) const;
};
} // namespace Constraints
diff --git a/src/core/electrostatics/elc.cpp b/src/core/electrostatics/elc.cpp
index 6c2c3f05313..8ef7d5366af 100644
--- a/src/core/electrostatics/elc.cpp
+++ b/src/core/electrostatics/elc.cpp
@@ -26,7 +26,6 @@
#include "electrostatics/elc.hpp"
#include "electrostatics/coulomb.hpp"
-#include "electrostatics/mmm-common.hpp"
#include "electrostatics/p3m.hpp"
#include "electrostatics/p3m_gpu.hpp"
diff --git a/src/core/electrostatics/mmm-common.hpp b/src/core/electrostatics/mmm-common.hpp
deleted file mode 100644
index c630406e546..00000000000
--- a/src/core/electrostatics/mmm-common.hpp
+++ /dev/null
@@ -1,47 +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
- * Common parts of the MMM family of methods for the electrostatic
- * interaction: MMM1D and ELC. This file contains the code for the
- * polygamma expansions used for the near formulas of MMM1D.
- *
- * The expansion of the polygamma functions is fairly easy and follows
- * directly from @cite abramowitz65a. For details, see @cite arnold02a.
- */
-
-#pragma once
-
-#include "mmm-modpsi.hpp"
-
-#include "specfunc.hpp"
-
-#include
-
-/** Modified polygamma for even order 2*n, n >= 0 */
-inline double mod_psi_even(int n, double x) {
- return evaluateAsTaylorSeriesAt(modPsi[2 * n], x * x);
-}
-
-/** Modified polygamma for odd order 2*n+1, n>= 0 */
-inline double mod_psi_odd(int n, double x) {
- return x * evaluateAsTaylorSeriesAt(modPsi[2 * n + 1], x * x);
-}
diff --git a/src/core/electrostatics/mmm-modpsi.cpp b/src/core/electrostatics/mmm-modpsi.cpp
index c19bc985cf4..972d359c1d3 100644
--- a/src/core/electrostatics/mmm-modpsi.cpp
+++ b/src/core/electrostatics/mmm-modpsi.cpp
@@ -21,15 +21,15 @@
#include "config/config.hpp"
-#include "mmm-modpsi.hpp"
+#ifdef ELECTROSTATICS
+
+#include "mmm1d.hpp"
#include "specfunc.hpp"
#include
#include
#include
-std::vector> modPsi;
-
static void preparePolygammaEven(int n, double binom,
std::vector &series) {
/* (-0.5 n) psi^2n/2n! (-0.5 n) and psi^(2n+1)/(2n)! series expansions
@@ -92,7 +92,7 @@ static void preparePolygammaOdd(int n, double binom,
}
}
-void create_mod_psi_up_to(int new_n) {
+void CoulombMMM1D::create_mod_psi_up_to(int new_n) {
auto const old_n = static_cast(modPsi.size() >> 1);
if (new_n > old_n) {
modPsi.resize(2 * new_n);
@@ -108,3 +108,5 @@ void create_mod_psi_up_to(int new_n) {
}
}
}
+
+#endif // ELECTROSTATICS
diff --git a/src/core/electrostatics/mmm-modpsi.hpp b/src/core/electrostatics/mmm-modpsi.hpp
deleted file mode 100644
index a129acdf5a6..00000000000
--- a/src/core/electrostatics/mmm-modpsi.hpp
+++ /dev/null
@@ -1,38 +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
- * Common parts of the MMM family of methods for the electrostatic
- * interaction: MMM1D and ELC. This file contains the code for the
- * CPU and GPU implementations.
- */
-
-#pragma once
-
-#include
-
-/** Table of the Taylor expansions of the modified polygamma functions */
-extern std::vector> modPsi;
-
-/** Create both the even and odd polygamma functions up to order
- * 2*new_n
- */
-void create_mod_psi_up_to(int new_n);
diff --git a/src/core/electrostatics/mmm1d.cpp b/src/core/electrostatics/mmm1d.cpp
index 18a5ace1ebc..c92ce68b7ca 100644
--- a/src/core/electrostatics/mmm1d.cpp
+++ b/src/core/electrostatics/mmm1d.cpp
@@ -26,8 +26,6 @@
#include "electrostatics/mmm1d.hpp"
#include "electrostatics/coulomb.hpp"
-#include "electrostatics/mmm-common.hpp"
-#include "electrostatics/mmm-modpsi.hpp"
#include "BoxGeometry.hpp"
#include "LocalBox.hpp"
@@ -95,6 +93,16 @@ static auto determine_minrad(double maxPWerror, int P,
return 0.5 * (rmin + rmax);
}
+/** Modified polygamma for even order 2*n, n >= 0 */
+static double mod_psi_even(auto const &modPsi, int n, double x) {
+ return evaluateAsTaylorSeriesAt(modPsi[2 * n], x * x);
+}
+
+/** Modified polygamma for odd order 2*n+1, n>= 0 */
+static double mod_psi_odd(auto const &modPsi, int n, double x) {
+ return x * evaluateAsTaylorSeriesAt(modPsi[2 * n + 1], x * x);
+}
+
void CoulombMMM1D::determine_bessel_radii() {
auto const &box_geo = *get_system().box_geo;
auto const &box_l = box_geo.length();
@@ -115,7 +123,8 @@ void CoulombMMM1D::prepare_polygamma_series() {
create_mod_psi_up_to(n + 1);
/* |uz*z| <= 0.5 */
- err = 2. * static_cast(n) * fabs(mod_psi_even(n, 0.5)) * rhomax2nm2;
+ err = 2. * static_cast(n) * fabs(mod_psi_even(modPsi, n, 0.5)) *
+ rhomax2nm2;
rhomax2nm2 *= rhomax2;
n++;
} while (err > 0.1 * maxPWerror);
@@ -183,12 +192,12 @@ Utils::Vector3d CoulombMMM1D::pair_force(double q1q2, Utils::Vector3d const &d,
if (rxy2 <= far_switch_radius_sq) {
/* polygamma summation */
auto sr = 0.;
- auto sz = mod_psi_odd(0, z_d);
+ auto sz = mod_psi_odd(modPsi, 0, z_d);
auto r2nm1 = 1.;
for (int n = 1; n < n_modPsi; n++) {
auto const deriv = static_cast(2 * n);
- auto const mpe = mod_psi_even(n, z_d);
- auto const mpo = mod_psi_odd(n, z_d);
+ auto const mpe = mod_psi_even(modPsi, n, z_d);
+ auto const mpo = mod_psi_odd(modPsi, n, z_d);
auto const r2n = r2nm1 * rxy2_d;
sz += r2n * mpo;
@@ -281,7 +290,7 @@ double CoulombMMM1D::pair_energy(double const q1q2, Utils::Vector3d const &d,
/* polygamma summation */
double r2n = 1.;
for (int n = 0; n < n_modPsi; n++) {
- auto const add = mod_psi_even(n, z_d) * r2n;
+ auto const add = mod_psi_even(modPsi, n, z_d) * r2n;
energy -= add;
if (fabs(add) < maxPWerror)
diff --git a/src/core/electrostatics/mmm1d.hpp b/src/core/electrostatics/mmm1d.hpp
index 24cada32aaf..28cc510d8c6 100644
--- a/src/core/electrostatics/mmm1d.hpp
+++ b/src/core/electrostatics/mmm1d.hpp
@@ -22,10 +22,15 @@
/**
* @file
* MMM1D algorithm for long-range Coulomb interactions on the CPU.
+ *
* Implementation of the MMM1D method for the calculation of the electrostatic
* interaction in one-dimensionally periodic systems. For details on the
* method see MMM in general. The MMM1D method works only with the N-squared
* cell system since neither the near nor far formula can be decomposed.
+ *
+ * MMM1D uses polygamma expansions for the near formula.
+ * The expansion of the polygamma functions is fairly easy and follows
+ * directly from @cite abramowitz65a. For details, see @cite arnold02a.
*/
#pragma once
@@ -113,7 +118,11 @@ struct CoulombMMM1D : public Coulomb::Actor {
static constexpr auto MAXIMAL_B_CUT = 30;
/** @brief From which distance a certain Bessel cutoff is valid. */
std::array bessel_radii;
+ /** @brief Table of Taylor expansions of the modified polygamma functions. */
+ std::vector> modPsi;
+ /** @brief Create even and odd polygamma functions up to order `2 * new_n`. */
+ void create_mod_psi_up_to(int new_n);
void determine_bessel_radii();
void prepare_polygamma_series();
void recalc_boxl_parameters();
diff --git a/src/core/electrostatics/specfunc.hpp b/src/core/electrostatics/specfunc.hpp
index f0f2f6aefc6..225b3d33dc0 100644
--- a/src/core/electrostatics/specfunc.hpp
+++ b/src/core/electrostatics/specfunc.hpp
@@ -30,8 +30,7 @@
* formula, the Bessel functions are evaluated using several different
* Chebychev expansions. Both achieve a precision of nearly machine precision,
* which is no problem for the Hurwitz zeta function, which is only used when
- * determining the coefficients for the modified polygamma functions (see @ref
- * mmm-common.hpp).
+ * determining the coefficients for the modified polygamma functions.
*/
#pragma once
diff --git a/src/core/energy.cpp b/src/core/energy.cpp
index 6bbbf823253..c09c340b277 100644
--- a/src/core/energy.cpp
+++ b/src/core/energy.cpp
@@ -22,7 +22,7 @@
#include "BoxGeometry.hpp"
#include "Observable_stat.hpp"
#include "cell_system/CellStructure.hpp"
-#include "constraints.hpp"
+#include "constraints/Constraints.hpp"
#include "energy_inline.hpp"
#include "nonbonded_interactions/nonbonded_interaction_data.hpp"
#include "short_range_loop.hpp"
@@ -39,7 +39,7 @@ namespace System {
std::shared_ptr System::calculate_energy() {
auto obs_energy_ptr = std::make_shared(
- 1ul, static_cast(::bonded_ia_params.get_next_key()),
+ 1ul, static_cast(bonded_ias->get_next_key()),
nonbonded_ias->get_max_seen_particle_type());
if (long_range_interactions_sanity_checks()) {
@@ -65,7 +65,7 @@ std::shared_ptr System::calculate_energy() {
short_range_loop(
[this, coulomb_kernel_ptr = get_ptr(coulomb_kernel), &obs_energy](
Particle const &p1, int bond_id, std::span partners) {
- auto const &iaparams = *bonded_ia_params.at(bond_id);
+ auto const &iaparams = *bonded_ias->at(bond_id);
auto const result = calc_bonded_energy(iaparams, p1, partners, *box_geo,
coulomb_kernel_ptr);
if (result) {
@@ -80,10 +80,10 @@ std::shared_ptr System::calculate_energy() {
auto const &ia_params =
nonbonded_ias->get_ia_param(p1.type(), p2.type());
add_non_bonded_pair_energy(p1, p2, d.vec21, sqrt(d.dist2), d.dist2,
- ia_params, coulomb_kernel_ptr,
+ ia_params, *bonded_ias, coulomb_kernel_ptr,
dipoles_kernel_ptr, obs_energy);
},
- *cell_structure, maximal_cutoff(), maximal_cutoff_bonded());
+ *cell_structure, maximal_cutoff(), bonded_ias->maximal_cutoff());
#ifdef ELECTROSTATICS
/* calculate k-space part of electrostatic interaction. */
@@ -95,8 +95,7 @@ std::shared_ptr System::calculate_energy() {
obs_energy.dipolar[1] = dipoles.calc_energy_long_range(local_parts);
#endif
- Constraints::constraints.add_energy(*box_geo, local_parts, get_sim_time(),
- obs_energy);
+ constraints->add_energy(local_parts, get_sim_time(), obs_energy);
#if defined(CUDA) and (defined(ELECTROSTATICS) or defined(DIPOLES))
auto const energy_host = gpu.copy_energy_to_host();
@@ -129,7 +128,7 @@ double System::particle_short_range_energy_contribution(int pid) {
auto const &ia_params = nonbonded_ias->get_ia_param(p.type(), p1.type());
// Add energy for current particle pair to result
ret += calc_non_bonded_pair_energy(p, p1, ia_params, vec, vec.norm(),
- coulomb_kernel_ptr);
+ *bonded_ias, coulomb_kernel_ptr);
};
cell_structure->run_on_particle_short_range_neighbors(*p, kernel);
}
diff --git a/src/core/energy_inline.hpp b/src/core/energy_inline.hpp
index 5736118405d..8dc554338ae 100644
--- a/src/core/energy_inline.hpp
+++ b/src/core/energy_inline.hpp
@@ -69,12 +69,14 @@
* @param ia_params the interaction parameters between the two particles
* @param d vector between p1 and p2.
* @param dist distance between p1 and p2.
+ * @param bonded_ias bonded interaction kernels.
* @param coulomb_kernel Coulomb energy kernel.
* @return the short-range interaction energy between the two particles
*/
inline double calc_non_bonded_pair_energy(
Particle const &p1, Particle const &p2, IA_parameters const &ia_params,
Utils::Vector3d const &d, double const dist,
+ [[maybe_unused]] BondedInteractionsMap const &bonded_ias,
Coulomb::ShortRangeEnergyKernel::kernel_type const *coulomb_kernel) {
double ret = 0;
@@ -83,6 +85,7 @@ inline double calc_non_bonded_pair_energy(
/* Lennard-Jones */
ret += lj_pair_energy(ia_params, dist);
#endif
+
#ifdef WCA
/* WCA */
ret += wca_pair_energy(ia_params, dist);
@@ -140,7 +143,8 @@ inline double calc_non_bonded_pair_energy(
#ifdef THOLE
/* Thole damping */
- ret += thole_pair_energy(p1, p2, ia_params, d, dist, coulomb_kernel);
+ ret +=
+ thole_pair_energy(p1, p2, ia_params, d, dist, bonded_ias, coulomb_kernel);
#endif
#ifdef TABULATED
@@ -163,12 +167,13 @@ inline double calc_non_bonded_pair_energy(
/** Add non-bonded and short-range Coulomb energies between a pair of particles
* to the energy observable.
- * @param p1 particle 1.
- * @param p2 particle 2.
- * @param d vector between p1 and p2.
- * @param dist distance between p1 and p2.
- * @param dist2 distance squared between p1 and p2.
+ * @param[in] p1 particle 1.
+ * @param[in] p2 particle 2.
+ * @param[in] d vector between p1 and p2.
+ * @param[in] dist distance between p1 and p2.
+ * @param[in] dist2 distance squared between p1 and p2.
* @param[in] ia_params non-bonded interaction kernels.
+ * @param[in] bonded_ias bonded interaction kernels.
* @param[in] coulomb_kernel Coulomb energy kernel.
* @param[in] dipoles_kernel Dipolar energy kernel.
* @param[in,out] obs_energy energy observable.
@@ -176,6 +181,7 @@ inline double calc_non_bonded_pair_energy(
inline void add_non_bonded_pair_energy(
Particle const &p1, Particle const &p2, Utils::Vector3d const &d,
double const dist, double const dist2, IA_parameters const &ia_params,
+ [[maybe_unused]] BondedInteractionsMap const &bonded_ias,
Coulomb::ShortRangeEnergyKernel::kernel_type const *coulomb_kernel,
Dipoles::ShortRangeEnergyKernel::kernel_type const *dipoles_kernel,
Observable_stat &obs_energy) {
@@ -185,7 +191,7 @@ inline void add_non_bonded_pair_energy(
#endif
obs_energy.add_non_bonded_contribution(
p1.type(), p2.type(), p1.mol_id(), p2.mol_id(),
- calc_non_bonded_pair_energy(p1, p2, ia_params, d, dist,
+ calc_non_bonded_pair_energy(p1, p2, ia_params, d, dist, bonded_ias,
coulomb_kernel));
#ifdef ELECTROSTATICS
diff --git a/src/core/forces.cpp b/src/core/forces.cpp
index bc317eb119b..d669b87deaf 100644
--- a/src/core/forces.cpp
+++ b/src/core/forces.cpp
@@ -33,12 +33,12 @@
#include "cells.hpp"
#include "collision.hpp"
#include "communication.hpp"
-#include "constraints.hpp"
+#include "constraints/Constraints.hpp"
#include "electrostatics/icc.hpp"
#include "electrostatics/p3m_gpu.hpp"
#include "forces_inline.hpp"
#include "galilei/ComFixed.hpp"
-#include "immersed_boundaries.hpp"
+#include "immersed_boundary/ImmersedBoundaries.hpp"
#include "integrators/Propagation.hpp"
#include "lb/particle_coupling.hpp"
#include "magnetostatics/dipoles.hpp"
@@ -134,7 +134,7 @@ void System::System::calculate_forces() {
#endif // CUDA
#ifdef COLLISION_DETECTION
- prepare_local_collision_queue();
+ collision_detection->clear_queue();
#endif
bond_breakage->clear_queue();
auto particles = cell_structure->local_particles();
@@ -170,51 +170,49 @@ void System::System::calculate_forces() {
#else
auto const dipole_cutoff = INACTIVE_CUTOFF;
#endif
+#ifdef COLLISION_DETECTION
+ auto const collision_detection_cutoff = collision_detection->cutoff();
+#else
+ auto const collision_detection_cutoff = INACTIVE_CUTOFF;
+#endif
short_range_loop(
- [coulomb_kernel_ptr = get_ptr(coulomb_kernel),
+ [coulomb_kernel_ptr = get_ptr(coulomb_kernel), &bonded_ias = *bonded_ias,
&bond_breakage = *bond_breakage, &box_geo = *box_geo](
Particle &p1, int bond_id, std::span partners) {
- return add_bonded_force(p1, bond_id, partners, bond_breakage, box_geo,
- coulomb_kernel_ptr);
+ return add_bonded_force(p1, bond_id, partners, bonded_ias,
+ bond_breakage, box_geo, coulomb_kernel_ptr);
},
[coulomb_kernel_ptr = get_ptr(coulomb_kernel),
dipoles_kernel_ptr = get_ptr(dipoles_kernel),
elc_kernel_ptr = get_ptr(elc_kernel), &nonbonded_ias = *nonbonded_ias,
- &thermostat = *thermostat,
+ &thermostat = *thermostat, &bonded_ias = *bonded_ias,
+#ifdef COLLISION_DETECTION
+ &collision_detection = *collision_detection,
+#endif
&box_geo = *box_geo](Particle &p1, Particle &p2, Distance const &d) {
auto const &ia_params =
nonbonded_ias.get_ia_param(p1.type(), p2.type());
- add_non_bonded_pair_force(
- p1, p2, d.vec21, sqrt(d.dist2), d.dist2, ia_params, thermostat,
- box_geo, coulomb_kernel_ptr, dipoles_kernel_ptr, elc_kernel_ptr);
+ add_non_bonded_pair_force(p1, p2, d.vec21, sqrt(d.dist2), d.dist2,
+ ia_params, thermostat, box_geo, bonded_ias,
+ coulomb_kernel_ptr, dipoles_kernel_ptr,
+ elc_kernel_ptr);
#ifdef COLLISION_DETECTION
- if (collision_params.mode != CollisionModeType::OFF)
- detect_collision(p1, p2, d.dist2);
+ if (collision_detection.mode != CollisionModeType::OFF) {
+ collision_detection.detect_collision(p1, p2, d.dist2);
+ }
#endif
},
- *cell_structure, maximal_cutoff(), maximal_cutoff_bonded(),
+ *cell_structure, maximal_cutoff(), bonded_ias->maximal_cutoff(),
VerletCriterion<>{*this, cell_structure->get_verlet_skin(),
get_interaction_range(), coulomb_cutoff, dipole_cutoff,
- collision_detection_cutoff()});
-
- Constraints::constraints.add_forces(*box_geo, particles, get_sim_time());
-
- for (int i = 0; i < max_oif_objects; i++) {
- // There are two global quantities that need to be evaluated:
- // object's surface and object's volume.
- auto const area_volume = boost::mpi::all_reduce(
- 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, *box_geo, *cell_structure);
- }
+ collision_detection_cutoff});
+
+ constraints->add_forces(particles, get_sim_time());
+ oif_global->calculate_forces();
// Must be done here. Forces need to be ghost-communicated
- immersed_boundaries.volume_conservation(*cell_structure);
+ immersed_boundaries->volume_conservation(*cell_structure);
if (thermostat->lb and (propagation->used_propagations &
PropagationMode::TRANS_LB_MOMENTUM_EXCHANGE)) {
diff --git a/src/core/forces_inline.hpp b/src/core/forces_inline.hpp
index 5f73826b4a3..161340dfa36 100644
--- a/src/core/forces_inline.hpp
+++ b/src/core/forces_inline.hpp
@@ -142,20 +142,6 @@ inline ParticleForce calc_central_radial_force(IA_parameters const &ia_params,
return pf;
}
-inline ParticleForce calc_central_radial_charge_force(
- Particle const &p1, Particle const &p2, IA_parameters const &ia_params,
- Utils::Vector3d const &d, double const dist,
- Coulomb::ShortRangeForceKernel::kernel_type const *coulomb_kernel) {
-
- ParticleForce pf{};
-/* Thole damping */
-#ifdef THOLE
- pf.f += thole_pair_force(p1, p2, ia_params, d, dist, coulomb_kernel);
-#endif
-
- return pf;
-}
-
inline ParticleForce calc_non_central_force(Particle const &p1,
Particle const &p2,
IA_parameters const &ia_params,
@@ -194,6 +180,7 @@ inline ParticleForce calc_opposing_force(ParticleForce const &pf,
* @param[in] ia_params non-bonded interaction kernels.
* @param[in] thermostat thermostat.
* @param[in] box_geo box geometry.
+ * @param[in] bonded_ias bonded interaction kernels.
* @param[in] coulomb_kernel Coulomb force kernel.
* @param[in] dipoles_kernel Dipolar force kernel.
* @param[in] elc_kernel ELC force correction kernel.
@@ -202,6 +189,7 @@ inline void add_non_bonded_pair_force(
Particle &p1, Particle &p2, Utils::Vector3d const &d, double dist,
double dist2, IA_parameters const &ia_params,
Thermostat::Thermostat const &thermostat, BoxGeometry const &box_geo,
+ [[maybe_unused]] BondedInteractionsMap const &bonded_ias,
Coulomb::ShortRangeForceKernel::kernel_type const *coulomb_kernel,
Dipoles::ShortRangeForceKernel::kernel_type const *dipoles_kernel,
Coulomb::ShortRangeForceCorrectionsKernel::kernel_type const *elc_kernel) {
@@ -217,8 +205,10 @@ inline void add_non_bonded_pair_force(
if (do_nonbonded(p1, p2)) {
#endif
pf += calc_central_radial_force(ia_params, d, dist);
- pf += calc_central_radial_charge_force(p1, p2, ia_params, d, dist,
- coulomb_kernel);
+#ifdef THOLE
+ pf.f += thole_pair_force(p1, p2, ia_params, d, dist, bonded_ias,
+ coulomb_kernel);
+#endif
pf += calc_non_central_force(p1, p2, ia_params, d, dist);
#ifdef EXCLUSIONS
}
@@ -455,6 +445,7 @@ inline bool add_bonded_four_body_force(Bonded_IA_Parameters const &iaparams,
inline bool
add_bonded_force(Particle &p1, int bond_id, std::span partners,
+ BondedInteractionsMap const &bonded_ia_params,
BondBreakage::BondBreakage &bond_breakage,
BoxGeometry const &box_geo,
Coulomb::ShortRangeForceKernel::kernel_type const *kernel) {
diff --git a/src/core/immersed_boundaries.cpp b/src/core/immersed_boundaries.cpp
deleted file mode 100644
index a1cac55a679..00000000000
--- a/src/core/immersed_boundaries.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2010-2022 The ESPResSo project
- *
- * 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 .
- */
-#include "immersed_boundaries.hpp"
-
-ImmersedBoundaries immersed_boundaries;
diff --git a/src/core/immersed_boundaries.hpp b/src/core/immersed_boundaries.hpp
deleted file mode 100644
index 441952b9d0a..00000000000
--- a/src/core/immersed_boundaries.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2010-2022 The ESPResSo project
- *
- * 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 IMMERSED_BOUNDARIES_HPP
-#define IMMERSED_BOUNDARIES_HPP
-#include "config/config.hpp"
-#include "immersed_boundary/ImmersedBoundaries.hpp"
-
-extern ImmersedBoundaries immersed_boundaries;
-
-#endif
diff --git a/src/core/immersed_boundary/CMakeLists.txt b/src/core/immersed_boundary/CMakeLists.txt
index 52243163e7e..47b0c01b3db 100644
--- a/src/core/immersed_boundary/CMakeLists.txt
+++ b/src/core/immersed_boundary/CMakeLists.txt
@@ -21,6 +21,5 @@ target_sources(
espresso_core
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/ibm_tribend.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ibm_triel.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/ibm_volcons.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ibm_common.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ImmersedBoundaries.cpp)
diff --git a/src/core/immersed_boundary/ImmersedBoundaries.cpp b/src/core/immersed_boundary/ImmersedBoundaries.cpp
index 0beaef4bb25..56b351c94c0 100644
--- a/src/core/immersed_boundary/ImmersedBoundaries.cpp
+++ b/src/core/immersed_boundary/ImmersedBoundaries.cpp
@@ -31,6 +31,7 @@
#include
#include
+#include
#include
#include
#include
@@ -47,13 +48,13 @@ void ImmersedBoundaries::volume_conservation(CellStructure &cs) {
/** Initialize volume conservation */
void ImmersedBoundaries::init_volume_conservation(CellStructure &cs) {
+ auto const &bonded_ias = *get_system().bonded_ias;
// Check since this function is called at the start of every integrate loop
// Also check if volume has been set due to reading of a checkpoint
if (not BoundariesFound) {
- BoundariesFound = std::any_of(
- bonded_ia_params.begin(), bonded_ia_params.end(), [](auto const &kv) {
- return (boost::get(&(*kv.second)) != nullptr);
- });
+ BoundariesFound = std::ranges::any_of(bonded_ias, [](auto const &kv) {
+ return (boost::get(&(*kv.second)) != nullptr);
+ });
}
if (!VolumeInitDone && BoundariesFound) {
@@ -62,14 +63,14 @@ void ImmersedBoundaries::init_volume_conservation(CellStructure &cs) {
// Loop through all bonded interactions and check if we need to set the
// reference volume
- for (auto &kv : bonded_ia_params) {
- if (auto *v = boost::get(&(*kv.second))) {
+ for (auto &kv : bonded_ias) {
+ if (auto *v = boost::get(kv.second.get())) {
// This check is important because InitVolumeConservation may be called
// accidentally during the integration. Then we must not reset the
// reference
BoundariesFound = true;
if (v->volRef == 0.) {
- v->volRef = VolumesCurrent[static_cast(v->softID)];
+ v->volRef = VolumesCurrent[v->softID];
}
}
}
@@ -78,13 +79,15 @@ void ImmersedBoundaries::init_volume_conservation(CellStructure &cs) {
}
}
-static const IBMVolCons *vol_cons_parameters(Particle const &p1) {
- auto const it = boost::find_if(p1.bonds(), [](auto const &bond) -> bool {
- return boost::get(bonded_ia_params.at(bond.bond_id()).get());
+static IBMVolCons const *
+vol_cons_parameters(BondedInteractionsMap const &bonded_ias,
+ Particle const &p1) {
+ auto const it = boost::find_if(p1.bonds(), [&](auto const &bond) -> bool {
+ return boost::get(bonded_ias.at(bond.bond_id()).get());
});
return (it != p1.bonds().end())
- ? boost::get(bonded_ia_params.at(it->bond_id()).get())
+ ? boost::get(bonded_ias.at(it->bond_id()).get())
: nullptr;
}
@@ -96,18 +99,19 @@ void ImmersedBoundaries::calc_volumes(CellStructure &cs) {
if (!BoundariesFound)
return;
- auto const &box_geo = *System::get_system().box_geo;
+ auto const &box_geo = *get_system().box_geo;
+ auto const &bonded_ias = *get_system().bonded_ias;
// 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, &box_geo](Particle &p1, int bond_id,
- std::span partners) {
- auto const vol_cons_params = vol_cons_parameters(p1);
+ cs.bond_loop([&tempVol, &box_geo, &bonded_ias](
+ Particle &p1, int bond_id, std::span partners) {
+ auto const vol_cons_params = vol_cons_parameters(bonded_ias, p1);
if (vol_cons_params &&
- boost::get(bonded_ia_params.at(bond_id).get()) != nullptr) {
+ boost::get(bonded_ias.at(bond_id).get()) != nullptr) {
// Our particle is the leading particle of a triel
// Get second and third particle of the triangle
Particle &p2 = *partners[0];
@@ -137,7 +141,7 @@ void ImmersedBoundaries::calc_volumes(CellStructure &cs) {
const double v213 = x2[0] * x1[1] * x3[2];
const double v123 = x1[0] * x2[1] * x3[2];
- tempVol[static_cast(vol_cons_params->softID)] +=
+ tempVol[vol_cons_params->softID] +=
1.0 / 6.0 * (-v321 + v231 + v312 - v132 - v213 + v123);
}
return false;
@@ -154,16 +158,17 @@ void ImmersedBoundaries::calc_volume_force(CellStructure &cs) {
if (!BoundariesFound)
return;
- auto const &box_geo = *System::get_system().box_geo;
+ auto const &box_geo = *get_system().box_geo;
+ auto const &bonded_ias = *get_system().bonded_ias;
- cs.bond_loop([this, &box_geo](Particle &p1, int bond_id,
- std::span