source: src/Graph/DepthFirstSearchAnalysis.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 8dbcaf, checked in by Frederik Heber <heber@…>, 11 years ago

FIX: CyclicStructureAnalysis did not work correctly.

  • many errors with local variables that probably should have been in the class.
  • we use OtherAtom in subsequent RetrieveCycleMembers() but we have not given CyclicBFSFromRootToRoot() its ref.
  • the idea now is to use first get all cycles (CyclicBFSFromRootToRoot(). RetrieveCycleMembers()) and then to assign all remaining atoms via AssignRingSizetoNonCycleMembers() with BFSToNextCycle() where we make use of locality property of BFS.
  • Property mode set to 100644
File size: 17.5 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 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * DepthFirstSearchAnalysis.cpp
26 *
27 * Created on: Feb 16, 2011
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "CodePatterns/MemDebug.hpp"
37
38#include "DepthFirstSearchAnalysis.hpp"
39
40#include <algorithm>
41#include <functional>
42
43#include "Atom/atom.hpp"
44#include "Bond/bond.hpp"
45#include "CodePatterns/Assert.hpp"
46#include "CodePatterns/Info.hpp"
47#include "CodePatterns/Log.hpp"
48#include "CodePatterns/Verbose.hpp"
49#include "Descriptors/AtomDescriptor.hpp"
50#include "Descriptors/MoleculeDescriptor.hpp"
51#include "Graph/ListOfLocalAtoms.hpp"
52#include "molecule.hpp"
53#include "MoleculeLeafClass.hpp"
54#include "MoleculeListClass.hpp"
55#include "World.hpp"
56
57DepthFirstSearchAnalysis::DepthFirstSearchAnalysis() :
58 CurrentGraphNr(0),
59 ComponentNumber(0),
60 BackStepping(false)
61{
62 ResetAllBondsToUnused();
63}
64
65DepthFirstSearchAnalysis::~DepthFirstSearchAnalysis()
66{}
67
68void DepthFirstSearchAnalysis::Init()
69{
70 CurrentGraphNr = 0;
71 ComponentNumber = 0;
72 BackStepping = false;
73 std::for_each(World::getInstance().getAtomIter(),World::getInstance().atomEnd(),
74 std::mem_fun(&atom::resetGraphNr));
75 std::for_each(World::getInstance().getAtomIter(),World::getInstance().atomEnd(),
76 std::mem_fun(&atom::InitComponentNr));
77}
78
79
80bond::ptr DepthFirstSearchAnalysis::FindNextUnused(atom *vertex) const
81{
82 const BondList& ListOfBonds = vertex->getListOfBonds();
83 for (BondList::const_iterator Runner = ListOfBonds.begin();
84 Runner != ListOfBonds.end();
85 ++Runner)
86 if ((*Runner)->IsUsed() == GraphEdge::white)
87 return ((*Runner));
88 return bond::ptr();
89}
90
91
92void DepthFirstSearchAnalysis::ResetAllBondsToUnused() const
93{
94 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
95 for(World::AtomComposite::const_iterator AtomRunner = allatoms.begin();
96 AtomRunner != allatoms.end();
97 ++AtomRunner) {
98 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
99 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
100 BondRunner != ListOfBonds.end();
101 ++BondRunner)
102 if ((*BondRunner)->leftatom == *AtomRunner)
103 (*BondRunner)->ResetUsed();
104 }
105}
106
107void DepthFirstSearchAnalysis::SetNextComponentNumber(atom *vertex, int nr) const
108{
109 size_t i = 0;
110 ASSERT(vertex != NULL,
111 "DepthFirstSearchAnalysis::SetNextComponentNumber() - Given vertex is NULL!");
112 const BondList& ListOfBonds = vertex->getListOfBonds();
113 for (; i < ListOfBonds.size(); i++) {
114 if (vertex->ComponentNr[i] == -1) { // check if not yet used
115 vertex->ComponentNr[i] = nr;
116 break;
117 } else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
118 break; // breaking here will not cause error!
119 }
120 ASSERT(i < ListOfBonds.size(),
121 "DepthFirstSearchAnalysis::SetNextComponentNumber() - All Component entries are already occupied!");
122}
123
124
125bool DepthFirstSearchAnalysis::PickLocalBackEdges(const ListOfLocalAtoms_t &ListOfLocalAtoms, std::deque<bond::ptr > *&LocalStack) const
126{
127 bool status = true;
128 if (BackEdgeStack.empty()) {
129 ELOG(1, "Reference BackEdgeStack is empty!");
130 return false;
131 }
132 std::deque<bond::ptr > MyBackEdgeStack = BackEdgeStack;
133
134 do { // go through all bonds and push local ones
135 const bond::ptr &Binder = MyBackEdgeStack.front(); // loop the stack for next item
136 MyBackEdgeStack.pop_front();
137 LOG(3, "INFO: Current candidate edge " << *Binder << ".");
138 const ListOfLocalAtoms_t::const_iterator leftiter = ListOfLocalAtoms.find(Binder->leftatom->getNr());
139 ASSERT( leftiter != ListOfLocalAtoms.end(),
140 "DepthFirstSearchAnalysis::PickLocalBackEdges() - could not find atom id "
141 +toString(Binder->leftatom->getNr())+" in ListOfLocalAtoms.");
142 atom * const Walker = leftiter->second; // get one atom in the reference molecule
143 if (Walker != NULL) { // if this Walker exists in the subgraph ...
144 const BondList& ListOfBonds = Walker->getListOfBonds();
145 for (BondList::const_iterator Runner = ListOfBonds.begin();
146 Runner != ListOfBonds.end();
147 ++Runner) {
148 atom * const OtherAtom = (*Runner)->GetOtherAtom(Walker);
149 const ListOfLocalAtoms_t::const_iterator rightiter = ListOfLocalAtoms.find((*Runner)->rightatom->getNr());
150 if (OtherAtom == rightiter->second) { // found the bond
151 LocalStack->push_front((*Runner));
152 LOG(3, "INFO: Found local edge " << *(*Runner) << ".");
153 break;
154 }
155 }
156 }
157 } while (!MyBackEdgeStack.empty());
158
159 return status;
160}
161
162
163
164void DepthFirstSearchAnalysis::OutputGraphInfoPerAtom() const
165{
166 LOG(1, "Final graph info for each atom is:");
167 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
168 for_each(allatoms.begin(),allatoms.end(),mem_fun(&atom::OutputGraphInfo));
169}
170
171
172void DepthFirstSearchAnalysis::OutputGraphInfoPerBond() const
173{
174 LOG(1, "Final graph info for each bond is:");
175 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
176 for(World::AtomComposite::const_iterator AtomRunner = allatoms.begin();
177 AtomRunner != allatoms.end();
178 ++AtomRunner) {
179 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
180 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
181 BondRunner != ListOfBonds.end();
182 ++BondRunner)
183 if ((*BondRunner)->leftatom == *AtomRunner) {
184 const bond::ptr Binder = *BondRunner;
185 if (DoLog(2)) {
186 std::stringstream output;
187 output << ((Binder->Type == GraphEdge::TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
188 output << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
189 Binder->leftatom->OutputComponentNumber(&output);
190 output << " === ";
191 output << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
192 Binder->rightatom->OutputComponentNumber(&output);
193 output << ">.";
194 LOG(2, output.str());
195 }
196 if (Binder->Cyclic) // cyclic ??
197 LOG(3, "Lowpoint at each side are equal: CYCLIC!");
198 }
199 }
200}
201
202
203unsigned int DepthFirstSearchAnalysis::CyclicBondAnalysis() const
204{
205 unsigned int NoCyclicBonds = 0;
206 World::AtomComposite allatoms = World::getInstance().getAllAtoms();
207 for(World::AtomComposite::const_iterator AtomRunner = allatoms.begin();
208 AtomRunner != allatoms.end();
209 ++AtomRunner) {
210 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
211 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
212 BondRunner != ListOfBonds.end();
213 ++BondRunner)
214 if ((*BondRunner)->leftatom == *AtomRunner)
215 if ((*BondRunner)->rightatom->LowpointNr == (*BondRunner)->leftatom->LowpointNr) { // cyclic ??
216 (*BondRunner)->Cyclic = true;
217 NoCyclicBonds++;
218 }
219 }
220 return NoCyclicBonds;
221}
222
223
224void DepthFirstSearchAnalysis::SetWalkersGraphNr(atom *&Walker)
225{
226 if (!BackStepping) { // if we don't just return from (8)
227 Walker->GraphNr = CurrentGraphNr;
228 Walker->LowpointNr = CurrentGraphNr;
229 LOG(1, "Setting Walker[" << Walker->getName() << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << ".");
230 AtomStack.push_front(Walker);
231 CurrentGraphNr++;
232 }
233}
234
235
236void DepthFirstSearchAnalysis::ProbeAlongUnusedBond(atom *&Walker, bond::ptr &Binder)
237{
238 atom *OtherAtom = NULL;
239
240 do { // (3) if Walker has no unused egdes, go to (5)
241 BackStepping = false; // reset backstepping flag for (8)
242 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
243 Binder = FindNextUnused(Walker);
244 if (Binder == NULL)
245 break;
246 LOG(2, "Current Unused Bond is " << *Binder << ".");
247 // (4) Mark Binder used, ...
248 Binder->MarkUsed(GraphEdge::black);
249 OtherAtom = Binder->GetOtherAtom(Walker);
250 LOG(2, "(4) OtherAtom is " << OtherAtom->getName() << ".");
251 if (OtherAtom->GraphNr != -1) {
252 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
253 Binder->Type = GraphEdge::BackEdge;
254 BackEdgeStack.push_front(Binder);
255 Walker->LowpointNr = (Walker->LowpointNr < OtherAtom->GraphNr) ? Walker->LowpointNr : OtherAtom->GraphNr;
256 LOG(3, "(4a) Visited: Setting Lowpoint of Walker[" << Walker->getName() << "] to " << Walker->LowpointNr << ".");
257 } else {
258 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
259 Binder->Type = GraphEdge::TreeEdge;
260 OtherAtom->Ancestor = Walker;
261 Walker = OtherAtom;
262 LOG(3, "(4b) Not Visited: OtherAtom[" << OtherAtom->getName() << "]'s Ancestor is now " << OtherAtom->Ancestor->getName() << ", Walker is OtherAtom " << OtherAtom->getName() << ".");
263 break;
264 }
265 Binder.reset();
266 } while (1); // (3)
267}
268
269
270void DepthFirstSearchAnalysis::CheckForaNewComponent(atom *&Walker, ConnectedSubgraph &Subgraph)
271{
272 atom *OtherAtom = NULL;
273
274 // (5) if Ancestor of Walker is ...
275 LOG(1, "(5) Number of Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "] is " << Walker->Ancestor->GraphNr << ".");
276
277 if (Walker->Ancestor->GraphNr != Root->GraphNr) {
278 // (6) (Ancestor of Walker is not Root)
279 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
280 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
281 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
282 LOG(2, "(6) Setting Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << ".");
283 } else {
284 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
285 Walker->Ancestor->SeparationVertex = true;
286 LOG(2, "(7) Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s is a separating vertex, creating component.");
287 SetNextComponentNumber(Walker->Ancestor, ComponentNumber);
288 LOG(3, "(7) Walker[" << Walker->getName() << "]'s Ancestor's Compont is " << ComponentNumber << ".");
289 SetNextComponentNumber(Walker, ComponentNumber);
290 LOG(3, "(7) Walker[" << Walker->getName() << "]'s Compont is " << ComponentNumber << ".");
291 do {
292 ASSERT(!AtomStack.empty(), "DepthFirstSearchAnalysis_CheckForaNewComponent() - AtomStack is empty!");
293 OtherAtom = AtomStack.front();
294 AtomStack.pop_front();
295 Subgraph.push_back(OtherAtom);
296 SetNextComponentNumber(OtherAtom, ComponentNumber);
297 LOG(3, "(7) Other[" << OtherAtom->getName() << "]'s Compont is " << ComponentNumber << ".");
298 } while (OtherAtom != Walker);
299 ComponentNumber++;
300 }
301 // (8) Walker becomes its Ancestor, go to (3)
302 LOG(2, "(8) Walker[" << Walker->getName() << "] is now its Ancestor " << Walker->Ancestor->getName() << ", backstepping. ");
303 Walker = Walker->Ancestor;
304 BackStepping = true;
305 }
306}
307
308
309void DepthFirstSearchAnalysis::CleanRootStackDownTillWalker(atom *&Walker, bond::ptr &Binder, ConnectedSubgraph &Subgraph)
310{
311 atom *OtherAtom = NULL;
312
313 if (!BackStepping) { // coming from (8) want to go to (3)
314 // (9) remove all from stack till Walker (including), these and Root form a component
315 //AtomStack.Output(out);
316 SetNextComponentNumber(Root, ComponentNumber);
317 LOG(3, "(9) Root[" << Root->getName() << "]'s Component is " << ComponentNumber << ".");
318 SetNextComponentNumber(Walker, ComponentNumber);
319 LOG(3, "(9) Walker[" << Walker->getName() << "]'s Component is " << ComponentNumber << ".");
320 do {
321 ASSERT(!AtomStack.empty(), "DepthFirstSearchAnalysis::CleanRootStackDownTillWalker() - AtomStack is empty!");
322 OtherAtom = AtomStack.front();
323 AtomStack.pop_front();
324 Subgraph.push_back(OtherAtom);
325 SetNextComponentNumber(OtherAtom, ComponentNumber);
326 LOG(3, "(7) Other[" << OtherAtom->getName() << "]'s Component is " << ComponentNumber << ".");
327 } while (OtherAtom != Walker);
328 ComponentNumber++;
329
330 // (11) Root is separation vertex, set Walker to Root and go to (4)
331 Walker = Root;
332 Binder = FindNextUnused(Walker);
333 if (Binder != NULL) { // Root is separation vertex
334 LOG(1, "(10) Walker is Root[" << Root->getName() << "], next Unused Bond is " << *Binder << ".");
335 LOG(1, "(11) Root is a separation vertex.");
336 Walker->SeparationVertex = true;
337 } else {
338 LOG(1, "(10) Walker is Root[" << Root->getName() << "], no next Unused Bond.");
339 }
340 }
341}
342
343
344const std::deque<bond::ptr >& DepthFirstSearchAnalysis::getBackEdgeStack() const
345{
346 return BackEdgeStack;
347}
348
349
350void DepthFirstSearchAnalysis::operator()()
351{
352 Info FunctionInfo("DepthFirstSearchAnalysis");
353 ListOfConnectedSubgraphs.clear();
354 int OldGraphNr = 0;
355 atom *Walker = NULL;
356 bond::ptr Binder;
357
358 if (World::getInstance().numAtoms() == 0)
359 return;
360
361 Init();
362
363 LOG(0, "STATUS: Start walking the bond graph.");
364 for(World::AtomIterator iter = World::getInstance().getAtomIter();
365 iter != World::getInstance().atomEnd();) { // don't advance, is done at the end
366 Root = *iter;
367 // (1) mark all edges unused, empty stack, set atom->GraphNr = -1 for all
368 AtomStack.clear();
369
370 // put into new subgraph molecule and add this to list of subgraphs
371 ConnectedSubgraph CurrentSubgraph;
372 CurrentSubgraph.push_back(Root);
373
374 OldGraphNr = CurrentGraphNr;
375 Walker = Root;
376 do { // (10)
377 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
378 SetWalkersGraphNr(Walker);
379
380 ProbeAlongUnusedBond(Walker, Binder);
381
382 if (Binder == NULL) {
383 LOG(2, "No more Unused Bonds.");
384 break;
385 } else
386 Binder.reset();
387 } while (1); // (2)
388
389 // if we came from backstepping, yet there were no more unused bonds, we end up here with no Ancestor, because Walker is Root! Then we are finished!
390 if ((Walker == Root) && (Binder == NULL))
391 break;
392
393 CheckForaNewComponent( Walker, CurrentSubgraph);
394
395 CleanRootStackDownTillWalker(Walker, Binder, CurrentSubgraph);
396
397 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
398
399 ListOfConnectedSubgraphs.push_back(CurrentSubgraph);
400 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
401 std::stringstream output;
402 output << CurrentSubgraph;
403 LOG(1, "INFO: Disconnected subgraph ranges from " << OldGraphNr << " to "
404 << CurrentGraphNr-1 << ": " << output.str());
405
406 // step on to next root
407 while (iter != World::getInstance().atomEnd()) {
408 if ((*iter)->GraphNr != -1) { // if already discovered, step on
409 iter++;
410 } else {
411 LOG(1,"Current next subgraph root candidate is " << (*iter)->getName()
412 << " with GraphNr " << (*iter)->GraphNr << ".");
413 break;
414 }
415 }
416 }
417 LOG(0, "STATUS: Done walking the bond graph.");
418
419 // set cyclic bond criterium on "same LP" basis
420 CyclicBondAnalysis();
421
422 OutputGraphInfoPerAtom();
423
424 OutputGraphInfoPerBond();
425}
426
427void DepthFirstSearchAnalysis::UpdateMoleculeStructure() const
428{
429 // remove all of World's molecules
430 for (World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
431 World::getInstance().getMoleculeIter() != World::getInstance().moleculeEnd();
432 iter = World::getInstance().getMoleculeIter()) {
433 World::getInstance().getMolecules()->erase(*iter);
434 World::getInstance().destroyMolecule(*iter);
435 }
436 // instantiate new molecules
437 molecule *newmol = NULL;
438 for (ConnectedSubgraphList::const_iterator iter = ListOfConnectedSubgraphs.begin();
439 iter != ListOfConnectedSubgraphs.end();
440 ++iter) {
441 newmol = (*iter).getMolecule();
442 if (DoLog(2)) {
443 LOG(2, "STATUS: Creating new molecule:");
444 std::stringstream output;
445 newmol->Output(&output);
446 std::stringstream outstream(output.str());
447 std::string line;
448 while (getline(outstream, line)) {
449 LOG(2, "\t"+line);
450 }
451 }
452 }
453}
454
455MoleculeLeafClass *DepthFirstSearchAnalysis::getMoleculeStructure() const
456{
457 MoleculeLeafClass *Subgraphs = new MoleculeLeafClass(NULL);
458 MoleculeLeafClass *MolecularWalker = Subgraphs;
459 for (World::MoleculeIterator iter = World::getInstance().getMoleculeIter();
460 iter != World::getInstance().moleculeEnd();
461 ++iter) {
462 // TODO: Remove the insertion into molecule when saving does not depend on them anymore. Also, remove molecule.hpp include
463 MolecularWalker = new MoleculeLeafClass(MolecularWalker);
464 MolecularWalker->Leaf = (*iter);
465 }
466 return Subgraphs;
467}
468
Note: See TracBrowser for help on using the repository browser.