franzblau.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 <franzblau.hpp>
16
31std::vector<std::vector<int>>
32primitive::ringNetwork(std::vector<std::vector<int>> nList, int maxDepth) {
33 //
34 primitive::Graph fullGraph; // Graph object, contains the connectivity
35 // information from the neighbourlist
36
37 // Find all possible rings, using backtracking. This may contain non-primitive
38 // rings as well.
39 fullGraph = primitive::countAllRingsFromIndex(nList, maxDepth);
40
41 // Remove all non-SP rings using the Franzblau algorithm.
42 fullGraph = primitive::removeNonSPrings(&fullGraph);
43
44 // The rings vector of vectors inside the fullGraph graph object is the ring
45 // network information we want
46 return fullGraph.rings;
47}
48
64primitive::countAllRingsFromIndex(std::vector<std::vector<int>> neighHbondList,
65 int maxDepth) {
66 //
67 primitive::Graph fullGraph; // Graph object
68 std::vector<int>
69 visited; // Contains the indices (NOT IDs) visited for a particular node
70 int depth; // Current depth
71
72 // ------------------------------
73 // Init
74 // Initialize the graph object with all the information from the neighbour
75 // list (of indices only)
76 fullGraph = primitive::populateGraphFromIndices(neighHbondList);
77 // ------------------------------
78 // Loop through every vertex
79 for (int iatom = 0; iatom < neighHbondList.size(); iatom++) {
80 visited.clear();
81 depth = 0;
82 // Call the function for getting rings
83 primitive::findRings(&fullGraph, iatom, &visited, maxDepth, depth);
84 } // loop through every vertex
85 // ------------------------------
86 // Restore back-up of the edges (some may have been removed)
87 fullGraph = primitive::restoreEdgesFromIndices(&fullGraph, neighHbondList);
88 // ------------------------------
89
90 return fullGraph;
91}
92
116int primitive::findRings(Graph *fullGraph, int v, std::vector<int> *visited,
117 int maxDepth, int depth, int root) {
118 //
119 int nnumNeighbours; // Number of nearest neighbours for iNode
120 int n; // Node of a neighbour (index)
121 // -------------
122 // For the first call:
123 if (root == -1) {
124 root = v; // Init the root as the current node
125 fullGraph->pts[v].inGraph = false; // Remove the root from the graph
126 } // first call
127 //
128 // Checks
129 if (depth >= maxDepth) {
130 return 1; // false?
131 } // searched until the maximum length specified
132 //
133 // Add the current node to the visited vector
134 visited->push_back(v);
135 // -------------
136 // Depth-first search
137 // 1. Pick a root node (above)
138 // 2. Search all the neighbouring nodes
139 // 3. Start a recursion call, from the second nearest neighbours
140 // 3(i) If the neighbour equals the root (selected in 1), ring has been found!
141 // 3(ii) Or else search for all the unvisited neighbours
142 // 4. Remove the root node from the graph
143 // 5. Update the vector of vectors containing all rings
144 // -------------
145 // Start the search
146 depth += 1; // Go to the next layer
147 nnumNeighbours = fullGraph->pts[v].neighListIndex.size();
148 // Loop through the neighbours of iNode
149 for (int j = 0; j < nnumNeighbours; j++) {
150 n = fullGraph->pts[v].neighListIndex[j]; // Neighbour index
151 // Has a ring been found?!
152 if (depth > 2 && n == root) {
153 // Add the visited vector to the rings vector of vector
154 fullGraph->rings.push_back(*visited);
155 } // A ring has been found!
156 // Otherwise search all the neighbours which have not been searched already
157 else if (fullGraph->pts[n].inGraph) {
158 fullGraph->pts[n].inGraph = false; // Set to false now
159 // Recursive call
160 primitive::findRings(fullGraph, n, visited, maxDepth, depth, root);
161 fullGraph->pts[n].inGraph = true; // Put n back in the graph
162 } // Search the other unsearched neighbours
163 } // end of search through all neighbours
164 // -------------
165 // When the depth is 2, remove just the root from the neighbours of iNode
166 if (depth == 2) {
167 // Search for root in the neighbour list of v
168 for (int j = 0; j < fullGraph->pts[v].neighListIndex.size(); j++) {
169 if (root == fullGraph->pts[v].neighListIndex[j]) {
170 fullGraph->pts[v].neighListIndex.erase(
171 fullGraph->pts[v].neighListIndex.begin() + j);
172 } // end of erase
173 } // end of search
174 } // remove root not edges
175
176 //
177 (*visited).pop_back();
178 //
179 return 0;
180}
181
194 std::vector<std::vector<int>> neighHbondList) {
195 //
196 primitive::Graph fullGraph; // Contains all the information of the pointCloud
197 primitive::Vertex iVertex; // The vertex corresponding to a particular point
198 int nnumNeighbours; // Number of nearest neighbours for iatom
199 std::vector<int> iNeigh; // Neighbours of the current iatom
200 int jatomID; // Atom ID of the nearest neighbour
201 int jatomIndex; // Atom index of the nearest neighbour
202 // ------------------------------
203 // Loop through every point in yCloud
204 for (int iatom = 0; iatom < yCloud->nop; iatom++) {
205 // -----
206 // Update the neighbours of iatom (only the indices!)
207 iNeigh.clear(); // init
208 nnumNeighbours = neighHbondList[iatom].size() -
209 1; // The first element is atomID of iatom
210 for (int j = 1; j <= nnumNeighbours; j++) {
211 jatomID = neighHbondList[iatom][j]; // Atom ID
212 // Get the atom index for the vector nearest neighbour list
213 auto it = yCloud->idIndexMap.find(jatomID);
214 if (it != yCloud->idIndexMap.end()) {
215 jatomIndex = it->second;
216 } // found jatomIndex
217 else {
218 std::cerr << "Panic induced!\n";
219 return fullGraph;
220 } // jatomIndex not found
221 // Update iNeigh
222 iNeigh.push_back(jatomIndex);
223 } // end of loop through nearest neighbours
224 // -----
225 // Update iVertex
226 iVertex.atomIndex = iatom;
227 iVertex.neighListIndex = iNeigh;
228 // Add to the Graph object
229 fullGraph.pts.push_back(iVertex);
230 } // end of loop through every iatom
231 // ------------------------------
232
233 return fullGraph;
234}
235
248primitive::populateGraphFromIndices(std::vector<std::vector<int>> nList) {
249 //
250 primitive::Graph fullGraph; // Contains all the information of the pointCloud
251 primitive::Vertex iVertex; // The vertex corresponding to a particular point
252 int nnumNeighbours; // Number of nearest neighbours for iatom
253 int iatom, jatom; // Atom index being saved
254 // ------------------------------
255 // Loop through every point in nList
256 for (int i = 0; i < nList.size(); i++) {
257 iatom = nList[i][0]; // Atom index of i
258 // neighListIndex is simply the i^th row of nList
259 //
260 // Update iVertex
261 iVertex.atomIndex = iatom;
262 iVertex.neighListIndex = nList[i];
263 // Add to the Graph object
264 fullGraph.pts.push_back(iVertex);
265 } // end of loop through iatom
266
267 return fullGraph;
268}
269
284 std::vector<std::vector<int>> nList) {
285 //
286 // ------------------------------
287 // Loop through every point in nList
288 for (int i = 0; i < nList.size(); i++) {
289 // neighListIndex is simply the i^th row of nList
290 // Update the neighListIndex list in the graph object
291 fullGraph->pts[i].neighListIndex = nList[i];
292 } // end of loop through iatom
293
294 return *fullGraph;
295}
296
308 //
309 int nVertices = fullGraph->pts.size(); // Number of vertices in the graph
310 int nRings = fullGraph->rings.size(); // Number of rings
311 std::vector<bool> ringsToRemove; // Vector containing the logical values for
312 // removal of the current ring index
313 std::vector<int> currentRing; // Current ring being evaluated
314 int ringSize; // Length of the current ring
315 bool removeRing; // Logical for removing the current ring (true) or not
316 std::vector<std::vector<int>>
317 emptyTempRings; // Empty vector of vectors to swap
318 std::vector<std::vector<int>>
319 primitiveRings; // Vector of vectors of rings after removing non SP rings
320 int currentV; // Current vertex
321 int currentN; // Current neighbour
322 int dist_r; // Distance over ring
323 int dist_g; // Distance over the entire graph
324 int d_jk; // Absolute difference between j and k
325 std::vector<int> path; // Vector containing a path
326 std::vector<int> visited; // Vector containing the visited points
327 // -------------------
328 // Make sure all the vertices are in the graph before removing non-SP rings
329 for (int iVer = 0; iVer < nVertices; iVer++) {
330 fullGraph->pts[iVer].inGraph = true;
331 } // end of loop through every vertex
332 // -------------------
333 // Loop through every ring
334 for (int iRing = 0; iRing < nRings; iRing++) {
335 currentRing = fullGraph->rings[iRing]; // Current ring
336 ringSize = currentRing.size(); // Length of the current ring
337 removeRing = false; // init
338 // Loop through every j^th vertex
339 for (int jVer = 0; jVer < ringSize; jVer++) {
340 // connect with all other, skip j-j (distance=0) and j-(j+1) (nearest
341 // neighbors)
342 for (int kVer = jVer + 2; kVer < ringSize; kVer++) {
343 // If not remove
344 if (!removeRing) {
345 currentV = currentRing[jVer]; // current 'vertex'
346 currentN = currentRing[kVer]; // Current 'neighbour'
347 d_jk = std::abs(jVer - kVer);
348 dist_r = std::min(d_jk, std::abs(d_jk - ringSize)) +
349 1; // Distance over the ring
350 path.clear(); // init
351 visited.clear();
352 // Call shortest path function
353 primitive::shortestPath(fullGraph, currentV, currentN, &path,
354 &visited, dist_r, 0);
355 dist_g = path.size(); // Length of the path over the graph
356 if (dist_g < dist_r) {
357 removeRing = true;
358 } // Decide whether to keep or remove the ring
359 } // If ring is not to be removed
360 } // end of loop through k^th vertex
361 } // end of loop through j^th vertex
362 // Update bool value for removal of currentRing
363 ringsToRemove.push_back(removeRing);
364 } // end of loop through rings
365 // -------------------
366 // Remove all the rings whose indices are given in the ringsToRemove vector
367 for (int i = 0; i < ringsToRemove.size(); i++) {
368 if (!ringsToRemove[i]) {
369 primitiveRings.push_back(fullGraph->rings[i]);
370 } // updates new copy
371 } // end of loop through ringsToRemove
372 // -------------------
373 // Update the graph rings with the primitiveRings
374 emptyTempRings.swap(fullGraph->rings);
375 fullGraph->rings = primitiveRings;
376 // -------------------
377 return *fullGraph;
378}
379
397int primitive::shortestPath(Graph *fullGraph, int v, int goal,
398 std::vector<int> *path, std::vector<int> *visited,
399 int maxDepth, int depth) {
400 int len_path = 0; // Length of the path
401 int nnumNeighbours; // Number of neighbours for a particular v
402 int n; // Index of the nearest neighbour of v
403 // Start the search for the shortest path
404 if (depth < maxDepth) {
405 depth += 1; // One layer below
406 (*visited).push_back(
407 v); // Add the current vertex to the path (visited points)
408 //
409 if (v == goal) {
410 len_path = (*path).size(); // Path of the length of visited points
411 // If the current path is shorter OR this is the first path found
412 if (depth < len_path || len_path == 0) {
413 (*path) = (*visited);
414 maxDepth = depth;
415 } // Current path is the shortest
416 } // Goal reached
417 // Recursive calls to function
418 else {
419 nnumNeighbours = fullGraph->pts[v].neighListIndex.size();
420 // Search all the neighbours
421 for (int j = 0; j < nnumNeighbours; j++) {
422 n = fullGraph->pts[v].neighListIndex[j]; // Index of nearest neighbour
423 // If n has not already been searched:
424 if (fullGraph->pts[n].inGraph == true) {
425 fullGraph->pts[n].inGraph = false; // Set to false
426 primitive::shortestPath(fullGraph, n, goal, path, visited, maxDepth,
427 depth); // Recursive call
428 fullGraph->pts[n].inGraph = true; // Put back in the graph
429 } // If n is in the graph, call recursively
430 } // End of loop over all neighbours
431 } // Goal not reached
432 //
433 // Pop the vector
434 (*visited).pop_back();
435 } // for depth less than maxDepth
436 return 0;
437}
438
445 //
446 std::vector<primitive::Vertex> tempPts;
447 std::vector<std::vector<int>> tempRings;
448 tempPts.swap(currentGraph->pts);
449 tempRings.swap(currentGraph->rings);
450 return *currentGraph;
451}
File for generating shortest-path rings according to the Franzblau algorithm.
Graph countAllRingsFromIndex(std::vector< std::vector< int > > neighHbondList, int maxDepth)
Creates a vector of vectors of all possible rings.
Definition franzblau.cpp:64
Graph populateGraphFromIndices(std::vector< std::vector< int > > nList)
Graph populateGraphFromNListID(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int > > neighHbondList)
Graph removeNonSPrings(Graph *fullGraph)
Removes the non-SP rings, using the Franzblau shortest path criterion.
std::vector< int > neighListIndex
This is the index according to pointCloud.
Definition franzblau.hpp:92
std::vector< std::vector< int > > rings
Graph restoreEdgesFromIndices(Graph *fullGraph, std::vector< std::vector< int > > nList)
Graph clearGraph(Graph *currentGraph)
Function for clearing vectors in Graph after multiple usage.
int shortestPath(Graph *fullGraph, int v, int goal, std::vector< int > *path, std::vector< int > *visited, int maxDepth, int depth=1)
Calculates the shortest path.
int findRings(Graph *fullGraph, int v, std::vector< int > *visited, int maxDepth, int depth, int root=-1)
Main function that searches for all rings.
std::vector< Vertex > pts
std::vector< std::vector< int > > ringNetwork(std::vector< std::vector< int > > nList, int maxDepth)
Definition franzblau.cpp:32
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
This is a per-frame object, containing all the vertices for the particular frame, along with the vect...
This is a collection of elements, for each point, required for graph traversal.
Definition franzblau.hpp:90