source: src/molecule_graph.cpp@ 5f5a7b

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

Added #include "Helpers/MemDebug.hpp" to all .cpp files

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