source: src/molecule_graph.cpp@ f2bb0f

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since f2bb0f was f2bb0f, checked in by Tillmann Crueger <crueger@…>, 15 years ago

FIX: Repaired memory smashing in CreateAdjacencyList

BROKEN: Unittests still fail

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