topo_bulk.cpp
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 #include <topo_bulk.hpp>
16 
17 // -----------------------------------------------------------------------------------------------------
18 // BULK RING SEARCH ONLY
19 // -----------------------------------------------------------------------------------------------------
20 
47  molSys::PointCloud<molSys::Point<double>, double> *yCloud, int maxDepth,
48  int firstFrame) {
49  //
51  ringsOneType; // Vector of vectors of rings of a single size
52  int nRings; // Number of rings of the current type
53  std::vector<int> nRingList; // Vector of the values of the number of rings
54  // for a particular frame
56  atomTypes; // contains int values for each ring type considered
57  // -------------------------------------------------------------------------------
58  // Init
59  nRingList.resize(
60  maxDepth -
61  2); // Has a value for every value of ringSize from 3, upto maxDepth
62  // The atomTypes vector is the same size as the pointCloud atoms
63  atomTypes.resize(yCloud->nop, 1); // The dummy or unclassified value is 1
64  // -------------------------------------------------------------------------------
65  // Run this loop for rings of sizes upto maxDepth
66  // The smallest possible ring is of size 3
67  for (int ringSize = 3; ringSize <= maxDepth; ringSize++) {
68  // Clear ringsOneType
69  ring::clearRingList(ringsOneType);
70  // Get rings of the current ring size
71  ringsOneType = ring::getSingleRingSize(rings, ringSize);
72  //
73  // Continue if there are zero rings of ringSize
74  if (ringsOneType.size() == 0) {
75  nRingList[ringSize - 3] = 0; // Update the number of prisms
76  continue;
77  } // skip if there are no rings
78  //
79  // -------------
80  // Number of rings with n nodes
81  nRings = ringsOneType.size();
82  // -------------
83  // Now that you have rings of a certain size:
84  nRingList[ringSize - 3] = nRings; // Update the number of n-membered rings
85  // -------------
86  } // end of loop through every possible ringSize
87 
88  // Get the atom types for all the ring types
89  ring::assignPolygonType(rings, &atomTypes, nRingList);
90 
91  // Write out the ring information
92  sout::writeRingNumBulk(path, yCloud->currentFrame, nRingList, maxDepth, firstFrame);
93  // Write out the lammps data file for the particular frame
94  sout::writeLAMMPSdataAllRings(yCloud, nList, atomTypes, maxDepth, path, false);
95 
96  return 0;
97 }
98 
99 // -----------------------------------------------------------------------------------------------------
100 // DDC / HC ALGORITHMS
101 // -----------------------------------------------------------------------------------------------------
102 
137  molSys::PointCloud<molSys::Point<double>, double> *yCloud, int firstFrame,
138  bool onlyTetrahedral) {
139  //
140  // Ring IDs of each type will be saved in these vectors
141  std::vector<int> listDDC; // Vector for ring indices of DDC
142  std::vector<int> listHC; // Vector for ring indices of HC
144  listMixed; // Vector for ring indices of rings that are both DDC and HC
146  ringType; // This vector will have a value for each ring inside
147  // ringList, of type enum strucType in gen.hpp
148  // Make a list of all the DDCs and HCs
149  std::vector<cage::Cage> cageList;
151  ringsOneType; // Vector of vectors of rings of a single size
152  int initRingSize; // Todo or not: calculate the PNCs or not
153  int maxRingSize = 6; // DDCs and HCs are for 6-membered rings
155  atomTypes; // This vector will have a value for every atom
156  // Number of types
157  int numHC, numDDC, mixedRings, prismaticRings, basalRings;
158 
159  // TODO: handle shapeMatching
160  bool doShapeMatching = true;
161  // Qualifier for the RMSD per atom:
162  std::vector<double> rmsdPerAtom;
163  //
164 
165  // test
166  // std::cout << "rings"
167  // << "\n";
168  // for (int i = 0; i < rings.size(); i++) {
169  // for (int j = 0; j < rings[i].size(); j++) {
170  // std::cout << rings[i][j] << " ";
171  // }
172  // std::cout << "\n";
173  // }
174  // std::cout << "\n";
175 
176  if (onlyTetrahedral) {
177  initRingSize = 6;
178  } else {
179  initRingSize = 5;
180  }
181 
182  // Init the atom type vector
183  atomTypes.resize(yCloud->nop); // Has a value for each atom
184  // Init the rmsd per atom (not used yet)
185  rmsdPerAtom.resize(yCloud->nop); // Has a value for each atom
186 
187  // ----------------------------------------------
188  // Init
189  // Get rings of size 5 or 6.
190  for (int ringSize = initRingSize; ringSize <= maxRingSize; ringSize++) {
191  // Clear ringsOneType
192  ring::clearRingList(ringsOneType);
193  // Get rings of the current ring size
194  ringsOneType = ring::getSingleRingSize(rings, ringSize);
195  // Skip for zero rings
196  if (ringsOneType.size() == 0) {
197  continue;
198  } // skip for no rings of ringSize
199  //
200  // Init the ringType vector
201  ringType.resize(
202  ringsOneType.size()); // Has a value for each ring. init to zero.
203  // ----------------------------------------------
204  if (ringSize == 6) {
205  // Get the cages
206 
207  // Find HC rings, saving the ring IDs (starting from 0) to listHC
208  listHC = ring::findHC(ringsOneType, &ringType, nList, &cageList);
209 
210  // Find DDC rings, saving the IDs to listDDC
211  listDDC = ring::findDDC(ringsOneType, &ringType, listHC, &cageList);
212 
213  // Find rings which are both DDCs and HCs (mixed)
214  // A dummy value of -10 in the listDDC and listHC vectors for mixed rings
215  listMixed =
216  ring::findMixedRings(ringsOneType, &ringType, &listDDC, &listHC);
217 
218  // Get the number of structures (DDCs, HCs, mixed rings, basal rings,
219  // prismatic rings)
220  ring::getStrucNumbers(ringType, cageList, &numHC, &numDDC, &mixedRings,
221  &prismaticRings, &basalRings);
222 
223  // Write out to a file
224  sout::writeTopoBulkData(path, yCloud->currentFrame, numHC, numDDC,
225  mixedRings, basalRings, prismaticRings,
226  firstFrame);
227  // Gets the atom type for every atom, to be used for printing out the ice
228  // types found
229  ring::getAtomTypesTopoBulk(ringsOneType, ringType, &atomTypes);
230  }
231  // Finding prismatic blocks
232  else {
233  // Get the prism block classifications
234  prism3::findBulkPrisms(ringsOneType, &ringType, nList, yCloud,
235  &rmsdPerAtom);
236  // Gets the atom type for every atom, to be used for printing out the ice
237  // types found
238  ring::getAtomTypesTopoBulk(ringsOneType, ringType, &atomTypes);
239  }
240  }
241 
242  // Print out the lammps data file with the bonds
243  sout::writeLAMMPSdataTopoBulk(yCloud, nList, atomTypes, path);
244  // To output the bonds between dummy atoms, uncomment the following line
245  // sout::writeLAMMPSdataTopoBulk(yCloud, nList, atomTypes, path, true);
246 
247  return 0;
248 }
249 
287  std::vector<int> listHC,
288  std::vector<cage::Cage> *cageList) {
289  std::vector<int> listDDC;
290  int totalRingNum = rings.size(); // Total number of hexagonal rings
291  std::vector<int> peripheralRings; // Indices which may be peripheral rings
292  bool cond1, cond2, cond3; // Conditions for DDC
293  int jring; // Index for peripheral ring being added
294  std::vector<int> DDCRings; // Indices of rings which constitute a single DDC,
295  // with the equatorial ring first
296  // Vector for checking if a ring is basal, prismatic or peripheral
298  notEquatorial; // true if the ring is prismatic, basal or peripheral.
299  notEquatorial.resize(totalRingNum); // Initialized to false
300 
301  // --------
302  // Set all basal and prismatic rings to true (which are part of an HC)
303  for (int i = 0; i < listHC.size(); i++) {
304  int currentRingIndex = listHC[i];
305  // Set this to true
306  notEquatorial[currentRingIndex] = true;
307  } // end of update of notEquatorial
308  // --------
309 
310  // To search for equatorial rings, loop through all
311  // the hexagonal rings
312  for (int iring = 0; iring < totalRingNum; iring++) {
313  // ------------
314  // Step zero: If the ring has been classified as a basal or prismatic ring
315  // in an HC or is a peripheral ring, then it cannot be the equatiorial ring
316  // in a DDC
317  //
318  if (notEquatorial[iring]) {
319  continue;
320  } // skip for rings which are not equatorial
321  //
322  // ------------
323  // Init
324  peripheralRings.clear();
325  // ------------
326  // Step one: Find all rings which contain each index (m_k) of the equatorial
327  // ring, iring, in at least three other rings
328  cond1 = ring::conditionOneDDC(rings, &peripheralRings, iring);
329  if (cond1 == false) {
330  continue;
331  }
332  // ------------
333  // Step two: For every triplet in iring, there is at least one
334  // hexagonal ring other than iring that passes through the triplet.
335  // The peripheral rings are stored in order of the starting element
336  // of each triplet.
337  cond2 = ring::conditionTwoDDC(rings, &peripheralRings, iring);
338  if (cond2 == false) {
339  continue;
340  }
341  // ------------
342  // Step three: For every triplet in the equatorial ring, there is at least
343  // one hexagonal ring other than iring that passes through the triplet.
344  // Rings corresponding to triplets need not be searched again since
345  // peripheralRings are stored in that order. Rings corresponding to T1, T3,
346  // T5 must have a common element. Similarly rings corresponding to T2, T4,
347  // T6 must have at least one common element. Alternating rings corresponding
348  // to triplets must have at least three common elements
349  cond3 = ring::conditionThreeDDC(rings, &peripheralRings);
350  if (cond3 == false) {
351  continue;
352  }
353  // ------------
354  // If the peripheral rings are duplicates, skip everything
355  sort(peripheralRings.begin(), peripheralRings.end());
356  peripheralRings.erase(
357  unique(peripheralRings.begin(), peripheralRings.end()),
358  peripheralRings.end());
359  // There should be 6 unique peripheral rings
360  if (peripheralRings.size() != 6) {
361  continue;
362  }
363  // ------------
364  // If iring is an equatorial ring, add it to the listDDC vector
365  if ((*ringType)[iring] == ring::strucType::unclassified) {
366  (*ringType)[iring] = ring::strucType::DDC;
367  listDDC.push_back(iring);
368  }
369  // Add the peripheral ring IDs too
370  for (int j = 0; j < peripheralRings.size(); j++) {
371  jring = peripheralRings[j];
372  if ((*ringType)[jring] == ring::strucType::unclassified) {
373  (*ringType)[jring] = ring::strucType::DDC;
374  listDDC.push_back(jring);
375  } else if ((*ringType)[jring] == ring::strucType::HCbasal) {
376  (*ringType)[jring] = ring::strucType::bothBasal;
377  listDDC.push_back(jring);
378  } // end of update
379  // never true
380  else if ((*ringType)[jring] == ring::strucType::HCprismatic) {
381  (*ringType)[jring] = ring::strucType::bothPrismatic;
382  listDDC.push_back(jring);
383  }
384  //
385  // Update the notEquatorial vector
386  notEquatorial[jring] = true;
387  } // end of update for peripheral rings
388  // Add rings to the cageList vector of struct Cages.
389  DDCRings.clear(); // init
390  DDCRings.push_back(iring); // Add the equatorial ring first
391  DDCRings.insert(std::end(DDCRings), std::begin(peripheralRings),
392  std::end(peripheralRings));
393  (*cageList).push_back({cage::cageType::DoubleDiaC, DDCRings});
394  // ------------
395  } // end of loop through all hexagonal rings
396 
397  return listDDC;
398 }
399 
417  std::vector<int> *peripheralRings, int iring) {
418  int index; // Atom ID to be compared
419  int noOfCommonRings =
420  0; // No of rings in which the element to be matched has been found
421  int jElement; // Atom ID being compared to index
422 
423  // Loop through each element of iring for finding matches
424  for (int m = 0; m < 6; m++) {
425  index = rings[iring][m]; // Atom Index to be compared and matched with
426  noOfCommonRings = 0; // init to zero.
427  // Loop through every ring except iring
428  for (int jring = 0; jring < rings.size(); jring++) {
429  if (iring == jring) {
430  continue;
431  } // Skip for iring
432  // -------
433  // Search every element of jring
434  for (int k = 0; k < 6; k++) {
435  jElement = rings[jring][k];
436  if (jElement == index) {
437  noOfCommonRings++;
438  (*peripheralRings).push_back(jring);
439  break;
440  } // if index is found inside jring
441  else {
442  continue;
443  }
444  } // end of loop through every element of jring
445  // -------
446  } // end of loop through all rings except iring
447  // If less than 3 rings have been found for each element, then this is
448  // not an equatorial ring
449  if (noOfCommonRings < 3) {
450  return false;
451  } // end of check for common ring number per element in iring
452  } // end of loop through each element of iring
453 
454  // iring is an equatorial ring. The duplicate ring IDs inside
455  // peripheralRings should be removed
456  std::vector<int>::iterator ip; // Iterator to find the last element upto
457  // which unique elements are present
458  // Duplicate IDs must be removed
459  int numElements =
460  (*peripheralRings).size(); // number of elements in peripheralRings
461  sort((*peripheralRings).begin(), (*peripheralRings).end());
462  ip = std::unique((*peripheralRings).begin(),
463  (*peripheralRings).begin() + numElements);
464  // Resize peripheral rings to remove undefined terms
465  (*peripheralRings).resize(std::distance((*peripheralRings).begin(), ip));
466 
467  return true;
468 }
469 
489  std::vector<int> *peripheralRings, int iring) {
490  std::vector<int> triplet; // Triplet formed from iring
491  int ringSize = 6; // Here, all the rings are hexagons
492  int j; // Used for making the triplet
493  int jring; // Peripheral ring ID to be searched
494  int count; // Number of rings found that match the triplet
496  newPeripherals; // Vector in which the new peripheral ring IDs are saved.
497  // This will be swapped with peripheralRings later
498 
499  for (int k = 0; k < ringSize; k++) {
500  triplet.clear(); // Clear the triplet
501  // Get a triplet
502  for (int i = k; i < k + 3; i++) {
503  j = i;
504  if (i >= ringSize) {
505  j = i - ringSize;
506  }
507  triplet.push_back(rings[iring][j]);
508  } // end of getting a triplet from k
509  // -------------
510  // Compare the triplet with every possible peripheral
511  // ring inside peripheralRings.
512  count = 0; // init to zero
513  // Loop through all possible peripheral rings
514  for (int m = 0; m < (*peripheralRings).size(); m++) {
515  jring = (*peripheralRings)[m]; // Ring ID of ring to be searched
516  // Search inside the ring with index jring for the triplet
517  bool foundTriplet = ring::findTripletInRing(rings[jring], triplet);
518 
519  // If the triplet has been found inside jring
520  if (foundTriplet) {
521  newPeripherals.push_back(jring); // Update new peripheral vector
522  count++;
523  break;
524  } // end of ring found
525  } // end of loop through all possible peripheral rings
526  // If count is 0, then the triplet was not found in any peripheral ring
527  if (count == 0) {
528  return false;
529  } // Return false since the triplet was not found
530  // -------------
531  } // end of looping through 0-6 to get triplets
532 
533  // Swap the old peripheral rings vector with the new one
534  (*peripheralRings).swap(newPeripherals);
535 
536  // If there are more than 6 peripheral rings, the code will fail
537  // Comment this out if you want
538  if ((*peripheralRings).size() > 6) {
539  std::cerr
540  << "There are more than 6 peripheral rings. The code will fail. \n";
541  return false;
542  } // end of check for more than 6 peripherals
543 
544  return true;
545 }
546 
570  std::vector<int> *peripheralRings) {
571  // New
572  std::vector<int> common; // Vector containing common elements
573  bool hasCommon; // true if the rings have a common element
574  int iring, jring; // Pairs of peripheral rings
575  // ----------------------------------------------------------------------------
576  // CONDITION 1: Rings corresponding to T1, T3, T5 should have at least one
577  // common element.
578  hasCommon = ring::commonElementsInThreeRings(rings[(*peripheralRings)[0]],
579  rings[(*peripheralRings)[2]],
580  rings[(*peripheralRings)[4]]);
581 
582  // If T1, T3, T5 don't have a common element, return false
583  if (!hasCommon) {
584  return false;
585  } // not a DDC
586  // ----------------------------------------------------------------------------
587  // CONDITION 2: Rings corresponding to T1, T3, T5 should have at least one
588  // common element.
589  hasCommon = ring::commonElementsInThreeRings(rings[(*peripheralRings)[1]],
590  rings[(*peripheralRings)[3]],
591  rings[(*peripheralRings)[5]]);
592 
593  // If T1, T3, T5 don't have a common element, return false
594  if (!hasCommon) {
595  return false;
596  } // not a DDC
597  // ----------------------------------------------------------------------------
598  // CONDITION 3: Rings corresponding to {T1, T3}, {T2, T4}, {T3, T5}, {T4,
599  // T6}
600  // must have three elements in common amongst them
601 
602  // Loops to get pairs of rings corresponding to the right triplets
603  for (int i = 0; i <= 3; i++) {
604  common.clear(); // init
605  // Pairs of rings corresponding to triplets.
606  iring = (*peripheralRings)[i];
607  jring = (*peripheralRings)[i + 2];
608  // Get the common elements
609  common = ring::findsCommonElements(rings[iring], rings[jring]);
610  // There should be at least three elements
611  if (common.size() < 3) {
612  return false;
613  } // not a DDC
614  } // end of getting iring and jring
615  // ----------------------------------------------------------------------------
616 
617  // iring is an equatorial ring and peripheralRings has the 6 peripheral rings
618  return true;
619 }
620 
654  std::vector<cage::Cage> *cageList) {
655  std::vector<int> listHC;
656  int totalRingNum = rings.size(); // Total number of hexagonal rings
657  std::vector<int> basal1; // First basal ring
658  std::vector<int> basal2; // Second basal ring
659  bool cond1, cond2; // Conditions for rings to be basal (true) or not (false)
661  HCRings; // Indices of rings which constitute a single HC, with the basal
662  // rings first, followed by prismatic rings
663  std::vector<int> prismaticRings; // Ring indices of prismatic rings
664  int kring; // Ring index of the prismatic rings
666  isPrismatic; // Flag for checking if the ring is prismatic (true) or not
667  // (false), since the basal rings are checked
668  isPrismatic.resize(totalRingNum); // Initialized to false
669 
670  // Two loops through all the rings are required to find pairs of basal rings
671  for (int iring = 0; iring < totalRingNum - 1; iring++) {
672  // -----------------------
673  // Skip if iring is prismatic
674  if (isPrismatic[iring]) {
675  continue;
676  } // Skip if prismatic
677  // -----------------------
678  cond1 = false;
679  cond2 = false;
680  basal1 = rings[iring]; // Assign iring to basal1
681  // Loop through the other rings to get a pair
682  for (int jring = iring + 1; jring < totalRingNum; jring++) {
683  // -----------------------
684  // Skip if iring is prismatic
685  if (isPrismatic[jring]) {
686  continue;
687  } // Skip if prismatic
688  // -----------------------
689  basal2 = rings[jring]; // Assign jring to basal2
690  // ------------
691  // Step one: Check to see if basal1 and basal2 have common
692  // elements or not. If they don't, then they cannot be basal rings
693  cond1 = ring::hasCommonElements(basal1, basal2);
694  if (cond1 == true) {
695  continue;
696  }
697  // -----------
698  // Step two and three: One of the elements of basal2 must be the nearest
699  // neighbour of either the first (index0; l1) or second (index1; l2)
700  // element of basal1. If m_k is the nearest neighbour of l1, m_{k+2} and
701  // m_{k+4} must be neighbours of l3 and l5(l5 or l3). Modify for l2.
702  cond2 = ring::basalConditions(nList, &basal1, &basal2);
703  if (cond2 == false) {
704  continue;
705  }
706  // -----------
707  // iring and jring are basal rings!
708  // Update iring
709  if ((*ringType)[iring] == ring::strucType::unclassified) {
710  (*ringType)[iring] = ring::strucType::HCbasal;
711  listHC.push_back(iring);
712  } else if ((*ringType)[iring] == ring::strucType::DDC) {
713  (*ringType)[iring] = ring::strucType::bothBasal;
714  listHC.push_back(iring);
715  }
716  // Update jring
717  if ((*ringType)[jring] == ring::strucType::unclassified) {
718  (*ringType)[jring] = ring::strucType::HCbasal;
719  listHC.push_back(jring);
720  } else if ((*ringType)[jring] == ring::strucType::DDC) {
721  (*ringType)[jring] = ring::strucType::bothBasal;
722  listHC.push_back(jring);
723  }
724  // Find the prismatic rings
725  prismaticRings.clear(); // Clear the prismatic ring vector first
726  ring::findPrismatic(rings, &listHC, ringType, iring, jring,
727  &prismaticRings);
728  // Update the prismatic rings
729  for (int k = 0; k < prismaticRings.size(); k++) {
730  kring =
731  prismaticRings[k]; // Current ring index of the (3) prismatic rings
732  // Update kring
733  if ((*ringType)[kring] == ring::strucType::unclassified) {
734  (*ringType)[kring] = ring::strucType::HCprismatic;
735  listHC.push_back(kring);
736  } else if ((*ringType)[kring] == ring::strucType::DDC) {
737  (*ringType)[kring] = ring::strucType::bothPrismatic;
738  listHC.push_back(kring);
739  }
740  //
741  // Update the isPrismatic vector
742  isPrismatic[kring] = true;
743  //
744  } // End of update of prismatic rings in listHC
745  // -----------
746  // Update the cageList vector of Cages
747  // Update the basal rings
748  HCRings.clear();
749  HCRings.push_back(iring);
750  HCRings.push_back(jring);
751  // Add the prismaticRings
752  HCRings.insert(std::end(HCRings), std::begin(prismaticRings),
753  std::end(prismaticRings));
754  (*cageList).push_back({cage::cageType::HexC, HCRings});
755  // -----------
756  } // end of loop through rest of the rings to get the second basal ring
757  } // end of loop through all rings for first basal ring
758 
759  sort(listHC.begin(), listHC.end());
760  auto ip = std::unique(listHC.begin(), listHC.end());
761  // Resize peripheral rings to remove undefined terms
762  listHC.resize(std::distance(listHC.begin(), ip));
763 
764  return listHC;
765 }
766 
787  std::vector<int> *basal1, std::vector<int> *basal2) {
788  int l1 = (*basal1)[0]; // first element of basal1 ring
789  int l2 = (*basal1)[1]; // second element of basal1 ring
790  int ringSize = 6; // Size of the ring; each ring contains 6 elements
791  int m_k; // Atom Index (in pointCloud) of element in basal2
792  int kIndex; // Index of m_k in basal2, corresponding to m_k
793  int currentKindex; // Current k index when finding alternating elements of
794  // basal2
795  std::vector<int> evenTriplet; // contains m_k, m_{k+2}, m_{k+4}
796  std::vector<int> oddTriplet; // contains m_{k+1}, m_{k+3}, m_{k+5}
797  int compare1, compare2; // l3 and l5 OR l4 and l6
798  int index;
799  bool l1_neighbour, l2_neighbour; // m_k is a neighbour of l1(true) or not
800  // (false); m_k is a neighbour of l2(true)
801  bool isNeigh, notNeigh; // Used to check if the rings are basal or not
802 
803  // ---------------------------------------------
804  // SEARCH FOR L1_NEIGHBOUR OR L2_NEIGHBOUR
805  // Search for whether an element of basal2 is a neighbour of l1 or l2
806  for (int k = 0; k < ringSize; k++) {
807  // init
808  l1_neighbour = false;
809  l2_neighbour = false;
810  m_k = (*basal2)[k];
811 
812  // ---------------
813  // CHECK IF M_K MATCHES L1 NEIGHBOURS
814  auto it1 = std::find(nList[l1].begin() + 1, nList[l1].end(), m_k);
815  // If m_k was found in l1's nList
816  if (it1 != nList[l1].end()) {
817  compare1 = (*basal1)[2]; // l3
818  compare2 = (*basal1)[4]; // l5
819  kIndex = k; // Saving the array index of m_k
820  l1_neighbour = true;
821  break;
822  } // m_k found in l1's nList
823  // ---------------
824  // CHECK IF M_K MATCHES L2 NEIGHBOURS
825  auto it2 = std::find(nList[l2].begin() + 1, nList[l2].end(), m_k);
826  // If m_k was found in l1's nList
827  if (it2 != nList[l2].end()) {
828  compare1 = (*basal1)[3]; // l4
829  compare2 = (*basal1)[5]; // l6
830  kIndex = k; // Saving the array index of m_k
831  l2_neighbour = true;
832  break;
833  } // m_k found in l1's nList
834  // ---------------
835  } // End of search for basal2 elements in l1 or l2's nList
836  // ---------------------------------------------
837 
838  // Return false if neither l1 nor l2 have any neighbours
839  // in basal2
840 
841  if (l1_neighbour == false && l2_neighbour == false) {
842  return false;
843  } // basal conditions not fulfilled
844 
845  // Get the alternating elements starting with kIndex.
846  // 'evenTriplet': m_k, m_{k+2}, m_{k+4} - neighbours of compare1 and compare2.
847  // 'oddTriplet': m_{k+1}, m_{k+3}, m_{k+5}- cannot be neighbours of basal1
848  for (int k = 0; k <= 5; k++) {
849  currentKindex = kIndex + k; // k
850  // Wrap-around
851  if (currentKindex >= ringSize) {
852  currentKindex -= ringSize;
853  } // end of wrap-around of k
854  //
855  // Update 'evenTriplet'
856  if (k % 2 == 0) {
857  evenTriplet.push_back((*basal2)[currentKindex]);
858  } // end of update of evenTriplet
859  // Update 'oddTriplet'
860  else {
861  oddTriplet.push_back((*basal2)[currentKindex]);
862  } // end of update of oddTriplet
863  } // End of getting alternating triplets
864 
865  // ---------------------------------------------
866  // CONDITION1: m_{k+2} and m_{k+4} must be bonded to l3 and l5 (if l1 is a
867  // neighbour) or m_{k+2} and m_{k+4} must be bonded to l4 and l6 (if l2 is a
868  // neighbour) Basically, this boils down to checking whether compare1 and
869  // compare2 are in the neighbour lists of the last two elements of evenTriplet
870 
871  isNeigh = ring::basalNeighbours(nList, &evenTriplet, compare1, compare2);
872 
873  // If condition1 is not true, then the candidate
874  // rings are not part of an HC
875  if (!isNeigh) {
876  return false;
877  } // Not an HC
878 
879  // ---------------------------------------------
880  // CONDITION2: m_{k+1}, m_{k+3} and m_{k+5} must NOT be bonded to any element
881  // in basal1.
882  // Basically, this boils down to checking whether the elements of oddTriplet
883  // are in the neighbour lists of all the elements of basal1.
884 
885  // condition 2. This must be true for an HC
886  notNeigh = ring::notNeighboursOfRing(nList, &oddTriplet, basal1);
887 
888  // If condition2 is not true, the the candidate rings
889  // are not part of an HC
890  if (!notNeigh) {
891  return false;
892  } // Not an HC
893 
894  // Otherwise, all the conditions are true and this is an HC
895  return true;
896 
897 } // end of function
898 
909  std::vector<int> *triplet, int atomOne,
910  int atomTwo) {
911  // Search for needles in a haystack :)
912  int needle1 = (*triplet)[1];
913  int needle2 = (*triplet)[2];
914  bool neighbourFound = false;
915  bool neighOne = false,
916  neighTwo = false; // Neighbour for atomOne, or neighbour for atomTwo
917  // ----------------------------
918  // For first element needle1, which must belong to either atomOne's or
919  // atomTwo's neighbour list Search atomOne's neighbours
920  auto it =
921  std::find(nList[atomOne].begin() + 1, nList[atomOne].end(), needle1);
922  if (it != nList[atomOne].end()) {
923  neighbourFound = true;
924  neighOne = true;
925  } // atomOne's neighbour
926  // If it is not atomOne's neighbour, it might be atomTwo's neighbour
927  if (!neighOne) {
928  it = std::find(nList[atomTwo].begin() + 1, nList[atomTwo].end(), needle1);
929  if (it != nList[atomTwo].end()) {
930  neighbourFound = true;
931  neighTwo = true;
932  } // end of check to see if neighbour was found
933  } // End of check to see if needle1 is atomTwo's neighbour
934  // ----------------------------
935  // If needle1 is not a neighbour of atomOne or atomTwo, return false
936  if (neighbourFound == false) {
937  return false;
938  }
939 
940  // Check to see if needle2 is a neighbour of either atomOne or atomTwo
941  // ===============
942  // if atomOne was a neighbour of needle1, needle2 must be a neighbour of
943  // atomTwo
944  if (neighOne) {
945  it = std::find(nList[atomTwo].begin() + 1, nList[atomTwo].end(), needle2);
946  // It is a neighbour
947  if (it != nList[atomTwo].end()) {
948  return true;
949  }
950  // It is not a neighbour
951  else {
952  return false;
953  }
954  } // End of check for neighbour of atomTwo
955  // ===============
956  // if atomTwo was a neighbour of needle1, needle2 must be a neighbour of
957  // atomOne
958  else {
959  it = std::find(nList[atomOne].begin() + 1, nList[atomOne].end(), needle2);
960  // It is a neighbour
961  if (it != nList[atomOne].end()) {
962  return true;
963  }
964  // It is not a neighbour
965  else {
966  return false;
967  }
968  }
969  // ===============
970 }
971 
982  std::vector<int> *triplet,
984  int iatom; // AtomID of the atom to be searched for inside the neighbour
985  // lists
986  int jatom; // AtomID of in whose neighbour list iatom will be searched for
988 
989  for (int i = 0; i < (*triplet).size(); i++) {
990  iatom = (*triplet)[i]; // AtomID to be searched for
991  // iatom must be searched for in the neighbour lists of all elements
992  // of the ring vector
993  for (int j = 0; j < (*ring).size(); j++) {
994  jatom = (*ring)[j];
995  // ------------------
996  // Search for iatom in the neighbour list of jatom
997  it = std::find(nList[jatom].begin() + 1, nList[jatom].end(), iatom);
998  // It is a neighbour!
999  if (it != nList[jatom].end()) {
1000  return false;
1001  }
1002  // ------------------
1003  } // end of loop through every element of ring
1004  } // end of loop through all triplet elements
1005 
1006  return true;
1007 }
1008 
1022  std::vector<int> *listHC,
1023  std::vector<ring::strucType> *ringType, int iring,
1024  int jring, std::vector<int> *prismaticRings) {
1025  int iIndex, jIndex; // Used for making rings to be searched
1026  int ringSize = rings[0].size(); // This is 6 for hexagons
1027  std::vector<int> iTriplet; // triplet formed from iring
1028  std::vector<int> jTriplet; // triplet formed from jring
1029  std::vector<int> common; // Common elements
1030 
1031  // Make all possible triplets out of iring
1032  for (int i = 0; i < ringSize; i++) {
1033  // init
1034  iTriplet.clear();
1035  // ------
1036  // Get a triplet
1037  for (int m = 0; m < 3; m++) {
1038  iIndex = i + m;
1039  if (iIndex >= ringSize) {
1040  iIndex -= ringSize;
1041  }
1042  iTriplet.push_back(rings[iring][iIndex]);
1043  } // end of getting a triplet from iring
1044 
1045  // -------------------------------------------
1046  // Now that a triplet has been found, find all rings with that triplet in
1047  // it!
1048  for (int kring = 0; kring < rings.size(); kring++) {
1049  // If this is the same as iring or jring, skip
1050  if (kring == iring || kring == jring) {
1051  continue;
1052  } // is not prismatic
1053  //
1054  // Now find out whether kring has the triplet or not!
1055  common = ring::findsCommonElements(iTriplet, rings[kring]);
1056 
1057  // If this triplet is not shared by kring
1058  // skip
1059  if (common.size() != 3) {
1060  continue;
1061  } // kring does not have iTriplet
1062 
1063  // -----------------
1064  // If kring does have the triplet, check to see if at least three other
1065  // elements of kring are shared by jring
1066  jTriplet.clear(); // init
1067  // Make jTriplet
1068  for (int j = 0; j < ringSize; j++) {
1069  int katom = rings[kring][j];
1070  auto it = std::find(iTriplet.begin(), iTriplet.end(), katom);
1071 
1072  // If not found, add it to jTriplet
1073  if (it == iTriplet.end()) {
1074  jTriplet.push_back(katom);
1075  } // update jTriplet
1076  } // end of making jTriplet out of kring
1077  // -----------------
1078 
1079  // Now search for jTriplet inside jring
1080  common = ring::findsCommonElements(jTriplet, rings[jring]);
1081 
1082  // Update the prismatic rings
1083  if (common.size() == 3) {
1084  //
1085  (*listHC).push_back(kring); // Update listHC vector
1086  (*prismaticRings).push_back(kring); // Update prismatic rings
1087  // Update the type inside ringType
1088  // If the ring is already a DDC ring, it is a mixed ring
1089  if ((*ringType)[kring] == ring::strucType::DDC) {
1090  (*ringType)[kring] = ring::strucType::bothPrismatic;
1091  }
1092  // If it is unclassified, it is just a prismatic ring
1093  if ((*ringType)[kring] == ring::strucType::unclassified) {
1094  (*ringType)[kring] = ring::strucType::HCprismatic;
1095  } // end ring update
1096  } // add kring to the list of prismatic rings
1097  } // end of searching through rings for kring
1098  // -------------------------------------------
1099  } // end of getting pairs of triplets
1100 
1101  return 0;
1102 }
1103 
1118  std::vector<strucType> *ringType,
1119  std::vector<int> *listDDC,
1120  std::vector<int> *listHC) {
1121  std::vector<int> listMixed;
1122  int dummyValue = -10;
1123 
1124  // Loop through all rings in the ringType and
1125  // adds the ring Indices of all rings which are both DDCs and HCs
1126  for (int iring = 0; iring < (*ringType).size(); iring++) {
1127  // If iring is of mixed type, add it to the listMixed vector
1128  if ((*ringType)[iring] == ring::strucType::bothBasal ||
1129  (*ringType)[iring] == ring::strucType::bothPrismatic) {
1130  listMixed.push_back(iring);
1131 
1132  //-----------------
1133  // Search for iring in listDDC
1134  std::sort((*listDDC).begin(), (*listDDC).end());
1135  auto iter = std::find((*listDDC).begin(), (*listDDC).end(), iring);
1136  if (iter != (*listDDC).end()) {
1137  *iter = dummyValue; // Assign dummy value to the mixed ring
1138  } // found in listDDC
1139  //-----------------
1140  //-----------------
1141  // Search for iring in listHC
1142  std::sort((*listHC).begin(), (*listHC).end());
1143  auto itr = std::find((*listHC).begin(), (*listHC).end(), iring);
1144  if (itr != (*listHC).end()) {
1145  *itr = dummyValue; // Assign dummy value to the mixed ring
1146  } // found in listHC
1147  //-----------------
1148 
1149  } // end of check for type
1150  } // end of loop through all every ring
1151 
1152  return listMixed;
1153 }
1154 
1166  std::vector<cage::iceType> *atomTypes) {
1167  cage::iceType iRingType; // Type of the current ring
1168  int iatom; // Current ring
1169  int ringSize = rings[0].size(); // Size of the ring
1170 
1171  // Loop through every ring in ringType
1172  for (int iring = 0; iring < ringType.size(); iring++) {
1173  //
1174  // Skip if the ring is unclassified
1175  if (ringType[iring] == ring::strucType::unclassified) {
1176  continue;
1177  } // skip for unclassified rings
1178 
1179  // ------------
1180  // Get the current ring type
1181  // DDC
1182  if (ringType[iring] == ring::strucType::DDC) {
1183  iRingType = cage::iceType::ddc;
1184  } // DDC atoms
1185  //
1186  // HC
1187  else if (ringType[iring] == ring::strucType::HCbasal ||
1188  ringType[iring] == ring::strucType::HCprismatic) {
1189  iRingType = cage::iceType::hc;
1190  } // HC atoms
1191  //
1192  // Mixed
1193  else if (ringType[iring] == ring::strucType::bothBasal ||
1194  ringType[iring] == ring::strucType::bothPrismatic) {
1195  iRingType = cage::iceType::mixed;
1196  } // HC atoms
1197  // Prism
1198  else if (ringType[iring] == ring::strucType::Prism ||
1199  ringType[iring] == ring::strucType::deformedPrism ||
1200  ringType[iring] == ring::strucType::mixedPrismRing) {
1201  iRingType = cage::iceType::pnc; // 5 membered pnc
1202  } // prism
1203  // Should never go here
1204  else {
1205  continue;
1206  } //
1207  // ------------
1208  // Otherwise, loop through every inside the ring and assign atomTypes the
1209  // iRingType
1210  for (int i = 0; i < ringSize; i++) {
1211  iatom = rings[iring][i]; // Atom index in ring
1212  if ((*atomTypes)[iatom] == cage::iceType::mixed ||
1213  (*atomTypes)[iatom] == cage::iceType::mixed2) {
1214  continue;
1215  } // Don't reassign
1216  // For atoms shared by PNCs and DDCs/HCs
1217  if (ringSize == 6) {
1218  if ((*atomTypes)[iatom] == cage::iceType::pnc) {
1219  (*atomTypes)[iatom] = cage::iceType::mixed2;
1220  } else {
1221  (*atomTypes)[iatom] = iRingType;
1222  }
1223  } else {
1224  (*atomTypes)[iatom] = iRingType;
1225  }
1226  } // end of loop thorugh the current ring
1227  } // end of loop through every ring
1228 
1229  return 0;
1230 }
1231 
1248  std::vector<cage::Cage> cageList, int *numHC,
1249  int *numDDC, int *mixedRings, int *prismaticRings,
1250  int *basalRings) {
1251  // Determines the number of HCs, DDCs, Mixed rings, prismatic and basal rings
1252  // Init
1253  *numHC = 0;
1254  *numDDC = 0;
1255  *mixedRings = 0;
1256  *prismaticRings = 0;
1257  *basalRings = 0;
1258  // ------------------------------------
1259  // GETTING THE CAGES (DDCs and HCs)
1260  // Loop through cages
1261  for (int icage = 0; icage < cageList.size(); icage++) {
1262  //
1263  // HC
1264  if (cageList[icage].type == cage::cageType::HexC) {
1265  *numHC += 1;
1266  } // end of updating HC number
1267  //
1268  // DDC
1269  if (cageList[icage].type == cage::cageType::DoubleDiaC) {
1270  *numDDC += 1;
1271  } // end of updating DDC number
1272  } // end of loop through cages
1273  // ------------------------------------
1274  // GETTING THE RINGSS (Mixed, Prismatic and Basal rings)
1275  // Loop through the rings
1276  for (int iring = 0; iring < ringType.size(); iring++) {
1277  // Mixed
1278  if (ringType[iring] == ring::strucType::bothBasal ||
1279  ringType[iring] == ring::strucType::bothPrismatic) {
1280  *mixedRings += 1;
1281  // Also update basal rings
1282  if (ringType[iring] == ring::strucType::bothBasal) {
1283  *basalRings += 1;
1284  } // mixed basal rings
1285  // Also update prismatic rings
1286  if (ringType[iring] == ring::strucType::bothPrismatic) {
1287  *prismaticRings += 1;
1288  } // mixed prismatic rings
1289  } // end of updating mixed
1290  //
1291  // HCs
1292  if (ringType[iring] == ring::strucType::HCprismatic) {
1293  *prismaticRings += 1;
1294  } // HC prismatic
1295  // basal HCs
1296  if (ringType[iring] == ring::strucType::HCbasal) {
1297  *basalRings += 1;
1298  } // HC basal
1299  } // end of loop through every ring
1300  // ------------------------------------
1301 
1302  return 0;
1303 } // end of function
1304 
1331  molSys::PointCloud<molSys::Point<double>, double> *yCloud,
1332  std::vector<double> *rmsdPerAtom, double heightCutoff) {
1333  int totalRingNum = rings.size(); // Total number of rings
1334  std::vector<int> basal1; // First basal ring
1335  std::vector<int> basal2; // Second basal ring
1336  bool cond1, cond2; // Conditions for rings to be basal (true) or not (false)
1337  int ringSize = rings[0].size(); // Number of nodes in each ring
1338  // Matrix for the reference ring for a given ringSize.
1339  Eigen::MatrixXd refPointSet(ringSize, 3);
1340 
1341  int axialDim = 2; // Default=z
1342  refPointSet = pntToPnt::getPointSetRefRing(ringSize, axialDim);
1343  //
1344 
1345  // Two loops through all the rings are required to find pairs of basal rings
1346  for (int iring = 0; iring < totalRingNum - 1; iring++) {
1347  cond1 = false;
1348  cond2 = false;
1349  basal1 = rings[iring]; // Assign iring to basal1
1350  // Loop through the other rings to get a pair
1351  for (int jring = iring + 1; jring < totalRingNum; jring++) {
1352  basal2 = rings[jring]; // Assign jring to basal2
1353  // ------------
1354  // Put extra check for axial basal rings if shapeMatching is being done
1355  // ------------
1356  // Step one: Check to see if basal1 and basal2 have common
1357  // elements or not. If they don't, then they cannot be basal rings
1358  cond1 = ring::hasCommonElements(basal1, basal2);
1359  if (cond1 == true) {
1360  continue;
1361  }
1362 
1363  // ------------
1364  bool smallDist =
1365  prism3::basalRingsSeparation(yCloud, basal1, basal2, heightCutoff);
1366  if (!smallDist) {
1367  continue;
1368  } // the basal rings are too far apart
1369 
1370  // Otherwise
1371  // Do shape matching here
1372  bool isPrism = match::matchUntetheredPrism(yCloud, nList, refPointSet,
1373  &basal1, &basal2, rmsdPerAtom);
1374 
1375  // Success! The rings are basal rings of a prism!
1376  if (isPrism) {
1377  //
1378  // Update iring
1379  if ((*ringType)[iring] == ring::strucType::unclassified) {
1380  (*ringType)[iring] = ring::strucType::Prism;
1381  }
1382  // Update jring
1383  if ((*ringType)[jring] == ring::strucType::unclassified) {
1384  (*ringType)[jring] = ring::strucType::Prism;
1385  }
1386  } // end of reduced criteria
1387  // Strict criteria
1388  else {
1389  cond2 = prism3::basalPrismConditions(nList, &basal1, &basal2);
1390  // If the condition is false then the strict criterion has not been met
1391  if (!cond2) {
1392  continue;
1393  }
1394  // Update iring
1395  if ((*ringType)[iring] == ring::strucType::unclassified) {
1396  (*ringType)[iring] = ring::strucType::Prism;
1397  }
1398  // Update jring
1399  if ((*ringType)[jring] == ring::strucType::unclassified) {
1400  (*ringType)[jring] = ring::strucType::Prism;
1401  }
1402  //
1403  // Shape-matching to get the RMSD (if shape-matching is desired)
1404 
1405  // bool isKnownPrism = match::matchPrism(
1406  // yCloud, nList, refPointSet, &basal1, &basal2, rmsdPerAtom, true);
1407 
1408  // -----------
1409  } // end of strict criteria
1410 
1411  } // end of loop through rest of the rings to get the second basal ring
1412  } // end of loop through all rings for first basal ring
1413 
1414  return 0;
1415 }
1416 
1430  std::vector<int> *basal1,
1431  std::vector<int> *basal2) {
1432  int l1 = (*basal1)[0]; // first element of basal1 ring
1433  int ringSize =
1434  (*basal1).size(); // Size of the ring; each ring contains n elements
1435  int m_k; // Atom ID of element in basal2
1436  bool l1_neighbour; // m_k is a neighbour of l1(true) or not (false)
1437 
1438  // isNeighbour is initialized to false for all basal2 elements; indication if
1439  // basal2 elements are neighbours of basal1
1440  std::vector<bool> isNeighbour(ringSize, false);
1441  int kIndex; // m_k index
1442  int lAtomID; // atomID of the current element of basal1
1443  int kAtomID; // atomID of the current element of basal2
1444 
1445  // ---------------------------------------------
1446  // COMPARISON OF basal2 ELEMENTS WITH l1
1447  for (int k = 0; k < ringSize; k++) {
1448  l1_neighbour = false;
1449  m_k = (*basal2)[k];
1450  // =================================
1451  // Checking to seee if m_k is be a neighbour of l1
1452  // Find m_k inside l1 neighbour list
1453  auto it = std::find(nList[l1].begin() + 1, nList[l1].end(), m_k);
1454 
1455  // If the element has been found, for l1
1456  if (it != nList[l1].end()) {
1457  l1_neighbour = true;
1458  kIndex = k;
1459  break;
1460  }
1461  } // l1 is a neighbour of m_k
1462 
1463  // If there is no nearest neighbour, then the two rings are not part of the
1464  // prism
1465  if (!l1_neighbour) {
1466  return false;
1467  }
1468 
1469  // ---------------------------------------------
1470  // NEIGHBOURS of basal1 in basal2
1471  isNeighbour[kIndex] = true;
1472 
1473  // All elements of basal1 must be neighbours of basal2
1474  for (int i = 1; i < ringSize; i++) {
1475  lAtomID = (*basal1)[i]; // element of basal1 ring
1476  for (int k = 0; k < ringSize; k++) {
1477  // Skip if already a neighbour
1478  if (isNeighbour[k]) {
1479  continue;
1480  }
1481  // Get the comparison basal2 element
1482  kAtomID = (*basal2)[k]; // element of basal2 ring;
1483 
1484  // Checking to see if kAtomID is a neighbour of lAtomID
1485  // Find kAtomID inside lAtomID neighbour list
1486  auto it1 =
1487  std::find(nList[lAtomID].begin() + 1, nList[lAtomID].end(), kAtomID);
1488 
1489  // If the element has been found, for l1
1490  if (it1 != nList[lAtomID].end()) {
1491  isNeighbour[k] = true;
1492  }
1493  } // Loop through basal2
1494  } // end of check for neighbours of basal1
1495 
1496  // ---------------------------------------------
1497 
1498  // They should all be neighbours
1499  for (int k = 0; k < ringSize; k++) {
1500  // Check to see if any element is false
1501  if (!isNeighbour[k]) {
1502  return false;
1503  }
1504  }
1505 
1506  // Everything works out!
1507  return true;
1508 }
1509 
1517  std::vector<int> *basal1,
1518  std::vector<int> *basal2) {
1519  int ringSize =
1520  (*basal1).size(); // Size of the ring; each ring contains n elements
1521  int m_k; // Atom ID of element in basal2
1522  bool isNeighbour = false; // This is true if there is at least one bond
1523  // between the basal rings
1524  int l_k; // Atom ID of element in basal1
1525 
1526  // ---------------------------------------------
1527  // COMPARISON OF basal2 ELEMENTS (m_k) WITH basal1 ELEMENTS (l_k)
1528  // Loop through all the elements of basal1
1529  for (int l = 0; l < ringSize; l++) {
1530  l_k = (*basal1)[l];
1531  // Search for the nearest neighbour of l_k in basal2
1532  // Loop through basal2 elements
1533  for (int m = 0; m < ringSize; m++) {
1534  m_k = (*basal2)[m];
1535  // Find m_k inside l_k neighbour list
1536  auto it = std::find(nList[l_k].begin() + 1, nList[l_k].end(), m_k);
1537 
1538  // If the element has been found, for l1
1539  if (it != nList[l_k].end()) {
1540  isNeighbour = true;
1541  break;
1542  } // found element
1543  } // end of loop through all the elements of basal2
1544 
1545  // If a neighbour has been found then
1546  if (isNeighbour) {
1547  return true;
1548  }
1549  } // end of loop through all the elements of basal1
1550 
1551  // If a neighbour has not been found, return false
1552  return false;
1553 }
1554 
1558  molSys::PointCloud<molSys::Point<double>, double> *yCloud,
1559  std::vector<int> basal1, std::vector<int> basal2, double heightCutoff) {
1560  //
1561  int ringSize = basal1.size();
1562  int l_k, m_k; // Atom indices
1563  double infHugeNumber = 100000;
1564  double leastDist = infHugeNumber;
1565  int index = -1; // starting index
1566  // For the first element of basal1:
1567 
1568  l_k = basal1[0]; // This is the atom particle C++ index
1569 
1570  // Search for the nearest neighbour of l_k in basal2
1571  // Loop through basal2 elements
1572  for (int m = 0; m < ringSize; m++) {
1573  m_k = basal2[m]; // Atom index to find in the neighbour list of iatom
1574 
1575  // Calculate the distance
1576  double dist = gen::periodicDist(yCloud, l_k, m_k);
1577 
1578  // Update the least distance
1579  if (leastDist > dist) {
1580  leastDist = dist; // This is the new least distance
1581  index = m;
1582  } // end of update of the least distance
1583 
1584  } // found element
1585 
1586  // If the element has been found, for l1
1587  if (leastDist < heightCutoff) {
1588  return true;
1589  } // end of check
1590  else {
1591  return false;
1592  }
1593 }
T begin(T... args)
T clear(T... args)
T distance(T... args)
T end(T... args)
T erase(T... args)
T find(T... args)
iceType
Definition: cage.hpp:75
double periodicDist(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:108
bool notNeighboursOfRing(std::vector< std::vector< int >> nList, std::vector< int > *triplet, std::vector< int > *ring)
Definition: topo_bulk.cpp:981
bool conditionOneDDC(std::vector< std::vector< int >> rings, std::vector< int > *peripheralRings, int iring)
Definition: topo_bulk.cpp:416
bool basalNeighbours(std::vector< std::vector< int >> nList, std::vector< int > *triplet, int atomOne, int atomTwo)
Definition: topo_bulk.cpp:908
bool relaxedPrismConditions(std::vector< std::vector< int >> nList, std::vector< int > *basal1, std::vector< int > *basal2)
Definition: topo_bulk.cpp:1516
std::vector< int > findDDC(std::vector< std::vector< int >> rings, std::vector< strucType > *ringType, std::vector< int > listHC, std::vector< cage::Cage > *cageList)
Definition: topo_bulk.cpp:285
bool conditionTwoDDC(std::vector< std::vector< int >> rings, std::vector< int > *peripheralRings, int iring)
Definition: topo_bulk.cpp:488
int getAtomTypesTopoBulk(std::vector< std::vector< int >> rings, std::vector< ring::strucType > ringType, std::vector< cage::iceType > *atomTypes)
Definition: topo_bulk.cpp:1164
int getStrucNumbers(std::vector< ring::strucType > ringType, std::vector< cage::Cage > cageList, int *numHC, int *numDDC, int *mixedRings, int *prismaticRings, int *basalRings)
Determines the number of HCs, DDCs, Mixed rings, prismatic and basal rings.
Definition: topo_bulk.cpp:1247
bool basalRingsSeparation(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< int > basal1, std::vector< int > basal2, double heightCutoff=8)
Check to see that candidate basal prisms are not really far from each other.
Definition: topo_bulk.cpp:1557
bool basalConditions(std::vector< std::vector< int >> nList, std::vector< int > *basal1, std::vector< int > *basal2)
Tests whether two rings are basal rings (true) or not (false)
Definition: topo_bulk.cpp:786
int bulkPolygonRingAnalysis(std::string path, std::vector< std::vector< int >> rings, std::vector< std::vector< int >> nList, molSys::PointCloud< molSys::Point< double >, double > *yCloud, int maxDepth, int firstFrame)
Definition: topo_bulk.cpp:44
int findPrismatic(std::vector< std::vector< int >> rings, std::vector< int > *listHC, std::vector< strucType > *ringType, int iring, int jring, std::vector< int > *prismaticRings)
Finds the prismatic rings from basal rings iring and jring.
Definition: topo_bulk.cpp:1021
int topoBulkAnalysis(std::string path, std::vector< std::vector< int >> rings, std::vector< std::vector< int >> nList, molSys::PointCloud< molSys::Point< double >, double > *yCloud, int firstFrame, bool onlyTetrahedral=true)
Definition: topo_bulk.cpp:134
bool conditionThreeDDC(std::vector< std::vector< int >> rings, std::vector< int > *peripheralRings)
Definition: topo_bulk.cpp:569
int findBulkPrisms(std::vector< std::vector< int >> rings, std::vector< ring::strucType > *ringType, std::vector< std::vector< int >> nList, molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< double > *rmsdPerAtom, double heightCutoff=8)
Find out which rings are prisms.
Definition: topo_bulk.cpp:1328
std::vector< int > findMixedRings(std::vector< std::vector< int >> rings, std::vector< strucType > *ringType, std::vector< int > *listDDC, std::vector< int > *listHC)
Definition: topo_bulk.cpp:1117
bool basalPrismConditions(std::vector< std::vector< int >> nList, std::vector< int > *basal1, std::vector< int > *basal2)
Definition: topo_bulk.cpp:1429
std::vector< int > findHC(std::vector< std::vector< int >> rings, std::vector< strucType > *ringType, std::vector< std::vector< int >> nList, std::vector< cage::Cage > *cageList)
Definition: topo_bulk.cpp:651
bool commonElementsInThreeRings(std::vector< int > ring1, std::vector< int > ring2, std::vector< int > ring3)
Common elements in 3 rings.
Definition: ring.cpp:114
bool findTripletInRing(std::vector< int > ring, std::vector< int > triplet)
Searches a particular ring for a triplet.
Definition: ring.cpp:148
int clearRingList(std::vector< std::vector< int >> &rings)
Erases memory for a vector of vectors for a list of rings.
Definition: ring.cpp:22
bool hasCommonElements(std::vector< int > ring1, std::vector< int > ring2)
Definition: ring.cpp:226
int assignPolygonType(std::vector< std::vector< int >> rings, std::vector< int > *atomTypes, std::vector< int > nRings)
Definition: ring.cpp:40
std::vector< std::vector< int > > getSingleRingSize(std::vector< std::vector< int >> rings, int ringSize)
Returns a vector of vectors of rings of a single size.
Definition: ring.cpp:200
std::vector< int > findsCommonElements(std::vector< int > ring1, std::vector< int > ring2)
Returns the common elements of two rings.
Definition: ring.cpp:85
@ HCbasal
The ring belongs only to a hexagonal cage (HC). Specifically, the ring is purely a basal ring of an H...
@ DDC
The ring belongs to a double-diamond cage (DDC).
@ bothPrismatic
The ring belongs to both a DDC and HC and is, thus, a 'mixed' ring. The ring is also one of the prism...
@ Prism
The ring belongs to a prism block, classified according to the prism identification scheme.
@ bothBasal
The ring belongs to both a DDC and HC. It is a 'mixed' ring. The ring is also one of the basal rings ...
@ HCprismatic
The ring belongs only to a hexagonal cage (HC); specifically the ring is purely a prismatic ring of a...
@ unclassified
The ring is unclassified, which may be either water or a deformed type which cannot be classified by ...
T insert(T... args)
bool matchUntetheredPrism(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, const Eigen::MatrixXd &refPoints, std::vector< int > *basal1, std::vector< int > *basal2, std::vector< double > *rmsdPerAtom)
Definition: shapeMatch.cpp:110
Eigen::MatrixXd getPointSetRefRing(int n, int axialDim)
Topological network criteria functions.
Definition: ring.hpp:64
int writeRingNumBulk(std::string path, int currentFrame, std::vector< int > nRings, int maxDepth, int firstFrame)
int writeLAMMPSdataAllRings(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, std::vector< int > atomTypes, int maxDepth, std::string path, bool isMonolayer=true)
Write a data file for rings of every type for a monolayer.
int writeTopoBulkData(std::string path, int currentFrame, int numHC, int numDDC, int mixedRings, int basalRings, int prismaticRings, int firstFrame)
int writeLAMMPSdataTopoBulk(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList, std::vector< cage::iceType > atomTypes, std::string path, bool bondsBetweenDummy=false)
T push_back(T... args)
T resize(T... args)
T size(T... args)
T sort(T... args)
This contains a collection of points; contains information for a particular frame.
Definition: mol_sys.hpp:170
This contains per-particle information.
Definition: mol_sys.hpp:149
File containing functions used specific to bulk topological network critera.
T unique(T... args)