source: src/molecule_graph.cpp@ 435065

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 435065 was 632508, checked in by Frederik Heber <heber@…>, 14 years ago

Moved files bondgraph.?pp -> Graph/BondGraph.?pp.

  • Property mode set to 100644
File size: 58.1 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/*
9 * molecule_graph.cpp
10 *
11 * Created on: Oct 5, 2009
12 * Author: heber
13 */
14
15// include config.h
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "CodePatterns/MemDebug.hpp"
21
22#include <stack>
23
24#include "atom.hpp"
25#include "bond.hpp"
26#include "Graph/BondGraph.hpp"
27#include "Box.hpp"
28#include "CodePatterns/Assert.hpp"
29#include "CodePatterns/Info.hpp"
30#include "CodePatterns/Log.hpp"
31#include "CodePatterns/Verbose.hpp"
32#include "config.hpp"
33#include "element.hpp"
34#include "Helpers/defs.hpp"
35#include "Helpers/fast_functions.hpp"
36#include "Helpers/helpers.hpp"
37#include "LinearAlgebra/RealSpaceMatrix.hpp"
38#include "linkedcell.hpp"
39#include "molecule.hpp"
40#include "PointCloudAdaptor.hpp"
41#include "World.hpp"
42#include "WorldTime.hpp"
43
44#define MAXBONDS 8
45
46struct BFSAccounting
47{
48 atom **PredecessorList;
49 int *ShortestPathList;
50 enum bond::Shading *ColorList;
51 std::deque<atom *> *BFSStack;
52 std::deque<atom *> *TouchedStack;
53 int AtomCount;
54 int BondOrder;
55 atom *Root;
56 bool BackStepping;
57 int CurrentGraphNr;
58 int ComponentNr;
59};
60
61/** Accounting data for Depth First Search.
62 */
63struct DFSAccounting
64{
65 std::deque<atom *> *AtomStack;
66 std::deque<bond *> *BackEdgeStack;
67 int CurrentGraphNr;
68 int ComponentNumber;
69 atom *Root;
70 bool BackStepping;
71};
72
73/************************************* Functions for class molecule *********************************/
74
75/** Checks for presence of bonds within atom list.
76 * TODO: more sophisticated check for bond structure (e.g. connected subgraph, ...)
77 * \return true - bonds present, false - no bonds
78 */
79bool molecule::hasBondStructure() const
80{
81 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
82 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
83 if (!ListOfBonds.empty())
84 return true;
85 }
86 return false;
87}
88
89/** Prints a list of all bonds to \a *out.
90 */
91void molecule::OutputBondsList() const
92{
93 DoLog(1) && (Log() << Verbose(1) << endl << "From contents of bond chain list:");
94 for(molecule::const_iterator AtomRunner = molecule::begin(); AtomRunner != molecule::end(); ++AtomRunner) {
95 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
96 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
97 BondRunner != ListOfBonds.end();
98 ++BondRunner)
99 if ((*BondRunner)->leftatom == *AtomRunner) {
100 DoLog(0) && (Log() << Verbose(0) << *(*BondRunner) << "\t" << endl);
101 }
102 }
103 DoLog(0) && (Log() << Verbose(0) << endl);
104}
105;
106
107
108/** Counts all cyclic bonds and returns their number.
109 * \note Hydrogen bonds can never by cyclic, thus no check for that
110 * \return number of cyclic bonds
111 */
112int molecule::CountCyclicBonds()
113{
114 NoCyclicBonds = 0;
115 int *MinimumRingSize = NULL;
116 MoleculeLeafClass *Subgraphs = NULL;
117 std::deque<bond *> *BackEdgeStack = NULL;
118 for(molecule::iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
119 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
120 if ((!ListOfBonds.empty()) && ((*ListOfBonds.begin())->Type == bond::Undetermined)) {
121 DoLog(0) && (Log() << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl);
122 Subgraphs = DepthFirstSearchAnalysis(BackEdgeStack);
123 while (Subgraphs->next != NULL) {
124 Subgraphs = Subgraphs->next;
125 delete (Subgraphs->previous);
126 }
127 delete (Subgraphs);
128 delete[] (MinimumRingSize);
129 break;
130 }
131 }
132 for(molecule::iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
133 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
134 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
135 BondRunner != ListOfBonds.end();
136 ++BondRunner)
137 if ((*BondRunner)->leftatom == *AtomRunner)
138 if ((*BondRunner)->Cyclic)
139 NoCyclicBonds++;
140 }
141 delete (BackEdgeStack);
142 return NoCyclicBonds;
143}
144;
145
146
147/** Sets atom::GraphNr and atom::LowpointNr to BFSAccounting::CurrentGraphNr.
148 * \param *Walker current node
149 * \param &BFS structure with accounting data for BFS
150 */
151void DepthFirstSearchAnalysis_SetWalkersGraphNr(atom *&Walker, struct DFSAccounting &DFS)
152{
153 if (!DFS.BackStepping) { // if we don't just return from (8)
154 Walker->GraphNr = DFS.CurrentGraphNr;
155 Walker->LowpointNr = DFS.CurrentGraphNr;
156 DoLog(1) && (Log() << Verbose(1) << "Setting Walker[" << Walker->getName() << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl);
157 DFS.AtomStack->push_front(Walker);
158 DFS.CurrentGraphNr++;
159 }
160}
161;
162
163/** During DFS goes along unvisited bond and touches other atom.
164 * Sets bond::type, if
165 * -# BackEdge: set atom::LowpointNr and push on \a BackEdgeStack
166 * -# TreeEgde: set atom::Ancestor and continue with Walker along this edge
167 * Continue until molecule::FindNextUnused() finds no more unused bonds.
168 * \param *mol molecule with atoms and finding unused bonds
169 * \param *&Binder current edge
170 * \param &DFS DFS accounting data
171 */
172void DepthFirstSearchAnalysis_ProbeAlongUnusedBond(const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS)
173{
174 atom *OtherAtom = NULL;
175
176 do { // (3) if Walker has no unused egdes, go to (5)
177 DFS.BackStepping = false; // reset backstepping flag for (8)
178 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
179 Binder = mol->FindNextUnused(Walker);
180 if (Binder == NULL)
181 break;
182 DoLog(2) && (Log() << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl);
183 // (4) Mark Binder used, ...
184 Binder->MarkUsed(bond::black);
185 OtherAtom = Binder->GetOtherAtom(Walker);
186 DoLog(2) && (Log() << Verbose(2) << "(4) OtherAtom is " << OtherAtom->getName() << "." << endl);
187 if (OtherAtom->GraphNr != -1) {
188 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
189 Binder->Type = bond::BackEdge;
190 DFS.BackEdgeStack->push_front(Binder);
191 Walker->LowpointNr = (Walker->LowpointNr < OtherAtom->GraphNr) ? Walker->LowpointNr : OtherAtom->GraphNr;
192 DoLog(3) && (Log() << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->getName() << "] to " << Walker->LowpointNr << "." << endl);
193 } else {
194 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
195 Binder->Type = bond::TreeEdge;
196 OtherAtom->Ancestor = Walker;
197 Walker = OtherAtom;
198 DoLog(3) && (Log() << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->getName() << "]'s Ancestor is now " << OtherAtom->Ancestor->getName() << ", Walker is OtherAtom " << OtherAtom->getName() << "." << endl);
199 break;
200 }
201 Binder = NULL;
202 } while (1); // (3)
203}
204;
205
206/** Checks whether we have a new component.
207 * if atom::LowpointNr of \a *&Walker is greater than atom::GraphNr of its atom::Ancestor, we have a new component.
208 * Meaning that if we touch upon a node who suddenly has a smaller atom::LowpointNr than its ancestor, then we
209 * have a found a new branch in the graph tree.
210 * \param *mol molecule with atoms and finding unused bonds
211 * \param *&Walker current node
212 * \param &DFS DFS accounting data
213 */
214void DepthFirstSearchAnalysis_CheckForaNewComponent(const molecule * const mol, atom *&Walker, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
215{
216 atom *OtherAtom = NULL;
217
218 // (5) if Ancestor of Walker is ...
219 DoLog(1) && (Log() << Verbose(1) << "(5) Number of Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "] is " << Walker->Ancestor->GraphNr << "." << endl);
220
221 if (Walker->Ancestor->GraphNr != DFS.Root->GraphNr) {
222 // (6) (Ancestor of Walker is not Root)
223 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
224 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
225 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
226 DoLog(2) && (Log() << Verbose(2) << "(6) Setting Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl);
227 } else {
228 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
229 Walker->Ancestor->SeparationVertex = true;
230 DoLog(2) && (Log() << Verbose(2) << "(7) Walker[" << Walker->getName() << "]'s Ancestor[" << Walker->Ancestor->getName() << "]'s is a separating vertex, creating component." << endl);
231 mol->SetNextComponentNumber(Walker->Ancestor, DFS.ComponentNumber);
232 DoLog(3) && (Log() << Verbose(3) << "(7) Walker[" << Walker->getName() << "]'s Ancestor's Compont is " << DFS.ComponentNumber << "." << endl);
233 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
234 DoLog(3) && (Log() << Verbose(3) << "(7) Walker[" << Walker->getName() << "]'s Compont is " << DFS.ComponentNumber << "." << endl);
235 do {
236 ASSERT(!DFS.AtomStack->empty(), "DepthFirstSearchAnalysis_CheckForaNewComponent() - DFS.AtomStack is empty!");
237 OtherAtom = DFS.AtomStack->front();
238 DFS.AtomStack->pop_front();
239 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
240 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
241 DoLog(3) && (Log() << Verbose(3) << "(7) Other[" << OtherAtom->getName() << "]'s Compont is " << DFS.ComponentNumber << "." << endl);
242 } while (OtherAtom != Walker);
243 DFS.ComponentNumber++;
244 }
245 // (8) Walker becomes its Ancestor, go to (3)
246 DoLog(2) && (Log() << Verbose(2) << "(8) Walker[" << Walker->getName() << "] is now its Ancestor " << Walker->Ancestor->getName() << ", backstepping. " << endl);
247 Walker = Walker->Ancestor;
248 DFS.BackStepping = true;
249 }
250}
251;
252
253/** Cleans the root stack when we have found a component.
254 * If we are not DFSAccounting::BackStepping, then we clear the root stack by putting everything into a
255 * component down till we meet DFSAccounting::Root.
256 * \param *mol molecule with atoms and finding unused bonds
257 * \param *&Walker current node
258 * \param *&Binder current edge
259 * \param &DFS DFS accounting data
260 */
261void DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(const molecule * const mol, atom *&Walker, bond *&Binder, struct DFSAccounting &DFS, MoleculeLeafClass *&LeafWalker)
262{
263 atom *OtherAtom = NULL;
264
265 if (!DFS.BackStepping) { // coming from (8) want to go to (3)
266 // (9) remove all from stack till Walker (including), these and Root form a component
267 //DFS.AtomStack->Output(out);
268 mol->SetNextComponentNumber(DFS.Root, DFS.ComponentNumber);
269 DoLog(3) && (Log() << Verbose(3) << "(9) Root[" << DFS.Root->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
270 mol->SetNextComponentNumber(Walker, DFS.ComponentNumber);
271 DoLog(3) && (Log() << Verbose(3) << "(9) Walker[" << Walker->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
272 do {
273 ASSERT(!DFS.AtomStack->empty(), "DepthFirstSearchAnalysis_CleanRootStackDownTillWalker() - DFS.AtomStack is empty!");
274 OtherAtom = DFS.AtomStack->front();
275 DFS.AtomStack->pop_front();
276 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
277 mol->SetNextComponentNumber(OtherAtom, DFS.ComponentNumber);
278 DoLog(3) && (Log() << Verbose(3) << "(7) Other[" << OtherAtom->getName() << "]'s Component is " << DFS.ComponentNumber << "." << endl);
279 } while (OtherAtom != Walker);
280 DFS.ComponentNumber++;
281
282 // (11) Root is separation vertex, set Walker to Root and go to (4)
283 Walker = DFS.Root;
284 Binder = mol->FindNextUnused(Walker);
285 DoLog(1) && (Log() << Verbose(1) << "(10) Walker is Root[" << DFS.Root->getName() << "], next Unused Bond is " << Binder << "." << endl);
286 if (Binder != NULL) { // Root is separation vertex
287 DoLog(1) && (Log() << Verbose(1) << "(11) Root is a separation vertex." << endl);
288 Walker->SeparationVertex = true;
289 }
290 }
291}
292;
293
294/** Initializes DFSAccounting structure.
295 * \param &DFS accounting structure to allocate
296 * \param *mol molecule with AtomCount, BondCount and all atoms
297 */
298void DepthFirstSearchAnalysis_Init(struct DFSAccounting &DFS, const molecule * const mol)
299{
300 DFS.AtomStack = new std::deque<atom *> (mol->getAtomCount());
301 DFS.CurrentGraphNr = 0;
302 DFS.ComponentNumber = 0;
303 DFS.BackStepping = false;
304 mol->ResetAllBondsToUnused();
305 DFS.BackEdgeStack->clear();
306}
307;
308
309/** Free's DFSAccounting structure.
310 * \param &DFS accounting structure to free
311 */
312void DepthFirstSearchAnalysis_Finalize(struct DFSAccounting &DFS)
313{
314 delete (DFS.AtomStack);
315 // delete (DFS.BackEdgeStack); // DON'T free, see DepthFirstSearchAnalysis(), is returned as allocated
316}
317;
318
319void molecule::init_DFS(struct DFSAccounting &DFS) const{
320 DepthFirstSearchAnalysis_Init(DFS, this);
321 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::resetGraphNr));
322 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::InitComponentNr));
323}
324
325/** Performs a Depth-First search on this molecule.
326 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
327 * articulations points, ...
328 * We use the algorithm from [Even, Graph Algorithms, p.62].
329 * \param *&BackEdgeStack NULL pointer to std::deque<bond *> with all the found back edges, allocated and filled on return
330 * \return list of each disconnected subgraph as an individual molecule class structure
331 */
332MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(std::deque<bond *> *&BackEdgeStack) const
333{
334 struct DFSAccounting DFS;
335 BackEdgeStack = new std::deque<bond *> (getBondCount());
336 DFS.BackEdgeStack = BackEdgeStack;
337 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
338 MoleculeLeafClass *LeafWalker = SubGraphs;
339 int OldGraphNr = 0;
340 atom *Walker = NULL;
341 bond *Binder = NULL;
342
343 if (getAtomCount() == 0)
344 return SubGraphs;
345 DoLog(0) && (Log() << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl);
346 init_DFS(DFS);
347
348 for (molecule::const_iterator iter = begin(); iter != end();) {
349 DFS.Root = *iter;
350 // (1) mark all edges unused, empty stack, set atom->GraphNr = -1 for all
351 DFS.AtomStack->clear();
352
353 // put into new subgraph molecule and add this to list of subgraphs
354 LeafWalker = new MoleculeLeafClass(LeafWalker);
355 LeafWalker->Leaf = World::getInstance().createMolecule();
356 LeafWalker->Leaf->AddCopyAtom(DFS.Root);
357
358 OldGraphNr = DFS.CurrentGraphNr;
359 Walker = DFS.Root;
360 do { // (10)
361 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
362 DepthFirstSearchAnalysis_SetWalkersGraphNr(Walker, DFS);
363
364 DepthFirstSearchAnalysis_ProbeAlongUnusedBond(this, Walker, Binder, DFS);
365
366 if (Binder == NULL) {
367 DoLog(2) && (Log() << Verbose(2) << "No more Unused Bonds." << endl);
368 break;
369 } else
370 Binder = NULL;
371 } while (1); // (2)
372
373 // 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!
374 if ((Walker == DFS.Root) && (Binder == NULL))
375 break;
376
377 DepthFirstSearchAnalysis_CheckForaNewComponent(this, Walker, DFS, LeafWalker);
378
379 DepthFirstSearchAnalysis_CleanRootStackDownTillWalker(this, Walker, Binder, DFS, LeafWalker);
380
381 } while ((DFS.BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
382
383 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
384 DoLog(0) && (Log() << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << DFS.CurrentGraphNr << "." << endl);
385 LeafWalker->Leaf->Output((ofstream *)&(Log() << Verbose(0)));
386 DoLog(0) && (Log() << Verbose(0) << endl);
387
388 // step on to next root
389 while ((iter != end()) && ((*iter)->GraphNr != -1)) {
390 //Log() << Verbose(1) << "Current next subgraph root candidate is " << (*iter)->Name << "." << endl;
391 if ((*iter)->GraphNr != -1) // if already discovered, step on
392 iter++;
393 }
394 }
395 // set cyclic bond criterium on "same LP" basis
396 CyclicBondAnalysis();
397
398 OutputGraphInfoPerAtom();
399
400 OutputGraphInfoPerBond();
401
402 // free all and exit
403 DepthFirstSearchAnalysis_Finalize(DFS);
404 DoLog(0) && (Log() << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl);
405 return SubGraphs;
406}
407;
408
409/** Scans through all bonds and set bond::Cyclic to true where atom::LowpointNr of both ends is equal: LP criterion.
410 */
411void molecule::CyclicBondAnalysis() const
412{
413 NoCyclicBonds = 0;
414 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
415 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
416 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
417 BondRunner != ListOfBonds.end();
418 ++BondRunner)
419 if ((*BondRunner)->leftatom == *AtomRunner)
420 if ((*BondRunner)->rightatom->LowpointNr == (*BondRunner)->leftatom->LowpointNr) { // cyclic ??
421 (*BondRunner)->Cyclic = true;
422 NoCyclicBonds++;
423 }
424 }
425}
426;
427
428/** Output graph information per atom.
429 */
430void molecule::OutputGraphInfoPerAtom() const
431{
432 DoLog(1) && (Log() << Verbose(1) << "Final graph info for each atom is:" << endl);
433 for_each(atoms.begin(),atoms.end(),mem_fun(&atom::OutputGraphInfo));
434}
435;
436
437/** Output graph information per bond.
438 */
439void molecule::OutputGraphInfoPerBond() const
440{
441 DoLog(1) && (Log() << Verbose(1) << "Final graph info for each bond is:" << endl);
442 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
443 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
444 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
445 BondRunner != ListOfBonds.end();
446 ++BondRunner)
447 if ((*BondRunner)->leftatom == *AtomRunner) {
448 const bond *Binder = *BondRunner;
449 if (DoLog(2)) {
450 ostream &out = (Log() << Verbose(2));
451 out << ((Binder->Type == bond::TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
452 out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
453 Binder->leftatom->OutputComponentNumber(&out);
454 out << " === ";
455 out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
456 Binder->rightatom->OutputComponentNumber(&out);
457 out << ">." << endl;
458 }
459 if (Binder->Cyclic) // cyclic ??
460 DoLog(3) && (Log() << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl);
461 }
462 }
463}
464;
465
466/** Initialise each vertex as white with no predecessor, empty queue, color Root lightgray.
467 * \param &BFS accounting structure
468 * \param AtomCount number of entries in the array to allocate
469 */
470void InitializeBFSAccounting(struct BFSAccounting &BFS, int AtomCount)
471{
472 BFS.AtomCount = AtomCount;
473 BFS.PredecessorList = new atom*[AtomCount];
474 BFS.ShortestPathList = new int[AtomCount];
475 BFS.ColorList = new enum bond::Shading[AtomCount];
476 BFS.BFSStack = new std::deque<atom *> (AtomCount);
477 BFS.TouchedStack = new std::deque<atom *> (AtomCount);
478
479 for (int i = AtomCount; i--;) {
480 BFS.ShortestPathList[i] = -1;
481 BFS.PredecessorList[i] = 0;
482 BFS.ColorList[i] = bond::white;
483 }
484};
485
486/** Free's accounting structure.
487 * \param &BFS accounting structure
488 */
489void FinalizeBFSAccounting(struct BFSAccounting &BFS)
490{
491 delete[](BFS.PredecessorList);
492 delete[](BFS.ShortestPathList);
493 delete[](BFS.ColorList);
494 delete (BFS.BFSStack);
495 delete (BFS.TouchedStack);
496 BFS.AtomCount = 0;
497};
498
499/** Clean the accounting structure.
500 * \param &BFS accounting structure
501 */
502void CleanBFSAccounting(struct BFSAccounting &BFS)
503{
504 atom *Walker = NULL;
505 while (!BFS.TouchedStack->empty()) {
506 Walker = BFS.TouchedStack->front();
507 BFS.TouchedStack->pop_front();
508 BFS.PredecessorList[Walker->getNr()] = NULL;
509 BFS.ShortestPathList[Walker->getNr()] = -1;
510 BFS.ColorList[Walker->getNr()] = bond::white;
511 }
512};
513
514/** Resets shortest path list and BFSStack.
515 * \param *&Walker current node, pushed onto BFSAccounting::BFSStack and BFSAccounting::TouchedStack
516 * \param &BFS accounting structure
517 */
518void ResetBFSAccounting(atom *&Walker, struct BFSAccounting &BFS)
519{
520 BFS.ShortestPathList[Walker->getNr()] = 0;
521 BFS.BFSStack->clear(); // start with empty BFS stack
522 BFS.BFSStack->push_front(Walker);
523 BFS.TouchedStack->push_front(Walker);
524};
525
526/** Performs a BFS from \a *Root, trying to find the same node and hence a cycle.
527 * \param *&BackEdge the edge from root that we don't want to move along
528 * \param &BFS accounting structure
529 */
530void CyclicStructureAnalysis_CyclicBFSFromRootToRoot(bond *&BackEdge, struct BFSAccounting &BFS)
531{
532 atom *Walker = NULL;
533 atom *OtherAtom = NULL;
534 do { // look for Root
535 ASSERT(!BFS.BFSStack->empty(), "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - BFS.BFSStack is empty!");
536 Walker = BFS.BFSStack->front();
537 BFS.BFSStack->pop_front();
538 DoLog(2) && (Log() << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *BFS.Root << "." << endl);
539 const BondList& ListOfBonds = Walker->getListOfBonds();
540 for (BondList::const_iterator Runner = ListOfBonds.begin();
541 Runner != ListOfBonds.end();
542 ++Runner) {
543 if ((*Runner) != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
544 OtherAtom = (*Runner)->GetOtherAtom(Walker);
545#ifdef ADDHYDROGEN
546 if (OtherAtom->getType()->getAtomicNumber() != 1) {
547#endif
548 DoLog(2) && (Log() << Verbose(2) << "Current OtherAtom is: " << OtherAtom->getName() << " for bond " << *(*Runner) << "." << endl);
549 if (BFS.ColorList[OtherAtom->getNr()] == bond::white) {
550 BFS.TouchedStack->push_front(OtherAtom);
551 BFS.ColorList[OtherAtom->getNr()] = bond::lightgray;
552 BFS.PredecessorList[OtherAtom->getNr()] = Walker; // Walker is the predecessor
553 BFS.ShortestPathList[OtherAtom->getNr()] = BFS.ShortestPathList[Walker->getNr()] + 1;
554 DoLog(2) && (Log() << Verbose(2) << "Coloring OtherAtom " << OtherAtom->getName() << " lightgray, its predecessor is " << Walker->getName() << " and its Shortest Path is " << BFS.ShortestPathList[OtherAtom->getNr()] << " egde(s) long." << endl);
555 //if (BFS.ShortestPathList[OtherAtom->getNr()] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
556 DoLog(3) && (Log() << Verbose(3) << "Putting OtherAtom into queue." << endl);
557 BFS.BFSStack->push_front(OtherAtom);
558 //}
559 } else {
560 DoLog(3) && (Log() << Verbose(3) << "Not Adding, has already been visited." << endl);
561 }
562 if (OtherAtom == BFS.Root)
563 break;
564#ifdef ADDHYDROGEN
565 } else {
566 DoLog(2) && (Log() << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl);
567 BFS.ColorList[OtherAtom->getNr()] = bond::black;
568 }
569#endif
570 } else {
571 DoLog(2) && (Log() << Verbose(2) << "Bond " << *(*Runner) << " not Visiting, is the back edge." << endl);
572 }
573 }
574 BFS.ColorList[Walker->getNr()] = bond::black;
575 DoLog(1) && (Log() << Verbose(1) << "Coloring Walker " << Walker->getName() << " black." << endl);
576 if (OtherAtom == BFS.Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
577 // step through predecessor list
578 while (OtherAtom != BackEdge->rightatom) {
579 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
580 break;
581 else
582 OtherAtom = BFS.PredecessorList[OtherAtom->getNr()];
583 }
584 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
585 DoLog(3) && (Log() << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl);
586 do {
587 ASSERT(!BFS.TouchedStack->empty(), "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - BFS.TouchedStack is empty!");
588 OtherAtom = BFS.TouchedStack->front();
589 BFS.TouchedStack->pop_front();
590 if (BFS.PredecessorList[OtherAtom->getNr()] == Walker) {
591 DoLog(4) && (Log() << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl);
592 BFS.PredecessorList[OtherAtom->getNr()] = NULL;
593 BFS.ShortestPathList[OtherAtom->getNr()] = -1;
594 BFS.ColorList[OtherAtom->getNr()] = bond::white;
595 // rats ... deque has no find()
596 std::deque<atom *>::iterator iter = find(
597 BFS.BFSStack->begin(),
598 BFS.BFSStack->end(),
599 OtherAtom);
600 ASSERT(iter != BFS.BFSStack->end(),
601 "CyclicStructureAnalysis_CyclicBFSFromRootToRoot() - can't find "+toString(*OtherAtom)+" on stack!");
602 BFS.BFSStack->erase(iter);
603 }
604 } while ((!BFS.TouchedStack->empty()) && (BFS.PredecessorList[OtherAtom->getNr()] == NULL));
605 BFS.TouchedStack->push_front(OtherAtom); // last was wrongly popped
606 OtherAtom = BackEdge->rightatom; // set to not Root
607 } else
608 OtherAtom = BFS.Root;
609 }
610 } while ((!BFS.BFSStack->empty()) && (OtherAtom != BFS.Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->getNr()] < MinimumRingSize[Walker->GetTrueFather()->getNr()])));
611};
612
613/** Climb back the BFSAccounting::PredecessorList and find cycle members.
614 * \param *&OtherAtom
615 * \param *&BackEdge denotes the edge we did not want to travel along when doing CyclicBFSFromRootToRoot()
616 * \param &BFS accounting structure
617 * \param *&MinimumRingSize minimum distance from this node possible without encountering oneself, set on return for each atom
618 * \param &MinRingSize global minimum distance from one node without encountering oneself, set on return
619 */
620void CyclicStructureAnalysis_RetrieveCycleMembers(atom *&OtherAtom, bond *&BackEdge, struct BFSAccounting &BFS, int *&MinimumRingSize, int &MinRingSize)
621{
622 atom *Walker = NULL;
623 int NumCycles = 0;
624 int RingSize = -1;
625
626 if (OtherAtom == BFS.Root) {
627 // now climb back the predecessor list and thus find the cycle members
628 NumCycles++;
629 RingSize = 1;
630 BFS.Root->GetTrueFather()->IsCyclic = true;
631 DoLog(1) && (Log() << Verbose(1) << "Found ring contains: ");
632 Walker = BFS.Root;
633 while (Walker != BackEdge->rightatom) {
634 DoLog(0) && (Log() << Verbose(0) << Walker->getName() << " <-> ");
635 Walker = BFS.PredecessorList[Walker->getNr()];
636 Walker->GetTrueFather()->IsCyclic = true;
637 RingSize++;
638 }
639 DoLog(0) && (Log() << Verbose(0) << Walker->getName() << " with a length of " << RingSize << "." << endl << endl);
640 // walk through all and set MinimumRingSize
641 Walker = BFS.Root;
642 MinimumRingSize[Walker->GetTrueFather()->getNr()] = RingSize;
643 while (Walker != BackEdge->rightatom) {
644 Walker = BFS.PredecessorList[Walker->getNr()];
645 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->getNr()])
646 MinimumRingSize[Walker->GetTrueFather()->getNr()] = RingSize;
647 }
648 if ((RingSize < MinRingSize) || (MinRingSize == -1))
649 MinRingSize = RingSize;
650 } else {
651 DoLog(1) && (Log() << Verbose(1) << "No ring containing " << *BFS.Root << " with length equal to or smaller than " << MinimumRingSize[BFS.Root->GetTrueFather()->getNr()] << " found." << endl);
652 }
653};
654
655/** From a given node performs a BFS to touch the next cycle, for whose nodes \a *&MinimumRingSize is set and set it accordingly.
656 * \param *&Root node to look for closest cycle from, i.e. \a *&MinimumRingSize is set for this node
657 * \param *&MinimumRingSize minimum distance from this node possible without encountering oneself, set on return for each atom
658 * \param AtomCount number of nodes in graph
659 */
660void CyclicStructureAnalysis_BFSToNextCycle(atom *&Root, atom *&Walker, int *&MinimumRingSize, int AtomCount)
661{
662 struct BFSAccounting BFS;
663 atom *OtherAtom = Walker;
664
665 InitializeBFSAccounting(BFS, AtomCount);
666
667 ResetBFSAccounting(Walker, BFS);
668 while (OtherAtom != NULL) { // look for Root
669 ASSERT(!BFS.BFSStack->empty(), "CyclicStructureAnalysis_BFSToNextCycle() - BFS.BFSStack is empty!");
670 Walker = BFS.BFSStack->front();
671 BFS.BFSStack->pop_front();
672 //Log() << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
673 const BondList& ListOfBonds = Walker->getListOfBonds();
674 for (BondList::const_iterator Runner = ListOfBonds.begin();
675 Runner != ListOfBonds.end();
676 ++Runner) {
677 // "removed (*Runner) != BackEdge) || " from next if, is u
678 if ((ListOfBonds.size() == 1)) { // only walk along DFS spanning tree (otherwise we always find SP of 1 being backedge Binder), but terminal hydrogens may be connected via backedge, hence extra check
679 OtherAtom = (*Runner)->GetOtherAtom(Walker);
680 //Log() << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
681 if (BFS.ColorList[OtherAtom->getNr()] == bond::white) {
682 BFS.TouchedStack->push_front(OtherAtom);
683 BFS.ColorList[OtherAtom->getNr()] = bond::lightgray;
684 BFS.PredecessorList[OtherAtom->getNr()] = Walker; // Walker is the predecessor
685 BFS.ShortestPathList[OtherAtom->getNr()] = BFS.ShortestPathList[Walker->getNr()] + 1;
686 //Log() << Verbose(2) << "Coloring OtherAtom " << OtherAtom->Name << " lightgray, its predecessor is " << Walker->Name << " and its Shortest Path is " << ShortestPathList[OtherAtom->getNr()] << " egde(s) long." << endl;
687 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
688 MinimumRingSize[Root->GetTrueFather()->getNr()] = BFS.ShortestPathList[OtherAtom->getNr()] + MinimumRingSize[OtherAtom->GetTrueFather()->getNr()];
689 OtherAtom = NULL; //break;
690 break;
691 } else
692 BFS.BFSStack->push_front(OtherAtom);
693 } else {
694 //Log() << Verbose(3) << "Not Adding, has already been visited." << endl;
695 }
696 } else {
697 //Log() << Verbose(3) << "Not Visiting, is a back edge." << endl;
698 }
699 }
700 BFS.ColorList[Walker->getNr()] = bond::black;
701 //Log() << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
702 }
703 //CleanAccountingLists(TouchedStack, PredecessorList, ShortestPathList, ColorList);
704
705 FinalizeBFSAccounting(BFS);
706}
707;
708
709/** All nodes that are not in cycles get assigned a \a *&MinimumRingSizeby BFS to next cycle.
710 * \param *&MinimumRingSize array with minimum distance without encountering onself for each atom
711 * \param &MinRingSize global minium distance
712 * \param &NumCyles number of cycles in graph
713 * \param *mol molecule with atoms
714 */
715void CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(int *&MinimumRingSize, int &MinRingSize, int &NumCycles, const molecule * const mol)
716{
717 atom *Root = NULL;
718 atom *Walker = NULL;
719 if (MinRingSize != -1) { // if rings are present
720 // go over all atoms
721 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
722 Root = *iter;
723
724 if (MinimumRingSize[Root->GetTrueFather()->getNr()] == mol->getAtomCount()) { // check whether MinimumRingSize is set, if not BFS to next where it is
725 Walker = Root;
726
727 //Log() << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
728 CyclicStructureAnalysis_BFSToNextCycle(Root, Walker, MinimumRingSize, mol->getAtomCount());
729
730 }
731 DoLog(1) && (Log() << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->getNr()] << "." << endl);
732 }
733 DoLog(1) && (Log() << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl);
734 } else
735 DoLog(1) && (Log() << Verbose(1) << "No rings were detected in the molecular structure." << endl);
736}
737;
738
739/** Analyses the cycles found and returns minimum of all cycle lengths.
740 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
741 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
742 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
743 * as cyclic and print out the cycles.
744 * \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!
745 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
746 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
747 */
748void molecule::CyclicStructureAnalysis(
749 std::deque<bond *> * BackEdgeStack,
750 int *&MinimumRingSize
751 ) const
752{
753 struct BFSAccounting BFS;
754 atom *Walker = NULL;
755 atom *OtherAtom = NULL;
756 bond *BackEdge = NULL;
757 int NumCycles = 0;
758 int MinRingSize = -1;
759
760 InitializeBFSAccounting(BFS, getAtomCount());
761
762 //Log() << Verbose(1) << "Back edge list - ";
763 //BackEdgeStack->Output(out);
764
765 DoLog(1) && (Log() << Verbose(1) << "Analysing cycles ... " << endl);
766 NumCycles = 0;
767 while (!BackEdgeStack->empty()) {
768 BackEdge = BackEdgeStack->front();
769 BackEdgeStack->pop_front();
770 // this is the target
771 BFS.Root = BackEdge->leftatom;
772 // this is the source point
773 Walker = BackEdge->rightatom;
774
775 ResetBFSAccounting(Walker, BFS);
776
777 DoLog(1) && (Log() << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl);
778 OtherAtom = NULL;
779 CyclicStructureAnalysis_CyclicBFSFromRootToRoot(BackEdge, BFS);
780
781 CyclicStructureAnalysis_RetrieveCycleMembers(OtherAtom, BackEdge, BFS, MinimumRingSize, MinRingSize);
782
783 CleanBFSAccounting(BFS);
784 }
785 FinalizeBFSAccounting(BFS);
786
787 CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(MinimumRingSize, MinRingSize, NumCycles, this);
788};
789
790/** Sets the next component number.
791 * This is O(N) as the number of bonds per atom is bound.
792 * \param *vertex atom whose next atom::*ComponentNr is to be set
793 * \param Nr number to use
794 */
795void molecule::SetNextComponentNumber(atom *vertex, int nr) const
796{
797 size_t i = 0;
798 if (vertex != NULL) {
799 const BondList& ListOfBonds = vertex->getListOfBonds();
800 for (; i < ListOfBonds.size(); i++) {
801 if (vertex->ComponentNr[i] == -1) { // check if not yet used
802 vertex->ComponentNr[i] = nr;
803 break;
804 } else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
805 break; // breaking here will not cause error!
806 }
807 if (i == ListOfBonds.size()) {
808 DoeLog(0) && (eLog()<< Verbose(0) << "Error: All Component entries are already occupied!" << endl);
809 performCriticalExit();
810 }
811 } else {
812 DoeLog(0) && (eLog()<< Verbose(0) << "Error: Given vertex is NULL!" << endl);
813 performCriticalExit();
814 }
815}
816;
817
818/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
819 * \param *vertex atom to regard
820 * \return bond class or NULL
821 */
822bond * molecule::FindNextUnused(atom *vertex) const
823{
824 const BondList& ListOfBonds = vertex->getListOfBonds();
825 for (BondList::const_iterator Runner = ListOfBonds.begin();
826 Runner != ListOfBonds.end();
827 ++Runner)
828 if ((*Runner)->IsUsed() == bond::white)
829 return ((*Runner));
830 return NULL;
831}
832;
833
834/** Resets bond::Used flag of all bonds in this molecule.
835 * \return true - success, false - -failure
836 */
837void molecule::ResetAllBondsToUnused() const
838{
839 for(molecule::const_iterator AtomRunner = begin(); AtomRunner != end(); ++AtomRunner) {
840 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
841 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
842 BondRunner != ListOfBonds.end();
843 ++BondRunner)
844 if ((*BondRunner)->leftatom == *AtomRunner)
845 (*BondRunner)->ResetUsed();
846 }
847}
848;
849
850/** Output a list of flags, stating whether the bond was visited or not.
851 * \param *list list to print
852 */
853void OutputAlreadyVisited(int *list)
854{
855 DoLog(4) && (Log() << Verbose(4) << "Already Visited Bonds:\t");
856 for (int i = 1; i <= list[0]; i++)
857 DoLog(0) && (Log() << Verbose(0) << list[i] << " ");
858 DoLog(0) && (Log() << Verbose(0) << endl);
859}
860;
861
862/** Storing the bond structure of a molecule to file.
863 * Simply stores Atom::Nr and then the Atom::Nr of all bond partners per line.
864 * \param &filename name of file
865 * \param path path to file, defaults to empty
866 * \return true - file written successfully, false - writing failed
867 */
868bool molecule::StoreAdjacencyToFile(std::string filename, std::string path)
869{
870 ofstream AdjacencyFile;
871 string line;
872 bool status = true;
873
874 if (path != "")
875 line = path + "/" + filename;
876 else
877 line = filename;
878 AdjacencyFile.open(line.c_str(), ios::out);
879 DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl);
880 if (AdjacencyFile.good()) {
881 AdjacencyFile << "m\tn" << endl;
882 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputAdjacency),&AdjacencyFile));
883 AdjacencyFile.close();
884 DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl);
885 } else {
886 DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl);
887 status = false;
888 }
889
890 return status;
891}
892;
893
894/** Storing the bond structure of a molecule to file.
895 * Simply stores Atom::Nr and then the Atom::Nr of all bond partners, one per line.
896 * \param &filename name of file
897 * \param path path to file, defaults to empty
898 * \return true - file written successfully, false - writing failed
899 */
900bool molecule::StoreBondsToFile(std::string filename, std::string path)
901{
902 ofstream BondFile;
903 string line;
904 bool status = true;
905
906 if (path != "")
907 line = path + "/" + filename;
908 else
909 line = filename;
910 BondFile.open(line.c_str(), ios::out);
911 DoLog(1) && (Log() << Verbose(1) << "Saving adjacency list ... " << endl);
912 if (BondFile.good()) {
913 BondFile << "m\tn" << endl;
914 for_each(atoms.begin(),atoms.end(),bind2nd(mem_fun(&atom::OutputBonds),&BondFile));
915 BondFile.close();
916 DoLog(1) && (Log() << Verbose(1) << "\t... done." << endl);
917 } else {
918 DoLog(1) && (Log() << Verbose(1) << "\t... failed to open file " << line << "." << endl);
919 status = false;
920 }
921
922 return status;
923}
924;
925
926bool CheckAdjacencyFileAgainstMolecule_Init(std::string &path, ifstream &File, int *&CurrentBonds)
927{
928 string filename;
929 filename = path + ADJACENCYFILE;
930 File.open(filename.c_str(), ios::out);
931 DoLog(1) && (Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl);
932 if (File.fail())
933 return false;
934
935 // allocate storage structure
936 CurrentBonds = new int[MAXBONDS]; // contains parsed bonds of current atom
937 for(int i=0;i<MAXBONDS;i++)
938 CurrentBonds[i] = 0;
939 return true;
940}
941;
942
943void CheckAdjacencyFileAgainstMolecule_Finalize(ifstream &File, int *&CurrentBonds)
944{
945 File.close();
946 File.clear();
947 delete[](CurrentBonds);
948}
949;
950
951void CheckAdjacencyFileAgainstMolecule_CompareBonds(bool &status, int &NonMatchNumber, atom *&Walker, size_t &CurrentBondsOfAtom, int AtomNr, int *&CurrentBonds, atom **ListOfAtoms)
952{
953 size_t j = 0;
954 int id = -1;
955
956 //Log() << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
957 const BondList& ListOfBonds = Walker->getListOfBonds();
958 if (CurrentBondsOfAtom == ListOfBonds.size()) {
959 for (BondList::const_iterator Runner = ListOfBonds.begin();
960 Runner != ListOfBonds.end();
961 ++Runner) {
962 id = (*Runner)->GetOtherAtom(Walker)->getNr();
963 j = 0;
964 for (; (j < CurrentBondsOfAtom) && (CurrentBonds[j++] != id);)
965 ; // check against all parsed bonds
966 if (CurrentBonds[j - 1] != id) { // no match ? Then mark in ListOfAtoms
967 ListOfAtoms[AtomNr] = NULL;
968 NonMatchNumber++;
969 status = false;
970 DoeLog(2) && (eLog() << Verbose(2) << id << " can not be found in list." << endl);
971 } else {
972 //Log() << Verbose(0) << "[" << id << "]\t";
973 }
974 }
975 //Log() << Verbose(0) << endl;
976 } else {
977 DoLog(0) && (Log() << Verbose(0) << "Number of bonds for Atom " << *Walker << " does not match, parsed " << CurrentBondsOfAtom << " against " << ListOfBonds.size() << "." << endl);
978 status = false;
979 }
980}
981;
982
983/** Checks contents of adjacency file against bond structure in structure molecule.
984 * \param *path path to file
985 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::Nr) to *Atom
986 * \return true - structure is equal, false - not equivalence
987 */
988bool molecule::CheckAdjacencyFileAgainstMolecule(std::string &path, atom **ListOfAtoms)
989{
990 ifstream File;
991 bool status = true;
992 atom *Walker = NULL;
993 int *CurrentBonds = NULL;
994 int NonMatchNumber = 0; // will number of atoms with differing bond structure
995 size_t CurrentBondsOfAtom = -1;
996 const int AtomCount = getAtomCount();
997
998 if (!CheckAdjacencyFileAgainstMolecule_Init(path, File, CurrentBonds)) {
999 DoLog(1) && (Log() << Verbose(1) << "Adjacency file not found." << endl);
1000 return true;
1001 }
1002
1003 char buffer[MAXSTRINGSIZE];
1004 int tmp;
1005 // Parse the file line by line and count the bonds
1006 while (!File.eof()) {
1007 File.getline(buffer, MAXSTRINGSIZE);
1008 stringstream line;
1009 line.str(buffer);
1010 int AtomNr = -1;
1011 line >> AtomNr;
1012 CurrentBondsOfAtom = -1; // we count one too far due to line end
1013 // parse into structure
1014 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
1015 Walker = ListOfAtoms[AtomNr];
1016 while (line >> ws >> tmp) {
1017 std::cout << "Recognized bond partner " << tmp << std::endl;
1018 CurrentBonds[++CurrentBondsOfAtom] = tmp;
1019 ASSERT(CurrentBondsOfAtom < MAXBONDS,
1020 "molecule::CheckAdjacencyFileAgainstMolecule() - encountered more bonds than allowed: "
1021 +toString(CurrentBondsOfAtom)+" >= "+toString(MAXBONDS)+"!");
1022 }
1023 // compare against present bonds
1024 CheckAdjacencyFileAgainstMolecule_CompareBonds(status, NonMatchNumber, Walker, CurrentBondsOfAtom, AtomNr, CurrentBonds, ListOfAtoms);
1025 } else {
1026 if (AtomNr != -1)
1027 DoeLog(2) && (eLog() << Verbose(2) << AtomNr << " is not valid in the range of ids [" << 0 << "," << AtomCount << ")." << endl);
1028 }
1029 }
1030 CheckAdjacencyFileAgainstMolecule_Finalize(File, CurrentBonds);
1031
1032 if (status) { // if equal we parse the KeySetFile
1033 DoLog(1) && (Log() << Verbose(1) << "done: Equal." << endl);
1034 } else
1035 DoLog(1) && (Log() << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl);
1036 return status;
1037}
1038;
1039
1040/** Picks from a global stack with all back edges the ones in the fragment.
1041 * \param **ListOfLocalAtoms array of father atom::Nr to local atom::Nr (reverse of atom::father)
1042 * \param *ReferenceStack stack with all the back egdes
1043 * \param *LocalStack stack to be filled
1044 * \return true - everything ok, false - ReferenceStack was empty
1045 */
1046bool molecule::PickLocalBackEdges(atom **ListOfLocalAtoms, std::deque<bond *> *&ReferenceStack, std::deque<bond *> *&LocalStack) const
1047{
1048 bool status = true;
1049 if (ReferenceStack->empty()) {
1050 DoLog(1) && (Log() << Verbose(1) << "ReferenceStack is empty!" << endl);
1051 return false;
1052 }
1053 bond *Binder = ReferenceStack->front();
1054 ReferenceStack->pop_front();
1055 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
1056 atom *Walker = NULL, *OtherAtom = NULL;
1057 ReferenceStack->push_front(Binder);
1058
1059 do { // go through all bonds and push local ones
1060 Walker = ListOfLocalAtoms[Binder->leftatom->getNr()]; // get one atom in the reference molecule
1061 if (Walker != NULL) { // if this Walker exists in the subgraph ...
1062 const BondList& ListOfBonds = Walker->getListOfBonds();
1063 for (BondList::const_iterator Runner = ListOfBonds.begin();
1064 Runner != ListOfBonds.end();
1065 ++Runner) {
1066 OtherAtom = (*Runner)->GetOtherAtom(Walker);
1067 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->getNr()]) { // found the bond
1068 LocalStack->push_front((*Runner));
1069 DoLog(3) && (Log() << Verbose(3) << "Found local edge " << *(*Runner) << "." << endl);
1070 break;
1071 }
1072 }
1073 }
1074 ASSERT(!ReferenceStack->empty(), "molecule::PickLocalBackEdges() - ReferenceStack is empty!");
1075 Binder = ReferenceStack->front(); // loop the stack for next item
1076 ReferenceStack->pop_front();
1077 DoLog(3) && (Log() << Verbose(3) << "Current candidate edge " << Binder << "." << endl);
1078 ReferenceStack->push_front(Binder);
1079 } while (FirstBond != Binder);
1080
1081 return status;
1082}
1083;
1084
1085void BreadthFirstSearchAdd_Init(struct BFSAccounting &BFS, atom *&Root, int AtomCount, int BondOrder, atom **AddedAtomList = NULL)
1086{
1087 BFS.AtomCount = AtomCount;
1088 BFS.BondOrder = BondOrder;
1089 BFS.PredecessorList = new atom*[AtomCount];
1090 BFS.ShortestPathList = new int[AtomCount];
1091 BFS.ColorList = new enum bond::Shading[AtomCount];
1092 BFS.BFSStack = new std::deque<atom *> (AtomCount);
1093
1094 BFS.Root = Root;
1095 BFS.BFSStack->clear();
1096 BFS.BFSStack->push_front(Root);
1097
1098 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
1099 for (int i = AtomCount; i--;) {
1100 BFS.PredecessorList[i] = NULL;
1101 BFS.ShortestPathList[i] = -1;
1102 if ((AddedAtomList != NULL) && (AddedAtomList[i] != NULL)) // mark already present atoms (i.e. Root and maybe others) as visited
1103 BFS.ColorList[i] = bond::lightgray;
1104 else
1105 BFS.ColorList[i] = bond::white;
1106 }
1107 //BFS.ShortestPathList[Root->getNr()] = 0; // done by Calloc
1108}
1109;
1110
1111void BreadthFirstSearchAdd_Free(struct BFSAccounting &BFS)
1112{
1113 delete[](BFS.PredecessorList);
1114 delete[](BFS.ShortestPathList);
1115 delete[](BFS.ColorList);
1116 delete (BFS.BFSStack);
1117 BFS.AtomCount = 0;
1118}
1119;
1120
1121void BreadthFirstSearchAdd_UnvisitedNode(molecule *Mol, struct BFSAccounting &BFS, atom *&Walker, atom *&OtherAtom, bond *&Binder, bond *&Bond, atom **&AddedAtomList, bond **&AddedBondList, bool IsAngstroem)
1122{
1123 if (Binder != Bond) // let other atom white if it's via Root bond. In case it's cyclic it has to be reached again (yet Root is from OtherAtom already black, thus no problem)
1124 BFS.ColorList[OtherAtom->getNr()] = bond::lightgray;
1125 BFS.PredecessorList[OtherAtom->getNr()] = Walker; // Walker is the predecessor
1126 BFS.ShortestPathList[OtherAtom->getNr()] = BFS.ShortestPathList[Walker->getNr()] + 1;
1127 DoLog(2) && (Log() << Verbose(2) << "Coloring OtherAtom " << OtherAtom->getName() << " " << ((BFS.ColorList[OtherAtom->getNr()] == bond::white) ? "white" : "lightgray") << ", its predecessor is " << Walker->getName() << " and its Shortest Path is " << BFS.ShortestPathList[OtherAtom->getNr()] << " egde(s) long." << endl);
1128 if ((((BFS.ShortestPathList[OtherAtom->getNr()] < BFS.BondOrder) && (Binder != Bond)))) { // Check for maximum distance
1129 DoLog(3) && (Log() << Verbose(3));
1130 if (AddedAtomList[OtherAtom->getNr()] == NULL) { // add if it's not been so far
1131 AddedAtomList[OtherAtom->getNr()] = Mol->AddCopyAtom(OtherAtom);
1132 DoLog(0) && (Log() << Verbose(0) << "Added OtherAtom " << OtherAtom->getName());
1133 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->getNr()], AddedAtomList[OtherAtom->getNr()], Binder);
1134 DoLog(0) && (Log() << Verbose(0) << " and bond " << *(AddedBondList[Binder->nr]) << ", ");
1135 } else { // this code should actually never come into play (all white atoms are not yet present in BondMolecule, that's why they are white in the first place)
1136 DoLog(0) && (Log() << Verbose(0) << "Not adding OtherAtom " << OtherAtom->getName());
1137 if (AddedBondList[Binder->nr] == NULL) {
1138 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->getNr()], AddedAtomList[OtherAtom->getNr()], Binder);
1139 DoLog(0) && (Log() << Verbose(0) << ", added Bond " << *(AddedBondList[Binder->nr]));
1140 } else
1141 DoLog(0) && (Log() << Verbose(0) << ", not added Bond ");
1142 }
1143 DoLog(0) && (Log() << Verbose(0) << ", putting OtherAtom into queue." << endl);
1144 BFS.BFSStack->push_front(OtherAtom);
1145 } else { // out of bond order, then replace
1146 if ((AddedAtomList[OtherAtom->getNr()] == NULL) && (Binder->Cyclic))
1147 BFS.ColorList[OtherAtom->getNr()] = bond::white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
1148 if (Binder == Bond)
1149 DoLog(3) && (Log() << Verbose(3) << "Not Queueing, is the Root bond");
1150 else if (BFS.ShortestPathList[OtherAtom->getNr()] >= BFS.BondOrder)
1151 DoLog(3) && (Log() << Verbose(3) << "Not Queueing, is out of Bond Count of " << BFS.BondOrder);
1152 if (!Binder->Cyclic)
1153 DoLog(0) && (Log() << Verbose(0) << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl);
1154 if (AddedBondList[Binder->nr] == NULL) {
1155 if ((AddedAtomList[OtherAtom->getNr()] != NULL)) { // .. whether we add or saturate
1156 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->getNr()], AddedAtomList[OtherAtom->getNr()], Binder);
1157 } else {
1158#ifdef ADDHYDROGEN
1159 if (!Mol->AddHydrogenReplacementAtom(Binder, AddedAtomList[Walker->getNr()], Walker, OtherAtom, IsAngstroem))
1160 exit(1);
1161#endif
1162 }
1163 }
1164 }
1165}
1166;
1167
1168void BreadthFirstSearchAdd_VisitedNode(molecule *Mol, struct BFSAccounting &BFS, atom *&Walker, atom *&OtherAtom, bond *&Binder, bond *&Bond, atom **&AddedAtomList, bond **&AddedBondList, bool IsAngstroem)
1169{
1170 DoLog(3) && (Log() << Verbose(3) << "Not Adding, has already been visited." << endl);
1171 // This has to be a cyclic bond, check whether it's present ...
1172 if (AddedBondList[Binder->nr] == NULL) {
1173 if ((Binder != Bond) && (Binder->Cyclic) && (((BFS.ShortestPathList[Walker->getNr()] + 1) < BFS.BondOrder))) {
1174 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->getNr()], AddedAtomList[OtherAtom->getNr()], Binder);
1175 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
1176#ifdef ADDHYDROGEN
1177 if(!Mol->AddHydrogenReplacementAtom(Binder, AddedAtomList[Walker->getNr()], Walker, OtherAtom, IsAngstroem))
1178 exit(1);
1179#endif
1180 }
1181 }
1182}
1183;
1184
1185/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
1186 * Gray vertices are always enqueued in an std::deque<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
1187 * white and putting into queue.
1188 * \param *Mol Molecule class to add atoms to
1189 * \param **AddedAtomList list with added atom pointers, index is atom father's number
1190 * \param **AddedBondList list with added bond pointers, index is bond father's number
1191 * \param *Root root vertex for BFS
1192 * \param *Bond bond not to look beyond
1193 * \param BondOrder maximum distance for vertices to add
1194 * \param IsAngstroem lengths are in angstroem or bohrradii
1195 */
1196void molecule::BreadthFirstSearchAdd(molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
1197{
1198 struct BFSAccounting BFS;
1199 atom *Walker = NULL, *OtherAtom = NULL;
1200 bond *Binder = NULL;
1201
1202 // add Root if not done yet
1203 if (AddedAtomList[Root->getNr()] == NULL) // add Root if not yet present
1204 AddedAtomList[Root->getNr()] = Mol->AddCopyAtom(Root);
1205
1206 BreadthFirstSearchAdd_Init(BFS, Root, BondOrder, getAtomCount(), AddedAtomList);
1207
1208 // and go on ... Queue always contains all lightgray vertices
1209 while (!BFS.BFSStack->empty()) {
1210 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
1211 // e.g. if current atom is 2, push to end of stack are of length 3, but first all of length 2 would be popped. They again
1212 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
1213 // followed by n+1 till top of stack.
1214 Walker = BFS.BFSStack->front(); // pop oldest added
1215 BFS.BFSStack->pop_front();
1216 const BondList& ListOfBonds = Walker->getListOfBonds();
1217 DoLog(1) && (Log() << Verbose(1) << "Current Walker is: " << Walker->getName() << ", and has " << ListOfBonds.size() << " bonds." << endl);
1218 for (BondList::const_iterator Runner = ListOfBonds.begin();
1219 Runner != ListOfBonds.end();
1220 ++Runner) {
1221 if ((*Runner) != NULL) { // don't look at bond equal NULL
1222 Binder = (*Runner);
1223 OtherAtom = (*Runner)->GetOtherAtom(Walker);
1224 DoLog(2) && (Log() << Verbose(2) << "Current OtherAtom is: " << OtherAtom->getName() << " for bond " << *(*Runner) << "." << endl);
1225 if (BFS.ColorList[OtherAtom->getNr()] == bond::white) {
1226 BreadthFirstSearchAdd_UnvisitedNode(Mol, BFS, Walker, OtherAtom, Binder, Bond, AddedAtomList, AddedBondList, IsAngstroem);
1227 } else {
1228 BreadthFirstSearchAdd_VisitedNode(Mol, BFS, Walker, OtherAtom, Binder, Bond, AddedAtomList, AddedBondList, IsAngstroem);
1229 }
1230 }
1231 }
1232 BFS.ColorList[Walker->getNr()] = bond::black;
1233 DoLog(1) && (Log() << Verbose(1) << "Coloring Walker " << Walker->getName() << " black." << endl);
1234 }
1235 BreadthFirstSearchAdd_Free(BFS);
1236}
1237;
1238
1239/** Adds a bond as a copy to a given one
1240 * \param *left leftatom of new bond
1241 * \param *right rightatom of new bond
1242 * \param *CopyBond rest of fields in bond are copied from this
1243 * \return pointer to new bond
1244 */
1245bond * molecule::CopyBond(atom *left, atom *right, bond *CopyBond)
1246{
1247 bond *Binder = AddBond(left, right, CopyBond->BondDegree);
1248 Binder->Cyclic = CopyBond->Cyclic;
1249 Binder->Type = CopyBond->Type;
1250 return Binder;
1251}
1252;
1253
1254void BuildInducedSubgraph_Init(atom **&ParentList, int AtomCount)
1255{
1256 // reset parent list
1257 ParentList = new atom*[AtomCount];
1258 for (int i=0;i<AtomCount;i++)
1259 ParentList[i] = NULL;
1260 DoLog(3) && (Log() << Verbose(3) << "Resetting ParentList." << endl);
1261}
1262;
1263
1264void BuildInducedSubgraph_FillParentList(const molecule *mol, const molecule *Father, atom **&ParentList)
1265{
1266 // fill parent list with sons
1267 DoLog(3) && (Log() << Verbose(3) << "Filling Parent List." << endl);
1268 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
1269 ParentList[(*iter)->father->getNr()] = (*iter);
1270 // Outputting List for debugging
1271 DoLog(4) && (Log() << Verbose(4) << "Son[" << (*iter)->father->getNr() << "] of " << (*iter)->father << " is " << ParentList[(*iter)->father->getNr()] << "." << endl);
1272 }
1273};
1274
1275void BuildInducedSubgraph_Finalize(atom **&ParentList)
1276{
1277 delete[](ParentList);
1278}
1279;
1280
1281bool BuildInducedSubgraph_CreateBondsFromParent(molecule *mol, const molecule *Father, atom **&ParentList)
1282{
1283 bool status = true;
1284 atom *OtherAtom = NULL;
1285 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
1286 DoLog(3) && (Log() << Verbose(3) << "Creating bonds." << endl);
1287 for (molecule::const_iterator iter = Father->begin(); iter != Father->end(); ++iter) {
1288 if (ParentList[(*iter)->getNr()] != NULL) {
1289 if (ParentList[(*iter)->getNr()]->father != (*iter)) {
1290 status = false;
1291 } else {
1292 const BondList& ListOfBonds = (*iter)->getListOfBonds();
1293 for (BondList::const_iterator Runner = ListOfBonds.begin();
1294 Runner != ListOfBonds.end();
1295 ++Runner) {
1296 OtherAtom = (*Runner)->GetOtherAtom((*iter));
1297 if (ParentList[OtherAtom->getNr()] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
1298 DoLog(4) && (Log() << Verbose(4) << "Endpoints of Bond " << (*Runner) << " are both present: " << ParentList[(*iter)->getNr()]->getName() << " and " << ParentList[OtherAtom->getNr()]->getName() << "." << endl);
1299 mol->AddBond(ParentList[(*iter)->getNr()], ParentList[OtherAtom->getNr()], (*Runner)->BondDegree);
1300 }
1301 }
1302 }
1303 }
1304 }
1305 return status;
1306}
1307;
1308
1309/** Adds bond structure to this molecule from \a Father molecule.
1310 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
1311 * with end points present in this molecule, bond is created in this molecule.
1312 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
1313 * \param *Father father molecule
1314 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
1315 * \todo not checked, not fully working probably
1316 */
1317bool molecule::BuildInducedSubgraph(const molecule *Father){
1318 bool status = true;
1319 atom **ParentList = NULL;
1320 DoLog(2) && (Log() << Verbose(2) << "Begin of BuildInducedSubgraph." << endl);
1321 BuildInducedSubgraph_Init(ParentList, Father->getAtomCount());
1322 BuildInducedSubgraph_FillParentList(this, Father, ParentList);
1323 status = BuildInducedSubgraph_CreateBondsFromParent(this, Father, ParentList);
1324 BuildInducedSubgraph_Finalize(ParentList);
1325 DoLog(2) && (Log() << Verbose(2) << "End of BuildInducedSubgraph." << endl);
1326 return status;
1327}
1328;
1329
1330/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
1331 * \param *Fragment Keyset of fragment's vertices
1332 * \return true - connected, false - disconnected
1333 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
1334 */
1335bool molecule::CheckForConnectedSubgraph(KeySet *Fragment)
1336{
1337 atom *Walker = NULL, *Walker2 = NULL;
1338 bool BondStatus = false;
1339 int size;
1340
1341 DoLog(1) && (Log() << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl);
1342 DoLog(2) && (Log() << Verbose(2) << "Disconnected atom: ");
1343
1344 // count number of atoms in graph
1345 size = 0;
1346 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
1347 size++;
1348 if (size > 1)
1349 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
1350 Walker = FindAtom(*runner);
1351 BondStatus = false;
1352 for (KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
1353 Walker2 = FindAtom(*runners);
1354 const BondList& ListOfBonds = Walker->getListOfBonds();
1355 for (BondList::const_iterator Runner = ListOfBonds.begin();
1356 Runner != ListOfBonds.end();
1357 ++Runner) {
1358 if ((*Runner)->GetOtherAtom(Walker) == Walker2) {
1359 BondStatus = true;
1360 break;
1361 }
1362 if (BondStatus)
1363 break;
1364 }
1365 }
1366 if (!BondStatus) {
1367 DoLog(0) && (Log() << Verbose(0) << (*Walker) << endl);
1368 return false;
1369 }
1370 }
1371 else {
1372 DoLog(0) && (Log() << Verbose(0) << "none." << endl);
1373 return true;
1374 }
1375 DoLog(0) && (Log() << Verbose(0) << "none." << endl);
1376
1377 DoLog(1) && (Log() << Verbose(1) << "End of CheckForConnectedSubgraph" << endl);
1378
1379 return true;
1380}
Note: See TracBrowser for help on using the repository browser.