source: src/molecule_graph.cpp@ e5ad5c

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

BUGFIX: BondGraphUnitTest was not working.

Changes:

  • atoms are now carbon, not hydrogen
  • added covalent and van-der-Waals radii to element creation
  • FIX: carbon now has Z = 2.
  • added test case for NULL BondTable (i.e. from covalent radii)

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

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