source: src/molecule_graph.cpp@ 7d8342

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 7d8342 was af2c424, checked in by Frederik Heber <heber@…>, 15 years ago

LinkedCell constructor rewritten.

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