source: src/Graph/DepthFirstSearchAnalysis.cpp@ 8b58ac

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 8b58ac was 94d5ac6, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: As we use GSL internally, we are as of now required to use GPL v2 license.

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