source: src/molecule_graph.cpp@ 7326b2

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

Extension to the periodic boundary case for analysis_correlation.cpp

other stuff:

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