4 #include "externalpotential.h" 5 #include "potentials_base.h" 8 #include "aux/eigensupport.h" 9 #include "aux/pairmatrix.h" 10 #include "smart_montecarlo.h" 11 #include <range/v3/range/conversion.hpp> 12 #include <spdlog/spdlog.h> 17 struct freesasa_parameters_fwd;
20 #if defined(__cpp_lib_parallel_algorithm) && __has_include(<tbb/tbb.h>) 24 #if defined(__cpp_lib_parallel_algorithm) && \ 25 __has_include(<tbb/tbb.h>) && ((defined(__clang__) && __clang_major__ >= 10) || (defined(__GNUC__) && __GNUC__ >= 10)) 26 #define HAS_PARALLEL_TRANSFORM_REDUCE 31 namespace ReactionCoordinate {
32 class ReactionCoordinateBase;
35 namespace pairpotential {
74 double energyOfAllGroups()
const;
78 double energy(
const Change& change)
override;
94 using Tcomplex = std::complex<double>;
100 double surface_dielectric_constant = 0;
101 double bjerrum_length = 0;
103 double kappa_squared = 0;
105 double const_inf = 0;
106 double check_k2_zero = 0;
107 bool use_spherical_sum =
true;
108 int num_kvectors = 0;
120 Policies policy = PBC;
125 {EwaldData::INVALID,
nullptr},
126 {EwaldData::PBC,
"PBC"},
127 {EwaldData::PBCEigen,
"PBCEigen"},
128 {EwaldData::IPBC,
"IPBC"},
129 {EwaldData::IPBCEigen,
"IPBCEigen"},
144 const Point&)
const = 0;
147 const Space::GroupVector& groups)
const = 0;
148 virtual void updateComplex(
EwaldData& d,
const Change& change,
const Space::GroupVector& groups,
149 const Space::GroupVector& oldgroups)
153 Space::GroupVector& groups) = 0;
154 virtual double surfaceEnergy(
156 const Space::GroupVector& groups) = 0;
157 virtual double reciprocalEnergy(
const EwaldData& d) = 0;
169 auto is_partially_inactive = [](
const Group& group) {
170 return group.size() != group.capacity();
172 if (std::ranges::any_of(groups, is_partially_inactive)) {
173 throw std::runtime_error(
"Eigen optimized Ewald not available with inactive groups");
175 auto first_particle = groups.front().begin();
176 auto last_particle = groups.back().end();
179 auto charge = asEigenVector(first_particle, last_particle,
181 return std::make_tuple(pos, charge);
184 static auto mapGroupsToEigen(
const Space::GroupVector& groups)
186 auto is_partially_inactive = [](
const Group& group) {
187 return group.size() != group.capacity();
189 if (std::ranges::any_of(groups, is_partially_inactive)) {
190 throw std::runtime_error(
"Eigen optimized Ewald not available with inactive groups");
192 auto first_particle = groups.front().begin();
193 auto last_particle = groups.back().end();
196 auto charge = asEigenVector(first_particle, last_particle,
198 return std::make_tuple(pos, charge);
201 static std::unique_ptr<EwaldPolicyBase> makePolicy(EwaldData::Policies);
211 void updateComplex(
EwaldData& data,
const Space::GroupVector& groups)
const override;
212 void updateComplex(
EwaldData& d,
const Change& change,
const Space::GroupVector& groups,
213 const Space::GroupVector& oldgroups)
const override;
214 double selfEnergy(
const EwaldData& d,
Change& change, Space::GroupVector& groups)
override;
216 const Space::GroupVector& groups)
override;
217 double reciprocalEnergy(
const EwaldData& d)
override;
233 using PolicyIonIon::updateComplex;
234 void updateComplex(
EwaldData&,
const Space::GroupVector&)
const override;
235 double reciprocalEnergy(
const EwaldData&)
override;
243 using PolicyIonIon::updateComplex;
246 void updateComplex(
EwaldData&,
const Space::GroupVector&)
const override;
247 void updateComplex(
EwaldData&,
const Change&,
const Space::GroupVector&,
248 const Space::GroupVector&)
const override;
257 using PolicyIonIonIPBC::updateComplex;
258 void updateComplex(
EwaldData&,
const Space::GroupVector&)
const override;
271 std::shared_ptr<EwaldPolicyBase> policy;
272 const Space::GroupVector* old_groups =
nullptr;
277 void init()
override;
278 void setOldGroups(
const Space::GroupVector&
280 void updateState(
const Change& change)
override;
281 double energy(
const Change& change)
override;
283 void to_json(
json& j)
const override;
284 void force(std::vector<Point>& forces)
override;
294 double pressure = 0.0;
295 static const std::map<std::string, double>
299 double energy(
const Change& change)
override;
300 void to_json(
json& j)
const override;
312 std::unique_ptr<ReactionCoordinate::ReactionCoordinateBase> coordinate;
313 std::optional<Faunus::pairpotential::HarmonicBond> harmonic;
317 double energy(
const Change& change)
override;
318 void to_json(
json& j)
const override;
335 std::map<int, BondVector> internal_bonds;
337 double sumBondEnergy(
const BondVector& bonds)
const;
340 const std::ranges::range
auto& particle_indices)
const;
341 void updateInternalBonds();
346 void to_json(
json& j)
const override;
347 double energy(
const Change& change)
override;
348 void force(std::vector<Point>& forces)
override;
361 const std::ranges::range
auto& particle_indices)
const 363 assert(std::is_sorted(particle_indices.begin(), particle_indices.end()));
365 auto index_is_included = [&](
auto index) {
366 return std::binary_search(particle_indices.begin(), particle_indices.end(), index);
368 auto affected_bonds = bonds | std::views::filter([&](
const auto& bond) {
369 return std::ranges::any_of(bond->indices, index_is_included);
371 auto bond_energy = [dist = spc.geometry.getDistanceFunc()](
const auto& bond) {
372 return bond->energyFunc(dist);
374 return std::transform_reduce(affected_bonds.begin(), affected_bonds.end(), 0.0, std::plus<>(),
388 using namespace std::views;
389 return iota(0, static_cast<int>(size)) |
390 filter([&](
auto i) {
return !std::binary_search(range.begin(), range.end(), i); });
401 bool allow_anisotropic_pair_potential =
true>
405 TPairPotential pair_potential;
415 : geometry(spc.geometry)
417 , potentials(potentials)
428 template <
typename T>
inline double potential(
const T& a,
const T& b)
const 431 if constexpr (allow_anisotropic_pair_potential) {
433 return pair_potential(a, b, r.squaredNorm(), r);
436 return pair_potential(a, b, geometry.
sqdist(a.pos, b.pos), {0, 0, 0});
441 template <
typename ParticleType>
442 inline Point force(
const ParticleType& a,
const ParticleType& b)
const 445 const Point b_towards_a = geometry.
vdist(a.pos, b.pos);
446 return pair_potential.force(a, b, b_towards_a.squaredNorm(), b_towards_a);
453 template <
typename... Args>
inline auto operator()(Args&&... args)
455 return potential(std::forward<Args>(args)...);
464 if (pair_potential.selfEnergy) {
465 faunus_logger->debug(
"Adding self-energy from {} to hamiltonian", pair_potential.name);
470 void from_json(
const json& j)
472 pairpotential::from_json(j, pair_potential);
473 if (!pair_potential.isotropic && !allow_anisotropic_pair_potential) {
474 throw std::logic_error(
"Only isotropic pair potentials are allowed.");
476 addPairPotentialSelfEnergy();
479 void to_json(
json& j)
const { pair_potential.to_json(j); }
482 template <
typename T>
483 concept RequirePairEnergy = requires(
T instance) {
486 instance.addPairPotentialSelfEnergy();
516 Scheme scheme = Scheme::SERIAL;
520 virtual void reserve(
size_t number_of_particles);
521 virtual void clear();
522 virtual void from_json(
const json& j);
523 virtual void to_json(
json& j)
const;
525 virtual explicit operator double();
530 template <
typename TOtherAccumulator>
533 value +=
static_cast<double>(acc);
539 {{EnergyAccumulatorBase::Scheme::INVALID,
nullptr},
540 {EnergyAccumulatorBase::Scheme::SERIAL,
"serial"},
541 {EnergyAccumulatorBase::Scheme::OPENMP,
"openmp"},
542 {EnergyAccumulatorBase::Scheme::PARALLEL,
"parallel"}})
545 concept RequireEnergyAccumulator = std::is_base_of_v<EnergyAccumulatorBase, T>;
557 template <RequirePairEnergy PairEnergy>
567 , pair_energy(pair_energy)
586 value += pair_energy.
potential(pair.first.get(), pair.second.get());
590 void from_json(
const json& j)
override 592 EnergyAccumulatorBase::from_json(j);
593 if (scheme != Scheme::SERIAL) {
594 faunus_logger->warn(
"unsupported summation scheme; falling back to 'serial'");
604 template <RequirePairEnergy PairEnergy>
608 std::vector<ParticlePair> particle_pairs;
611 const size_t max_particles_in_buffer =
617 , pair_energy(pair_energy)
622 void reserve(
size_t number_of_particles)
override 625 number_of_particles = std::min(number_of_particles, max_particles_in_buffer);
626 const auto number_of_pairs = (number_of_particles - 1U) * number_of_particles / 2U;
627 faunus_logger->debug(
628 std::format(
"reserving memory for {} energy pairs ({} MB)", number_of_pairs,
629 number_of_pairs *
sizeof(
ParticlePair) / (1024U * 1024U)));
630 particle_pairs.reserve(number_of_pairs);
632 catch (std::exception& e) {
633 throw std::runtime_error(std::format(
634 "cannot allocate memory for energy pairs: {}. Use another summation policy.",
639 void clear()
override 642 particle_pairs.clear();
660 assert(particle_pairs.capacity() > 0);
661 if (particle_pairs.size() == particle_pairs.capacity()) {
664 particle_pairs.emplace_back(pair);
668 explicit operator double()
override 672 value += accumulateOpenMP();
674 case Scheme::PARALLEL:
675 value += accumulateParallel();
678 value += accumulateSerial();
680 particle_pairs.clear();
685 double accumulateSerial()
const 688 for (
const auto& [particle1, particle2] : particle_pairs) {
689 sum += pair_energy.
potential(particle1.get(), particle2.get());
694 double accumulateParallel()
const 696 #if defined(HAS_PARALLEL_TRANSFORM_REDUCE) 697 return std::transform_reduce(
698 std::execution::par, particle_pairs.cbegin(), particle_pairs.cend(), 0.0, std::plus<>(),
699 [&](
const auto& pair) {
700 return pair_energy.
potential(pair.first.get(), pair.second.get());
703 return accumulateSerial();
707 double accumulateOpenMP()
const 710 #pragma omp parallel for reduction(+ : sum) 711 for (
const auto& pair : particle_pairs) {
712 sum += pair_energy.
potential(pair.first.get(), pair.second.get());
718 template <RequirePairEnergy TPairEnergy>
719 std::unique_ptr<EnergyAccumulatorBase>
720 createEnergyAccumulator(
const json& j,
const TPairEnergy& pair_energy,
double initial_value)
722 std::unique_ptr<EnergyAccumulatorBase> accumulator;
723 if (j.value(
"summation_policy", EnergyAccumulatorBase::Scheme::SERIAL) !=
724 EnergyAccumulatorBase::Scheme::SERIAL) {
726 std::make_unique<DelayedEnergyAccumulator<TPairEnergy>>(pair_energy, initial_value);
727 faunus_logger->debug(
"activated delayed energy summation");
731 std::make_unique<InstantEnergyAccumulator<TPairEnergy>>(pair_energy, initial_value);
732 faunus_logger->debug(
"activated instant energy summation");
734 accumulator->from_json(j);
748 double default_cutoff_squared = pc::max_value;
754 void setSingleCutoff(
double cutoff);
767 cutoff_squared(group1.
id, group2.
id);
770 double getCutoff(
size_t id1,
size_t id2)
const;
776 template <
typename... Args>
inline auto operator()(Args&&... args)
778 return cut(std::forward<Args>(args)...);
820 void from_json(
const json& j) { Energy::from_json(j, cut); }
822 void to_json(
json& j)
const { Energy::to_json(j, cut); }
837 template <RequireEnergyAccumulator TAccumulator,
typename T>
840 pair_accumulator += {std::cref(a), std::cref(b)};
855 template <RequireEnergyAccumulator TAccumulator,
typename TGroup>
858 const auto& moldata = group.traits();
859 if (!moldata.rigid) {
860 const int group_size = group.size();
861 for (
int i = 0; i < group_size - 1; ++i) {
862 for (
int j = i + 1; j < group_size; ++j) {
865 if (group.isAtomic() || !moldata.isPairExcluded(i, j)) {
866 particle2particle(pair_accumulator, group[i], group[j]);
885 template <RequireEnergyAccumulator TAccumulator,
typename TGroup>
886 void groupInternal(TAccumulator& pair_accumulator,
const TGroup& group,
const std::size_t index)
888 const auto& moldata = group.traits();
889 if (!moldata.rigid) {
890 if (group.isAtomic()) {
893 for (
int i = 0; i < index; ++i) {
894 particle2particle(pair_accumulator, group[index], group[i]);
896 for (
int i = index + 1; i < group.size(); ++i) {
897 particle2particle(pair_accumulator, group[index], group[i]);
902 for (
int i = 0; i < index; ++i) {
903 if (!moldata.isPairExcluded(index, i)) {
904 particle2particle(pair_accumulator, group[index], group[i]);
907 for (
int i = index + 1; i < group.size(); ++i) {
908 if (!moldata.isPairExcluded(index, i)) {
909 particle2particle(pair_accumulator, group[index], group[i]);
931 template <RequireEnergyAccumulator TAccumulator,
typename TGroup,
typename TIndex>
932 void groupInternal(TAccumulator& pair_accumulator,
const TGroup& group,
const TIndex& index)
934 auto& moldata = group.traits();
935 if (!moldata.rigid) {
936 if (index.size() == 1) {
937 groupInternal(pair_accumulator, group, index[0]);
944 for (
int i : index) {
945 for (
int j : index_complement) {
946 if (!moldata.isPairExcluded(i, j)) {
947 particle2particle(pair_accumulator, group[i], group[j]);
952 for (
auto i_it = index.begin(); i_it < index.end(); ++i_it) {
953 for (
auto j_it = std::next(i_it); j_it < index.end(); ++j_it) {
954 if (!moldata.isPairExcluded(*i_it, *j_it)) {
955 particle2particle(pair_accumulator, group[*i_it], group[*j_it]);
979 template <RequireEnergyAccumulator TAccumulator,
typename TGroup>
980 void group2group(TAccumulator& pair_accumulator,
const TGroup& group1,
const TGroup& group2)
982 if (!cut(group1, group2)) {
983 for (
auto& particle1 : group1) {
984 for (
auto& particle2 : group2) {
985 particle2particle(pair_accumulator, particle1, particle2);
1015 template <RequireEnergyAccumulator TAccumulator,
typename TGroup>
1016 void group2group(TAccumulator& pair_accumulator,
const TGroup& group1,
const TGroup& group2,
1017 const std::vector<std::size_t>& index1)
1019 if (!cut(group1, group2)) {
1020 for (
auto particle1_ndx : index1) {
1021 for (
auto& particle2 : group2) {
1022 particle2particle(pair_accumulator, *(group1.begin() + particle1_ndx),
1052 template <RequireEnergyAccumulator TAccumulator,
typename TGroup>
1053 void group2group(TAccumulator& pair_accumulator,
const TGroup& group1,
const TGroup& group2,
1054 const std::vector<std::size_t>& index1,
const std::vector<std::size_t>& index2)
1056 if (!cut(group1, group2)) {
1057 if (!index2.empty()) {
1059 group2group(pair_accumulator, group2, group1, index2);
1062 for (
auto particle1_ndx : index1) {
1063 for (
auto particle2_ndx : index2_complement) {
1064 particle2particle(pair_accumulator, group2[particle2_ndx],
1065 group1[particle1_ndx]);
1069 else if (!index1.empty()) {
1071 group2group(pair_accumulator, group1, group2, index1);
1097 template <RequireEnergyAccumulator TAccumulator,
typename TGroup,
typename TGroups>
1098 void group2groups(TAccumulator& pair_accumulator,
const TGroup& group,
const TGroups& groups)
1100 for (
auto& other_group : groups) {
1101 if (&other_group != &group) {
1102 group2group(pair_accumulator, group, other_group);
1128 template <RequireEnergyAccumulator TAccumulator,
typename TGroup,
typename TGroups>
1130 const TGroups& group_index,
const std::vector<std::size_t>& index)
1132 for (
auto other_group_ndx : group_index) {
1133 const auto& other_group = spc.
groups[other_group_ndx];
1134 if (&other_group != &group) {
1135 group2group(pair_accumulator, group, other_group, index);
1155 template <RequireEnergyAccumulator TAccumulator,
typename Tgroup>
1156 void group2all(TAccumulator& pair_accumulator,
const Tgroup& group)
1158 for (
auto& other_group : spc.
groups) {
1159 if (&other_group != &group) {
1160 group2group(pair_accumulator, group, other_group);
1182 template <RequireEnergyAccumulator TAccumulator,
typename TGroup>
1183 void group2all(TAccumulator& pair_accumulator,
const TGroup& group,
const int index)
1185 const auto& particle = group[index];
1186 for (
auto& other_group : spc.
groups) {
1187 if (&other_group != &group) {
1188 if (!cut(other_group, group)) {
1189 for (
auto& other_particle : other_group) {
1190 particle2particle(pair_accumulator, particle, other_particle);
1212 template <RequireEnergyAccumulator TAccumulator,
typename Tgroup>
1213 void group2all(TAccumulator& pair_accumulator,
const Tgroup& group,
1214 const std::vector<std::size_t>& index)
1216 if (index.size() == 1) {
1217 group2all(pair_accumulator, group, index[0]);
1220 for (
auto& other_group : spc.
groups) {
1221 if (&other_group != &group) {
1222 group2group(pair_accumulator, group, other_group, index);
1241 template <RequireEnergyAccumulator TAccumulator,
typename T>
1244 for (
auto group1_ndx_it = group_index.begin(); group1_ndx_it < group_index.end();
1248 for (
auto group2_ndx_it = std::next(group1_ndx_it); group2_ndx_it < group_index.end();
1250 group2group(pair_accumulator, spc.
groups[*group1_ndx_it],
1251 spc.
groups[*group2_ndx_it]);
1268 template <RequireEnergyAccumulator TAccumulator,
typename T>
1271 groups2self(pair_accumulator, group_index);
1273 for (
auto group1_ndx : group_index) {
1274 for (
auto group2_ndx : index_complement) {
1275 group2group(pair_accumulator, spc.
groups[group1_ndx], spc.
groups[group2_ndx]);
1290 template <RequireEnergyAccumulator TAccumulator>
void all(TAccumulator& pair_accumulator)
1292 for (
auto group_it = spc.
groups.begin(); group_it < spc.
groups.end(); ++group_it) {
1293 groupInternal(pair_accumulator, *group_it);
1294 for (
auto other_group_it = std::next(group_it); other_group_it < spc.
groups.end();
1296 group2group(pair_accumulator, *group_it, *other_group_it);
1313 template <RequireEnergyAccumulator TAccumulator,
typename TCondition>
1314 void all(TAccumulator& pair_accumulator, TCondition condition)
1316 for (
auto group_it = spc.
groups.begin(); group_it < spc.
groups.end(); ++group_it) {
1317 if (condition(*group_it)) {
1318 groupInternal(pair_accumulator, *group_it);
1320 for (
auto other_group_it = std::next(group_it); other_group_it < spc.
groups.end();
1322 group2group(pair_accumulator, *group_it, *other_group_it);
1347 template <RequireEnergyAccumulator TAccumulator>
1350 const auto& change_data = change.
groups.at(0);
1351 const auto& group = spc.
groups.at(change_data.group_index);
1352 if (change_data.relative_atom_indices.size() == 1) {
1354 pairing.group2all(pair_accumulator, group, change_data.relative_atom_indices[0]);
1355 if (change_data.internal) {
1356 pairing.groupInternal(pair_accumulator, group,
1357 change_data.relative_atom_indices[0]);
1361 const bool change_all =
1362 change_data.relative_atom_indices.empty();
1364 pairing.group2all(pair_accumulator, group);
1365 if (change_data.internal) {
1366 pairing.groupInternal(pair_accumulator, group);
1370 pairing.group2all(pair_accumulator, group, change_data.relative_atom_indices);
1371 if (change_data.internal) {
1372 pairing.groupInternal(pair_accumulator, group,
1373 change_data.relative_atom_indices);
1390 template <RequireEnergyAccumulator TAccumulator>
1396 ranges::to<std::vector>;
1397 auto filter_active = [](
int size) {
1398 return std::views::filter([size](
const auto i) {
return i < size; });
1402 for (
auto change_group1_it = change.
groups.begin(); change_group1_it < change.
groups.end();
1403 ++change_group1_it) {
1404 const auto& group1 = spc.
groups.at(change_group1_it->group_index);
1406 const auto index1 = change_group1_it->relative_atom_indices |
1407 filter_active(group1.size()) | ranges::to<std::vector>;
1408 if (!index1.empty()) {
1410 pairing.group2groups(pair_accumulator, group1, fixed, index1);
1414 for (
auto change_group2_it = std::next(change_group1_it);
1415 change_group2_it < change.
groups.end(); ++change_group2_it) {
1416 const auto& group2 = spc.
groups.at(change_group2_it->group_index);
1417 const auto index2 = change_group2_it->relative_atom_indices |
1418 filter_active(group2.size()) | ranges::to<std::vector>;
1419 if (!index1.empty() || !index2.empty()) {
1422 pairing.group2group(pair_accumulator, group1, group2, index1, index2);
1425 if (!index1.empty() && !
molecules.at(group1.id).rigid) {
1427 if (change_group1_it->all) {
1428 pairing.groupInternal(pair_accumulator, group1);
1431 pairing.groupInternal(pair_accumulator, group1, index1);
1447 template <RequireEnergyAccumulator TAccumulator>
1450 assert(std::is_sorted(change.
groups.begin(), change.
groups.end()));
1452 pairing.all(pair_accumulator);
1456 pairing.all(pair_accumulator, [](
auto& group) {
1457 return group.isAtomic() || group.traits().compressible;
1461 if (change.
groups.size() == 1) {
1464 accumulateGroup(pair_accumulator, change);
1469 pairing.groups2all(pair_accumulator, moved);
1473 accumulateSpeciation(pair_accumulator, change);
1483 void from_json(
const json& j) { pairing.from_json(j); }
1485 void to_json(
json& j)
const { pairing.to_json(j); }
1488 template <
typename Accumulator>
1489 void group2group(Accumulator& pair_accumulator,
const Space::GroupType& group1,
1492 pairing.group2group(std::forward<Accumulator&>(pair_accumulator),
1493 std::forward<const Space::GroupType&>(group1),
1494 std::forward<const Space::GroupType&>(group2));
1501 virtual double particleParticleEnergy(
const Particle& particle1,
const Particle& particle2) = 0;
1502 virtual double groupGroupEnergy(
const Group& group1,
const Group& group2) = 0;
1512 template <RequirePairEnergy TPairEnergy,
typename TPairingPolicy>
1521 std::shared_ptr<EnergyAccumulatorBase>
1527 , pair_energy(spc, pot)
1532 energy_accumulator = createEnergyAccumulator(j, pair_energy, 0.0);
1536 double particleParticleEnergy(
const Particle& particle1,
const Particle& particle2)
override 1538 return pair_energy(particle1, particle2);
1541 double groupGroupEnergy(
const Group& group1,
const Group& group2)
override 1544 pairing.group2group(accumulator, group1, group2);
1545 return static_cast<double>(accumulator);
1548 void from_json(
const json& j)
1550 pair_energy.from_json(j);
1551 pairing.from_json(j);
1556 pair_energy.to_json(j);
1558 energy_accumulator->to_json(j);
1563 energy_accumulator->clear();
1566 energy_accumulator)) {
1567 pairing.accumulate(*ptr, change);
1570 energy_accumulator)) {
1571 pairing.accumulate(*ptr, change);
1574 pairing.accumulate(*energy_accumulator, change);
1576 return static_cast<double>(*energy_accumulator);
1584 void force(std::vector<Point>& forces)
override 1588 assert(forces.size() == spc.
particles.size() &&
1589 "the forces size must match the particle size");
1590 for (
size_t i = 0; i < spc.
particles.size() - 1; ++i) {
1591 for (
size_t j = i + 1; j < spc.
particles.size(); ++j) {
1613 template <RequirePairEnergy TPairEnergy,
typename TPairingPolicy>
1618 Eigen::MatrixXf energy_cache;
1621 template <
typename TGroup>
double g2g(
const TGroup& g1,
const TGroup& g2)
1623 int i = &g1 - spc.groups.data();
1624 int j = &g2 - spc.groups.data();
1628 if (EnergyTerm::state ==
1629 EnergyTerm::MonteCarloState::TRIAL) {
1631 Base::pairing.group2group(energy_accumulator, g1, g2);
1632 energy_cache(i, j) =
static_cast<double>(energy_accumulator);
1634 return energy_cache(i, j);
1637 template <
typename TGroup>
1638 double g2g(
const TGroup& g1,
const TGroup& g2,
1639 [[maybe_unused]]
const std::vector<std::size_t>& index)
1658 const auto groups_size = spc.
groups.size();
1659 energy_cache.resize(groups_size, groups_size);
1660 energy_cache.setZero();
1662 for (
auto i = 0; i < groups_size - 1; ++i) {
1663 for (
auto j = i + 1; j < groups_size; ++j) {
1665 Base::pairing.group2group(u, spc.
groups.at(i), spc.
groups.at(j));
1666 energy_cache(i, j) =
static_cast<double>(u);
1677 double energy_sum = 0.0;
1679 for (
auto i = spc.
groups.begin(); i < spc.
groups.end(); ++i) {
1680 for (
auto j = std::next(i); j < Base::spc.groups.end(); ++j) {
1681 energy_sum += g2g(*i, *j);
1687 if (change.
groups.size() == 1) {
1688 const auto& d = change.
groups[0];
1689 const auto& g1 = spc.
groups.at(d.group_index);
1690 for (
auto g2_it = spc.
groups.begin(); g2_it < spc.
groups.end(); ++g2_it) {
1691 if (&g1 != &(*g2_it)) {
1692 energy_sum += g2g(g1, *g2_it, d.relative_atom_indices);
1703 for (
auto i = moved.begin(); i < moved.end(); ++i) {
1704 for (
auto j = std::next(i); j < moved.end(); ++j) {
1714 for (
auto i : moved) {
1715 for (
auto j : fixed) {
1722 ranges::to<std::vector>;
1723 const size_t moved_size = moved.size();
1724 const size_t fixed_size = fixed.size();
1725 for (
auto i = 0; i < moved_size; ++i) {
1726 for (
auto j = 0; j < fixed_size; ++j) {
1727 energy_sum += g2g(spc.
groups[moved[i]], spc.
groups[fixed[j]]);
1741 auto other =
dynamic_cast<decltype(this)
>(base_ptr);
1744 energy_cache.triangularView<Eigen::StrictlyUpper>() =
1745 (other->energy_cache).template triangularView<Eigen::StrictlyUpper>();
1748 for (
const auto& d : change.
groups) {
1749 for (
int i = 0; i < d.group_index; i++) {
1750 energy_cache(i, d.group_index) = other->energy_cache(i, d.group_index);
1752 for (
size_t i = d.group_index + 1; i < spc.
groups.size(); i++) {
1753 energy_cache(d.group_index, i) = other->energy_cache(d.group_index, i);
1760 #ifdef ENABLE_FREESASA 1771 std::vector<double> positions;
1772 std::vector<double> radii;
1773 std::vector<double> sasa;
1776 double cosolute_molarity = 0.;
1777 std::unique_ptr<freesasa_parameters_fwd> parameters;
1780 void to_json(
json& j)
const override;
1782 void updateSASA(
const Change& change);
1783 void init()
override;
1791 template <
typename Tfirst,
typename Tend>
1792 void updateRadii(Tfirst begin, Tend end, [[maybe_unused]]
const Change& change)
1794 const auto number_of_particles = std::distance(begin, end);
1796 radii.reserve(number_of_particles);
1797 std::transform(begin, end, std::back_inserter(radii),
1798 [](
const Particle& particle) {
return particle.
traits().sigma * 0.5; });
1807 template <
typename Tfirst,
typename Tend>
1808 void updatePositions(Tfirst begin, Tend end, [[maybe_unused]]
const Change& change)
1810 const auto number_of_particles = std::distance(begin, end);
1812 positions.reserve(3 * number_of_particles);
1814 const auto* xyz = particle.pos.data();
1815 positions.insert(positions.end(), xyz, xyz + 3);
1825 FreeSASAEnergy(
const Space& spc,
double cosolute_molarity,
double probe_radius);
1826 FreeSASAEnergy(
const json& j,
const Space& spc);
1827 double energy(
const Change& change)
override;
1829 const std::vector<double>& getAreas()
const {
return sasa; }
1843 void to_json(
json& j)
const override;
1847 void init()
override;
1848 using index_type = size_t;
1851 double cosolute_molarity = 0.0;
1852 std::unique_ptr<SASA::SASABase>
1858 return static_cast<index_type
>(std::addressof(particle) -
1864 int slices_per_atom = 25,
bool dense_container =
true);
1866 const std::vector<double>& getAreas()
const;
1867 double energy(
const Change& change)
override;
1877 std::vector<std::vector<index_type>>
1879 std::vector<index_type>
1883 void init()
override;
1885 void updateChangedIndices(
const Change& change);
1886 void insertChangedNeighboursOf(index_type index, std::set<index_type>& target_indices)
const;
1889 SASAEnergy(
const Space& spc,
double cosolute_molarity,
double probe_radius,
1890 int slices_per_atom = 25,
bool dense_container =
true);
1892 double energy(
const Change& change)
override;
1906 double scale_energy = 1.0;
1907 const Point& particle;
1908 void to_json(
json& j)
const override;
1912 double energy(
const Change& change)
override;
1928 MoleculeData::index_type molid1;
1929 MoleculeData::index_type molid2;
1930 std::map<MoleculeData::index_type, Average<double>> mean_charges;
1931 std::unique_ptr<ExprFunction<double>> expr;
1932 json json_input_backup;
1936 double mean_charge1 = 0;
1937 double mean_charge2 = 0;
1938 double mass_center_separation = 0;
1941 Properties properties;
1943 void to_json(
json& j)
const override;
1944 void setParameters(
const Group& group1,
const Group& group2);
1948 double energy(
const Change& change)
override;
1957 double maximum_allowed_energy = pc::infty;
1960 decltype(vec)& energy_terms;
1962 addEwald(
const json& j,
1964 void checkBondedMolecules()
const;
1965 void to_json(
json& j)
const override;
1967 std::unique_ptr<EnergyTerm> createEnergy(
Space& spc,
const std::string& name,
const json& j);
1971 void init()
override;
1972 void updateState(
const Change& change)
override;
1974 double energy(
const Change& change)
override;
1975 const std::vector<double>&
1976 latestEnergies()
const;
auto operator()(Args &&... args)
A functor alias for cut().
Definition: energy.h:776
nlohmann::json json
JSON object.
Definition: json_support.h:10
void sync(EnergyTerm *base_ptr, const Change &change) override
Copy energy matrix from other.
Definition: energy.h:1739
Eigen::Vector3d Point
3D vector used for positions, velocities, forces etc.
Definition: coordinates.h:7
auto asEigenMatrix(iter begin, iter end, memberptr m)
Eigen::Map facade to data members in STL container.
Definition: eigensupport.h:46
void all(TAccumulator &pair_accumulator, TCondition condition)
Cross pairing between all particles in the space.
Definition: energy.h:1314
double potential(const T &a, const T &b) const
Computes pair potential energy.
Definition: energy.h:428
Point pos
Particle position vector.
Definition: particle.h:227
int id
Molecule id.
Definition: group.h:183
const Space & spc
space to operate on
Definition: energy.h:1516
GroupPairingPolicy(Space &spc)
Definition: energy.h:814
Ion-Ion Ewald with isotropic periodic boundary conditions (IPBC) using Eigen operations.
Definition: energy.h:255
std::vector< Point > PointVector
Vector of 3D vectors.
Definition: core.h:24
Geometry class for spheres, cylinders, cuboids, hexagonal prism, truncated octahedron, slits.
Definition: geometry.h:342
void group2group(TAccumulator &pair_accumulator, const TGroup &group1, const TGroup &group2, const std::vector< std::size_t > &index1, const std::vector< std::size_t > &index2)
Cross pairing of particles in two groups.
Definition: energy.h:1053
Computes pair quantity difference for a systen perturbation.
Definition: energy.h:1334
bool moved_to_moved_interactions
If several groups are moved, should they interact with each other?
Definition: space.h:35
void group2all(TAccumulator &pair_accumulator, const Tgroup &group, const std::vector< std::size_t > &index)
Complete cartesian pairing between selected particles in a group and particles in other groups in spa...
Definition: energy.h:1213
The keys of the intra map are group index and the values is a vector of BondData. ...
Definition: energy.h:329
std::unique_ptr< SASA::SASABase > sasa
performs neighbour searching and subsequent sasa calculation
Definition: energy.h:1853
double T
floating point size
Definition: units.h:73
std::vector< GroupChange > groups
Touched groups by index in group vector.
Definition: space.h:56
void groupInternal(TAccumulator &pair_accumulator, const TGroup &group, const TIndex &index)
Pairing in the group involving only the particles present in the index.
Definition: energy.h:932
auto touchedGroupIndex() const
List of moved groups (index)
Definition: space.h:61
Provides a fast inlineable interface for non-bonded pair potential energy computation.
Definition: energy.h:402
void group2group(TAccumulator &pair_accumulator, const TGroup &group1, const TGroup &group2)
Complete cartesian pairing of particles in two groups.
Definition: energy.h:980
const Space & spc
Space to operate on.
Definition: energy.h:1849
Pressure term for NPT ensemble.
Definition: energy.h:290
Ion-Ion Ewald with periodic boundary conditions (PBC) using Eigen operations.
Definition: energy.h:231
void group2all(TAccumulator &pair_accumulator, const Tgroup &group)
Complete cartesian pairing between particles in a group and particles in other groups in space...
Definition: energy.h:1156
Used to add self energies to atoms from i.e.
Definition: externalpotential.h:194
A basic accumulator which immediately computes and adds energy of a pair of particles upon addition u...
Definition: energy.h:558
auto indexComplement(std::integral auto size, const std::ranges::range auto &range)
Provides a complementary set of ints with respect to the iota set of a given size.
Definition: energy.h:386
Interface for energy accumulators.
Definition: energy.h:501
bool everything
Everything has changed (particles, groups, volume)
Definition: space.h:32
std::string cite
Optional reference, preferably DOI, to further information.
Definition: energy.h:140
Ewald summation reciprocal energy.
Definition: energy.h:266
TCutoff cut
a cutoff functor that determines if energy between two groups can be ignored
Definition: energy.h:808
class for calculating SASA energies calculating SASA of each particle every step
Definition: energy.h:1840
std::pair< ParticleRef, ParticleRef > ParticlePair
References to two particles.
Definition: energy.h:506
const std::reference_wrapper< const Particle > ParticleRef
Particle reference.
Definition: energy.h:505
double sqdist(const Point &, const Point &) const
(Minimum) squared distance between two points
Definition: geometry.h:460
std::shared_ptr< EnergyAccumulatorBase > energy_accumulator
energy accumulator used for storing and summing pair-wise energies
Definition: energy.h:1522
Computes change in the non-bonded energy, assuming pairwise additive energy terms.
Definition: energy.h:1513
Data class for Ewald k-space calculations.
Definition: energy.h:92
Ion-Ion Ewald with isotropic periodic boundary conditions (IPBC)
Definition: energy.h:241
void to_json(json &j) const override
json output
Definition: energy.h:1554
Custom energy between pair of molecules.
Definition: energy.h:1924
void accumulateGroup(TAccumulator &pair_accumulator, const Change &change)
Computes pair quantity difference if only a single group has changed.
Definition: energy.h:1348
auto operator()(Args &&... args)
A functor alias for potential().
Definition: energy.h:453
double energy(const Change &change) override
energy due to change
Definition: energy.h:1561
bool isAtomic() const
Is it an atomic group?
Definition: group.h:187
auto activeParticles()
Range with all active particles.
Definition: space.h:302
double energy(const Change &change) override
energy due to change
Definition: energy.h:1671
Determines if two groups are separated beyond the cutoff distance.
Definition: energy.h:746
PairEnergy(Space &spc, BasePointerVector< EnergyTerm > &potentials)
Definition: energy.h:414
Particle pairing to calculate pairẃise interaction using particles' groups internally.
Definition: energy.h:804
void group2groups(TAccumulator &pair_accumulator, const TGroup &group, const TGroups &groups)
Complete cartesian pairing between particles in a group and a union of groups.
Definition: energy.h:1098
void addPairPotentialSelfEnergy()
Registers the potential self-energy to hamiltonian if needed.
Definition: energy.h:462
void groupInternal(TAccumulator &pair_accumulator, const TGroup &group, const std::size_t index)
Pairings of a single particle within the group.
Definition: energy.h:886
static auto mapGroupsToEigen(Space::GroupVector &groups)
Represent charges and positions using an Eigen facade (Map)
Definition: energy.h:167
Properties of changed groups.
Definition: space.h:40
Particle class for storing positions, id, and other properties.
Definition: particle.h:220
const AtomData & traits() const
get properties from AtomData
Definition: particle.cpp:183
Computes non-bonded energy contribution from changed particles.
Definition: energy.h:1614
void group2group(TAccumulator &pair_accumulator, const TGroup &group1, const TGroup &group2, const std::vector< std::size_t > &index1)
Cross pairing of particles in two groups.
Definition: energy.h:1016
concept RequirePairPotential
Concept matching a particle pair potential derived from Potential::PairPotentialBase ...
Definition: potentials_base.h:180
Stores a vector of particle pairs and postpones the energy evaluation until operator double() is call...
Definition: energy.h:605
Cell list class templates.
Definition: actions.cpp:11
class for calculating SASA energies calculating SASA of particles based on change object every step ...
Definition: energy.h:1874
bool volume_change
The volume has changed.
Definition: space.h:33
Check if particles are outside the simulation container.
Definition: energy.h:69
auto indexOf(const Particle &particle) const
absolute index of particle in space particle vector
Definition: energy.h:1856
End of Group class.
Definition: group.h:177
Aggregate and sum energy terms.
Definition: energy.h:1954
Eigen::VectorXd Aks
1xK for update optimization (see Eq.24, DOI:10.1063/1.481216)
Definition: energy.h:96
void all(TAccumulator &pair_accumulator)
Cross pairing between all particles in the space.
Definition: energy.h:1290
All energies inherit from this class.
Definition: externalpotential.h:21
std::vector< double > areas
Target buffer for calculated surface areas.
Definition: energy.h:1850
double charge
Particle charge.
Definition: particle.h:226
void accumulate(TAccumulator &pair_accumulator, const Change &change)
Computes pair quantity difference from changed particles.
Definition: energy.h:1448
ParticleVector particles
All particles are stored here!
Definition: space.h:120
Constrain system using reaction coordinates.
Definition: energy.h:308
NLOHMANN_JSON_SERIALIZE_ENUM(SpheroCylinderData::PatchType, {{SpheroCylinderData::PatchType::Invalid, nullptr}, {SpheroCylinderData::PatchType::Full, "full"}, {SpheroCylinderData::PatchType::Capped, "capped"}, {SpheroCylinderData::PatchType::None, "none"}}) class AtomData
General properties for atoms.
Definition: atomdata.h:61
TPairEnergy pair_energy
a functor to compute non-bonded energy between two particles, see PairEnergy
Definition: energy.h:1517
void groupInternal(TAccumulator &pair_accumulator, const TGroup &group)
All pairings within a group.
Definition: energy.h:856
std::vector< MoleculeData > molecules
List of molecule types.
Definition: molecule.cpp:22
Specify changes made to a system.
Definition: space.h:29
void force(std::vector< Point > &forces) override
Calculates the force on all particles.
Definition: energy.h:1584
void emplace_back(Args &... args)
Create an (derived) instance and append a pointer to it to the vector.
Definition: auxiliary.h:268
void accumulateSpeciation(TAccumulator &pair_accumulator, const Change &change)
Computes pair quantity difference if the number of particles has changed.
Definition: energy.h:1391
bool matter_change
The number of atomic or molecular species has changed.
Definition: space.h:34
void groups2all(TAccumulator &pair_accumulator, const T &group_index)
Cross pairing of particles between a union of groups and its complement in space. ...
Definition: energy.h:1269
bool cut(const Group &group1, const Group &group2)
Determines if two groups are separated beyond the cutoff distance.
Definition: energy.h:761
Eigen::VectorXcd Q_dipole
Complex 1xK vectors.
Definition: energy.h:97
const Space & spc
a space to operate on
Definition: energy.h:807
Placeholder for atoms and molecules.
Definition: space.h:92
Definition: energy.h:1498
Point vdist(const Point &, const Point &) const override
Minimum distance vector b->a.
Definition: geometry.h:429
Base class for Ewald k-space updates policies.
Definition: energy.h:137
Eigen::Matrix3Xd k_vectors
k-vectors, 3xK
Definition: energy.h:95
GroupVector groups
All groups are stored here (i.e. molecules)
Definition: space.h:121
Oscillating energy on a single particle.
Definition: energy.h:1902
Point mass_center
Mass center.
Definition: group.h:185
void groups2self(TAccumulator &pair_accumulator, const T &group_index)
Cross pairing of particles among a union of groups.
Definition: energy.h:1242
void reserve(size_t number_of_particles) override
Reserve memory for (N-1)*N/2 interaction pairs.
Definition: energy.h:622
size_t numParticles(Selection selection=Selection::ACTIVE) const
Number of (active) particles.
Definition: space.cpp:367
void particle2particle(TAccumulator &pair_accumulator, const T &a, const T &b) const
Add two interacting particles to the accumulator.
Definition: energy.h:838
Ion-Ion Ewald using periodic boundary conditions (PBC)
Definition: energy.h:207
void group2all(TAccumulator &pair_accumulator, const TGroup &group, const int index)
Complete cartesian pairing between a single particle in a group and particles in other groups in spac...
Definition: energy.h:1183
void group2groups(TAccumulator &pair_accumulator, const TGroup &group, const TGroups &group_index, const std::vector< std::size_t > &index)
Cross pairing of particles in a group and a union of groups.
Definition: energy.h:1129
TPairingPolicy pairing
pairing policy to effectively sum up the pairwise additive non-bonded energy
Definition: energy.h:1520
void init() override
Cache pair interactions in matrix.
Definition: energy.h:1656