source: src/Graph/DepthFirstSearchAnalysis.cpp@ c8302f3

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 c8302f3 was 88c8ec, checked in by Frederik Heber <heber@…>, 12 years ago

REFACTOR: Replaced all "bond *" appearances by bond::ptr.

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