source: src/Graph/CyclicStructureAnalysis.cpp@ 3fbdca

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 3fbdca was ec7511, checked in by Frederik Heber <heber@…>, 11 years ago

FIX: CyclicStructureAnalysis falsely used DFS, skipped some cycles.

  • FIX: CyclicStructureAnalysis did use DFS instead of BFS for finding cycles. Note that CyclicStructureAnalysis with coronene would find supercycles and not the smaller interconnected ones.
  • FIX: Cycles were skipped when all bonds marked cyclic, not enough. In interconnected aromatic rings, bonds may very well be marked as cyclic from earlier extraction of cycles and yet the specific cycle might not have been found yet (e.g. coronene). In this case we now check whether this particular cycle has already been extracted and only skip if so.
  • TESTFIX: added new fragmentation regression tests on some metallic systems.
  • this is mainly for regression on bond graph detection and cycle analysis.
  • Property mode set to 100644
File size: 19.3 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * CyclicStructureAnalysis.cpp
25 *
26 * Created on: Feb 16, 2011
27 * Author: heber
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include "CodePatterns/MemDebug.hpp"
36
37#include "CyclicStructureAnalysis.hpp"
38
39#include <algorithm>
40
41#include "Atom/atom.hpp"
42#include "Bond/bond.hpp"
43#include "CodePatterns/Assert.hpp"
44#include "CodePatterns/Info.hpp"
45#include "CodePatterns/Log.hpp"
46#include "CodePatterns/Verbose.hpp"
47#include "Element/element.hpp"
48#include "molecule.hpp"
49
50CyclicStructureAnalysis::CyclicStructureAnalysis(const enum HydrogenTreatment _treatment) :
51 treatment(_treatment)
52{}
53
54CyclicStructureAnalysis::~CyclicStructureAnalysis()
55{}
56
57/** Initialise vertex as white with no predecessor, no shortest path(-1), color white.
58 * \param atom_id id of atom whose node we address
59 */
60void CyclicStructureAnalysis::InitNode(atomId_t atom_id)
61{
62 ShortestPathList[atom_id] = -1;
63 PredecessorList[atom_id] = 0;
64 ColorList[atom_id] = GraphEdge::white;
65}
66
67void CyclicStructureAnalysis::Reset()
68{
69 // clear what's present
70 ShortestPathList.clear();
71 PredecessorList.clear();
72 ColorList.clear();
73 BFSStack.clear();
74 TouchedStack.clear();
75}
76
77/** Clean the accounting structure for all nodes touched so far.
78 */
79void CyclicStructureAnalysis::CleanAllTouched()
80{
81 atom *Walker = NULL;
82 while (!TouchedStack.empty()) {
83 Walker = TouchedStack.front();
84 TouchedStack.pop_front();
85 PredecessorList[Walker->getNr()] = NULL;
86 ShortestPathList[Walker->getNr()] = -1;
87 ColorList[Walker->getNr()] = GraphEdge::white;
88 }
89}
90
91/** Resets shortest path list and BFSStack.
92 * \param *&Walker current node, pushed onto BFSStack and TouchedStack
93 */
94void CyclicStructureAnalysis::InitializeToRoot(atom *&Root)
95{
96 ColorList.clear();
97 ShortestPathList.clear();
98 ShortestPathList[Root->getNr()] = 0;
99 PredecessorList.clear();
100 BFSStack.clear(); // start with empty BFS stack
101 BFSStack.push_front(Root);
102 TouchedStack.push_front(Root);
103}
104
105/** Performs a BFS from \a *Root, trying to find the same node and hence a cycle.
106 * \param OtherAtom pointing to Root on return indicating found cycle
107 * \param *&BackEdge the edge from root that we don't want to move along
108 */
109void CyclicStructureAnalysis::CyclicBFSFromRootToRoot(atom *&OtherAtom, bond::ptr &BackEdge)
110{
111 atom *Walker = NULL;
112 do { // look for Root
113 ASSERT(!BFSStack.empty(), "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - BFSStack is empty!");
114 Walker = BFSStack.back();
115 BFSStack.pop_back();
116 LOG(2, "INFO: Current Walker is " << *Walker << ", we look for SP to Root " << *Root << ".");
117 const BondList& ListOfBonds = Walker->getListOfBonds();
118 for (BondList::const_iterator Runner = ListOfBonds.begin();
119 Runner != ListOfBonds.end();
120 ++Runner) {
121 if ((*Runner) != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
122 OtherAtom = (*Runner)->GetOtherAtom(Walker);
123 if ((treatment == IncludeHydrogen) || (OtherAtom->getType()->getAtomicNumber() != 1)) {
124 LOG(2, "INFO: Current OtherAtom is: " << OtherAtom->getName() << " for bond " << *(*Runner) << ".");
125 if (ColorList[OtherAtom->getNr()] == GraphEdge::white) {
126 TouchedStack.push_front(OtherAtom);
127 ColorList[OtherAtom->getNr()] = GraphEdge::lightgray;
128 PredecessorList[OtherAtom->getNr()] = Walker; // Walker is the predecessor
129 ShortestPathList[OtherAtom->getNr()] = ShortestPathList[Walker->getNr()] + 1;
130 LOG(2, "INFO: Coloring OtherAtom " << OtherAtom->getName() << " lightgray, its predecessor is " << Walker->getName() << " and its Shortest Path is " << ShortestPathList[OtherAtom->getNr()] << " egde(s) long.");
131 //if (ShortestPathList[OtherAtom->getNr()] < MinimumRingSize[Walker->GetTrueFather()->getNr()]) { // Check for maximum distance
132 LOG(3, "ACCEPT: Putting OtherAtom " << OtherAtom->getName() << " into queue.");
133 BFSStack.push_front(OtherAtom);
134 //}
135 } else {
136 LOG(3, "REJECT: Not Adding, has already been visited.");
137 }
138 if (OtherAtom == Root)
139 break;
140 } else {
141 LOG(2, "INFO: Skipping hydrogen atom " << *OtherAtom << ".");
142 ColorList[OtherAtom->getNr()] = GraphEdge::black;
143 }
144 } else {
145 LOG(2, "REJECT: Bond " << *(*Runner) << " not Visiting, is the back edge.");
146 }
147 }
148 ColorList[Walker->getNr()] = GraphEdge::black;
149 LOG(1, "INFO: Coloring Walker " << Walker->getName() << " " << GraphEdge::getColorName(ColorList[Walker->getNr()]) << ".");
150 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
151 // step through predecessor list
152 LOG(4, "DEBUG: Checking whether all predecessors are already marked cyclic ...");
153 while (OtherAtom != BackEdge->rightatom) { // Note that leftatom is Root itself
154 if (!OtherAtom->GetTrueFather()->IsCyclic) { // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
155 LOG(4, "\tDEBUG: OtherAtom " << *OtherAtom << " is not cyclic, breaking.");
156 break;
157 } else
158 OtherAtom = PredecessorList[OtherAtom->getNr()];
159 }
160 LOG(4, "DEBUG: Checking done.");
161 // if each atom in found cycle is cyclic, loop's been found before already
162 if (OtherAtom == BackEdge->rightatom) { // loop got round completely
163 LOG(3, "INFO: All bonds are marked cyclic already, checking allcycles whether cycle is already present.");
164 const cycle_t currentcycle = extractCurrentCycle(BackEdge);
165 const cycles_t::const_iterator iter =
166 std::find(allcycles.begin(), allcycles.end(), currentcycle);
167 if (iter == allcycles.end()) { // not found
168 OtherAtom = Root;
169 LOG(2, "INFO: Cycle is not present.");
170 LOG(2, "INFO: We have reached Root " << *OtherAtom << " and may extract the cycle.");
171 } else {
172 LOG(2, "INFO: Cycle is already present.");
173 do {
174 ASSERT(!TouchedStack.empty(), "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - TouchedStack is empty!");
175 OtherAtom = TouchedStack.front();
176 TouchedStack.pop_front();
177 if (PredecessorList[OtherAtom->getNr()] == Walker) {
178 LOG(4, "INFO: Removing " << *OtherAtom << " from lists and stacks.");
179 PredecessorList[OtherAtom->getNr()] = NULL;
180 ShortestPathList[OtherAtom->getNr()] = -1;
181 ColorList[OtherAtom->getNr()] = GraphEdge::white;
182 // rats ... deque has no find()
183 std::deque<atom *>::iterator iter = find(
184 BFSStack.begin(),
185 BFSStack.end(),
186 OtherAtom);
187 ASSERT(iter != BFSStack.end(),
188 "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - can't find "+toString(*OtherAtom)+" on stack!");
189 BFSStack.erase(iter);
190 }
191 } while ((!TouchedStack.empty()) && (PredecessorList[OtherAtom->getNr()] == NULL));
192 TouchedStack.push_front(OtherAtom); // last was wrongly popped
193 OtherAtom = BackEdge->rightatom; // set to not Root
194 }
195 } else {
196 OtherAtom = Root;
197 LOG(2, "INFO: We have reached Root " << *OtherAtom << " and may extract the cycle.");
198 }
199 }
200 } while ((!BFSStack.empty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->getNr()] < MinimumRingSize[Walker->GetTrueFather()->getNr()])));
201}
202
203/** Extracts cycle from BFSAccounting::PredecessorList with given \a BackEdge and current \a Root.
204 *
205 * \param BackEdge back edge of this cycle
206 */
207CyclicStructureAnalysis::cycle_t CyclicStructureAnalysis::extractCurrentCycle(
208 bond::ptr &BackEdge)
209{
210 CyclicStructureAnalysis::cycle_t currentcycle;
211 atom *Walker = Root;
212 currentcycle.insert(Walker->GetTrueFather()->getId());
213 std::stringstream output;
214 while (Walker != BackEdge->rightatom) { // leftatom is root
215 Walker = PredecessorList[Walker->getNr()];
216 Walker->GetTrueFather()->IsCyclic = true;
217 output << Walker->getName() << " <-> ";
218#ifndef NDEBUG
219 std::pair< cycle_t::iterator, bool > inserter =
220#endif
221 currentcycle.insert(Walker->GetTrueFather()->getId());
222 ASSERT( inserter.second,
223 "CyclicStructureAnalysis::RetrieveCycleMembers() - we already inserted "
224 +toString(Walker->GetTrueFather()->getId())+" into currentcycle.");
225 }
226 LOG(3, "INFO: " << output.str() << Root->getName());
227 return currentcycle;
228}
229
230/** Climb back the BFSAccounting::PredecessorList and find cycle members.
231 * \param *&OtherAtom
232 * \param *&BackEdge denotes the edge we did not want to travel along when doing CyclicBFSFromRootToRoot()
233 * \param &BFS accounting structure
234 * \param &MinRingSize global minimum distance from one node without encountering oneself, set on return
235 * \param &NumCyles number of cycles in graph
236 */
237void CyclicStructureAnalysis::RetrieveCycleMembers(
238 atom *&OtherAtom,
239 bond::ptr &BackEdge,
240 int &MinRingSize,
241 int &NumCycles)
242{
243 atom *Walker = NULL;
244 int RingSize = -1;
245
246 if (OtherAtom == Root) {
247 // now climb back the predecessor list and thus find the cycle members
248 NumCycles++;
249 Root->GetTrueFather()->IsCyclic = true;
250
251 // exctract cycle
252 {
253 allcycles.push_back(extractCurrentCycle(BackEdge));
254 CyclicStructureAnalysis::cycle_t &lastcycle = allcycles.back();
255 RingSize = lastcycle.size();
256 LOG(0, "INFO: " << "Found ring contains: " << lastcycle << " with a length of " << RingSize);
257 }
258
259 // walk through all and set MinimumRingSize
260 Walker = Root;
261 if ((MinimumRingSize.count(Walker->GetTrueFather()->getNr()) == 0)
262 || (RingSize < MinimumRingSize[Walker->GetTrueFather()->getNr()])) {
263 MinimumRingSize[Walker->GetTrueFather()->getNr()] = RingSize;
264 } else {
265 LOG(3, "INFO: Not setting MinimumRingSize of "<< *(Walker->GetTrueFather())
266 << " to " << RingSize << " which is already set to "
267 << MinimumRingSize[Walker->GetTrueFather()->getNr()] << ".");
268 }
269 while (Walker != BackEdge->rightatom) { // note that Root is leftatom
270 Walker = PredecessorList[Walker->getNr()];
271 if ((MinimumRingSize.count(Walker->GetTrueFather()->getNr()) == 0)
272 || (RingSize < MinimumRingSize[Walker->GetTrueFather()->getNr()]))
273 MinimumRingSize[Walker->GetTrueFather()->getNr()] = RingSize;
274 }
275 if ((RingSize < MinRingSize) || (MinRingSize == -1))
276 MinRingSize = RingSize;
277 } else {
278 LOG(1, "INFO: No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Root->GetTrueFather()->getNr()] << " found.");
279 }
280}
281
282/** From a given node performs a BFS to touch the next cycle, for whose nodes \a MinimumRingSize is set and set it accordingly.
283 * \param *&Walker node to look for closest cycle from, i.e. \a MinimumRingSize is set for this node
284 * \param AtomCount number of nodes in graph
285 */
286void CyclicStructureAnalysis::BFSToNextCycle(atom *Walker)
287{
288 atom *Root = Walker;
289 atom *OtherAtom = Walker;
290
291 Reset();
292
293 InitializeToRoot(Walker);
294 while (OtherAtom != NULL) { // look for Root
295 ASSERT(!BFSStack.empty(), "CyclicStructureAnalysis_BFSToNextCycle() - BFSStack is empty!");
296 Walker = BFSStack.front();
297 BFSStack.pop_front();
298 LOG(2, "INFO: Current Walker is " << *Walker << ", BFS-stepping away from Root " << *Root << ".");
299 const BondList& ListOfBonds = Walker->getListOfBonds();
300 for (BondList::const_iterator Runner = ListOfBonds.begin();
301 Runner != ListOfBonds.end();
302 ++Runner) {
303 // "removed (*Runner) != BackEdge) || " from next if, is u
304
305 // only walk along DFS spanning tree (otherwise we always find SP of 1
306 // being backedge Binder), but terminal hydrogens may be connected via
307 // backedge, hence extra check
308// if ((ListOfBonds.size() != 1)) {
309 OtherAtom = (*Runner)->GetOtherAtom(Walker);
310 if ((treatment == IncludeHydrogen) || (OtherAtom->getType()->getAtomicNumber() != 1)) {
311 LOG(2, "INFO: Current OtherAtom is: " << OtherAtom->getName() << " for bond " << *(*Runner) << ".");
312 if (ColorList[OtherAtom->getNr()] == GraphEdge::white) {
313 TouchedStack.push_front(OtherAtom);
314 ColorList[OtherAtom->getNr()] = GraphEdge::lightgray;
315 PredecessorList[OtherAtom->getNr()] = Walker; // Walker is the predecessor
316 ShortestPathList[OtherAtom->getNr()] = ShortestPathList[Walker->getNr()] + 1;
317 LOG(2, "ACCEPT: Coloring OtherAtom "
318 << OtherAtom->getName() << " lightgray, its predecessor is "
319 << Walker->getName() << " and its Shortest Path is "
320 << ShortestPathList[OtherAtom->getNr()] << " egde(s) long.");
321 // distance is a locally optimal criterion (we have eliminated all
322 // cycles already). Hence, we may assume that all set MinimumRingSize
323 // correspond to shortest distances to cycles. I.e., as soon as we reach
324 // as set MinimumRingSize we may use it and the current shortest path
325 // distance to it
326 if (MinimumRingSize.count(OtherAtom->GetTrueFather()->getNr())) {
327 LOG(2, "SUCCESS: Found set MinimumRingSize at " << *OtherAtom
328 << ", walking back to Root " << *Root << ".");
329 // set all predecessors
330 const unsigned int shorttestpath = ShortestPathList[OtherAtom->getNr()];
331 atom *Backwalker = OtherAtom;
332 while (Backwalker != Root) {
333 Backwalker = PredecessorList[Backwalker->getNr()];
334 MinimumRingSize[Backwalker->GetTrueFather()->getNr()] =
335 (shorttestpath - ShortestPathList[Backwalker->getNr()])
336 + MinimumRingSize[OtherAtom->GetTrueFather()->getNr()];
337 LOG(2, "Setting MinimumRingSize of " << *Backwalker << " to "
338 << MinimumRingSize[Backwalker->GetTrueFather()->getNr()] << ".");
339 }
340 OtherAtom = NULL; //break;
341 break;
342 } else
343 BFSStack.push_front(OtherAtom);
344 } else {
345 LOG(3, "REJECT: Not Adding, has already been visited.");
346 }
347 } else {
348 LOG(3, "REJECT: Not Visiting, is a back edge to hydrogen.");
349 }
350// }
351 }
352 ColorList[Walker->getNr()] = GraphEdge::black;
353 LOG(1, "INFO: Coloring Walker " << Walker->getName() << " " << GraphEdge::getColorName(ColorList[Walker->getNr()]) << ".");
354 }
355}
356
357/** All nodes that are not in cycles get assigned a \a *&MinimumRingSize by BFS to next cycle.
358 * \param *&MinimumRingSize array with minimum distance without encountering oneself for each atom
359 * \param MinRingSize global minium distance
360 * \param NumCyles number of cycles in graph
361 */
362void CyclicStructureAnalysis::AssignRingSizetoNonCycleMembers(const int MinRingSize, const int NumCycles)
363{
364 atom *Walker = NULL;
365 if (MinRingSize != -1) { // if rings are present
366 // go over all atoms
367 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
368 for (World::AtomComposite::const_iterator iter = allatoms.begin();
369 iter != allatoms.end();
370 ++iter) {
371 Walker = *iter;
372
373 if (MinimumRingSize.find(Walker->GetTrueFather()->getNr()) == MinimumRingSize.end()) { // check whether MinimumRingSize is set, if not BFS to next where it is
374 LOG(1, "---------------------------------------------------------------------------------------------------------");
375 BFSToNextCycle(Walker);
376 }
377 ASSERT(MinimumRingSize.find(Walker->GetTrueFather()->getNr()) != MinimumRingSize.end(),
378 "CyclicStructureAnalysis::AssignRingSizetoNonCycleMembers() - BFSToNextCycle did not set MinimumRingSize of "
379 +toString(*(Walker->GetTrueFather()))+".");
380 LOG(1, "INFO: Minimum ring size of " << *Walker << " is " << MinimumRingSize[Walker->GetTrueFather()->getNr()] << ".");
381 }
382 LOG(1, "INFO: Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycle(s) total.");
383 } else
384 LOG(1, "INFO: No rings were detected in the molecular structure.");
385}
386
387/** Analyses the cycles found and returns minimum of all cycle lengths.
388 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
389 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
390 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
391 * as cyclic and print out the cycles.
392 * \param *BackEdgeStack stack with all back edges found during DFS scan. Beware: This stack contains the bonds from the total molecule, not from the subgraph!
393 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
394 */
395void CyclicStructureAnalysis::operator()(std::deque<bond::ptr > * BackEdgeStack)
396{
397 Info FunctionInfo("CyclicStructureAnalysis");
398 atom *Walker = NULL;
399 atom *OtherAtom = NULL;
400 bond::ptr BackEdge;
401 int NumCycles = 0;
402 int MinRingSize = -1;
403
404 // clear cycle container
405 allcycles.clear();
406
407 {
408 std::stringstream output;
409 output << "Back edge list - ";
410 for (std::deque<bond::ptr >::const_iterator iter = BackEdgeStack->begin();
411 iter != BackEdgeStack->end(); ++iter)
412 output << **iter << " ";
413 LOG(0, output.str());
414 }
415
416 LOG(1, "STATUS: Analysing cycles ... ");
417 NumCycles = 0;
418 while (!BackEdgeStack->empty()) {
419 BackEdge = BackEdgeStack->front();
420 BackEdgeStack->pop_front();
421 // this is the target
422 Root = BackEdge->leftatom;
423 // this is the source point
424 Walker = BackEdge->rightatom;
425
426 InitializeToRoot(Walker);
427
428 LOG(1, "---------------------------------------------------------------------------------------------------------");
429 OtherAtom = NULL;
430 // go to next cycle via BFS
431 CyclicBFSFromRootToRoot(OtherAtom, BackEdge);
432 // get all member nodes of this cycle
433 RetrieveCycleMembers(OtherAtom, BackEdge, MinRingSize, NumCycles);
434
435 CleanAllTouched();
436 }
437 AssignRingSizetoNonCycleMembers(MinRingSize, NumCycles);
438}
439
440/** Output a list of flags, stating whether the bond was visited or not.
441 * \param *list list to print
442 */
443void CyclicStructureAnalysis::OutputAlreadyVisited(int *list)
444{
445 std::stringstream output;
446 output << "Already Visited Bonds:\t";
447 for (int i = 1; i <= list[0]; i++)
448 output << list[i] << " ";
449 LOG(0, output.str());
450}
451
452const std::map<atomId_t, int >& CyclicStructureAnalysis::getMinimumRingSize() const
453{
454 return MinimumRingSize;
455}
Note: See TracBrowser for help on using the repository browser.