ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
statistics_chain.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21/** \file
22 * Implementation of \ref statistics_chain.hpp "statistics_chain.hpp".
23 */
24
26
27#include "BoxGeometry.hpp"
28#include "Particle.hpp"
30#include "communication.hpp"
31#include "system/System.hpp"
32
33#include <utils/Vector.hpp>
34#include <utils/math/sqr.hpp>
36
37#include <boost/mpi/collectives/all_reduce.hpp>
38
39#include <array>
40#include <cmath>
41#include <functional>
42#include <stdexcept>
43#include <unordered_map>
44#include <vector>
45
46/**
47 * @brief Gather particle properties (or any derived quantities) on MPI rank 0.
48 * The data is collected into an unordered map.
49 */
50template <typename T> struct GatherParticleTraits {
51private:
52 std::vector<int> buffer_pid{};
53 std::vector<T> buffer_obs{};
54
55public:
56 virtual T kernel(Particle const &) const = 0;
57 virtual ~GatherParticleTraits() = default;
58
59 void fetch(CellStructure const &cell_structure, int pid) {
60 auto const ptr = cell_structure.get_local_particle(pid);
61 if (ptr != nullptr and not ptr->is_ghost()) {
62 buffer_pid.emplace_back(pid);
63 buffer_obs.emplace_back(kernel(*ptr));
64 }
65 }
66
67 auto join() {
68 std::unordered_map<int, T> map{};
71 if (::comm_cart.rank() == 0) {
72 for (std::size_t i = 0u; i < buffer_pid.size(); ++i) {
73 map[buffer_pid[i]] = buffer_obs[i];
74 }
75 }
76 buffer_pid.clear();
77 buffer_obs.clear();
78 return map;
79 }
80};
81
82struct GatherPos : public GatherParticleTraits<Utils::Vector3d> {
83 ~GatherPos() override = default;
85 GatherPos(BoxGeometry const &box_geo) : m_box_geo{box_geo} {}
86 Utils::Vector3d kernel(Particle const &p) const override {
88 }
89};
90
91struct GatherCom : public GatherParticleTraits<Utils::Vector3d> {
92 ~GatherCom() override = default;
94 GatherCom(BoxGeometry const &box_geo) : m_box_geo{box_geo} {}
95 Utils::Vector3d kernel(Particle const &p) const override {
96 return m_box_geo.unfolded_position(p.pos(), p.image_box()) * p.mass();
97 }
98};
99
100struct GatherMass : public GatherParticleTraits<double> {
101 ~GatherMass() override = default;
102 double kernel(Particle const &p) const override { return p.mass(); }
103};
104
105std::array<double, 4> calc_re(System::System const &system, int chain_start,
106 int chain_length, int n_chains) {
107 auto const &cell_structure = *system.cell_structure;
108 GatherPos prefetch{*system.box_geo};
109 double dist = 0.0, dist2 = 0.0, dist4 = 0.0;
110 std::array<double, 4> re{};
111
112 for (int i = 0; i < n_chains; i++) {
113 auto const pid2 = chain_start + i * chain_length;
114 auto const pid1 = pid2 + chain_length - 1;
115 prefetch.fetch(cell_structure, pid1);
116 prefetch.fetch(cell_structure, pid2);
117 }
118 auto const map = prefetch.join();
119 if (::comm_cart.rank() == 0) {
120 for (int i = 0; i < n_chains; i++) {
121 auto const pid2 = chain_start + i * chain_length;
122 auto const pid1 = pid2 + chain_length - 1;
123 auto const norm2 = (map.at(pid1) - map.at(pid2)).norm2();
124 dist += sqrt(norm2);
125 dist2 += norm2;
126 dist4 += norm2 * norm2;
127 }
128 auto const tmp = static_cast<double>(n_chains);
129 re[0] = dist / tmp;
130 re[2] = dist2 / tmp;
131 re[1] = (n_chains == 1) ? 0. : std::sqrt(re[2] - Utils::sqr(re[0]));
132 re[3] = (n_chains == 1) ? 0. : std::sqrt(dist4 / tmp - Utils::sqr(re[2]));
133 }
134 return re;
135}
136
137std::array<double, 4> calc_rg(System::System const &system, int chain_start,
138 int chain_length, int n_chains) {
139 auto const &cell_structure = *system.cell_structure;
140 GatherPos prefetch_pos{*system.box_geo};
141 GatherCom prefetch_com{*system.box_geo};
142 GatherMass prefetch_mass{};
143 double r_G = 0.0, r_G2 = 0.0, r_G4 = 0.0;
144 std::array<double, 4> rg{};
145
146 auto has_virtual = false;
147 for (int i = 0; i < n_chains * chain_length; ++i) {
148 auto const pid = chain_start + i;
149 auto const ptr = cell_structure.get_local_particle(pid);
150 if (ptr != nullptr and not ptr->is_ghost() and ptr->is_virtual()) {
151 has_virtual = true;
152 break;
153 }
154 }
155 if (boost::mpi::all_reduce(::comm_cart, has_virtual, std::logical_or<>{})) {
156 throw std::runtime_error(
157 "Center of mass is not well-defined for chains including virtual "
158 "sites. Virtual sites do not have a meaningful mass.");
159 }
160
161 for (int i = 0; i < n_chains * chain_length; ++i) {
162 auto const pid = chain_start + i;
163 prefetch_com.fetch(cell_structure, pid);
164 prefetch_pos.fetch(cell_structure, pid);
165 prefetch_mass.fetch(cell_structure, pid);
166 }
167
168 auto const map_pos = prefetch_pos.join();
169 auto const map_com = prefetch_com.join();
170 auto const map_mass = prefetch_mass.join();
171 if (::comm_cart.rank() == 0) {
172 for (int i = 0; i < n_chains; i++) {
173 double M = 0.0;
174 Utils::Vector3d r_CM{};
175 for (int j = 0; j < chain_length; j++) {
176 auto const pid = chain_start + i * chain_length + j;
177 r_CM += map_com.at(pid);
178 M += map_mass.at(pid);
179 }
180 r_CM /= M;
181 double tmp = 0.0;
182 for (int j = 0; j < chain_length; ++j) {
183 auto const pid = chain_start + i * chain_length + j;
184 auto const d = map_pos.at(pid) - r_CM;
185 tmp += d.norm2();
186 }
187 tmp /= static_cast<double>(chain_length);
188 r_G += sqrt(tmp);
189 r_G2 += tmp;
190 r_G4 += tmp * tmp;
191 }
192 auto const tmp = static_cast<double>(n_chains);
193 rg[0] = r_G / tmp;
194 rg[2] = r_G2 / tmp;
195 rg[1] = (n_chains == 1) ? 0. : std::sqrt(rg[2] - Utils::sqr(rg[0]));
196 rg[3] = (n_chains == 1) ? 0. : std::sqrt(r_G4 / tmp - Utils::sqr(rg[2]));
197 }
198 return rg;
199}
200
201std::array<double, 2> calc_rh(System::System const &system, int chain_start,
202 int chain_length, int n_chains) {
203 auto const &cell_structure = *system.cell_structure;
204 GatherPos prefetch{*system.box_geo};
205 double r_H = 0.0, r_H2 = 0.0;
206 std::array<double, 2> rh{};
207
208 auto const chain_l = static_cast<double>(chain_length);
209 auto const prefac = 0.5 * chain_l * (chain_l - 1.);
210 for (int p = 0; p < n_chains; p++) {
211 for (int i = chain_start + chain_length * p;
212 i < chain_start + chain_length * (p + 1); i++) {
213 prefetch.fetch(cell_structure, i);
214 for (int j = i + 1; j < chain_start + chain_length * (p + 1); j++) {
215 prefetch.fetch(cell_structure, j);
216 }
217 }
218 }
219 auto const map = prefetch.join();
220 if (::comm_cart.rank() == 0) {
221 for (int p = 0; p < n_chains; p++) {
222 double ri = 0.0;
223 for (int i = chain_start + chain_length * p;
224 i < chain_start + chain_length * (p + 1); i++) {
225 for (int j = i + 1; j < chain_start + chain_length * (p + 1); j++) {
226 ri += 1.0 / (map.at(i) - map.at(j)).norm();
227 }
228 }
229 auto const tmp = prefac / ri;
230 r_H += tmp;
231 r_H2 += tmp * tmp;
232 }
233 auto const tmp = static_cast<double>(n_chains);
234 rh[0] = r_H / tmp;
235 rh[1] = (n_chains == 1) ? 0. : std::sqrt(r_H2 / tmp - Utils::sqr(rh[0]));
236 }
237 return rh;
238}
Vector implementation and trait types for boost qvm interoperability.
auto unfolded_position(Utils::Vector3d const &pos, Utils::Vector3i const &image_box) const
Unfold particle coordinates to image box.
Describes a cell structure / cell system.
Particle * get_local_particle(int id)
Get a local particle by id.
Main system class.
std::shared_ptr< CellStructure > cell_structure
std::shared_ptr< BoxGeometry > box_geo
DEVICE_QUALIFIER constexpr reference at(size_type i)
Definition Array.hpp:97
boost::mpi::communicator comm_cart
The communicator.
void gather_buffer(std::vector< T, Allocator > &buffer, boost::mpi::communicator const &comm, int root=0)
Gather buffer with different size on each node.
DEVICE_QUALIFIER constexpr T sqr(T x)
Calculates the SQuaRe of x.
Definition sqr.hpp:28
std::array< double, 4 > calc_rg(System::System const &system, int chain_start, int chain_length, int n_chains)
Calculate the radius of gyration.
std::array< double, 2 > calc_rh(System::System const &system, int chain_start, int chain_length, int n_chains)
Calculate the hydrodynamic radius (ref.
std::array< double, 4 > calc_re(System::System const &system, int chain_start, int chain_length, int n_chains)
Calculate the end-to-end-distance.
This file contains the code for statistics on chains.
GatherCom(BoxGeometry const &box_geo)
BoxGeometry const & m_box_geo
Utils::Vector3d kernel(Particle const &p) const override
~GatherCom() override=default
~GatherMass() override=default
double kernel(Particle const &p) const override
Gather particle properties (or any derived quantities) on MPI rank 0.
virtual T kernel(Particle const &) const =0
void fetch(CellStructure const &cell_structure, int pid)
virtual ~GatherParticleTraits()=default
BoxGeometry const & m_box_geo
Utils::Vector3d kernel(Particle const &p) const override
~GatherPos() override=default
GatherPos(BoxGeometry const &box_geo)
Struct holding all information for one particle.
Definition Particle.hpp:450
auto const & mass() const
Definition Particle.hpp:507
auto const & image_box() const
Definition Particle.hpp:499
auto const & pos() const
Definition Particle.hpp:486