Loading...
Searching...
No Matches
generic.hpp
Go to the documentation of this file.
1//-----------------------------------------------------------------------------------
2// d-SEAMS - Deferred Structural Elucidation Analysis for Molecular Simulations
3//
4// Copyright (c) 2018--present d-SEAMS core team
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the MIT License as published by
8// the Open Source Initiative.
9//
10// A copy of the MIT License is included in the LICENSE file of this repository.
11// You should have received a copy of the MIT License along with this program.
12// If not, see <https://opensource.org/licenses/MIT>.
13//-----------------------------------------------------------------------------------
14
15#ifndef SEAMS_GENERIC_H_
16#define SEAMS_GENERIC_H_
17
18#include <algorithm>
19#include <array>
20#include <cmath>
21#include <cstddef>
22#include <filesystem>
23#include <iostream>
24#include <sstream>
25#include <string>
26#include <vector>
27#include <mol_sys.hpp>
28
29// C++20
30#include <numbers>
31// Eigen
32#include <Eigen/Core>
33#include <Eigen/Dense>
34
38
43
54
55namespace gen {
56
60constexpr double pi = std::numbers::pi;
61
67inline double radDeg(double angle) { return (angle * 180) / gen::pi; }
68
70double eigenVecAngle(std::vector<double> OO, std::vector<double> OH);
71
73double getAverageWithoutOutliers(std::vector<double> inpVec);
74
83inline double calcMedian(std::vector<double> *input) {
84 int n = (*input).size(); // Number of elements
85 double median; // Output median value
86
87 // Sort a copy (avoid mutating input)
88 std::vector<double> sorted = *input;
89 std::sort(sorted.begin(), sorted.end());
90
91 // Calculate the median
92 // For even values, the median is the average of the two middle values
93 if (n % 2 == 0) {
94 median = 0.5 * (sorted[n / 2] + sorted[n / 2 - 1]);
95 } else {
96 median = sorted[(n + 1) / 2 - 1];
97 }
98
99 return median;
100}
101
102// Recover H (columns a, b, c) and origin from a LAMMPS dump box with the
103// same mapping as nneigh::lammpsBoxToLcCell: box[0..3] are bound spans,
104// box[3..6] are tilt factors xy, xz, yz, boxLow is the bound lo.
105// Convert each cartesian point to fractional coordinates relative to
106// origin, wrap the fractional difference, and map back through H.
107inline std::array<double, 3> triclinicMinImage(
108 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, double xi,
109 double yi, double zi, double xj, double yj, double zj) {
110 const auto &box = yCloud.box;
111 const auto &boxLow = yCloud.boxLow;
112 const double xspan = box[0];
113 const double yspan = box[1];
114 const double zspan = box[2];
115 const double xlo_b = boxLow.size() > 0 ? boxLow[0] : 0.0;
116 const double ylo_b = boxLow.size() > 1 ? boxLow[1] : 0.0;
117 const double zlo_b = boxLow.size() > 2 ? boxLow[2] : 0.0;
118 const double xy = box[3];
119 const double xz = box[4];
120 const double yz = box[5];
121 const double xmin = std::min(std::min(0.0, xy), std::min(xz, xy + xz));
122 const double xmax = std::max(std::max(0.0, xy), std::max(xz, xy + xz));
123 const double ymin = std::min(0.0, yz);
124 const double ymax = std::max(0.0, yz);
125 const double lx = xspan - xmax + xmin;
126 const double ly = yspan - ymax + ymin;
127 const double lz = zspan;
128 const double ox = xlo_b - xmin;
129 const double oy = ylo_b - ymin;
130 const double oz = zlo_b;
131
132 auto toFrac = [&](double x, double y, double z) {
133 const double sz = (z - oz) / lz;
134 const double sy = (y - oy - yz * sz) / ly;
135 const double sx = (x - ox - xy * sy - xz * sz) / lx;
136 return std::array<double, 3>{sx, sy, sz};
137 };
138 const auto si = toFrac(xi, yi, zi);
139 const auto sj = toFrac(xj, yj, zj);
140 double dsx = si[0] - sj[0];
141 double dsy = si[1] - sj[1];
142 double dsz = si[2] - sj[2];
143 dsx -= std::round(dsx);
144 dsy -= std::round(dsy);
145 dsz -= std::round(dsz);
146 return {lx * dsx + xy * dsy + xz * dsz, ly * dsy + yz * dsz, lz * dsz};
147}
148
149// Generic function for getting the unwrapped distance
159inline double
161 int iatom, int jatom) {
162 if (yCloud.box.size() >= 6) {
163 const auto dr = triclinicMinImage(
164 yCloud, yCloud.pts[iatom].x, yCloud.pts[iatom].y, yCloud.pts[iatom].z,
165 yCloud.pts[jatom].x, yCloud.pts[jatom].y, yCloud.pts[jatom].z);
166 return dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2];
167 }
168
169 std::array<double, 3> dr;
170 double r2 = 0.0; // Squared absolute distance
171
172 // Get x1-x2 etc
173 dr[0] = std::fabs(yCloud.pts[iatom].x - yCloud.pts[jatom].x);
174 dr[1] = std::fabs(yCloud.pts[iatom].y - yCloud.pts[jatom].y);
175 dr[2] = std::fabs(yCloud.pts[iatom].z - yCloud.pts[jatom].z);
176
177 // Three-axis wrap for an orthorhombic length-3 box
178 for (int k = 0; k < 3; k++) {
179 dr[k] -= yCloud.box[k] * std::round(dr[k] / yCloud.box[k]);
180 r2 += dr[k] * dr[k];
181 }
182
183 return r2;
184}
185
195inline double
197 int iatom, int jatom) {
198 return std::sqrt(periodicDistSq(yCloud, iatom, jatom));
199}
200
201// Scalar pair batch. Highway BatchPeriodicDistSq is ortho-only; a
202// tilt dump (box.size() >= 6) must go through periodicDistSq.
204 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
205 const int *jatom, std::size_t n, double *distSq) {
206 for (std::size_t k = 0; k < n; k++) {
207 distSq[k] = periodicDistSq(yCloud, iatom, jatom[k]);
208 }
209}
210
211// Bound spans, then tilt when box.size() >= 6.
212inline std::string formatDumpBox(const std::vector<double> &box) {
213 std::ostringstream oss;
214 if (box.size() >= 3) {
215 oss << box[0] << ' ' << box[1] << ' ' << box[2];
216 }
217 if (box.size() >= 6) {
218 oss << " xy " << box[3] << " xz " << box[4] << " yz " << box[5];
219 }
220 return oss.str();
221}
222
223// ITEM line plus three bound lines. Tilt is a third field per line.
225 std::ostream &os,
226 const molSys::PointCloud<molSys::Point<double>, double> &yCloud) {
227 const bool tilt = yCloud.box.size() >= 6;
228 if (tilt) {
229 os << "ITEM: BOX BOUNDS xy xz yz pp pp pp\n";
230 } else {
231 os << "ITEM: BOX BOUNDS pp pp pp\n";
232 }
233 for (int k = 0; k < 3; k++) {
234 const double lo = (static_cast<std::size_t>(k) < yCloud.boxLow.size())
235 ? yCloud.boxLow[k]
236 : 0.0;
237 const double len = (static_cast<std::size_t>(k) < yCloud.box.size())
238 ? yCloud.box[k]
239 : 0.0;
240 os << lo << ' ' << lo + len;
241 if (tilt) {
242 os << ' ' << yCloud.box[static_cast<std::size_t>(k + 3)];
243 }
244 os << '\n';
245 }
246}
247
258inline std::array<double, 3> relDistFromPoint(
259 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
260 double xj, double yj, double zj) {
261 if (yCloud.box.size() >= 6) {
262 return triclinicMinImage(yCloud, yCloud.pts[iatom].x, yCloud.pts[iatom].y,
263 yCloud.pts[iatom].z, xj, yj, zj);
264 }
265
266 std::array<double, 3> dr = {yCloud.pts[iatom].x - xj, yCloud.pts[iatom].y - yj,
267 yCloud.pts[iatom].z - zj};
268 for (int k = 0; k < 3; k++) {
269 if (dr[k] < -yCloud.box[k] * 0.5) {
270 dr[k] += yCloud.box[k];
271 }
272 if (dr[k] >= yCloud.box[k] * 0.5) {
273 dr[k] -= yCloud.box[k];
274 }
275 }
276 return dr;
277}
278
280 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
281 const std::vector<double> &singlePoint) {
282 const auto dr =
283 relDistFromPoint(yCloud, iatom, singlePoint[0], singlePoint[1],
284 singlePoint[2]);
285 return std::sqrt(dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]);
286}
287
288// Generic function for getting the distance (no PBCs applied)
298inline double
299distance(const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
300 int jatom) {
301 std::array<double, 3> dr;
302 double r2 = 0.0; // Squared absolute distance
303
304 // Get x1-x2 etc
305 dr[0] = fabs(yCloud.pts[iatom].x - yCloud.pts[jatom].x);
306 dr[1] = fabs(yCloud.pts[iatom].y - yCloud.pts[jatom].y);
307 dr[2] = fabs(yCloud.pts[iatom].z - yCloud.pts[jatom].z);
308
309 // Get the squared absolute distance
310 for (int k = 0; k < 3; k++) {
311 r2 += pow(dr[k], 2.0);
312 }
313
314 return sqrt(r2);
315}
316
317// Generic function for getting the relative coordinates
328inline std::array<double, 3>
329relDist(const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
330 int jatom) {
331 return relDistFromPoint(yCloud, iatom, yCloud.pts[jatom].x,
332 yCloud.pts[jatom].y, yCloud.pts[jatom].z);
333}
334
335// Function for sorting according to atom ID
336// Comparator for std::sort
345 const molSys::Point<double> &b) {
346 return a.atomID < b.atomID;
347}
348
350[[nodiscard]] int prettyPrintYoda(const molSys::PointCloud<molSys::Point<double>, double> &yCloud,
351 std::string outFile);
352
354[[nodiscard]] int unwrappedCoordShift(
355 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatomIndex,
356 int jatomIndex, double *x_i, double *y_i, double *z_i, double *x_j,
357 double *y_j, double *z_j);
358
361double angDistDegQuaternions(std::vector<double> quat1,
362 std::vector<double> quat2);
363
369inline std::vector<std::string> tokenizer(std::string line) {
370 std::istringstream iss(line);
371 std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
372 std::istream_iterator<std::string>{}};
373 return tokens;
374}
375
380inline std::vector<double> tokenizerDouble(std::string line) {
381 std::istringstream iss(line);
382 std::vector<double> tokens;
383 double number; // Each number being read in from the line
384 while (iss >> number) {
385 tokens.push_back(number);
386 }
387 return tokens;
388}
389
394inline std::vector<int> tokenizerInt(std::string line) {
395 std::istringstream iss(line);
396 std::vector<int> tokens;
397 int number; // Each number being read in from the line
398 while (iss >> number) {
399 tokens.push_back(number);
400 }
401 return tokens;
402}
403
408inline bool file_exists(const std::string &name) {
409 return std::filesystem::exists(name);
410}
411
420inline std::vector<std::complex<double>>
421avgVector(std::vector<std::complex<double>> v, int l, int neigh) {
422 if (neigh == 0) {
423 return v;
424 }
425 for (int m = 0; m < 2 * l + 1; m++) {
426 v[m] = (1.0 / static_cast<double>(neigh)) * v[m];
427 }
428
429 return v;
430}
431
432} // namespace gen
433
434#endif // SEAMS_GENERIC_H_
double distance(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, int jatom)
Inline generic function for obtaining the wrapped distance between two particles WITHOUT applying PBC...
Definition generic.hpp:299
std::vector< std::complex< double > > avgVector(std::vector< std::complex< double > > v, int l, int neigh)
Calculates the complex vector, normalized by the number of nearest neighbours, of length .
Definition generic.hpp:421
void writeDumpBoxBounds(std::ostream &os, const molSys::PointCloud< molSys::Point< double >, double > &yCloud)
Definition generic.hpp:224
std::array< double, 3 > relDist(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, int jatom)
Inline generic function for getting the relative unwrapped distance between two particles for each di...
Definition generic.hpp:329
double periodicDist(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, int jatom)
Inline generic function for obtaining the unwrapped periodic distance between two particles,...
Definition generic.hpp:196
double eigenVecAngle(std::vector< double > OO, std::vector< double > OH)
Eigen function for getting the angle (in radians) between the O–O and O-H vectors.
double calcMedian(std::vector< double > *input)
Inline generic function for calculating the median given a vector of the values.
Definition generic.hpp:83
std::array< double, 3 > triclinicMinImage(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, double xi, double yi, double zi, double xj, double yj, double zj)
Definition generic.hpp:107
std::string formatDumpBox(const std::vector< double > &box)
Definition generic.hpp:212
std::vector< double > tokenizerDouble(std::string line)
Function for tokenizing line strings into a vector of doubles.
Definition generic.hpp:380
constexpr double pi
Uses Boost to get the value of pi.
Definition generic.hpp:60
bool file_exists(const std::string &name)
Function for checking if a file exists or not.
Definition generic.hpp:408
std::vector< std::string > tokenizer(std::string line)
Function for tokenizing line strings into words (strings) delimited by whitespace.
Definition generic.hpp:369
int prettyPrintYoda(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, std::string outFile)
Generic function for printing all the struct information.
double angDistDegQuaternions(std::vector< double > quat1, std::vector< double > quat2)
std::array< double, 3 > relDistFromPoint(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, double xj, double yj, double zj)
Inline generic function for obtaining the unwrapped periodic distance between one particle and anothe...
Definition generic.hpp:258
void batchPeriodicDistSq(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, const int *jatom, std::size_t n, double *distSq)
Definition generic.hpp:203
int unwrappedCoordShift(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatomIndex, int jatomIndex, double *x_i, double *y_i, double *z_i, double *x_j, double *y_j, double *z_j)
Shift particles (unwrapped coordinates).
std::vector< int > tokenizerInt(std::string line)
Function for tokenizing line strings into a vector of ints.
Definition generic.hpp:394
double radDeg(double angle)
Inline function for converting radians->degrees.
Definition generic.hpp:67
bool compareByAtomID(const molSys::Point< double > &a, const molSys::Point< double > &b)
Inline generic function for sorting or comparing two particles, according to the atom ID when the ent...
Definition generic.hpp:344
double getAverageWithoutOutliers(std::vector< double > inpVec)
Get the average, after excluding the outliers, using quartiles.
double unWrappedDistFromPoint(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, const std::vector< double > &singlePoint)
Definition generic.hpp:279
double periodicDistSq(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, int jatom)
Inline generic function for obtaining the unwrapped periodic distance between two particles,...
Definition generic.hpp:160
The main molecular system handler.
Small generic functions that are shared by all namespaces.
Definition generic.hpp:55
This contains a collection of points; contains information for a particular frame.
Definition mol_sys.hpp:173
This contains per-particle information.
Definition mol_sys.hpp:152