source: src/molecule_graph.cpp@ eecd33

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

"not working parsed molecule into subgraph splitting"-BUG fixed, BugFinder branch can be closed.

  • config::Load() - atoms were not in the right order for MaxOrder-test (12). Hence, the BondFragmentAdjacency could not be parsed. Now, we just take the subgraphs as the association of each atom to a molecule, i.e. we make a list and then re-link each atom to its new connected subgraph molecule, which is returned as the MoleculeListClass.

other fixes:

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