source: src/molecule_graph.cpp@ 32ea56

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

Removed several calls to molecule::ActOnEachAtom() from molecule_graph.cpp

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