source: src/molecule_graph.cpp@ e7350d4

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

Made BondGraph an instance of World, removed from config.

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