ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
Cluster.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config/config.hpp"
21
22#ifdef GSL
23#include "gsl/gsl_fit.h"
24#endif
25
26#include "Cluster.hpp"
27
28#include "BoxGeometry.hpp"
29#include "Particle.hpp"
30#include "errorhandling.hpp"
31#include "particle_node.hpp"
32#include "system/System.hpp"
33
34#include <utils/Vector.hpp>
35
36#include <algorithm>
37#include <cmath>
38#include <cstddef>
39#include <numeric>
40#include <stdexcept>
41#include <utility>
42#include <vector>
43
44namespace ClusterAnalysis {
45
46// Center of mass of an aggregate
50
51// Center of mass of an aggregate
53Cluster::center_of_mass_subcluster(std::vector<int> const &particle_ids) {
54 sanity_checks();
55 auto const &box_geo = *System::get_system().box_geo;
56 Utils::Vector3d com{};
57
58 // The distances between the particles are "folded", such that all distances
59 // are smaller than box_l/2 in a periodic system. The 1st particle
60 // of the cluster is arbitrarily chosen as reference.
61
62 auto const reference_position =
63 box_geo.folded_position(get_particle_data(particles[0]).pos());
64 double total_mass = 0.;
65 for (int pid : particle_ids) {
66 auto const folded_pos =
67 box_geo.folded_position(get_particle_data(pid).pos());
68 auto const dist_to_reference =
69 box_geo.get_mi_vector(folded_pos, reference_position);
70 com += dist_to_reference * get_particle_data(pid).mass();
71 total_mass += get_particle_data(pid).mass();
72 }
73
74 // Normalize by number of particles
75 com /= total_mass;
76
77 // Re-add reference position
78 com += reference_position;
79
80 // Fold into simulation box
81 return box_geo.folded_position(com);
82}
83
85 sanity_checks();
86 auto const &box_geo = *System::get_system().box_geo;
87 double ld = 0.;
88 for (auto a = particles.begin(); a != particles.end(); a++) {
89 for (auto b = a; ++b != particles.end();) {
90 auto const dist = box_geo
91 .get_mi_vector(get_particle_data(*a).pos(),
93 .norm();
94
95 // Larger than previous largest distance?
96 ld = std::max(ld, dist);
97 }
98 }
99 return ld;
100}
101
102// Radius of gyration
106
107double
108Cluster::radius_of_gyration_subcluster(std::vector<int> const &particle_ids) {
109 sanity_checks();
110 auto const &box_geo = *System::get_system().box_geo;
111 // Center of mass
112 Utils::Vector3d com = center_of_mass_subcluster(particle_ids);
113 double sum_sq_dist = 0.;
114 for (auto const pid : particle_ids) {
115 // calculate square length of this distance
116 sum_sq_dist +=
117 box_geo.get_mi_vector(com, get_particle_data(pid).pos()).norm2();
118 }
119
120 return sqrt(sum_sq_dist / static_cast<double>(particle_ids.size()));
121}
122
123template <typename T>
124std::vector<std::size_t> sort_indices(const std::vector<T> &v) {
125
126 // Unsorted for unsorted vector (0..n-1)
127 std::vector<std::size_t> idx(v.size());
128 std::iota(idx.begin(), idx.end(), 0);
129
130 // sort indices based on comparing values in v
131 std::sort(idx.begin(), idx.end(),
132 [&v](std::size_t i1, std::size_t i2) { return v[i1] < v[i2]; });
133 return idx;
134}
135
136std::pair<double, double> Cluster::fractal_dimension(double dr) {
137#ifdef GSL
138 sanity_checks();
139 auto const &box_geo = *System::get_system().box_geo;
141 // calculate Df using linear regression on the logarithms of the radii of
142 // gyration against the number of particles in sub-clusters. Particles are
143 // included step by step from the center of mass outwards
144
145 // Distances of particles from the center of mass
146 std::vector<double> distances;
147
148 for (auto const &it : particles) {
149 distances.push_back(box_geo.get_mi_vector(com, get_particle_data(it).pos())
150 .norm()); // add distance from the current particle
151 // to the com in the distances vectors
152 }
153
154 // Get particle indices in the cluster which yield distances sorted in
155 // ascending order from center of mass.
156 auto particle_indices = sort_indices(distances);
157
158 // Particle ids in the current sub-cluster
159 std::vector<int> subcluster_ids;
160
161 std::vector<double> log_pcounts; // particle count
162 std::vector<double> log_diameters; // corresponding radii of gyration
163 double last_dist = 0;
164 for (auto const idx : particle_indices) {
165 subcluster_ids.push_back(particles[idx]);
166 if (distances[idx] < last_dist + dr)
167 continue;
168
169 last_dist = distances[idx];
170 if (subcluster_ids.size() == 1)
171 continue;
172 auto const current_rg = radius_of_gyration_subcluster(subcluster_ids);
173 log_pcounts.push_back(log(static_cast<double>(subcluster_ids.size())));
174 log_diameters.push_back(log(current_rg * 2.0));
175 }
176 double c0, c1, cov00, cov01, cov11, sumsq;
177 gsl_fit_linear(log_diameters.data(), 1, log_pcounts.data(), 1,
178 log_pcounts.size(), &c0, &c1, &cov00, &cov01, &cov11, &sumsq);
179 double mean_sq_residual = sumsq / static_cast<double>(log_diameters.size());
180 return {c1, mean_sq_residual};
181#else
182 runtimeErrorMsg() << "GSL (gnu scientific library) is required for fractal "
183 "dimension calculation.";
184 return {0, 0};
185#endif
186}
187
188void Cluster::sanity_checks() const {
189 auto const &box_geo = *System::get_system().box_geo;
190 if (box_geo.type() != BoxType::CUBOID) {
191 throw std::runtime_error(
192 "Cluster analysis is not compatible with non-cuboid box types");
193 }
194}
195
196} // namespace ClusterAnalysis
Vector implementation and trait types for boost qvm interoperability.
float dr[3]
__shared__ int pos[MAXDEPTH *THREADS5/WARPSIZE]
Utils::Vector3d center_of_mass()
Definition Cluster.cpp:47
std::pair< double, double > fractal_dimension(double dr)
Calculate the fractal dimension N(r) via r^d, where N(r) counts the number of particles in a sphere o...
Definition Cluster.cpp:136
Utils::Vector3d center_of_mass_subcluster(std::vector< int > const &particle_ids)
Calculate the center of mass of the cluster.
Definition Cluster.cpp:53
std::vector< int > particles
Ids of the particles in the cluster.
double longest_distance()
Longest distance between any combination of two particles.
Definition Cluster.cpp:84
double radius_of_gyration()
Calculate radius of gyration of the cluster.
Definition Cluster.cpp:103
double radius_of_gyration_subcluster(std::vector< int > const &particle_ids)
Definition Cluster.cpp:108
std::shared_ptr< BoxGeometry > box_geo
This file contains the defaults for ESPResSo.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
#define runtimeErrorMsg()
std::vector< std::size_t > sort_indices(const std::vector< T > &v)
Definition Cluster.cpp:124
System & get_system()
const Particle & get_particle_data(int p_id)
Get particle data.
Particles creation and deletion.
auto const & mass() const
Definition Particle.hpp:450
auto const & pos() const
Definition Particle.hpp:429