bulkTUM.cpp
Go to the documentation of this file.
Code
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
53 std::string path, std::vector<std::vector<int>> rings,
54 std::vector<std::vector<int>> nList,
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
60 std::vector<ring::strucType>
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;
65 std::vector<std::vector<int>>
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
69 std::vector<cage::iceType>
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;
85 std::vector<int>
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
253 const Eigen::MatrixXd &refPoints, cage::Cage cageUnit,
254 std::vector<std::vector<int>> rings, std::vector<std::vector<int>> nList,
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
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
377Eigen::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
386 std::vector<ring::strucType>
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
435Eigen::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
444 std::vector<ring::strucType>
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
486int tum3::updateRMSDatom(std::vector<std::vector<int>> rings,
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
529int tum3::averageRMSDatom(std::vector<double> *rmsdPerAtom,
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// -----------------------------------------------------------------
581std::vector<cage::Cage> tum3::topoBulkCriteria(
582 std::string path, std::vector<std::vector<int>> rings,
583 std::vector<std::vector<int>> nList,
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
590 std::vector<int>
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// -----------------------------------------------------------------
645 molSys::PointCloud<molSys::Point<double>, double> *yCloud, std::string path,
646 std::vector<std::vector<int>> rings, std::vector<cage::Cage> cageList,
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
653 std::vector<bool>
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
801std::vector<int> tum3::atomsFromCages(std::vector<std::vector<int>> rings,
802 std::vector<cage::Cage> cageList,
803 std::vector<int> clusterCages) {
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}
File containing functions used specific to bulk topological unit matching (TUM) criterion.
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 > > neighbourListByIndex(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int > > nList)
std::vector< std::vector< int > > neighListO(double rcutoff, molSys::PointCloud< molSys::Point< double >, double > *yCloud, int typeI)
std::vector< std::vector< int > > ringNetwork(std::vector< std::vector< int > > nList, int maxDepth)
Definition franzblau.cpp:32
int getAtomTypesTopoBulk(std::vector< std::vector< int > > rings, std::vector< ring::strucType > ringType, std::vector< cage::iceType > *atomTypes)
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.
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.
std::vector< int > findDDC(std::vector< std::vector< int > > rings, std::vector< strucType > *ringType, std::vector< int > listHC, std::vector< cage::Cage > *cageList)
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)
std::vector< int > findMixedRings(std::vector< std::vector< int > > rings, std::vector< strucType > *ringType, std::vector< int > *listDDC, std::vector< int > *listHC)
Eigen::MatrixXd buildRefHC(std::string fileName)
Build a reference Hexagonal cage, reading in from a template XYZ file.
Definition bulkTUM.cpp:377
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
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 averageRMSDatom(std::vector< double > *rmsdPerAtom, std::vector< int > *noOfCommonAtoms)
Average the RMSD per atom.
Definition bulkTUM.cpp:529
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 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 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
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
int clearRingList(std::vector< std::vector< int > > &rings)
Erases memory for a vector of vectors for a list of rings.
Definition ring.cpp:22
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
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
molSys::PointCloud< molSys::Point< double >, double > readXYZ(std::string filename)
Function for reading in atom coordinates from an XYZ file.
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.
Eigen::MatrixXd changeHexCageOrder(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< int > basal1, std::vector< int > basal2, int startingIndex=0)
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.
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.
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