source: src/molecule_graph.cpp@ 03c77c

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

bonds::previous and ::next removed, lists.hpp deleted.

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