source: src/molecule_graph.cpp@ 9879f6

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

Huge Refactoring due to class molecule now being an STL container.

  • molecule::start and molecule::end were dropped. Hence, the usual construct Walker = start while (Walker->next != end) {

Walker = walker->next
...

}
was changed to
for (molecule::iterator iter = begin(); iter != end(); ++iter) {

...

}
and (*iter) used instead of Walker.

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