10 #include "../utils/message.h" 11 #include "../utils/runtime_error.h" 24 auto el_beads =
generators[index]->get_element(
"Targets");
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"});
30 auto &beads = el_beads->get_data();
32 auto special_bonds_exist = el_beads->check_optional_keys(
"special-bonds");
34 auto el_box =
generators[index]->get_element(
"Box");
36 el_box->check_required_keys({
"lo_x",
"lo_y",
"lo_z",
"hi_x",
"hi_y",
"hi_z"});
38 auto &box = el_box->get_data();
42 const auto n_beads = beads.size();
45 rs_and_Is_per_mass.reserve(n_beads);
47 for (
const auto &bead : beads)
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>()));
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>();
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;
69 for (
int i = 0; i != 3; ++i)
71 if (neighbor_limits(i) < r_margined)
74 "Box length is too short in " +
Str(
"xyz").substr(i, 1));
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);
85 const auto reciprocal_bin_width = 1.0 /
bin_width;
87 const double one_third = 1.0 / 3.0;
88 const double two_thirds = 2.0 / 3.0;
110 for (
int i = 0; i != n_beads; ++i)
112 auto sbonds_i = special_bonds_exist ?
115 auto &tmp_i = rs_and_Is_per_mass[i];
116 auto &r_i = tmp_i.first;
117 auto &I_i = tmp_i.second;
119 for (
int j = i+1; j != n_beads; ++j)
121 if (!sbonds_i.empty() && sbonds_i.find(
122 beads[j][
"id"].get<int>()) != sbonds_i.cend())
continue;
124 auto &tmp_j = rs_and_Is_per_mass[j];
125 auto &I_j = tmp_j.second;
127 auto dr_original = tmp_j.first - r_i;
129 for (
int ix = image_range_x.first; ix <= image_range_x.second; ++ix)
131 auto dx = dr_original(0) + ix*box_length(0);
133 if (neighbor_limits(0) < abs(dx))
continue;
135 for (
int iy = image_range_y.first; iy <= image_range_y.second; ++iy)
137 auto dy = dr_original(1) + iy*box_length(1);
139 if (neighbor_limits(1) < abs(dy))
continue;
141 for (
int iz = image_range_z.first; iz <= image_range_z.second; ++iz)
143 auto dz = dr_original(2) + iz*box_length(2);
145 if (neighbor_limits(2) < abs(dz))
continue;
147 auto r2 = dx*dx + dy*dy + dz*dz;
149 if (r2_margined <= r2)
continue;
155 auto Rg2_i = 0.5 * I_i.trace();
156 auto Rg2_j = 0.5 * I_j.trace();
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;
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);
173 floor(r*reciprocal_bin_width) : round(r*reciprocal_bin_width);
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;
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)));
194 if (r2 < r2_max && r_margined <= r_modified)
199 if (r_max <= r_modified)
203 else if (r_max < 0.0)
209 floor(r_modified*reciprocal_bin_width) :
210 round(r_modified*reciprocal_bin_width);
216 counts(r_index) += 2;
259 auto reciprocal_counts = (1.0 / counts_tmp.cast<
double>())
260 .unaryExpr([](
double x)
262 return std::isfinite(x) ? x : 0.0;
269 counts_sum += counts_tmp;
271 Rg2_para_sum += Rg2_para_tmp;
272 Rg2_perp_sum += Rg2_perp_tmp;
275 auto reciprocal_counts = (1.0 / counts_sum.cast<
double>())
276 .unaryExpr([](
double x)
278 return std::isfinite(x) ? x : 0.0;
319 auto &iso = type2traj[
"isotropic"];
323 iso.push_back(array.sqrt());
326 auto ¶ = type2traj[
"parallel"];
330 para.push_back(array.sqrt());
333 auto &perp = type2traj[
"perpendicular"];
337 perp.push_back(array.sqrt());
Vec< ArrayXi > counts_traj
Vec< ShPtr< Generator > > generators
virtual void finish() override
Compute rdf and rdf_traj from number_traj, volume_traj and counts_traj.
std::string Str
Str is an alias for string.
std::unordered_set< T > Set
Set is an alias for unordered set (same as set in Python).
std::vector< T > Vec
Vec is an alias for vector (same as list in Python).
virtual void prepare() override
Resize number_traj, volume_traj and counts_traj.
Vec< double > volume_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.
void warning(const Str &msg)
Waning with a message.
Namespace for utility functions.
Eigen::Array< double, Eigen::Dynamic, 1 > ArrayXd
ArrayXd is an alias for a column array of float numbers.
std::unordered_map< T, U > Map
Map is an alias for unordered map (same as dict in Python).
Eigen::Vector3d Vector3d
Vector3d is an alias for a 3-elements column vector of float numbers.
Eigen::Matrix3d Matrix3d
Matrix3d is an alias for a 3x3 matrix of float numbers.