topo_bulk.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 <topo_bulk.hpp>
16
17// -----------------------------------------------------------------------------------------------------
18// BULK RING SEARCH ONLY
19// -----------------------------------------------------------------------------------------------------
20
45 std::string path, std::vector<std::vector<int>> rings,
46 std::vector<std::vector<int>> nList,
47 molSys::PointCloud<molSys::Point<double>, double> *yCloud, int maxDepth,
48 int firstFrame) {
49 //
50 std::vector<std::vector<int>>
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
55 std::vector<int>
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
135 std::string path, std::vector<std::vector<int>> rings,
136 std::vector<std::vector<int>> nList,
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
143 std::vector<int>
144 listMixed; // Vector for ring indices of rings that are both DDC and HC
145 std::vector<ring::strucType>
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;
150 std::vector<std::vector<int>>
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
154 std::vector<cage::iceType>
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
285std::vector<int> ring::findDDC(std::vector<std::vector<int>> rings,
286 std::vector<ring::strucType> *ringType,
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
297 std::vector<bool>
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
416bool ring::conditionOneDDC(std::vector<std::vector<int>> rings,
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
488bool ring::conditionTwoDDC(std::vector<std::vector<int>> rings,
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
495 std::vector<int>
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
569bool ring::conditionThreeDDC(std::vector<std::vector<int>> rings,
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
651std::vector<int> ring::findHC(std::vector<std::vector<int>> rings,
652 std::vector<ring::strucType> *ringType,
653 std::vector<std::vector<int>> nList,
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)
660 std::vector<int>
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
665 std::vector<bool>
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
786bool ring::basalConditions(std::vector<std::vector<int>> nList,
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
908bool ring::basalNeighbours(std::vector<std::vector<int>> nList,
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
981bool ring::notNeighboursOfRing(std::vector<std::vector<int>> nList,
982 std::vector<int> *triplet,
983 std::vector<int> *ring) {
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
987 std::vector<int>::iterator it;
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
1021int ring::findPrismatic(std::vector<std::vector<int>> rings,
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
1117std::vector<int> ring::findMixedRings(std::vector<std::vector<int>> rings,
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
1164int ring::getAtomTypesTopoBulk(std::vector<std::vector<int>> rings,
1165 std::vector<ring::strucType> ringType,
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
1247int ring::getStrucNumbers(std::vector<ring::strucType> ringType,
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
1329 std::vector<std::vector<int>> rings, std::vector<ring::strucType> *ringType,
1330 std::vector<std::vector<int>> nList,
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
1429bool prism3::basalPrismConditions(std::vector<std::vector<int>> nList,
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
1516bool prism3::relaxedPrismConditions(std::vector<std::vector<int>> nList,
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
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}
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
int getAtomTypesTopoBulk(std::vector< std::vector< int > > rings, std::vector< ring::strucType > ringType, std::vector< cage::iceType > *atomTypes)
bool notNeighboursOfRing(std::vector< std::vector< int > > nList, std::vector< int > *triplet, std::vector< int > *ring)
bool conditionTwoDDC(std::vector< std::vector< int > > rings, std::vector< int > *peripheralRings, int iring)
bool conditionOneDDC(std::vector< std::vector< int > > rings, std::vector< int > *peripheralRings, int iring)
bool basalPrismConditions(std::vector< std::vector< int > > nList, std::vector< int > *basal1, std::vector< int > *basal2)
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)
bool conditionThreeDDC(std::vector< std::vector< int > > rings, std::vector< int > *peripheralRings)
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)
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.
bool basalNeighbours(std::vector< std::vector< int > > nList, std::vector< int > *triplet, int atomOne, int atomTwo)
std::vector< int > findDDC(std::vector< std::vector< int > > rings, std::vector< strucType > *ringType, std::vector< int > listHC, std::vector< cage::Cage > *cageList)
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.
bool relaxedPrismConditions(std::vector< std::vector< int > > nList, std::vector< int > *basal1, std::vector< int > *basal2)
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
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)
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.
std::vector< int > findMixedRings(std::vector< std::vector< int > > rings, std::vector< strucType > *ringType, std::vector< int > *listDDC, std::vector< int > *listHC)
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 assignPolygonType(std::vector< std::vector< int > > rings, std::vector< int > *atomTypes, std::vector< int > nRings)
Definition ring.cpp:40
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
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 ...
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)
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)
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.