15#ifndef SEAMS_GENERIC_H_
16#define SEAMS_GENERIC_H_
29#ifdef SEAMS_HAS_MINIMAGE
64constexpr double pi = std::numbers::pi;
88 int n = (*input).size();
92 std::vector<double> sorted = *input;
93 std::sort(sorted.begin(), sorted.end());
98 median = 0.5 * (sorted[n / 2] + sorted[n / 2 - 1]);
100 median = sorted[(n + 1) / 2 - 1];
106#ifdef SEAMS_HAS_MINIMAGE
108inline bool pointCloudCell(
111 const auto &box = yCloud.box;
112 const auto &boxLow = yCloud.boxLow;
113 const double xlo_b = boxLow.size() > 0 ? boxLow[0] : 0.0;
114 const double ylo_b = boxLow.size() > 1 ? boxLow[1] : 0.0;
115 const double zlo_b = boxLow.size() > 2 ? boxLow[2] : 0.0;
116 if (box.size() >= 6) {
117 return mi_cell_from_lammps_bounds(box[0], box[1], box[2], box[3], box[4],
118 box[5], xlo_b, ylo_b, zlo_b, out) == 0;
120 if (box.size() >= 3 && box[0] > 0.0 && box[1] > 0.0 && box[2] > 0.0) {
121 *out = mi_cell_ortho(box[0], box[1], box[2]);
156 const auto &box = yCloud.box;
157 const auto &boxLow = yCloud.boxLow;
158 b.
ox = boxLow.size() > 0 ? boxLow[0] : 0.0;
159 b.
oy = boxLow.size() > 1 ? boxLow[1] : 0.0;
160 b.
oz = boxLow.size() > 2 ? boxLow[2] : 0.0;
161 if (box.size() >= 6) {
162 const double xy = box[3];
163 const double xz = box[4];
164 const double yz = box[5];
165 const double xmin = std::min(std::min(0.0, xy), std::min(xz, xy + xz));
166 const double xmax = std::max(std::max(0.0, xy), std::max(xz, xy + xz));
167 const double ymin = std::min(0.0, yz);
168 const double ymax = std::max(0.0, yz);
169 b.
lx = box[0] - xmax + xmin;
170 b.
ly = box[1] - ymax + ymin;
178 }
else if (box.size() >= 3) {
185 if (!(b.
lx > 0.0 && b.
ly > 0.0 && b.
lz > 0.0)) {
188 const double bcz = b.
xy * b.
yz - b.
ly * b.
xz;
204 double zi,
double xj,
double yj,
207 std::array<double, 3> dr = {xi - xj, yi - yj, zi - zj};
208 const double len[3] = {b.
lx, b.
ly, b.
lz};
209 for (
int k = 0; k < 3; k++) {
210 dr[
static_cast<std::size_t
>(k)] -=
211 len[k] * std::floor(dr[
static_cast<std::size_t
>(k)] / len[k] + 0.5);
215 const double sz_i = (zi - b.
oz) / b.
lz;
216 const double sy_i = (yi - b.
oy - b.
yz * sz_i) / b.
ly;
217 const double sx_i = (xi - b.
ox - b.
xy * sy_i - b.
xz * sz_i) / b.
lx;
218 const double sz_j = (zj - b.
oz) / b.
lz;
219 const double sy_j = (yj - b.
oy - b.
yz * sz_j) / b.
ly;
220 const double sx_j = (xj - b.
ox - b.
xy * sy_j - b.
xz * sz_j) / b.
lx;
221 double dsx = sx_i - sx_j;
222 double dsy = sy_i - sy_j;
223 double dsz = sz_i - sz_j;
224 dsx -= std::round(dsx);
225 dsy -= std::round(dsy);
226 dsz -= std::round(dsz);
227 return {b.
lx * dsx + b.
xy * dsy + b.
xz * dsz, b.
ly * dsy + b.
yz * dsz,
232 double xj,
double yj,
double zj) {
233 const auto dr =
fracDelta(b, xi, yi, zi, xj, yj, zj);
234 return dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2];
245#ifdef SEAMS_HAS_MINIMAGE
246inline bool euclideanDelta(
248 double yi,
double zi,
double xj,
double yj,
double zj,
double dr[3]) {
250 if (!pointCloudCell(yCloud, &cell)) {
253 const double p[3] = {xj, yj, zj};
254 const double q[3] = {xi, yi, zi};
255 return mi_displacement_euclidean(&cell, p, q, dr) == 0;
262 std::vector<double> xyz;
267makeCellFrame(
const molSys::PointCloud<molSys::Point<double>,
double> &yCloud) {
269 if (!pointCloudCell(yCloud, &f.cell)) {
272 const std::size_t n = yCloud.pts.size();
274 for (std::size_t i = 0; i < n; i++) {
275 f.xyz[3 * i] = yCloud.pts[i].x;
276 f.xyz[3 * i + 1] = yCloud.pts[i].y;
277 f.xyz[3 * i + 2] = yCloud.pts[i].z;
284inline double euclideanDistSq(
const CellFrame &f,
int i,
int j) {
286 if (mi_displacement_euclidean(&f.cell, &f.xyz[3 *
static_cast<std::size_t
>(j)],
287 &f.xyz[3 *
static_cast<std::size_t
>(i)],
291 return dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2];
300 double yi,
double zi,
double xj,
double yj,
double zj) {
303 const auto dr =
fracDelta(b, xi, yi, zi, xj, yj, zj);
304 const double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2];
308#ifdef SEAMS_HAS_MINIMAGE
309 double ed[3] = {0.0, 0.0, 0.0};
310 if (euclideanDelta(yCloud, xi, yi, zi, xj, yj, zj, ed)) {
311 return {ed[0], ed[1], ed[2]};
316 const auto &box = yCloud.box;
317 const auto &boxLow = yCloud.boxLow;
318 const double xspan = box[0];
319 const double yspan = box[1];
320 const double zspan = box[2];
321 const double xlo_b = boxLow.size() > 0 ? boxLow[0] : 0.0;
322 const double ylo_b = boxLow.size() > 1 ? boxLow[1] : 0.0;
323 const double zlo_b = boxLow.size() > 2 ? boxLow[2] : 0.0;
324 const double xy = box[3];
325 const double xz = box[4];
326 const double yz = box[5];
327 const double xmin = std::min(std::min(0.0, xy), std::min(xz, xy + xz));
328 const double xmax = std::max(std::max(0.0, xy), std::max(xz, xy + xz));
329 const double ymin = std::min(0.0, yz);
330 const double ymax = std::max(0.0, yz);
331 const double lx = xspan - xmax + xmin;
332 const double ly = yspan - ymax + ymin;
333 const double lz = zspan;
334 const double ox = xlo_b - xmin;
335 const double oy = ylo_b - ymin;
336 const double oz = zlo_b;
337 const double sz_i = (zi - oz) / lz;
338 const double sy_i = (yi - oy - yz * sz_i) / ly;
339 const double sx_i = (xi - ox - xy * sy_i - xz * sz_i) / lx;
340 const double sz_j = (zj - oz) / lz;
341 const double sy_j = (yj - oy - yz * sz_j) / ly;
342 const double sx_j = (xj - ox - xy * sy_j - xz * sz_j) / lx;
343 double dsx = sx_i - sx_j;
344 double dsy = sy_i - sy_j;
345 double dsz = sz_i - sz_j;
346 dsx -= std::round(dsx);
347 dsy -= std::round(dsy);
348 dsz -= std::round(dsz);
349 return {lx * dsx + xy * dsy + xz * dsz, ly * dsy + yz * dsz, lz * dsz};
365 int iatom,
int jatom) {
366 const auto &
pi = yCloud.pts[
static_cast<std::size_t
>(iatom)];
367 const auto &pj = yCloud.pts[
static_cast<std::size_t
>(jatom)];
373#ifdef SEAMS_HAS_MINIMAGE
374 double ed[3] = {0.0, 0.0, 0.0};
375 if (euclideanDelta(yCloud,
pi.x,
pi.y,
pi.z, pj.x, pj.y, pj.z, ed)) {
376 return ed[0] * ed[0] + ed[1] * ed[1] + ed[2] * ed[2];
381 if (yCloud.box.size() >= 6) {
384 return dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2];
386 std::array<double, 3> dr;
388 dr[0] = std::fabs(
pi.x - pj.x);
389 dr[1] = std::fabs(
pi.y - pj.y);
390 dr[2] = std::fabs(
pi.z - pj.z);
391 for (
int k = 0; k < 3; k++) {
392 dr[
static_cast<std::size_t
>(k)] -=
393 yCloud.box[
static_cast<std::size_t
>(k)] *
394 std::round(dr[
static_cast<std::size_t
>(k)] /
395 yCloud.box[
static_cast<std::size_t
>(k)]);
396 r2 += dr[
static_cast<std::size_t
>(k)] * dr[
static_cast<std::size_t
>(k)];
403 int iatom,
int jatom) {
418 int iatom,
int jatom) {
428 const int *jatom, std::size_t n,
double *distSq) {
430#ifdef SEAMS_HAS_MINIMAGE
433 if (pointCloudCell(yCloud, &cell)) {
434 const auto &
pi = yCloud.pts[
static_cast<std::size_t
>(iatom)];
435 const double p[3] = {
pi.x,
pi.y,
pi.z};
436 std::vector<double> qs(n * 3);
437 for (std::size_t k = 0; k < n; ++k) {
438 const auto &pj = yCloud.pts[
static_cast<std::size_t
>(jatom[k])];
440 qs[3 * k + 1] = pj.y;
441 qs[3 * k + 2] = pj.z;
443 if (mi_dist2_many(&cell, p, qs.data(), n, distSq) == 0) {
444 for (std::size_t k = 0; k < n; ++k) {
448 const double q[3] = {qs[3 * k], qs[3 * k + 1], qs[3 * k + 2]};
449 double ed[3] = {0.0, 0.0, 0.0};
450 if (mi_displacement_euclidean(&cell, q, p, ed) == 0) {
451 distSq[k] = ed[0] * ed[0] + ed[1] * ed[1] + ed[2] * ed[2];
459 for (std::size_t k = 0; k < n; k++) {
466 std::ostringstream oss;
467 if (box.size() >= 3) {
468 oss << box[0] <<
' ' << box[1] <<
' ' << box[2];
470 if (box.size() >= 6) {
471 oss <<
" xy " << box[3] <<
" xz " << box[4] <<
" yz " << box[5];
480 const bool tilt = yCloud.box.size() >= 6;
482 os <<
"ITEM: BOX BOUNDS xy xz yz pp pp pp\n";
484 os <<
"ITEM: BOX BOUNDS pp pp pp\n";
486 for (
int k = 0; k < 3; k++) {
487 const double lo = (
static_cast<std::size_t
>(k) < yCloud.boxLow.size())
490 const double len = (
static_cast<std::size_t
>(k) < yCloud.box.size())
493 os << lo <<
' ' << lo + len;
495 os <<
' ' << yCloud.box[
static_cast<std::size_t
>(k + 3)];
515 double xj,
double yj,
double zj) {
517 const auto &
pi = yCloud.pts[
static_cast<std::size_t
>(iatom)];
519 const double r2 = dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2];
523#ifdef SEAMS_HAS_MINIMAGE
524 double ed[3] = {0.0, 0.0, 0.0};
525 if (euclideanDelta(yCloud,
pi.x,
pi.y,
pi.z, xj, yj, zj, ed)) {
526 return {ed[0], ed[1], ed[2]};
531 if (yCloud.box.size() >= 6) {
533 yCloud.pts[iatom].z, xj, yj, zj);
536 std::array<double, 3> dr = {yCloud.pts[iatom].x - xj, yCloud.pts[iatom].y - yj,
537 yCloud.pts[iatom].z - zj};
538 for (
int k = 0; k < 3; k++) {
539 if (dr[k] < -yCloud.box[k] * 0.5) {
540 dr[k] += yCloud.box[k];
542 if (dr[k] >= yCloud.box[k] * 0.5) {
543 dr[k] -= yCloud.box[k];
551 double xj,
double yj,
double zj) {
557 const std::vector<double> &singlePoint) {
561 return std::sqrt(dr[0] * dr[0] + dr[1] * dr[1] + dr[2] * dr[2]);
577 std::array<double, 3> dr;
581 dr[0] = fabs(yCloud.pts[iatom].x - yCloud.pts[jatom].x);
582 dr[1] = fabs(yCloud.pts[iatom].y - yCloud.pts[jatom].y);
583 dr[2] = fabs(yCloud.pts[iatom].z - yCloud.pts[jatom].z);
586 for (
int k = 0; k < 3; k++) {
587 r2 += pow(dr[k], 2.0);
604inline std::array<double, 3>
608 yCloud.pts[jatom].y, yCloud.pts[jatom].z);
627 std::string outFile);
632 int jatomIndex,
double *x_i,
double *y_i,
double *z_i,
double *x_j,
633 double *y_j,
double *z_j);
638 std::vector<double> quat2);
645inline std::vector<std::string>
tokenizer(std::string line) {
646 std::istringstream iss(line);
647 std::vector<std::string> tokens{std::istream_iterator<std::string>{iss},
648 std::istream_iterator<std::string>{}};
657 std::istringstream iss(line);
658 std::vector<double> tokens;
660 while (iss >> number) {
661 tokens.push_back(number);
671 std::istringstream iss(line);
672 std::vector<int> tokens;
674 while (iss >> number) {
675 tokens.push_back(number);
685 return std::filesystem::exists(name);
696inline std::vector<std::complex<double>>
697avgVector(std::vector<std::complex<double>> v,
int l,
int neigh) {
701 for (
int m = 0; m < 2 * l + 1; m++) {
702 v[m] = (1.0 /
static_cast<double>(neigh)) * v[m];
double fracDistSq(const FracBox &b, double xi, double yi, double zi, double xj, double yj, double zj)
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...
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 .
void writeDumpBoxBounds(std::ostream &os, const molSys::PointCloud< molSys::Point< double >, double > &yCloud)
std::array< double, 3 > relDistFromPoint(const FracBox &b, 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...
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...
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,...
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.
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)
std::string formatDumpBox(const std::vector< double > &box)
FracBox makeFracBox(const molSys::PointCloud< molSys::Point< double >, double > &yCloud)
std::vector< double > tokenizerDouble(std::string line)
Function for tokenizing line strings into a vector of doubles.
constexpr double pi
Uses Boost to get the value of pi.
bool smithInside(const FracBox &b, double r2)
bool file_exists(const std::string &name)
Function for checking if a file exists or not.
std::vector< std::string > tokenizer(std::string line)
Function for tokenizing line strings into words (strings) delimited by whitespace.
int prettyPrintYoda(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, std::string outFile)
Generic function for printing all the struct information.
std::array< double, 3 > fracDelta(const FracBox &b, double xi, double yi, double zi, double xj, double yj, double zj)
double periodicDistSq(const FracBox &b, const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, int jatom)
Inline generic function for obtaining the unwrapped periodic distance between two particles,...
double angDistDegQuaternions(std::vector< double > quat1, std::vector< double > quat2)
void batchPeriodicDistSq(const molSys::PointCloud< molSys::Point< double >, double > &yCloud, int iatom, const int *jatom, std::size_t n, double *distSq)
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.
double radDeg(double angle)
Inline function for converting radians->degrees.
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...
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)
The main molecular system handler.
Small generic functions that are shared by all namespaces.
This contains a collection of points; contains information for a particular frame.
This contains per-particle information.