source: src/molecule_graph.cpp@ d4a44c

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

Removed molecule::BondDistance, replaced by BondGraph::getMinMaxDistance().

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