32#include "communication.hpp"
35#include "system/System.hpp"
42#include <boost/mpi/collectives/broadcast.hpp>
43#include <boost/mpi/collectives/reduce.hpp>
58template <
typename Archive,
typename... T>
59void serialize(Archive &ar, std::tuple<T...> &pack,
unsigned int const) {
60 std::apply([&](
auto &...item) { ((ar & item), ...); }, pack);
59void serialize(Archive &ar, std::tuple<T...> &pack,
unsigned int const) {
…}
66 using type = std::tuple<std::invoke_result_t<F, Particle const &>...>;
70 using type = std::invoke_result_t<F, Particle const &>;
78template <
class... Trait>
80 std::vector<int>
const &p_types,
86 buffer.emplace_back(trait(p)...);
98 std::vector<int>
const &set2) {
101 std::vector<int> buf_type{};
102 std::vector<Utils::Vector3d> buf_pos{};
104 auto const &box_geo = *system.
box_geo;
105 auto const accept_all = set1.empty() or set2.empty();
107 if (accept_all or contains(set1, p.type()) or contains(set2, p.type())) {
108 buf_type.emplace_back(p.type());
109 buf_pos.emplace_back(box_geo.unfolded_position(p.pos(), p.image_box()));
120 auto mindist_sq = std::numeric_limits<double>::infinity();
121 for (std::size_t j = 0ul; j < buf_type.size(); ++j) {
124 if (set1.empty() || contains(set1, buf_type[j]))
126 if (set2.empty() || contains(set2, buf_type[j]))
130 for (
auto i = j + 1ul; i != buf_type.size(); ++i) {
133 if (((in_set & 1) and (set2.empty() or contains(set2, buf_type[i]))) or
134 ((in_set & 2) and (set1.empty() or contains(set1, buf_type[i])))) {
135 mindist_sq = std::min(
136 mindist_sq, box_geo.get_mi_vector(buf_pos[j], buf_pos[i]).norm2());
141 return std::sqrt(mindist_sq);
145 bool include_particles,
146 bool include_lbfluid) {
148 if (include_particles) {
153 return m + p.mass() * p.v();
163 auto const &box_geo = *system.
box_geo;
166 double local_mass = 0.;
168 for (
auto const &p : cell_structure.local_particles()) {
169 if ((p.type() == p_type or p_type == -1) and not p.is_virtual()) {
170 local_com += box_geo.unfolded_position(p.pos(), p.image_box()) * p.mass();
171 local_mass += p.mass();
176 boost::mpi::reduce(
::comm_cart, local_com, com, std::plus<>(), 0);
177 boost::mpi::reduce(
::comm_cart, local_mass, mass, std::plus<>(), 0);
182 auto const &box_geo = *system.
box_geo;
186 for (
auto const &p : cell_structure.local_particles()) {
187 if ((p.type() == p_type or p_type == -1) and not p.is_virtual()) {
188 auto const pos = box_geo.unfolded_position(p.pos(), p.image_box());
196 std::vector<int>
const &p_types) {
197 auto const &box_geo = *system.
box_geo;
198 auto const trait_pos = [&box_geo](
Particle const &p) {
199 return box_geo.unfolded_position(p.pos(), p.image_box());
207 static_cast<double>(buf_pos.size());
209 for (
unsigned int i = 0u; i < 3u; ++i) {
210 for (
unsigned int j = 0u; j < 3u; ++j) {
212 mat[i * 3u + j] = mat[j * 3u + i];
214 mat[i * 3u + j] = std::accumulate(
215 buf_pos.begin(), buf_pos.end(), 0.,
217 return acc + (pos[i] - center[i]) * (pos[j] - center[j]);
222 mat /=
static_cast<double>(buf_pos.size());
229 auto const &box_geo = *system.
box_geo;
235 for (
auto const &p : cell_structure.local_particles()) {
236 if (p.type() == p_type and not p.is_virtual()) {
237 auto const pos = box_geo.unfolded_position(p.pos(), p.image_box()) - com;
238 auto const mass = p.mass();
239 mat[0] += mass * (pos[1] * pos[1] + pos[2] * pos[2]);
240 mat[4] += mass * (pos[0] * pos[0] + pos[2] * pos[2]);
241 mat[8] += mass * (pos[0] * pos[0] + pos[1] * pos[1]);
242 mat[1] -= mass * (pos[0] * pos[1]);
243 mat[2] -= mass * (pos[0] * pos[2]);
244 mat[5] -= mass * (pos[1] * pos[2]);
256 std::vector<int> buf_pid{};
257 auto const dist_sq = dist * dist;
258 auto const &box_geo = *system.
box_geo;
261 auto const r_sq = box_geo.get_mi_vector(pos, p.pos()).norm2();
262 if (r_sq < dist_sq) {
263 buf_pid.push_back(p.id());
275std::vector<std::vector<double>>
277 std::vector<int>
const &p1_types,
278 std::vector<int>
const &p2_types,
double r_min,
279 double r_max,
int r_bins,
bool log_flag,
bool int_flag) {
281 auto const &box_geo = *system.
box_geo;
282 auto const trait_id = [](
Particle const &p) {
return p.id(); };
283 auto const trait_pos = [&box_geo](
Particle const &p) {
284 return box_geo.unfolded_position(p.pos(), p.image_box());
292 auto const start_dist2 =
Utils::sqr(r_max + 1.);
293 auto const inv_bin_width =
294 (log_flag) ?
static_cast<double>(r_bins) / std::log(r_max / r_min)
295 :
static_cast<double>(r_bins) / (r_max - r_min);
299 std::vector<double> distribution(r_bins);
301 for (
auto const &[pid1, pos1] : buf1) {
302 auto min_dist2 = start_dist2;
304 for (
auto const &[pid2, pos2] : buf2) {
306 auto const act_dist2 = box_geo.get_mi_vector(pos1, pos2).norm2();
307 if (act_dist2 < min_dist2) {
308 min_dist2 = act_dist2;
312 if (min_dist2 <= r_max2) {
313 if (min_dist2 >= r_min2) {
314 auto const min_dist = std::sqrt(min_dist2);
316 auto const ind =
static_cast<int>(
317 ((log_flag) ? std::log(min_dist / r_min) : (min_dist - r_min)) *
319 if (ind >= 0 and ind < r_bins) {
320 distribution[ind] += 1.0;
331 low /=
static_cast<double>(cnt);
332 for (
int i = 0; i < r_bins; i++) {
333 distribution[i] /=
static_cast<double>(cnt);
338 distribution[0] += low;
339 for (
int i = 0; i < r_bins - 1; i++)
340 distribution[i + 1] += distribution[i];
344 std::vector<double> radii(r_bins);
346 auto const log_fac = std::pow(r_max / r_min, 1. / r_bins);
347 radii[0] = r_min * std::sqrt(log_fac);
348 for (
int i = 1; i < r_bins; ++i) {
349 radii[i] = radii[i - 1] * log_fac;
352 auto const bin_width = (r_max - r_min) /
static_cast<double>(r_bins);
353 for (
int i = 0; i < r_bins; ++i) {
354 radii[i] = r_min + bin_width / 2. +
static_cast<double>(i) * bin_width;
358 return {radii, distribution};
361std::vector<std::vector<double>>
364 auto const &box_geo = *system.
box_geo;
365 auto const trait_pos = [&box_geo](
Particle const &p) {
366 return box_geo.unfolded_position(p.pos(), p.image_box());
369 auto const order_sq =
Utils::sqr(
static_cast<std::size_t
>(order));
370 auto const twoPI_L = 2. * std::numbers::pi * system.
box_geo->length_inv()[0];
371 std::vector<double> ff(2ul * order_sq + 1ul);
372 std::vector<double> wavevectors;
373 std::vector<double> intensities;
376 for (
int i = 0; i <= order; i++) {
377 for (
int j = -order; j <= order; j++) {
378 for (
int k = -order; k <= order; k++) {
379 auto const n = i * i + j * j + k * k;
380 if ((
static_cast<std::size_t
>(n) <= order_sq) && (n >= 1)) {
381 double C_sum = 0.0, S_sum = 0.0;
382 for (
auto const &pos : buf_pos) {
387 ff[2 * n - 2] += C_sum * C_sum + S_sum * S_sum;
394 std::size_t length = 0;
395 for (std::size_t qi = 0; qi < order_sq; qi++) {
396 if (ff[2 * qi + 1] != 0) {
397 ff[2 * qi] /=
static_cast<double>(buf_pos.size()) * ff[2 * qi + 1];
402 wavevectors.resize(length);
403 intensities.resize(length);
406 for (std::size_t i = 0; i < order_sq; i++) {
407 if (ff[2 * i + 1] != 0) {
408 wavevectors[cnt] = twoPI_L * std::sqrt(
static_cast<double>(i + 1));
409 intensities[cnt] = ff[2 * i];
415 return {std::move(wavevectors), std::move(intensities)};
Vector implementation and trait types for boost qvm interoperability.
std::shared_ptr< CellStructure > cell_structure
std::shared_ptr< BoxGeometry > box_geo
boost::mpi::communicator comm_cart
The communicator.
__device__ void vector_product(float const *a, float const *b, float *out)
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
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.
bool contains(Range &&rng, T const &value)
Check whether a range contains a value.
void serialize(Archive &ar, std::tuple< T... > &pack, unsigned int const)
Serialize std::tuple.
Exports for the NpT code.
Utils::Vector3d center_of_mass(System::System const &system, int p_type)
Calculate the center of mass of particles of a certain type.
Utils::Vector3d angular_momentum(System::System const &system, int p_type)
Calculate the angular momentum of particles of a certain type.
std::vector< int > nbhood(System::System const &system, Utils::Vector3d const &pos, double dist)
Find all particles within a given radius dist around a position pos.
Utils::Vector9d moment_of_inertia_matrix(System::System const &system, int p_type)
Calculate the moment of inertia of particles of a certain type.
Utils::Vector9d gyration_tensor(System::System const &system, std::vector< int > const &p_types)
Calculate the gyration tensor of particles of certain types.
Utils::Vector3d calc_linear_momentum(System::System const &system, bool include_particles, bool include_lbfluid)
Calculate total momentum of the system (particles & LB fluid).
std::vector< std::vector< double > > structure_factor(System::System const &system, std::vector< int > const &p_types, int order)
Calculate the spherically averaged structure factor.
double mindist(System::System const &system, std::vector< int > const &set1, std::vector< int > const &set2)
Calculate the minimal distance of two particles with types in set1 and set2, respectively.
static auto gather_traits_for_types(System::System const &system, std::vector< int > const &p_types, Trait &&...trait)
Gather particle traits to MPI rank 0.
std::vector< std::vector< double > > calc_part_distribution(System::System const &system, std::vector< int > const &p1_types, std::vector< int > const &p2_types, double r_min, double r_max, int r_bins, bool log_flag, bool int_flag)
Calculate the distribution of particles around others.
Statistical tools to analyze simulations.
std::invoke_result_t< F, Particle const & > type
Decay a tuple of only 1 type to that type.
std::tuple< std::invoke_result_t< F, Particle const & >... > type
bool is_solver_set() const
Return true if a LB solver is active.
auto get_lattice_speed() const
Get the lattice speed (agrid/tau).
Utils::Vector3d get_momentum() const
Struct holding all information for one particle.