bulkTUM.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 <bulkTUM.hpp>
16 
17 // -----------------------------------------------------------------------------------------------------
18 // TOPOLOGICAL UNIT MATCHING ALGORITHMS
19 // -----------------------------------------------------------------------------------------------------
20 
55  molSys::PointCloud<molSys::Point<double>, double> *yCloud, int firstFrame,
56  bool printClusters, bool onlyTetrahedral) {
57  // The input rings vector has rings of all sizes
58 
59  // ringType has a value for rings of a particular size
61  ringType; // This vector will have a value for each ring inside
62  // ringList, of type enum strucType in gen.hpp
63  // Make a list of all the DDCs and HCs
64  std::vector<cage::Cage> cageList;
66  ringsOneType; // Vector of vectors of rings of a single size
67  int initRingSize; // Todo or not: calculate the PNCs or not
68  int maxRingSize = 6; // DDCs and HCs are for 6-membered rings
70  atomTypes; // This vector will have a value for every atom
71  // Number of types
72  int numHC, numDDC, mixedRings, prismaticRings, basalRings;
73  // Shape-matching variables ----
74  double rmsd; // RMSD value for a particular cage type
75  std::vector<double> quat; // Quaternion obtained from shape-matching
76  std::vector<std::vector<double>> quatList; // List of quaternions
77  // Reference points
78  Eigen::MatrixXd refPntsDDC(14,
79  3); // Reference point set (Eigen matrix) for a DDC
80  Eigen::MatrixXd refPntsHC(12,
81  3); // Reference point set (Eigen matrix) for a DDC
82 
83  // Vector for the RMSD per atom and the RMSD per ring:
84  std::vector<double> rmsdPerAtom;
86  noOfCommonElements; // An atom can belong to more than one ring or shape
87  //
88 
89  if (onlyTetrahedral) {
90  initRingSize = 6;
91  } else {
92  initRingSize = 5;
93  }
94 
95  // Init the atom type vector
96  atomTypes.resize(yCloud->nop); // Has a value for each atom
97  // Init the rmsd per atom
98  rmsdPerAtom.resize(yCloud->nop, -1); // Has a value for each atom
99  noOfCommonElements.resize(yCloud->nop); // Has a value for each atom
100 
101  // ----------------------------------------------
102  // Init
103  // Get rings of size 5 or 6.
104  for (int ringSize = initRingSize; ringSize <= maxRingSize; ringSize++) {
105  // Clear ringsOneType
106  ring::clearRingList(ringsOneType);
107  // Get rings of the current ring size
108  ringsOneType = ring::getSingleRingSize(rings, ringSize);
109  // Skip for zero rings
110  if (ringsOneType.size() == 0) {
111  continue;
112  } // skip for no rings of ringSize
113  //
114  // Init the ringType vector
115  ringType.resize(
116  ringsOneType.size()); // Has a value for each ring. init to zero.
117  // ----------------------------------------------
118  if (ringSize == 6) {
119  // Get the cages
120 
121  // Find the DDCs and HCs
122  cageList = tum3::topoBulkCriteria(path, ringsOneType, nList, yCloud,
123  firstFrame, &numHC, &numDDC, &ringType);
124 
125  // Gets the atom type for every atom, to be used for printing out the ice
126  // types found
127  ring::getAtomTypesTopoBulk(ringsOneType, ringType, &atomTypes);
128  }
129  // Finding the 5-membered prismatic blocks
130  else {
131  // Get the prism block classifications
132  prism3::findBulkPrisms(ringsOneType, &ringType, nList, yCloud,
133  &rmsdPerAtom);
134  // Gets the atom type for every atom, to be used for printing out the ice
135  // types found
136  ring::getAtomTypesTopoBulk(ringsOneType, ringType, &atomTypes);
137  }
138  }
139 
140  // --------------------------------------------------
141  // SHAPE-MATCHING
142  //
143  // Get the reference point sets
144  //
145  std::string filePathHC = "templates/hc.xyz";
146  std::string filePathDDC = "templates/ddc.xyz";
147  refPntsHC = tum3::buildRefHC(filePathHC); // HC
148  refPntsDDC = tum3::buildRefDDC(filePathDDC); // DDC
149  //
150  // Init
151  //
152  // Loop through all the atoms and set commonElements to 1 for PNC atoms
153  for (int i = 0; i < yCloud->nop; i++) {
154  if (rmsdPerAtom[i] != -1) {
155  noOfCommonElements[i] = 1;
156  } // for atoms which have been updated
157  } // end of updating commonElements
158  //
159  // Loop through the entire cageList vector of cages to match the HCs and DDCs
160  //
161  // HCs are first, followed by DDCs.
162  //
163  // Go through all the HCs
164  for (int icage = 0; icage < numHC; icage++) {
165  // Match against a perfect HC
166  tum3::shapeMatchHC(yCloud, refPntsHC, cageList[icage], ringsOneType, nList,
167  &quat, &rmsd);
168  // Update the vector of quaternions
169  quatList.push_back(quat);
170  // Update the RMSD per ring
171  tum3::updateRMSDatom(ringsOneType, cageList[icage], rmsd, &rmsdPerAtom,
172  &noOfCommonElements, atomTypes);
173  } // end of looping through all HCs
174  // --------------------------------------------------
175  // Go through all the DDCs
176  for (int icage = numHC; icage < cageList.size(); icage++) {
177  // Match against a perfect DDC
178  tum3::shapeMatchDDC(yCloud, refPntsDDC, cageList, icage, ringsOneType,
179  &quat, &rmsd);
180  // Update the vector of quaternions
181  quatList.push_back(quat);
182  // Update the RMSD per ring
183  tum3::updateRMSDatom(ringsOneType, cageList[icage], rmsd, &rmsdPerAtom,
184  &noOfCommonElements, atomTypes);
185  } // end of looping through all HCs
186 
187  // --------------------------------------------------
188  // Getting the RMSD per atom
189  // Average the RMSD per atom
190  tum3::averageRMSDatom(&rmsdPerAtom, &noOfCommonElements);
191  // --------------------------------------------------
192 
193  // Print out the lammps data file with the bonds and types
194  sout::writeLAMMPSdataTopoBulk(yCloud, nList, atomTypes, path);
195  // To output the bonds between dummy atoms, uncomment the following line
196  // sout::writeLAMMPSdataTopoBulk(yCloud, nList, atomTypes, path, true);
197 
198  // --------------------------------------------------
199  // Writes out the dumpfile
200  //
201  std::vector<int> dumpAtomTypes; // Must be typecast to int
202  dumpAtomTypes.resize(atomTypes.size());
203  // Change from enum to int
204  for (int i = 0; i < atomTypes.size(); i++) {
205  if (atomTypes[i] == cage::iceType::hc) {
206  dumpAtomTypes[i] = 1;
207  } // HC
208  else if (atomTypes[i] == cage::iceType::ddc) {
209  dumpAtomTypes[i] = 2;
210  } // DDC
211  else if (atomTypes[i] == cage::iceType::mixed) {
212  dumpAtomTypes[i] = 3;
213  } // mixed rings
214  else if (atomTypes[i] == cage::iceType::pnc) {
215  dumpAtomTypes[i] = 4;
216  } // pnc
217  else if (atomTypes[i] == cage::iceType::mixed2) {
218  dumpAtomTypes[i] = 5;
219  } // shared by pnc and ddc/hc
220  else {
221  dumpAtomTypes[i] = 0;
222  } // dummy atoms
223  } // end of changing the type to int
224  sout::writeLAMMPSdumpCages(yCloud, rmsdPerAtom, dumpAtomTypes, path,
225  firstFrame);
226  // --------------------------------------------------
227  //
228  // PRINT THE CLUSTERS
229  //
230  if (printClusters) {
231  // Print the clusters
232  tum3::clusterCages(yCloud, path, ringsOneType, cageList, numHC, numDDC);
233  } // end of printing individual clusters
234  // --------------------------------------------------
235  return 0;
236 }
237 
238 // Shape-matching for an HC
252  molSys::PointCloud<molSys::Point<double>, double> *yCloud,
253  const Eigen::MatrixXd &refPoints, cage::Cage cageUnit,
255  std::vector<double> *quat, double *rmsd) {
256  //
257  int iring,
258  jring; // Indices in the ring vector of vectors for the basal rings
259  std::vector<int> basal1,
260  basal2; // Re-ordered basal rings matched to each other
261  int ringSize = 6; // Each ring has 6 nodes
262  Eigen::MatrixXd targetPointSet(12, 3); // Target point set (Eigen matrix)
263  //
264  std::vector<double> rmsdList; // List of RMSD per atom
265  // Variables for looping through possible permutations
266  //
267  std::vector<double> currentQuat; // quaternion rotation
268  double currentRmsd; // least RMSD
269  double currentScale; // scale
270  double scale; // Final scale
271  int index; // Int for describing which permutation matches the best
272 
273  // Init
274  iring = cageUnit.rings[0]; // Index of basal1
275  jring = cageUnit.rings[1]; // Index of basal2
276  rmsdList.resize(yCloud->nop); // Not actually updated here
277  //
278  // ----------------
279  // Re-order the basal rings so that they are matched
280  pntToPnt::relOrderHC(yCloud, rings[iring], rings[jring], nList, &basal1,
281  &basal2);
282  // ----------------
283  // Loop through all possible permutations
284  //
285  for (int i = 0; i < ringSize; i++) {
286  // Change the order of the target points somehow!
287  //
288  targetPointSet = pntToPnt::changeHexCageOrder(yCloud, basal1, basal2, i);
289  // Shape-matching
290  absor::hornAbsOrientation(refPoints, targetPointSet, &currentQuat,
291  &currentRmsd, &rmsdList, &currentScale);
292  if (i == 0) {
293  *quat = currentQuat;
294  *rmsd = currentRmsd;
295  scale = currentScale;
296  index = 0;
297  } else {
298  if (currentRmsd < *rmsd) {
299  *quat = currentQuat;
300  *rmsd = currentRmsd;
301  scale = currentScale;
302  index = i;
303  } // update
304  } // Update if this is a better match
305  } // Loop through possible permutations
306  // ----------------
307  return 0;
308 }
309 
310 // Shape-matching for a DDC
324  molSys::PointCloud<molSys::Point<double>, double> *yCloud,
325  const Eigen::MatrixXd &refPoints, std::vector<cage::Cage> cageList,
326  int cageIndex, std::vector<std::vector<int>> rings,
327  std::vector<double> *quat, double *rmsd) {
328  //
329  std::vector<int> ddcOrder; // Connectivity of the DDC
330  int ringSize = 6; // Each ring has 6 nodes
331  Eigen::MatrixXd targetPointSet(14, 3); // Target point set (Eigen matrix)
332  //
333  std::vector<double> rmsdList; // List of RMSD per atom
334  // Variables for looping through possible permutations
335  //
336  std::vector<double> currentQuat; // quaternion rotation
337  double currentRmsd; // least RMSD
338  double currentScale; // scale
339  double scale; // Final scale
340  int index; // Int for describing which permutation matches the best
341 
342  // ----------------
343  // Save the order of the DDC in a vector
344  ddcOrder = pntToPnt::relOrderDDC(cageIndex, rings, cageList);
345  // ----------------
346  // Loop through all possible permutations
347  //
348  for (int i = 0; i < ringSize; i++) {
349  // Change the order of the target points somehow!
350  //
351  targetPointSet = pntToPnt::changeDiaCageOrder(yCloud, ddcOrder, i);
352  // Shape-matching
353  absor::hornAbsOrientation(refPoints, targetPointSet, &currentQuat,
354  &currentRmsd, &rmsdList, &currentScale);
355  if (i == 0) {
356  *quat = currentQuat;
357  *rmsd = currentRmsd;
358  scale = currentScale;
359  index = 0;
360  } else {
361  if (currentRmsd < *rmsd) {
362  *quat = currentQuat;
363  *rmsd = currentRmsd;
364  scale = currentScale;
365  index = i;
366  } // update
367  } // Update if this is a better match
368  } // Loop through possible permutations
369  // ----------------
370  return 0;
371 }
372 
377 Eigen::MatrixXd tum3::buildRefHC(std::string fileName) {
378  //
379  Eigen::MatrixXd refPnts(12, 3); // Reference point set (Eigen matrix)
380  // Get the reference HC point set
381  // molSys::PointCloud<molSys::Point<double>, double>
382  // setCloud; // PointCloud for holding the reference point values
383  // Variables for rings
384  std::vector<std::vector<int>> nList; // Neighbour list
385  std::vector<std::vector<int>> rings; // Rings
387  ringType; // This vector will have a value for each ring inside
388  std::vector<int> listHC; // Contains atom indices of atoms making up HCs
389  // Make a list of all the DDCs and HCs
390  std::vector<cage::Cage> cageList;
391  int iring, jring;
392  //
393  // read in the XYZ file into the pointCloud setCloud
394  //
395  auto setCloud = sinp::readXYZ(fileName);
396  // box lengths
397  for (int i = 0; i < 3; i++) {
398  setCloud.box[i] = 50;
399  } // end of setting box lengths
400  //
401 
402  nList = nneigh::neighListO(3.5, &setCloud, 1);
403  // Neighbour list by index
404  nList = nneigh::neighbourListByIndex(&setCloud, nList);
405  // Find the vector of vector of rings
406  rings = primitive::ringNetwork(nList, 6);
407  // init the ringType vector
408  ringType.resize(rings.size());
409  // Find the HCs
410  listHC = ring::findHC(rings, &ringType, nList, &cageList);
411  // Get the basal rings from cageList
412  iring = cageList[0].rings[0];
413  jring = cageList[0].rings[1];
414  //
415  std::vector<int> matchedBasal1,
416  matchedBasal2; // Re-ordered basal rings 1 and 2
417  // Reordered basal rings
418  // Getting the target Eigen vectors
419  // Get the re-ordered matched basal rings, ordered with respect to each
420  // other
421 
422  pntToPnt::relOrderHC(&setCloud, rings[iring], rings[jring], nList,
423  &matchedBasal1, &matchedBasal2);
424  // Get the reference point set
425  refPnts =
426  pntToPnt::changeHexCageOrder(&setCloud, matchedBasal1, matchedBasal2, 0);
427  //
428  return refPnts;
429 }
430 
435 Eigen::MatrixXd tum3::buildRefDDC(std::string fileName) {
436  //
437  Eigen::MatrixXd refPnts(14, 3); // Reference point set (Eigen matrix)
438  // Get the reference HC point set
440  setCloud; // PointCloud for holding the reference point values
441  // Variables for rings
442  std::vector<std::vector<int>> nList; // Neighbour list
443  std::vector<std::vector<int>> rings; // Rings
445  ringType; // This vector will have a value for each ring inside
446  std::vector<int> listDDC,
447  listHC; // Contains atom indices of atoms making up DDCs and HCs
448  std::vector<int> ddcOrder; // Atom indices of particles in the DDC
449  // Make a list of all the DDCs and HCs
450  std::vector<cage::Cage> cageList;
451  int iring, jring;
452  //
453  // read in the XYZ file into the pointCloud setCloud
454  //
455  setCloud = sinp::readXYZ(fileName);
456 
457  // box lengths
458  for (int i = 0; i < 3; i++) {
459  setCloud.box[i] = 50;
460  } // end of setting box lengths
461  //
462 
463  nList = nneigh::neighListO(3.5, &setCloud, 1);
464  // Neighbour list by index
465  nList = nneigh::neighbourListByIndex(&setCloud, nList);
466  // Find the vector of vector of rings
467  rings = primitive::ringNetwork(nList, 6);
468  // init the ringType vector
469  ringType.resize(rings.size());
470  // Find the DDCs
471  listDDC = ring::findDDC(rings, &ringType, listHC, &cageList);
472  // Save the order of the DDC in a vector
473  ddcOrder = pntToPnt::relOrderDDC(0, rings, cageList);
474  // Get the reference point set
475  refPnts = pntToPnt::changeDiaCageOrder(&setCloud, ddcOrder, 0);
476  //
477  return refPnts;
478 }
479 
487  cage::Cage cageUnit, double rmsd,
488  std::vector<double> *rmsdPerAtom,
489  std::vector<int> *noOfCommonAtoms,
490  std::vector<cage::iceType> atomTypes) {
491  //
492  int nRings = cageUnit.rings.size(); // Number of rings in the current cage
493  int iring; // Index according to the rings vector of vector, for the current
494  // ring inside the cage
495  int iatom; // Current atom index
496  int ringSize = rings[0].size(); // Number of nodes in each ring (6)
497 
498  // Loop through the rings in each cage
499  for (int i = 0; i < nRings; i++) {
500  iring = cageUnit.rings[i]; // Current ring
501 
502  // Loop through all the atoms in the ring
503  for (int j = 0; j < ringSize; j++) {
504  iatom = rings[iring][j]; // Current atom index
505 
506  // Skip for PNC atoms
507  if (atomTypes[iatom] == cage::iceType::pnc || atomTypes[iatom] == cage::iceType::mixed2) {
508  continue;
509  } // Do not update if the atom is a PNC
510  //
511  // UPDATE
512  if ((*rmsdPerAtom)[iatom] == -1) {
513  (*rmsdPerAtom)[iatom] = rmsd;
514  (*noOfCommonAtoms)[iatom] = 1;
515  } else {
516  (*rmsdPerAtom)[iatom] += rmsd;
517  (*noOfCommonAtoms)[iatom] += 1;
518  }
519  } // end of looping through all the atoms in the ring
520 
521  } // end of looping through the rings in the cage
522 
523  return 0;
524 }
525 
530  std::vector<int> *noOfCommonAtoms) {
531  //
532  int nop = (*rmsdPerAtom).size(); // Number of particles
533 
534  for (int iatom = 0; iatom < nop; iatom++) {
535  //
536  if ((*noOfCommonAtoms)[iatom] == 0) {
537  (*rmsdPerAtom)[iatom] = -1; // Dummy atom
538  } else {
539  (*rmsdPerAtom)[iatom] /= (*noOfCommonAtoms)[iatom];
540  }
541  } // end of averaging
542 
543  return 0;
544 } // end of function
545 
546 // -----------------------------------------------------------------
547 //
548 // TOPOLOGICAL NETWORK ALGORITHMS
549 //
550 // -----------------------------------------------------------------
584  molSys::PointCloud<molSys::Point<double>, double> *yCloud, int firstFrame,
585  int *numHC, int *numDDC, std::vector<ring::strucType> *ringType) {
586  //
587  // Ring IDs of each type will be saved in these vectors
588  std::vector<int> listDDC; // Vector for ring indices of DDC
589  std::vector<int> listHC; // Vector for ring indices of HC
591  listMixed; // Vector for ring indices of rings that are both DDC and HC
592  // ringList, of type enum strucType in gen.hpp
593  // Make a list of all the DDCs and HCs
594  std::vector<cage::Cage> cageList;
595  // Number of types
596  int mixedRings, prismaticRings, basalRings;
597 
598  // ----------------------------------------------
599  // Init
600  //
601  *numHC = 0; // Number of hexagonal cages
602  *numDDC = 0; // Init the number of DDCs
603  // Quit the function for zero rings
604  if (rings.size() == 0) {
605  return cageList;
606  } // skip for no rings of ringSize
607  //
608  // Init the ringType vector
609  (*ringType).resize(rings.size()); // Has a value for each ring. init to zero.
610  // ----------------------------------------------
611  // Get the cages
612 
613  // Find HC rings, saving the ring IDs (starting from 0) to listHC
614  listHC = ring::findHC(rings, ringType, nList, &cageList);
615 
616  // Find DDC rings, saving the IDs to listDDC
617  listDDC = ring::findDDC(rings, ringType, listHC, &cageList);
618 
619  // Find rings which are both DDCs and HCs (mixed)
620  // A dummy value of -10 in the listDDC and listHC vectors for mixed rings
621  listMixed = ring::findMixedRings(rings, ringType, &listDDC, &listHC);
622 
623  // Get the number of structures (DDCs, HCs, mixed rings, basal rings,
624  // prismatic rings)
625  ring::getStrucNumbers(*ringType, cageList, numHC, numDDC, &mixedRings,
626  &prismaticRings, &basalRings);
627 
628  // Write out to a file
629  sout::writeTopoBulkData(path, yCloud->currentFrame, *numHC, *numDDC,
630  mixedRings, basalRings, prismaticRings, firstFrame);
631 
632  return cageList;
633 }
634 
635 // -----------------------------------------------------------------
636 //
637 // CLUSTERING ALGORITHMS
638 //
639 // -----------------------------------------------------------------
647  int numHC, int numDDC) {
648  //
649  std::vector<int> linkedList; // Linked list for the clustered cages
650  int nCages = numHC + numDDC; // Number of cages in total
651  int j, temp; // Variables used inside the loops
652  bool isNeighbour; // true if cages are adjacent to each other, false otherwise
654  visited; // To make sure you don't go through the same cages again.
655  int singleDDCs, singleHCs; // Number of single DDCs and HCs
656  // Units are in Angstrom^3
657  double volDDC = 72.7; // The calculated alpha volume of a single DDC
658  double volHC = 40.63; // The calculated alpha volume of a single HC
659  int nextElement; // value in list
660  int index; // starting index value
661  int currentIndex; // Current cage index
662  int iClusterNumber; // Number in the current cluster
663  std::vector<int> nClusters; // Number of cages in each cluster
664  std::vector<int> clusterCages; // Indices of each cage in the cluster
665  std::vector<int> atoms; // Vector containing the atom indices of all the
666  // atoms in the cages
667  cage::cageType type; // Type of the cages in the cluster
668  // -----------------------------------------------------------
669  // INITIALIZATION
670  linkedList.resize(nCages); // init to dummy value
671  // Initial values of the list.
672  for (int icage = 0; icage < nCages; icage++) {
673  // Assign the index as the ID
674  linkedList[icage] = icage; // Index
675  } // init of cluster IDs
676  // -----------------------------------------------------------
677  // GETTING THE LINKED LIST
678  //
679  // HCs first
680  for (int i = 0; i < nCages - 1; i++) {
681  // If iatom is already in a cluster, skip it
682  if (linkedList[i] != i) {
683  continue;
684  } // Already part of a cluster
685  //
686  j = i; // Init of j
687  // Execute the next part of the loop while j is not equal to i
688  do {
689  //
690  // Go through the rest of the atoms (KLOOP)
691  for (int k = i + 1; k < nCages; k++) {
692  // Skip if already part of a cluster
693  if (linkedList[k] != k) {
694  continue;
695  } // Already part of a cluster
696  //
697  // k and j must be of the same type
698  if (cageList[k].type != cageList[j].type) {
699  continue;
700  } // skip if k and j are not of the same type
701  // Check to see if k is a nearest neighbour of j
702  isNeighbour =
703  ring::hasCommonElements(cageList[k].rings, cageList[j].rings);
704  if (isNeighbour) {
705  // Swap!
706  temp = linkedList[j];
707  linkedList[j] = linkedList[k];
708  linkedList[k] = temp;
709  } // j and k are neighbouring cages
710  } // end of loop through k (KLOOP)
711  //
712  j = linkedList[j];
713  } while (j != i); // end of control for j!=i
714  } // end of getting the linked list (looping through every i)
715  // -----------------------------------------------------------
716  // WRITE-OUTS
717  //
718  // init
719  visited.resize(nCages);
720  singleDDCs = 0;
721  singleHCs = 0;
722 
723  for (int i = 0; i < nCages; i++) {
724  //
725  if (visited[i]) {
726  continue;
727  } // Already counted
728  // Now that the cage has been visited, set it to true
729  visited[i] = true; // Visited
730  // If only one cage is in the cluster
731  if (linkedList[i] == i) {
732  // Add to the number of single DDCs
733  if (cageList[i].type == cage::cageType::DoubleDiaC) {
734  singleDDCs++;
735  } // add to the single DDCs
736  else {
737  singleHCs++;
738  } // single HCs
739  continue;
740  } // cluster has only one cage
741  //
742  // init
743  clusterCages.resize(0);
744  //
745  type = cageList[i].type;
746  currentIndex = i;
747  nextElement = linkedList[currentIndex];
748  index = i;
749  iClusterNumber = 1; // at least one value
750  clusterCages.push_back(i); // Add the first cage
751  // Get the other cages in the cluster
752  while (nextElement != index) {
753  iClusterNumber++;
754  currentIndex = nextElement;
755  visited[currentIndex] = true;
756  clusterCages.push_back(currentIndex); // Add the first cage
757  nextElement = linkedList[currentIndex];
758  } // get number
759  // Update the number of molecules in the cluster
760  nClusters.push_back(iClusterNumber);
761  // --------------
762  // PRINT OUT
763  atoms = tum3::atomsFromCages(rings, cageList, clusterCages);
764  int clusterID = nClusters.size();
765  // Write out the cluster
766  sout::writeXYZcluster(path, yCloud, atoms, clusterID, type);
767  // Print out the cages into an XYZ file
768  // --------------
769  } // end of loop through
770  // -----------------------------------------------------------
771  // Write out the stuff for single cages
772  // ----------------
773  std::ofstream outputFile;
774  // Make the output directory if it doesn't exist
775  sout::makePath(path);
776  std::string outputDirName = path + "bulkTopo";
777  sout::makePath(outputDirName);
778  outputDirName = path + "bulkTopo/clusterXYZ/";
779  sout::makePath(outputDirName);
780  outputDirName = path + "bulkTopo/clusterXYZ/frame-" +
781  std::to_string(yCloud->currentFrame);
782  sout::makePath(outputDirName);
783  // ----------------
784  // Write output to file inside the output directory
785  outputFile.open(path + "bulkTopo/clusterXYZ/frame-" +
786  std::to_string(yCloud->currentFrame) + "/info.dat");
787  outputFile << "# volDDC volHC in Angstrom^3\n";
788  outputFile << singleDDCs * volDDC << " " << singleHCs * volHC << "\n";
789  outputFile << "There are " << singleDDCs << " single DDCs\n";
790  outputFile << "There are " << singleHCs << " single HCs\n";
791  outputFile.close(); // Close the file
792  // -----------------------------------------------------------
793  return 0;
794 } // end of the function
795 
796 
802  std::vector<cage::Cage> cageList,
804  //
805  std::vector<int> atoms; // Contains the atom indices (not IDs) of atoms
806  int ringSize = rings[0].size(); // Number of nodes in each ring
807  int iring; // Index of ring in rings vector of vectors
808  int icage; // Index of the current cage in cageList
809  int iatom; // Atom index
810  //
811  for (int i = 0; i < clusterCages.size(); i++) {
812  //
813  icage = clusterCages[i];
814  // Loop through every ring in the cage
815  for (int j = 0; j < cageList[icage].rings.size(); j++) {
816  iring = cageList[icage].rings[j]; // Current ring index
817  // Loop through every atom in iring
818  for (int k = 0; k < ringSize; k++) {
819  iatom = rings[iring][k];
820  atoms.push_back(iatom); // Add the atom
821  } // Loop through every atom in iring
822  } // loop through every ring in the current cage
823  } // end of loop through all cages
824 
825  // Remove the duplicates in the atoms vector
826  // Duplicate IDs must be removed
827  //
828  sort(atoms.begin(), atoms.end());
829  auto ip = std::unique(atoms.begin(), atoms.end());
830  // Resize peripheral rings to remove undefined terms
831  atoms.resize(std::distance(atoms.begin(), ip));
832  //
833  // Return the vector of atoms
834  return atoms;
835 }
T begin(T... args)
File containing functions used specific to bulk topological unit matching (TUM) criterion.
T close(T... args)
T distance(T... args)
T end(T... args)
cageType
Definition: cage.hpp:54
std::vector< int > rings
type of the cage : can be DDC or HC
Definition: cage.hpp:88
std::vector< T > box
Number of atoms.
Definition: mol_sys.hpp:174
std::vector< std::vector< int > > neighListO(double rcutoff, molSys::PointCloud< molSys::Point< double >, double > *yCloud, int typeI)
Definition: neighbours.cpp:118
std::vector< std::vector< int > > neighbourListByIndex(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> nList)
Definition: neighbours.cpp:341
std::vector< std::vector< int > > ringNetwork(std::vector< std::vector< int >> nList, int maxDepth)
Definition: franzblau.cpp:32
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
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
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
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
int shapeMatchHC(molSys::PointCloud< molSys::Point< double >, double > *yCloud, const Eigen::MatrixXd &refPoints, cage::Cage cageUnit, std::vector< std::vector< int >> rings, std::vector< std::vector< int >> nList, std::vector< double > *quat, double *rmsd)
Shape-matching for a target HC.
Definition: bulkTUM.cpp:251
Eigen::MatrixXd buildRefHC(std::string fileName)
Build a reference Hexagonal cage, reading in from a template XYZ file.
Definition: bulkTUM.cpp:377
std::vector< int > atomsFromCages(std::vector< std::vector< int >> rings, std::vector< cage::Cage > cageList, std::vector< int > clusterCages)
Gets the atoms in the cages of a given cluster.
Definition: bulkTUM.cpp:801
int clusterCages(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::string path, std::vector< std::vector< int >> rings, std::vector< cage::Cage > cageList, int numHC, int numDDC)
Definition: bulkTUM.cpp:644
int averageRMSDatom(std::vector< double > *rmsdPerAtom, std::vector< int > *noOfCommonAtoms)
Average the RMSD per atom.
Definition: bulkTUM.cpp:529
int shapeMatchDDC(molSys::PointCloud< molSys::Point< double >, double > *yCloud, const Eigen::MatrixXd &refPoints, std::vector< cage::Cage > cageList, int cageIndex, std::vector< std::vector< int >> rings, std::vector< double > *quat, double *rmsd)
Shape-matching for a target DDC.
Definition: bulkTUM.cpp:323
int topoUnitMatchingBulk(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 printClusters, bool onlyTetrahedral)
Definition: bulkTUM.cpp:52
int clearRingList(std::vector< std::vector< int >> &rings)
Erases memory for a vector of vectors for a list of rings.
Definition: ring.cpp:22
int updateRMSDatom(std::vector< std::vector< int >> rings, cage::Cage cageUnit, double rmsd, std::vector< double > *rmsdPerAtom, std::vector< int > *noOfCommonAtoms, std::vector< cage::iceType > atomTypes)
Definition: bulkTUM.cpp:486
std::vector< cage::Cage > topoBulkCriteria(std::string path, std::vector< std::vector< int >> rings, std::vector< std::vector< int >> nList, molSys::PointCloud< molSys::Point< double >, double > *yCloud, int firstFrame, int *numHC, int *numDDC, std::vector< ring::strucType > *ringType)
Definition: bulkTUM.cpp:581
Eigen::MatrixXd buildRefDDC(std::string fileName)
Build a reference Double-Diamond cage, reading in from a template XYZ file.
Definition: bulkTUM.cpp:435
bool hasCommonElements(std::vector< int > ring1, std::vector< int > ring2)
Definition: ring.cpp:226
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
molSys::PointCloud< molSys::Point< double >, double > readXYZ(std::string filename)
Function for reading in atom coordinates from an XYZ file.
Definition: seams_input.cpp:73
int hornAbsOrientation(const Eigen::MatrixXd &refPoints, const Eigen::MatrixXd &targetPoints, std::vector< double > *quat, double *rmsd, std::vector< double > *rmsdList, double *scale)
Get the absolute orientation using Horn's algorithm (with quaternions)
Eigen::MatrixXd changeDiaCageOrder(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< int > ddcOrder, int startingIndex=0)
std::vector< int > relOrderDDC(int index, std::vector< std::vector< int >> rings, std::vector< cage::Cage > cageList)
Matches the order of the basal rings of an DDC or a potential HC.
int relOrderHC(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< int > basal1, std::vector< int > basal2, std::vector< std::vector< int >> nList, std::vector< int > *matchedBasal1, std::vector< int > *matchedBasal2)
Matches the order of the basal rings of an HC or a potential HC.
Eigen::MatrixXd changeHexCageOrder(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< int > basal1, std::vector< int > basal2, int startingIndex=0)
int makePath(const std::string &path)
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)
int writeLAMMPSdumpCages(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< double > rmsdPerAtom, std::vector< int > atomTypes, std::string path, int firstFrame)
Write out a LAMMPS dump file containing the RMSD per atom for bulk ice.
int writeXYZcluster(std::string path, molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< int > atoms, int clusterID, cage::cageType type)
Function for writing out the XYZ files for each cluster.
T open(T... args)
T push_back(T... args)
T resize(T... args)
T size(T... args)
This contains a cage, with the constituent rings.
Definition: cage.hpp:86
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
T to_string(T... args)
T unique(T... args)