franzblau.cpp
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------------
2 // d-SEAMS - Deferred Structural Elucidation Analysis for Molecular Simulations
3 //
4 // Copyright (c) 2018--present d-SEAMS core team
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the MIT License as published by
8 // the Open Source Initiative.
9 //
10 // A copy of the MIT License is included in the LICENSE file of this repository.
11 // You should have received a copy of the MIT License along with this program.
12 // If not, see <https://opensource.org/licenses/MIT>.
13 //-----------------------------------------------------------------------------------
14 
15 #include <franzblau.hpp>
16 
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 
65  int maxDepth) {
66  //
67  primitive::Graph fullGraph; // Graph object
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 
116 int 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 
193  molSys::PointCloud<molSys::Point<double>, double> *yCloud,
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 
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
317  emptyTempRings; // Empty vector of vectors to swap
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 
397 int 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  //
447  std::vector<std::vector<int>> tempRings;
448  tempPts.swap(currentGraph->pts);
449  tempRings.swap(currentGraph->rings);
450  return *currentGraph;
451 }
T clear(T... args)
File for generating shortest-path rings according to the Franzblau algorithm.
Graph restoreEdgesFromIndices(Graph *fullGraph, std::vector< std::vector< int >> nList)
Definition: franzblau.cpp:283
Graph populateGraphFromNListID(molSys::PointCloud< molSys::Point< double >, double > *yCloud, std::vector< std::vector< int >> neighHbondList)
Definition: franzblau.cpp:192
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)
Definition: franzblau.cpp:248
Graph removeNonSPrings(Graph *fullGraph)
Removes the non-SP rings, using the Franzblau shortest path criterion.
Definition: franzblau.cpp:307
std::vector< std::vector< int > > ringNetwork(std::vector< std::vector< int >> nList, int maxDepth)
Definition: franzblau.cpp:32
std::vector< int > neighListIndex
This is the index according to pointCloud.
Definition: franzblau.hpp:92
std::vector< std::vector< int > > rings
Definition: franzblau.hpp:112
Graph clearGraph(Graph *currentGraph)
Function for clearing vectors in Graph after multiple usage.
Definition: franzblau.cpp:444
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.
Definition: franzblau.cpp:397
int findRings(Graph *fullGraph, int v, std::vector< int > *visited, int maxDepth, int depth, int root=-1)
Main function that searches for all rings.
Definition: franzblau.cpp:116
std::vector< Vertex > pts
Definition: franzblau.hpp:109
T min(T... args)
T push_back(T... args)
T size(T... args)
This contains a collection of points; contains information for a particular frame.
Definition: mol_sys.hpp:170
This contains per-particle information.
Definition: mol_sys.hpp:149
This is a per-frame object, containing all the vertices for the particular frame, along with the vect...
Definition: franzblau.hpp:108
This is a collection of elements, for each point, required for graph traversal.
Definition: franzblau.hpp:90
T swap(T... args)