source: src/molecule_graph.cpp@ 4b5cf8

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 4b5cf8 was 4b5cf8, checked in by Frederik Heber <heber@…>, 14 years ago

BondedParticle::OutputBondOfAtom() now takes stream to print to.

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