source: src/molecule_graph.cpp@ 1bfc8e

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 1bfc8e was 9d37ac, checked in by Frederik Heber <heber@…>, 14 years ago

DOCUFIX: Removed *out as parameter from waaay back ...

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