18 namespace bg = boost::geometry;
63 result.
resize(2 * orderL + 1);
65 for (
int k = 0; k < 2 * orderL + 1; k++) {
69 result[k] = boost::math::spherical_harmonic(orderL, m, theta, phi);
85 bg::model::point<long double, 3, bg::cs::cartesian> cartesianPoint;
86 bg::model::point<long double, 3, bg::cs::spherical<bg::radian>> azuPoint;
88 bg::set<0>(cartesianPoint, cartCoord[0]);
89 bg::set<1>(cartesianPoint, cartCoord[1]);
90 bg::set<2>(cartesianPoint, cartCoord[2]);
92 bg::transform(cartesianPoint, azuPoint);
93 result[0] = bg::get<0>(azuPoint);
94 result[1] = bg::get<1>(azuPoint);
110 double theta = angles[1];
111 double phi = angles[0];
115 for (
int m = 0; m < 7; m++) {
138 double theta = angles[1];
139 double phi = angles[0];
152 result = constant *
std::exp(-1.0 * i * phi) * sin(theta) *
153 (5.0 *
std::pow(cos(theta), 2.0) - 1);
157 result = constant * (5.0 *
std::pow(cos(theta), 3.0) - 3.0 * cos(theta));
161 result = constant *
std::exp(i * phi) * sin(theta) *
162 (5.0 *
std::pow(cos(theta), 2.0) - 1);
192 double theta = angles[1];
193 double phi = angles[0];
197 for (
int m = 0; m < 13; m++) {
220 double theta = angles[1];
221 double phi = angles[0];
235 (11.0 *
std::pow(cos(theta), 2.0) - 1);
240 (11.0 *
std::pow(cos(theta), 3.0) - 3.0 * cos(theta));
246 18.0 *
std::pow(cos(theta), 2.0) + 1.0);
250 result = constant *
std::exp(-1.0 * i * phi) * sin(theta) *
252 30.0 *
std::pow(cos(theta), 3.0) + 5.0 * cos(theta));
256 result = constant * (231.0 *
std::pow(cos(theta), 6.0) -
258 105.0 *
std::pow(cos(theta), 2.0) - 5.0);
262 result = constant *
std::exp(i * phi) * sin(theta) *
264 30.0 *
std::pow(cos(theta), 3.0) + 5.0 * cos(theta));
270 18.0 *
std::pow(cos(theta), 2.0) + 1.0);
275 (11.0 *
std::pow(cos(theta), 3.0) - 3.0 * cos(theta));
277 }
else if (m == 10) {
280 (11.0 *
std::pow(cos(theta), 2.0) - 1);
282 }
else if (m == 11) {
287 }
else if (m == 12) {
323 QlmTotal.
ptq.resize(yCloud->nop);
326 for (
int iatom = 0; iatom < nList.size(); iatom++) {
330 nList[iatomIndex][0];
331 nnumNeighbours = nList[iatomIndex].size() - 1;
333 for (
int j = 1; j <= nnumNeighbours; j++) {
335 jatomID = nList[iatomIndex][j];
338 auto it = yCloud->idIndexMap.find(jatomID);
340 if (it != yCloud->idIndexMap.end()) {
341 jatomIndex = it->second;
344 std::cerr <<
"Something is wrong with the ID and index map.\n";
352 angles[1] = acos(delta[2] / r);
353 angles[0] = atan2(delta[0], delta[1]);
363 for (
int m = 0; m < 2 * l + 1; m++) {
364 QlmTotal.
ptq[iatomIndex].ylm[m] += yl[m];
370 QlmTotal.
ptq[iatomIndex].ylm =
377 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
382 if (yCloud->pts[iatom].inSlice ==
false) {
388 nnumNeighbours = nList[iatomIndex].size() - 1;
389 yCloud->pts[iatomIndex].c_ij.reserve(nnumNeighbours);
391 for (
int j = 1; j <= nnumNeighbours; j++) {
393 dot_product = {0, 0};
397 jatomID = nList[iatomIndex][j];
399 auto it = yCloud->idIndexMap.find(jatomID);
401 if (it != yCloud->idIndexMap.end()) {
402 jatomIndex = it->second;
405 std::cerr <<
"Something is wrong with the ID and index map.\n";
409 for (
int m = 0; m < 2 * l + 1; m++) {
410 qI = QlmTotal.
ptq[iatomIndex].ylm[m];
411 qJ = QlmTotal.
ptq[jatomIndex].ylm[m];
412 dot_product = dot_product + (qI * std::conj(qJ));
413 Inorm = Inorm + (qI * std::conj(qI));
414 Jnorm = Jnorm + (qJ * std::conj(qJ));
417 complexDenominator =
std::sqrt(Inorm * Jnorm);
418 complexCij = dot_product / complexDenominator;
420 cij_real = complexCij.
real();
422 if (cij_real < -0.8) {
424 }
else if (cij_real > -0.2 && cij_real < -0.05) {
429 yCloud->pts[iatomIndex].c_ij.push_back(temp_cij);
440 int ih, ic, water, interIce, unknown, total;
441 ih = ic = water = unknown = interIce = total = 0;
442 int num_staggrd, num_eclipsd, na;
446 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
451 if (yCloud->pts[iatom].inSlice ==
false) {
457 num_staggrd = num_eclipsd = na =
460 nnumNeighbours = nList[iatom].size() - 1;
462 for (
int j = 0; j < nnumNeighbours; j++) {
463 bondType = yCloud->pts[iatom].c_ij[j].classifier;
480 if (num_staggrd >= 4) {
485 else if (num_eclipsd == 1 && num_staggrd == 3) {
490 else if (
isInterfacial(yCloud, nList, iatom, num_staggrd, num_eclipsd)) {
507 int firstFrame,
bool isSlice,
std::string outputFileName) {
508 int ih, ic, water, interIce, unknown, total;
509 ih = ic = water = unknown = interIce = total = 0;
510 int num_staggrd, num_eclipsd, na;
514 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
519 if (yCloud->pts[iatom].inSlice ==
false) {
525 num_staggrd = num_eclipsd = na =
528 nnumNeighbours = nList[iatom].size() - 1;
530 for (
int j = 0; j < nnumNeighbours; j++) {
531 bondType = yCloud->pts[iatom].c_ij[j].classifier;
548 if (num_staggrd >= 4) {
553 else if (num_eclipsd == 1 && num_staggrd == 3) {
558 else if (
isInterfacial(yCloud, nList, iatom, num_staggrd, num_eclipsd)) {
579 outputFile.
open(path +
"bop/" + outputFileName, std::ios_base::app);
582 if (yCloud->currentFrame == firstFrame) {
583 outputFile <<
"Frame Ic Ih Interfacial Water Total \n";
586 outputFile << yCloud->currentFrame <<
" " << ic <<
" " << ih <<
" "
587 << interIce <<
" " << water <<
" " << total <<
"\n";
626 QlmTotal.
ptq.resize(yCloud->nop);
629 for (
int iatom = 0; iatom < nList.size(); iatom++) {
633 nList[iatomIndex][0];
634 nnumNeighbours = nList[iatomIndex].size() - 1;
636 for (
int j = 1; j <= nnumNeighbours; j++) {
638 jatomID = nList[iatomIndex][j];
641 auto it = yCloud->idIndexMap.find(jatomID);
643 if (it != yCloud->idIndexMap.end()) {
644 jatomIndex = it->second;
647 std::cerr <<
"Something is wrong with the ID and index map.\n";
655 angles[1] = acos(delta[2] / r);
656 angles[0] = atan2(delta[0], delta[1]);
666 for (
int m = 0; m < 2 * l + 1; m++) {
667 QlmTotal.
ptq[iatomIndex].ylm[m] += yl[m];
673 QlmTotal.
ptq[iatomIndex].ylm =
680 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
685 if (yCloud->pts[iatom].inSlice ==
false) {
691 nnumNeighbours = nList[iatomIndex].size() - 1;
692 yCloud->pts[iatomIndex].c_ij.reserve(nnumNeighbours);
694 for (
int j = 1; j <= nnumNeighbours; j++) {
696 dot_product = {0, 0};
700 jatomID = nList[iatomIndex][j];
702 auto it = yCloud->idIndexMap.find(jatomID);
704 if (it != yCloud->idIndexMap.end()) {
705 jatomIndex = it->second;
708 std::cerr <<
"Something is wrong with the ID and index map.\n";
712 for (
int m = 0; m < 2 * l + 1; m++) {
713 qI = QlmTotal.
ptq[iatomIndex].ylm[m];
714 qJ = QlmTotal.
ptq[jatomIndex].ylm[m];
715 dot_product = dot_product + (qI * std::conj(qJ));
716 Inorm = Inorm + (qI * std::conj(qI));
717 Jnorm = Jnorm + (qJ * std::conj(qJ));
720 complexDenominator =
std::sqrt(Inorm * Jnorm);
721 complexCij = dot_product / complexDenominator;
723 cij_real = complexCij.
real();
725 if (cij_real <= -0.8) {
727 }
else if (cij_real >= -0.35 && cij_real <= 0.25) {
732 yCloud->pts[iatomIndex].c_ij.push_back(temp_cij);
757 int firstFrame,
bool isSlice,
759 int ih, ic, interIce, water, unknown, clath, interClath,
761 ih = ic = water = unknown = interIce = total = 0;
762 clath = interClath = 0;
763 int num_staggrd, num_eclipsd, na;
767 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
772 if (yCloud->pts[iatom].inSlice ==
false) {
779 nList[iatom].size() - 1;
780 num_staggrd = num_eclipsd = na =
783 for (
int j = 0; j < nnumNeighbours; j++) {
784 bondType = yCloud->pts[iatom].c_ij[j].classifier;
796 if (nnumNeighbours == 4) {
798 if (num_eclipsd == 0 && num_staggrd == 4) {
803 else if (num_eclipsd == 1 && num_staggrd == 3) {
808 else if (
isInterfacial(yCloud, nList, iatom, num_staggrd, num_eclipsd)) {
813 else if (num_eclipsd == 4 && num_staggrd == 0) {
818 else if (num_eclipsd == 3) {
844 outputFile.
open(path +
"bop/" + outputFileName, std::ios_base::app);
847 if (yCloud->currentFrame == firstFrame) {
848 outputFile <<
"Frame Ic Ih Interfacial Clath InterClath Water Total\n";
851 outputFile << yCloud->currentFrame <<
" " << ic <<
" " << ih <<
" "
852 << interIce <<
" " << clath <<
" " << interClath <<
" " << water
853 <<
" " << total <<
"\n";
889 double q_value = 0.0;
891 QlmTotal.
ptq.resize(yCloud->nop);
892 resultQ.
resize(yCloud->nop);
895 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
898 nnumNeighbours = nList[iatom].size() - 1;
900 for (
int j = 1; j <= nnumNeighbours; j++) {
902 jatomID = nList[iatom][j];
905 auto it = yCloud->idIndexMap.find(jatomID);
907 if (it != yCloud->idIndexMap.end()) {
908 jatomIndex = it->second;
910 std::cerr <<
"Your map must be wrong.\n";
920 angles[1] = acos(delta[2] / r);
921 angles[0] = atan2(delta[0], delta[1]);
931 for (
int m = 0; m < 2 * l + 1; m++) {
932 QlmTotal.
ptq[iatom].ylm[m] += yl[m];
938 QlmTotal.
ptq[iatom].ylm =
945 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
953 nnumNeighbours = nList[iatom].size() - 1;
957 for (
int j = 1; j <= nnumNeighbours; j++) {
959 dot_product = {0, 0};
963 jatomID = nList[iatom][j];
966 auto it = yCloud->idIndexMap.find(jatomID);
968 if (it != yCloud->idIndexMap.end()) {
969 jatomIndex = it->second;
972 for (
int m = 0; m < 2 * l + 1; m++) {
973 qI = QlmTotal.
ptq[iatom].ylm[m];
974 qJ = QlmTotal.
ptq[jatomIndex].ylm[m];
975 dot_product = dot_product + (qI * std::conj(qJ));
976 Inorm = Inorm + (qI * std::conj(qI));
977 Jnorm = Jnorm + (qJ * std::conj(qJ));
980 complexDenominator =
std::sqrt(Inorm * Jnorm);
981 complexCij = dot_product / complexDenominator;
983 cij_real = complexCij.
real();
990 q_value /= (double)nnumNeighbours;
992 resultQ[iatom] = q_value;
1020 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
1023 if ((*q6)[iatom] > 0.5) {
1026 nnumNeighbours = yCloud->pts[iatom].c_ij.size();
1027 for (
int j = 0; j < nnumNeighbours; j++) {
1028 avgQ3 += yCloud->pts[iatom].c_ij[j].c_value;
1030 avgQ3 /= (double)nnumNeighbours;
1033 if (avgQ3 <= -0.75) {
1034 if (avgQ3 < -0.85) {
1062 int firstFrame,
bool isSlice,
std::string outputFileName) {
1063 int ih, ic, interIce, water, unknown, clath, interClath,
1065 ih = ic = water = unknown = interIce = total = 0;
1066 clath = interClath = 0;
1068 for (
int iatom = 0; iatom < yCloud->nop; iatom++) {
1072 if (yCloud->pts[iatom].inSlice ==
false) {
1102 outputFile.
open(path +
"bop/" + outputFileName, std::ios_base::app);
1105 if (yCloud->currentFrame == firstFrame) {
1106 outputFile <<
"Frame Ic Ih Interfacial Clath InterClath Water Total\n";
1109 outputFile << yCloud->currentFrame <<
" " << ic <<
" " << ih <<
" "
1110 << interIce <<
" " << clath <<
" " << interClath <<
" " << water
1111 <<
" " << total <<
"\n";
1133 int nnumNeighbours =
1134 nList[iatom].size() - 1;
1135 int neighStaggered =
1143 if (num_staggrd == 2) {
1145 for (
int j = 1; j <= nnumNeighbours; j++) {
1147 jatomID = nList[iatom][j];
1149 auto it = yCloud->idIndexMap.find(jatomID);
1151 if (it != yCloud->idIndexMap.end()) {
1152 jatomIndex = it->second;
1154 std::cerr <<
"Something is gravely wrong with your map.\n";
1159 if (neighStaggered > 2) {
1166 if (num_staggrd == 3 && num_eclipsd == 0) {
1168 for (
int j = 1; j <= nnumNeighbours; j++) {
1171 jatomID = nList[iatom][j];
1173 auto it = yCloud->idIndexMap.find(jatomID);
1175 if (it != yCloud->idIndexMap.end()) {
1176 jatomIndex = it->second;
1178 std::cerr <<
"Something is gravely wrong with your map.\n";
1183 if (neighStaggered == 2) {
1204 int num_staggrd = 0;
1207 int nnumNeighbours =
1208 nList[jatom].size() - 1;
1211 for (
int i = 0; i < nnumNeighbours; i++) {
1212 bondType = yCloud->pts[jatom].c_ij[i].classifier;
File for the bond order parameter analysis.
std::vector< std::complex< double > > lookupTableQ6Vec(std::array< double, 2 > angles)
Lookup table for Q6.
std::vector< double > getq6(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, bool isSlice=false)
std::vector< std::complex< double > > lookupTableQ3Vec(std::array< double, 2 > angles)
Lookup table for Q3.
molSys::PointCloud< molSys::Point< double >, double > getCorrelPlus(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, bool isSlice=false)
Gets c_ij and then classifies bond types according to the CHILL+ algorithm.
molSys::PointCloud< molSys::Point< double >, double > getIceTypePlus(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, std::string path, int firstFrame, bool isSlice=false, std::string outputFileName="chillPlus.txt")
Classifies each atom according to the CHILL+ algorithm.
std::vector< YlmAtom > ptq
molSys::PointCloud< molSys::Point< double >, double > getCorrel(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, bool isSlice=false)
std::array< double, 2 > radialCoord(std::array< double, 3 > cartCoord)
int printIceType(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::string path, int firstFrame, bool isSlice=false, std::string outputFileName="superChill.txt")
Prints out the iceType for a particular frame onto the terminal.
std::complex< double > lookupTableQ6(int m, std::array< double, 2 > angles)
Lookup table for Q6 (m=0 to m=12)
bool isInterfacial(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, int iatom, int num_staggrd, int num_eclipsd)
std::vector< std::complex< double > > spheriHarmo(int orderL, std::array< double, 2 > radialCoord)
int numStaggered(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, int jatom)
Finds the number of staggered bonds for a given atom of index jatom.
std::complex< double > lookupTableQ3(int m, std::array< double, 2 > angles)
Lookup table for Q3 (m=0 to m=6)
molSys::PointCloud< molSys::Point< double >, double > getIceTypeNoPrint(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, bool isSlice=false)
Classifies each atom according to the CHILL algorithm without printing.
molSys::PointCloud< molSys::Point< double >, double > reclassifyWater(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< double > *q6)
molSys::PointCloud< molSys::Point< double >, double > getIceType(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, std::string path, int firstFrame, bool isSlice=false, std::string outputFileName="chill.txt")
Classifies each atom according to the CHILL algorithm.
std::vector< std::complex< double > > avgVector(std::vector< std::complex< double >> v, int l, int neigh)
std::array< double, 3 > relDist(molSys::PointCloud< molSys::Point< double >, double > *yCloud, int iatom, int jatom)
double c_value
Classifier according to CHILL, CHILL+ etc.
@ hexagonal
Ih, or particle type signifying Hexagonal Ice.
@ reCubic
Reclassified as cubic ice, according to the order parameter.
@ interfacial
Interfacial ice: ice-like molecules which do not fulfill the strict criteria of the Ic or Ih phases.
@ cubic
Ic, or particle type signifying Cubic Ice.
@ interClathrate
Interfacial clathrate ice phase.
@ water
Liquid/amorphous phase.
@ reHex
Reclassified as hexagonal ice, according to the order parameter.
@ clathrate
Clathrate ice phase.
@ unclassified
Not classified into any other category.
@ eclipsed
The bond is an eclipsed bond.
@ out_of_range
The bond cannot be classified as either staggered or eclipsed.
@ staggered
The bond is a staggered bond, according to the or value.
int makePath(const std::string &path)
This is the local orientational bond order parameter , of length .
This contains a collection of points; contains information for a particular frame.
This contains per-particle information.
This contains the bond classifier of enum class type bond_type, and the bond correlation factor.