ppap4lmp  0.7.2
pro_radial_distribution_function_with_deformation.cpp
Go to the documentation of this file.
1 
10 #include "../utils/message.h"
11 #include "../utils/runtime_error.h"
12 
13 namespace ut = utils;
14 
15 /* ------------------------------------------------------------------ */
16 
18  const int index)
19 {
20  /* NOTE:
21  Although 'bead' is used for variable names,
22  RDF of something other than beads can be computed too.
23  */
24  auto el_beads = generators[index]->get_element("Targets");
25 
26  el_beads->check_required_keys({
27  "I_xx", "I_yy", "I_zz", "I_xy", "I_xz", "I_yz", "mass",
28  "x", "y", "z", "id"});
29 
30  auto &beads = el_beads->get_data();
31 
32  auto special_bonds_exist = el_beads->check_optional_keys("special-bonds");
33 
34  auto el_box = generators[index]->get_element("Box");
35 
36  el_box->check_required_keys({"lo_x", "lo_y", "lo_z", "hi_x", "hi_y", "hi_z"});
37 
38  auto &box = el_box->get_data();
39 
40  // prepare
41 
42  const auto n_beads = beads.size();
43 
44  Vec<std::pair<Vector3d,Matrix3d>> rs_and_Is_per_mass;
45  rs_and_Is_per_mass.reserve(n_beads);
46 
47  for (const auto &bead : beads)
48  {
49  rs_and_Is_per_mass.push_back(std::make_pair(
50  (Vector3d() << bead["x"], bead["y"], bead["z"]).finished(),
51  (Matrix3d() << bead["I_xx"], bead["I_xy"], bead["I_xz"],
52  bead["I_xy"], bead["I_yy"], bead["I_yz"],
53  bead["I_xz"], bead["I_yz"], bead["I_zz"]).finished()
54  / bead["mass"].get<double>()));
55  }
56 
57  ArrayXd box_length(3);
58  box_length << box["hi_x"].get<double>() - box["lo_x"].get<double>(),
59  box["hi_y"].get<double>() - box["lo_y"].get<double>(),
60  box["hi_z"].get<double>() - box["lo_z"].get<double>();
61 
62  ArrayXd neighbor_limits = beyond_half ? box_length : 0.5 * box_length;
63 
64  const auto r_max = bin_from_r ? n_bins * bin_width : (n_bins-0.5) * bin_width;
65  const auto r_margined = r_max + margin;
66  const auto r2_max = r_max * r_max;
67  const auto r2_margined = r_margined * r_margined;
68 
69  for (int i = 0; i != 3; ++i)
70  {
71  if (neighbor_limits(i) < r_margined)
72  {
74  "Box length is too short in " + Str("xyz").substr(i, 1));
75  }
76  }
77 
78  const std::pair<int,int> image_range_x = box.value("pbc_x", false) ?
79  std::make_pair(-1, 1) : std::make_pair(0, 0);
80  const std::pair<int,int> image_range_y = box.value("pbc_y", false) ?
81  std::make_pair(-1, 1) : std::make_pair(0, 0);
82  const std::pair<int,int> image_range_z = box.value("pbc_z", false) ?
83  std::make_pair(-1, 1) : std::make_pair(0, 0);
84 
85  const auto reciprocal_bin_width = 1.0 / bin_width;
86 
87  const double one_third = 1.0 / 3.0;
88  const double two_thirds = 2.0 / 3.0;
89 
90  // loop over all pairs of beads
91 
92  number_traj[index] = n_beads;
93  volume_traj[index] = box_length.prod();
94 
95  counts_traj[index] = ArrayXi::Zero(n_bins);
96  auto &counts = counts_traj[index];
97 
98  raw_counts_traj[index] = ArrayXi::Zero(n_bins);
99  auto &raw_counts = raw_counts_traj[index];
100 
101  Rg2_sum_traj[index] = ArrayXd::Zero(n_bins);
102  auto &Rg2_sum = Rg2_sum_traj[index];
103 
104  Rg2_para_sum_traj[index] = ArrayXd::Zero(n_bins);
105  auto &Rg2_para_sum = Rg2_para_sum_traj[index];
106 
107  Rg2_perp_sum_traj[index] = ArrayXd::Zero(n_bins);
108  auto &Rg2_perp_sum = Rg2_perp_sum_traj[index];
109 
110  for (int i = 0; i != n_beads; ++i)
111  {
112  auto sbonds_i = special_bonds_exist ?
113  beads[i]["special-bonds"].get<Set<int>>() : Set<int>();
114 
115  auto &tmp_i = rs_and_Is_per_mass[i];
116  auto &r_i = tmp_i.first;
117  auto &I_i = tmp_i.second;
118 
119  for (int j = i+1; j != n_beads; ++j)
120  {
121  if (!sbonds_i.empty() && sbonds_i.find(
122  beads[j]["id"].get<int>()) != sbonds_i.cend()) continue;
123 
124  auto &tmp_j = rs_and_Is_per_mass[j];
125  auto &I_j = tmp_j.second;
126 
127  auto dr_original = tmp_j.first - r_i;
128 
129  for (int ix = image_range_x.first; ix <= image_range_x.second; ++ix)
130  {
131  auto dx = dr_original(0) + ix*box_length(0);
132 
133  if (neighbor_limits(0) < abs(dx)) continue;
134 
135  for (int iy = image_range_y.first; iy <= image_range_y.second; ++iy)
136  {
137  auto dy = dr_original(1) + iy*box_length(1);
138 
139  if (neighbor_limits(1) < abs(dy)) continue;
140 
141  for (int iz = image_range_z.first; iz <= image_range_z.second; ++iz)
142  {
143  auto dz = dr_original(2) + iz*box_length(2);
144 
145  if (neighbor_limits(2) < abs(dz)) continue;
146 
147  auto r2 = dx*dx + dy*dy + dz*dz;
148 
149  if (r2_margined <= r2) continue;
150 
151  Vector3d e_ij;
152  e_ij << dx, dy, dz;
153  e_ij.normalize();
154 
155  auto Rg2_i = 0.5 * I_i.trace();
156  auto Rg2_j = 0.5 * I_j.trace();
157 
158  /* NOTE:
159  Using `auto` leads to an Eigen related error (I cannot
160  figure out the details).
161  */
162  double Rg2_perp_i = 1.5 * e_ij.transpose() * I_i * e_ij;
163  double Rg2_perp_j = 1.5 * e_ij.transpose() * I_j * e_ij;
164 
165  auto Rg2_para_i = 3.0 * (Rg2_i - two_thirds*Rg2_perp_i);
166  auto Rg2_para_j = 3.0 * (Rg2_j - two_thirds*Rg2_perp_j);
167 
168  auto r = sqrt(r2);
169 
170  if (r < r_max)
171  {
172  auto r_index = bin_from_r ?
173  floor(r*reciprocal_bin_width) : round(r*reciprocal_bin_width);
174 
175  raw_counts(r_index) += 2;
176  Rg2_sum(r_index) += Rg2_i + Rg2_j;
177  Rg2_para_sum(r_index) += Rg2_para_i + Rg2_para_j;
178  Rg2_perp_sum(r_index) += Rg2_perp_i + Rg2_perp_j;
179  }
180 
181  auto r_modified = r + (
182  (sqrt(one_third*Rg2_i) - sqrt(one_third*Rg2_para_i)) +
183  (sqrt(one_third*Rg2_j) - sqrt(one_third*Rg2_para_j)));
184 
185  /* NOTE:
186  The below lines check if the margin is efficiently large;
187  no distance becomes out of range by the modification.
188  This somewhat ensure that every modified distance smaller
189  than `r_max` is counted (I made an assumption: if no
190  distance goes from [0,r_max) to [r_margined,+inf), no
191  distance goes from [r_margined,+inf) to [0,r_max) by the
192  modification.
193  */
194  if (r2 < r2_max && r_margined <= r_modified)
195  {
196  ut::warning("Margin is too small");
197  }
198 
199  if (r_max <= r_modified)
200  {
201  continue;
202  }
203  else if (r_max < 0.0)
204  {
205  ut::runtime_error("Deformation might be too large");
206  }
207 
208  auto r_index = bin_from_r ?
209  floor(r_modified*reciprocal_bin_width) :
210  round(r_modified*reciprocal_bin_width);
211 
212  /* NOTE:
213  Adding 2 (not 1) is for taking both directions
214  (i -> j & j -> i) into consideration at once.
215  */
216  counts(r_index) += 2;
217  }
218  }
219  }
220  }
221  }
222 }
223 
224 /* ------------------------------------------------------------------ */
225 
227 {
228  ProRDF::prepare();
229 
231  Rg2_sum_traj.resize(n_generators);
234 }
235 
236 /* ------------------------------------------------------------------ */
237 
239 {
240  ProRDF::finish();
241 
245 
246  // NOTE: Do not use `auto` for initialization using Eigen's Zero().
247  ArrayXi counts_sum = ArrayXi::Zero(n_bins);
248  ArrayXd Rg2_sum = ArrayXd::Zero(n_bins);
249  ArrayXd Rg2_para_sum = ArrayXd::Zero(n_bins);
250  ArrayXd Rg2_perp_sum = ArrayXd::Zero(n_bins);
251 
252  for (int i = 0; i != n_generators; ++i)
253  {
254  auto &counts_tmp = raw_counts_traj[i];
255  auto &Rg2_tmp = Rg2_sum_traj[i];
256  auto &Rg2_para_tmp = Rg2_para_sum_traj[i];
257  auto &Rg2_perp_tmp = Rg2_perp_sum_traj[i];
258 
259  auto reciprocal_counts = (1.0 / counts_tmp.cast<double>())
260  .unaryExpr([](double x)
261  {
262  return std::isfinite(x) ? x : 0.0;
263  });
264 
265  Rg2_array_traj[i] = Rg2_tmp * reciprocal_counts;
266  Rg2_para_array_traj[i] = Rg2_para_tmp * reciprocal_counts;
267  Rg2_perp_array_traj[i] = Rg2_perp_tmp * reciprocal_counts;
268 
269  counts_sum += counts_tmp;
270  Rg2_sum += Rg2_tmp;
271  Rg2_para_sum += Rg2_para_tmp;
272  Rg2_perp_sum += Rg2_perp_tmp;
273  }
274 
275  auto reciprocal_counts = (1.0 / counts_sum.cast<double>())
276  .unaryExpr([](double x)
277  {
278  return std::isfinite(x) ? x : 0.0;
279  });
280 
281  Rg2_array = Rg2_sum * reciprocal_counts;
282  Rg2_para_array = Rg2_para_sum * reciprocal_counts;
283  Rg2_perp_array = Rg2_perp_sum * reciprocal_counts;
284 
285  raw_counts_traj.clear();
286  raw_counts_traj.shrink_to_fit();
287  Rg2_sum_traj.clear();
288  Rg2_sum_traj.shrink_to_fit();
289  Rg2_para_sum_traj.clear();
290  Rg2_para_sum_traj.shrink_to_fit();
291  Rg2_perp_sum_traj.clear();
292  Rg2_perp_sum_traj.shrink_to_fit();
293 }
294 
295 /* ------------------------------------------------------------------ */
296 
298  double margin_)
299 {
300  margin = margin_;
301 }
302 
303 /* ------------------------------------------------------------------ */
304 
306 {
307  return {
308  {"isotropic", Rg2_array.sqrt()},
309  {"parallel", Rg2_para_array.sqrt()},
310  {"perpendicular", Rg2_perp_array.sqrt()}};
311 }
312 
313 /* ------------------------------------------------------------------ */
314 
316 {
317  Map<Str,Vec<ArrayXd>> type2traj;
318 
319  auto &iso = type2traj["isotropic"];
320 
321  for (const auto &array : Rg2_array_traj)
322  {
323  iso.push_back(array.sqrt());
324  }
325 
326  auto &para = type2traj["parallel"];
327 
328  for (const auto &array : Rg2_array_traj)
329  {
330  para.push_back(array.sqrt());
331  }
332 
333  auto &perp = type2traj["perpendicular"];
334 
335  for (const auto &array : Rg2_array_traj)
336  {
337  perp.push_back(array.sqrt());
338  }
339 
340  return type2traj;
341 }
342 
343 /* ------------------------------------------------------------------ */
344 
346 {
347  return {
348  {"isotropic", Rg2_array},
349  {"parallel", Rg2_para_array},
350  {"perpendicular", Rg2_perp_array}};
351 }
352 
353 /* ------------------------------------------------------------------ */
354 
356 {
357  return {
358  {"isotropic", Rg2_array_traj},
359  {"parallel", Rg2_para_array_traj},
360  {"perpendicular", Rg2_perp_array_traj}};
361 }
This file has a definition of ProRadialDistributionFunctionWithDeformation class, which is a subclass...
virtual void run_impl(const int index) override
Implementation of analysis using an element of generators.
Vec< ShPtr< Generator > > generators
Definition: processor.h:37
virtual void finish() override
Compute rdf and rdf_traj from number_traj, volume_traj and counts_traj.
Map< Str, Vec< ArrayXd > > get_squared_gyration_radius_traj()
Get list of temporary square of gyration radius as function of distance from a reference particle...
void set_margin(double margin_)
Set margin for distance from a reference particle: this program uses a sample including particles of ...
std::string Str
Str is an alias for string.
Definition: std.h:21
int n_generators
Definition: processor.h:31
Map< Str, ArrayXd > get_squared_gyration_radius()
Get averaged square of gyration radius as function of distance from a reference particle. The returned value is dictionary of which keys are isotropic, parallel and perpendicular, and corresponding values are function for general gyration radius, gyration radius in* the particle-to-particle axis and gyration radius around* the particle-to-particle axis, respectively.
std::unordered_set< T > Set
Set is an alias for unordered set (same as set in Python).
Definition: std.h:49
Map< Str, ArrayXd > get_gyration_radius()
Get averaged gyration radius as function of distance from a reference particle. The returned value is...
std::vector< T > Vec
Vec is an alias for vector (same as list in Python).
Definition: std.h:27
virtual void prepare() override
Resize number_traj, volume_traj and counts_traj.
void runtime_error(const Str &msg)
Raise (for Python) and throw (for C++) a runtime error.
Eigen::Array< int, Eigen::Dynamic, 1 > ArrayXi
ArrayXi is an alias for a column array of integers.
Definition: eigen.h:37
void warning(const Str &msg)
Waning with a message.
Definition: message.cpp:40
Map< Str, Vec< ArrayXd > > get_gyration_radius_traj()
Get list of temporary gyration radius as function of distance from a reference particle. The returned value is dictionary of which keys are isotropic, parallel and perpendicular, and corresponding values are lists of functions for general gyration radius, gyration radius in* the particle-to-particle axis and gyration radius around* the particle-to-particle axis, respectively. Each element of the lists corresponds to each snapshot of the simulation.
Namespace for utility functions.
Definition: join.h:14
Eigen::Array< double, Eigen::Dynamic, 1 > ArrayXd
ArrayXd is an alias for a column array of float numbers.
Definition: eigen.h:42
virtual void prepare() override
Call ProRDF::prepare and then resize raw_counts_traj, Rg2_sum_traj, Rg2_para_sum_traj and Rg2_perp_su...
std::unordered_map< T, U > Map
Map is an alias for unordered map (same as dict in Python).
Definition: std.h:38
Eigen::Vector3d Vector3d
Vector3d is an alias for a 3-elements column vector of float numbers.
Definition: eigen.h:100
Eigen::Matrix3d Matrix3d
Matrix3d is an alias for a 3x3 matrix of float numbers.
Definition: eigen.h:90
virtual void finish() override
Call ProRDF::finish and then compute Rg2_array, Rg2_para_array, Rg2_perp_array, Rg2_array_traj, Rg2_para_array_traj and Rg2_perp_array_traj from raw_counts_traj, Rg2_sum_traj, Rg2_para_sum_traj and Rg2_perp_sum_traj.