source: src/molecule_graph.cpp@ ea7176

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 ea7176 was ea7176, checked in by Tillmann Crueger <crueger@…>, 15 years ago

FIX: Made AtomCount a Cacheable so that the number of atoms in a molecule will always be correct

All unittests working.
All Complete testcases fail.

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