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#ifdef SEAMS_HAS_MINIMAGE
30#include <minimage.h>
31#endif
32
33// C++20
34#include <numbers>
35// Eigen
36#include <Eigen/Core>
37#include <Eigen/Dense>
38
42
47
58
59namespace gen {
60
64constexpr double pi = std::numbers::pi;
65
71inline double radDeg(double angle) { return (angle * 180) / gen::pi; }
72
74double eigenVecAngle(std::vector<double> OO, std::vector<double> OH);
75
77double getAverageWithoutOutliers(std::vector<double> inpVec);
78
87inline double calcMedian(std::vector<double> *input) {
88 int n = (*input).size(); // Number of elements
89 double median; // Output median value
90
91 // Sort a copy (avoid mutating input)
92 std::vector<double> sorted = *input;
93 std::sort(sorted.begin(), sorted.end());
94
95 // Calculate the median
96 // For even values, the median is the average of the two middle values
97 if (n % 2 == 0) {
98 median = 0.5 * (sorted[n / 2] + sorted[n / 2 - 1]);
99 } else {
100 median = sorted[(n + 1) / 2 - 1];
101 }
102
103 return median;
104}
105
106#ifdef SEAMS_HAS_MINIMAGE
107// Dump bound spans plus optional tilt onto an mi_cell.
108inline mi_cell pointCloudCell(
109 const molSys::PointCloud<molSys::Point<double>, double> &yCloud) {
110 const auto &box = yCloud.box;
111 const auto &boxLow = yCloud.boxLow;
112 const double xlo_b = boxLow.size() > 0 ? boxLow[0] : 0.0;
113 const double ylo_b = boxLow.size() > 1 ? boxLow[1] : 0.0;
114 const double zlo_b = boxLow.size() > 2 ? boxLow[2] : 0.0;
115 mi_cell c = mi_cell_ortho(0.0, 0.0, 0.0);
116 if (box.size() >= 6) {
117 mi_cell_from_lammps_bounds(box[0], box[1], box[2], box[3], box[4], box[5],
118 xlo_b, ylo_b, zlo_b, &c);
119 } else if (box.size() >= 3) {
120 c = mi_cell_ortho(box[0], box[1], box[2]);
121 c.ox = xlo_b;
122 c.oy = ylo_b;
123 c.oz = zlo_b;
124 }
125 return c;
126}
127#endif
128
129// Recover H (columns a, b, c) and origin from a LAMMPS dump box with the
130// same mapping as nneigh::lammpsBoxToLcCell: box[0..3] are bound spans,
131// box[3..6] are tilt factors xy, xz, yz, boxLow is the bound lo.
132// Convert each cartesian point to fractional coordinates relative to
133// origin, wrap the fractional difference, and map back through H.
134inline std::array<double, 3> triclinicMinImage(
135 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, double xi,
136 double yi, double zi, double xj, double yj, double zj) {
137#ifdef SEAMS_HAS_MINIMAGE
138 const mi_cell cell = pointCloudCell(yCloud);
139 const double p[3] = {xj, yj, zj};
140 const double q[3] = {xi, yi, zi};
141 double dr[3] = {0.0, 0.0, 0.0};
142 mi_displacement(&cell, p, q, dr);
143 return {dr[0], dr[1], dr[2]};
144#else
145 const auto &box = yCloud.box;
146 const auto &boxLow = yCloud.boxLow;
147 const double xspan = box[0];
148 const double yspan = box[1];
149 const double zspan = box[2];
150 const double xlo_b = boxLow.size() > 0 ? boxLow[0] : 0.0;
151 const double ylo_b = boxLow.size() > 1 ? boxLow[1] : 0.0;
152 const double zlo_b = boxLow.size() > 2 ? boxLow[2] : 0.0;
153 const double xy = box[3];
154 const double xz = box[4];
155 const double yz = box[5];
156 const double xmin = std::min(std::min(0.0, xy), std::min(xz, xy + xz));
157 const double xmax = std::max(std::max(0.0, xy), std::max(xz, xy + xz));
158 const double ymin = std::min(0.0, yz);
159 const double ymax = std::max(0.0, yz);
160 const double lx = xspan - xmax + xmin;
161 const double ly = yspan - ymax + ymin;
162 const double lz = zspan;
163 const double ox = xlo_b - xmin;
164 const double oy = ylo_b - ymin;
165 const double oz = zlo_b;
166
167 auto toFrac = [&](double x, double y, double z) {
168 const double sz = (z - oz) / lz;
169 const double sy = (y - oy - yz * sz) / ly;
170 const double sx = (x - ox - xy * sy - xz * sz) / lx;
171 return std::array<double, 3>{sx, sy, sz};
172 };
173 const auto si = toFrac(xi, yi, zi);
174 const auto sj = toFrac(xj, yj, zj);
175 double dsx = si[0] - sj[0];
176 double dsy = si[1] - sj[1];
177 double dsz = si[2] - sj[2];
178 dsx -= std::round(dsx);
179 dsy -= std::round(dsy);
180 dsz -= std::round(dsz);
181 return {lx * dsx + xy * dsy + xz * dsz, ly * dsy + yz * dsz, lz * dsz};
182#endif
183}
184
185// Generic function for getting the unwrapped distance
195inline double
197 int iatom, int jatom) {
198#ifdef SEAMS_HAS_MINIMAGE
199 const mi_cell cell = pointCloudCell(yCloud);
200 const double p[3] = {yCloud.pts[iatom].x, yCloud.pts[iatom].y,
201 yCloud.pts[iatom].z};
202 const double q[3] = {yCloud.pts[jatom].x, yCloud.pts[jatom].y,
203 yCloud.pts[jatom].z};
204 double out = 0.0;
205 mi_dist2(&cell, p, q, &out);
206 return out;
207#else
208 if (yCloud.box.size() >= 6) {
209 const auto dr = triclinicMinImage(
210 yCloud, yCloud.pts[iatom].x, yCloud.pts[iatom].y, yCloud.pts[iatom].z,
211 yCloud.pts[jatom].x, yCloud.pts[jatom].y, yCloud.pts[jatom].z);
212 return dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2];
213 }
214
215 std::array<double, 3> dr;
216 double r2 = 0.0; // Squared absolute distance
217
218 // Get x1-x2 etc
219 dr[0] = std::fabs(yCloud.pts[iatom].x - yCloud.pts[jatom].x);
220 dr[1] = std::fabs(yCloud.pts[iatom].y - yCloud.pts[jatom].y);
221 dr[2] = std::fabs(yCloud.pts[iatom].z - yCloud.pts[jatom].z);
222
223 // Three-axis wrap for an orthorhombic length-3 box
224 for (int k = 0; k < 3; k++) {
225 dr[k] -= yCloud.box[k] * std::round(dr[k] / yCloud.box[k]);
226 r2 += dr[k] * dr[k];
227 }
228
229 return r2;
230#endif
231}
232
242inline double
244 int iatom, int jatom) {
245 return std::sqrt(periodicDistSq(yCloud, iatom, jatom));
246}
247
248// Scalar pair batch. Highway BatchPeriodicDistSq is ortho-only; a
249// tilt dump (box.size() >= 6) must go through periodicDistSq.
251 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
252 const int *jatom, std::size_t n, double *distSq) {
253 for (std::size_t k = 0; k < n; k++) {
254 distSq[k] = periodicDistSq(yCloud, iatom, jatom[k]);
255 }
256}
257
258// Bound spans, then tilt when box.size() >= 6.
259inline std::string formatDumpBox(const std::vector<double> &box) {
260 std::ostringstream oss;
261 if (box.size() >= 3) {
262 oss << box[0] << ' ' << box[1] << ' ' << box[2];
263 }
264 if (box.size() >= 6) {
265 oss << " xy " << box[3] << " xz " << box[4] << " yz " << box[5];
266 }
267 return oss.str();
268}
269
270// ITEM line plus three bound lines. Tilt is a third field per line.
272 std::ostream &os,
273 const molSys::PointCloud<molSys::Point<double>, double> &yCloud) {
274 const bool tilt = yCloud.box.size() >= 6;
275 if (tilt) {
276 os << "ITEM: BOX BOUNDS xy xz yz pp pp pp\n";
277 } else {
278 os << "ITEM: BOX BOUNDS pp pp pp\n";
279 }
280 for (int k = 0; k < 3; k++) {
281 const double lo = (static_cast<std::size_t>(k) < yCloud.boxLow.size())
282 ? yCloud.boxLow[k]
283 : 0.0;
284 const double len = (static_cast<std::size_t>(k) < yCloud.box.size())
285 ? yCloud.box[k]
286 : 0.0;
287 os << lo << ' ' << lo + len;
288 if (tilt) {
289 os << ' ' << yCloud.box[static_cast<std::size_t>(k + 3)];
290 }
291 os << '\n';
292 }
293}
294
305inline std::array<double, 3> relDistFromPoint(
306 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
307 double xj, double yj, double zj) {
308#ifdef SEAMS_HAS_MINIMAGE
309 const mi_cell cell = pointCloudCell(yCloud);
310 const double p[3] = {xj, yj, zj};
311 const double q[3] = {yCloud.pts[iatom].x, yCloud.pts[iatom].y,
312 yCloud.pts[iatom].z};
313 double dr[3] = {0.0, 0.0, 0.0};
314 mi_displacement(&cell, p, q, dr);
315 return {dr[0], dr[1], dr[2]};
316#else
317 if (yCloud.box.size() >= 6) {
318 return triclinicMinImage(yCloud, yCloud.pts[iatom].x, yCloud.pts[iatom].y,
319 yCloud.pts[iatom].z, xj, yj, zj);
320 }
321
322 std::array<double, 3> dr = {yCloud.pts[iatom].x - xj, yCloud.pts[iatom].y - yj,
323 yCloud.pts[iatom].z - zj};
324 for (int k = 0; k < 3; k++) {
325 if (dr[k] < -yCloud.box[k] * 0.5) {
326 dr[k] += yCloud.box[k];
327 }
328 if (dr[k] >= yCloud.box[k] * 0.5) {
329 dr[k] -= yCloud.box[k];
330 }
331 }
332 return dr;
333#endif
334}
335
337 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
338 const std::vector<double> &singlePoint) {
339 const auto dr =
340 relDistFromPoint(yCloud, iatom, singlePoint[0], singlePoint[1],
341 singlePoint[2]);
342 return std::sqrt(dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]);
343}
344
345// Generic function for getting the distance (no PBCs applied)
355inline double
356distance(const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
357 int jatom) {
358 std::array<double, 3> dr;
359 double r2 = 0.0; // Squared absolute distance
360
361 // Get x1-x2 etc
362 dr[0] = fabs(yCloud.pts[iatom].x - yCloud.pts[jatom].x);
363 dr[1] = fabs(yCloud.pts[iatom].y - yCloud.pts[jatom].y);
364 dr[2] = fabs(yCloud.pts[iatom].z - yCloud.pts[jatom].z);
365
366 // Get the squared absolute distance
367 for (int k = 0; k < 3; k++) {
368 r2 += pow(dr[k], 2.0);
369 }
370
371 return sqrt(r2);
372}
373
374// Generic function for getting the relative coordinates
385inline std::array<double, 3>
386relDist(const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatom,
387 int jatom) {
388 return relDistFromPoint(yCloud, iatom, yCloud.pts[jatom].x,
389 yCloud.pts[jatom].y, yCloud.pts[jatom].z);
390}
391
392// Function for sorting according to atom ID
393// Comparator for std::sort
402 const molSys::Point<double> &b) {
403 return a.atomID < b.atomID;
404}
405
407[[nodiscard]] int prettyPrintYoda(const molSys::PointCloud<molSys::Point<double>, double> &yCloud,
408 std::string outFile);
409
411[[nodiscard]] int unwrappedCoordShift(
412 const molSys::PointCloud<molSys::Point<double>, double> &yCloud, int iatomIndex,
413 int jatomIndex, double *x_i, double *y_i, double *z_i, double *x_j,
414 double *y_j, double *z_j);
415
418double angDistDegQuaternions(std::vector<double> quat1,
419 std::vector<double> quat2);
420
426inline std::vector<std::string> tokenizer(std::string line) {
427 std::istringstream iss(line);
428 std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
429 std::istream_iterator<std::string>{}};
430 return tokens;
431}
432
437inline std::vector<double> tokenizerDouble(std::string line) {
438 std::istringstream iss(line);
439 std::vector<double> tokens;
440 double number; // Each number being read in from the line
441 while (iss >> number) {
442 tokens.push_back(number);
443 }
444 return tokens;
445}
446
451inline std::vector<int> tokenizerInt(std::string line) {
452 std::istringstream iss(line);
453 std::vector<int> tokens;
454 int number; // Each number being read in from the line
455 while (iss >> number) {
456 tokens.push_back(number);
457 }
458 return tokens;
459}
460
465inline bool file_exists(const std::string &name) {
466 return std::filesystem::exists(name);
467}
468
477inline std::vector<std::complex<double>>
478avgVector(std::vector<std::complex<double>> v, int l, int neigh) {
479 if (neigh == 0) {
480 return v;
481 }
482 for (int m = 0; m < 2 * l + 1; m++) {
483 v[m] = (1.0 / static_cast<double>(neigh)) * v[m];
484 }
485
486 return v;
487}
488
489} // namespace gen
490
491#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:356
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:478
void writeDumpBoxBounds(std::ostream &os, const molSys::PointCloud< molSys::Point< double >, double > &yCloud)
Definition generic.hpp:271
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:386
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:243
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:87
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:134
std::string formatDumpBox(const std::vector< double > &box)
Definition generic.hpp:259
std::vector< double > tokenizerDouble(std::string line)
Function for tokenizing line strings into a vector of doubles.
Definition generic.hpp:437
constexpr double pi
Uses Boost to get the value of pi.
Definition generic.hpp:64
bool file_exists(const std::string &name)
Function for checking if a file exists or not.
Definition generic.hpp:465
std::vector< std::string > tokenizer(std::string line)
Function for tokenizing line strings into words (strings) delimited by whitespace.
Definition generic.hpp:426
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:305
void batchPeriodicDistSq(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, const int *jatom, std::size_t n, double *distSq)
Definition generic.hpp:250
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:451
double radDeg(double angle)
Inline function for converting radians->degrees.
Definition generic.hpp:71
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:401
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:336
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:196
The main molecular system handler.
Small generic functions that are shared by all namespaces.
Definition generic.hpp:59
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