source: src/molecule_graph.cpp@ 5e8e02

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

Removed all inclusions of GSL-Headers from molecule.hpp

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