source: src/molecule_graph.cpp@ 2aeefd

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 2aeefd was 7218f8, checked in by Frederik Heber <heber@…>, 16 years ago

Several memory bugfixes (thx valgrind).

Fixed Calloc:

Signed-off-by: Frederik Heber <heber@…>

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