source: src/molecule_graph.cpp@ ae38fb

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

Fixing not created adjacency list, partially fixing subgraph dissection in config::Load()

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