ppap4lmp  0.7.2
pro_radial_distribution_function.cpp
Go to the documentation of this file.
1 
9 #define _USE_MATH_DEFINES
10 
11 #include <cmath>
12 
14 #include "../utils/message.h"
15 
16 namespace ut = utils;
17 
18 /* ------------------------------------------------------------------ */
19 
21  const ElPtr &targets,
22  const ElPtr &box)
23 {
25  new GenDict({{"Targets", targets}, {"Box", box}})));
26 }
27 
28 /* ------------------------------------------------------------------ */
29 
31  const Vec<std::pair<ElPtr,ElPtr>> &pairs)
32 {
33  Vec<ShPtr<GenDict>> gens;
34 
35  for (const auto &pair : pairs)
36  {
37  gens.push_back(ShPtr<GenDict>(
38  new GenDict({{"Targets", pair.first}, {"Box", pair.second}})));
39  }
40 
41  register_generators(gens);
42 }
43 
44 /* ------------------------------------------------------------------ */
45 
47  const int index)
48 {
49  /* NOTE:
50  Although 'atom' is used for variable names,
51  RDF of something other than atoms can be computed too.
52  */
53  auto el_atoms = generators[index]->get_element("Targets");
54 
55  el_atoms->check_required_keys({"x", "y", "z", "id"});
56 
57  auto &atoms = el_atoms->get_data();
58 
59  auto special_bonds_exist = el_atoms->check_optional_keys("special-bonds");
60 
61  auto el_box = generators[index]->get_element("Box");
62 
63  el_box->check_required_keys({"lo_x", "lo_y", "lo_z", "hi_x", "hi_y", "hi_z"});
64 
65  auto &box = el_box->get_data();
66 
67  ArrayXXd rs;
68  el_atoms->make_2darray_from_data(rs, {"x", "y", "z"});
69 
70  ArrayXd box_length(3);
71  box_length << box["hi_x"].get<double>() - box["lo_x"].get<double>(),
72  box["hi_y"].get<double>() - box["lo_y"].get<double>(),
73  box["hi_z"].get<double>() - box["lo_z"].get<double>();
74 
75  ArrayXd neighbor_limits = beyond_half ? box_length : 0.5 * box_length;
76 
77  const auto r_max = bin_from_r ?
78  n_bins * bin_width : (n_bins-0.5) * bin_width;
79  const auto r2_max = r_max*r_max;
80 
81  for (int i = 0; i != 3; ++i)
82  {
83  if (neighbor_limits(i) < r_max)
84  {
86  "Box length is too short in " + Str("xyz").substr(i, 1));
87  }
88  }
89 
90  const std::pair<int,int> image_range_x = box.value("pbc_x", false) ?
91  std::make_pair(-1, 1) : std::make_pair(0, 0);
92  const std::pair<int,int> image_range_y = box.value("pbc_y", false) ?
93  std::make_pair(-1, 1) : std::make_pair(0, 0);
94  const std::pair<int,int> image_range_z = box.value("pbc_z", false) ?
95  std::make_pair(-1, 1) : std::make_pair(0, 0);
96 
97  const auto reciprocal_bin_width = 1.0 / bin_width;
98 
99  const auto n_atoms = atoms.size();
100 
101  number_traj[index] = n_atoms;
102  volume_traj[index] = box_length.prod();
103  counts_traj[index] = ArrayXi::Zero(n_bins);
104 
105  auto &counts = counts_traj[index];
106 
107  for (int i = 0; i != n_atoms; ++i)
108  {
109  auto sbonds_i = special_bonds_exist ?
110  atoms[i]["special-bonds"].get<Set<int>>() : Set<int>();
111 
112  auto r_i = rs.row(i);
113 
114  for (int j = i+1; j != n_atoms; ++j)
115  {
116  if (!sbonds_i.empty() && sbonds_i.find(
117  atoms[j]["id"].get<int>()) != sbonds_i.cend()) continue;
118 
119  auto dr_original = rs.row(j) - r_i;
120 
121  for (int ix = image_range_x.first; ix <= image_range_x.second; ++ix)
122  {
123  auto dx = dr_original(0) + ix*box_length(0);
124 
125  if (neighbor_limits(0) < abs(dx)) continue;
126 
127  for (int iy = image_range_y.first; iy <= image_range_y.second; ++iy)
128  {
129  auto dy = dr_original(1) + iy*box_length(1);
130 
131  if (neighbor_limits(1) < abs(dy)) continue;
132 
133  for (int iz = image_range_z.first; iz <= image_range_z.second; ++iz)
134  {
135  auto dz = dr_original(2) + iz*box_length(2);
136 
137  if (neighbor_limits(2) < abs(dz)) continue;
138 
139  auto r2 = dx*dx + dy*dy + dz*dz;
140 
141  if (r2_max <= r2) continue;
142 
143  auto r = sqrt(r2);
144 
145  auto r_index = bin_from_r ?
146  floor(r*reciprocal_bin_width) : round(r*reciprocal_bin_width);
147 
148  /* NOTE:
149  Adding 2 (not 1) is for taking both directions
150  (i -> j & j -> i) into consideration at once.
151  */
152  counts(r_index) += 2;
153 
154  }
155  }
156  }
157  }
158  }
159 }
160 
161 /* ------------------------------------------------------------------ */
162 
164 {
165  number_traj.resize(n_generators);
166  volume_traj.resize(n_generators);
167  counts_traj.resize(n_generators);
168 }
169 
170 /* ------------------------------------------------------------------ */
171 
173 {
174  ArrayXd shell_volume(n_bins);
175 
176  const double ball_coeff = 4.0 * M_PI / 3.0;
177 
178  for (int i = 0; i != n_bins; ++i)
179  {
180  auto r_inner = bin_from_r ?
181  i * bin_width : std::max(0.0, (i-0.5) * bin_width);
182  auto r_outer = bin_from_r ?
183  (i+1) * bin_width : (i+0.5) * bin_width;
184 
185  shell_volume(i) = ball_coeff * (pow(r_outer, 3) - pow(r_inner, 3));
186  }
187 
188  int number_sum = 0;
189  double volume_sum = 0.0;
190  ArrayXi counts_sum = ArrayXi::Zero(n_bins);
191 
192  rdf_traj.reserve(n_generators);
193 
194  for (int i = 0; i != n_generators; ++i)
195  {
196  auto &number_tmp = number_traj[i];
197  auto &volume_tmp = volume_traj[i];
198  auto &counts_tmp = counts_traj[i];
199 
200  auto density_tmp = number_tmp / volume_tmp;
201  auto number_distribution_tmp
202  = counts_tmp.cast<double>() / double(number_tmp);
203 
204  rdf_traj.push_back(
205  number_distribution_tmp / (density_tmp*shell_volume));
206 
207  number_sum += number_tmp;
208  volume_sum += volume_tmp;
209  counts_sum += counts_tmp;
210  }
211 
212  auto density = number_sum / volume_sum;
213  auto number_distribution
214  = counts_sum.cast<double>() / double(number_sum);
215 
216  rdf = number_distribution / (density*shell_volume);
217 
218  number_traj.clear();
219  number_traj.shrink_to_fit();
220  volume_traj.clear();
221  volume_traj.shrink_to_fit();
222  counts_traj.clear();
223  counts_traj.shrink_to_fit();
224 }
225 
226 /* ------------------------------------------------------------------ */
227 
229  double bin_width_,
230  int n_bins_)
231 {
232  n_bins = n_bins_;
233  bin_width = bin_width_;
234 }
235 
236 /* ------------------------------------------------------------------ */
237 
239  bool bin_from_r_)
240 {
241  bin_from_r = bin_from_r_;
242 }
243 
244 /* ------------------------------------------------------------------ */
245 
247  bool beyond_half_)
248 {
249  beyond_half = beyond_half_;
250 }
251 
252 /* ------------------------------------------------------------------ */
253 
255 {
256  ArrayXd rs(n_bins);
257 
258  for (int i = 0; i != n_bins; ++i)
259  {
260  rs(i) = i * bin_width;
261  }
262 
263  return rs;
264 }
265 
266 /* ------------------------------------------------------------------ */
267 
269 {
270  return rdf;
271 }
272 
273 /* ------------------------------------------------------------------ */
274 
276 {
277  return rdf_traj;
278 }
Vec< ShPtr< Generator > > generators
Definition: processor.h:37
const Vec< ArrayXd > & get_rdf_traj()
Get a sequence of radial distribution functions as list of one-dimensional arrays.
ShPtr< Element > ElPtr
An alias for a shared pointer of Element class.
Definition: element.h:378
virtual void run_impl(const int index) override
Implementation of analysis using an element of generators.
ProRadialDistributionFunction(const ElPtr &targets, const ElPtr &box)
Constructor of ProRadialDistributionFunction class for a snapshot of simulation.
virtual void finish() override
Compute rdf and rdf_traj from number_traj, volume_traj and counts_traj.
Eigen::Array< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > ArrayXXd
ArrayXXd is an alias for a two-dimensional array of float numbers.
Definition: eigen.h:32
This file has a definition of ProRadialDistributionFunction class, which is a subclass of Processor c...
std::string Str
Str is an alias for string.
Definition: std.h:21
const ArrayXd & get_rdf()
Get the radial distribution function as a one-dimensional array.
int n_generators
Definition: processor.h:31
void bin_from_r_to_r_plus_dr(bool bin_from_r_=true)
By default, the bins are [0, 0.5*dr), [0.5*dr, 1.5*dr), ... . If this method is called without a para...
std::unordered_set< T > Set
Set is an alias for unordered set (same as set in Python).
Definition: std.h:49
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 register_generator(const ShPtr< GEN > &gen)
Definition: processor.cpp:16
const ArrayXd get_r_axis()
Get a one-dimensional array of distance, [0, dr, 2*dr, ... ], where dr is width of a bin...
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
GenDict is a dictionary (or map) of Generator objects.
Definition: gen_dict.h:20
Namespace for utility functions.
Definition: join.h:14
void beyond_half_box_length(bool beyond_half_=true)
Use a sample including particles of which distance from a reference particle are larger than half the...
Eigen::Array< double, Eigen::Dynamic, 1 > ArrayXd
ArrayXd is an alias for a column array of float numbers.
Definition: eigen.h:42
std::shared_ptr< T > ShPtr
ShPtr is an alias for shared pointer.
Definition: std.h:16
void set_bin(double bin_width_, int n_bins_)
Set width and number of bins in the distance axis. Each bin is a spherical shell of which center is p...
void register_generators(const Vec< ShPtr< GEN >> &gens)
Definition: processor.cpp:36