source: src/molecule_graph.cpp@ ce5f05

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 Candidate_v1.7.0 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 ce5f05 was ce5f05, checked in by Frederik Heber <heber@…>, 15 years ago

Moved Shading and EdgeType from defs.hpp to bond.hpp, getColor from molecule to class bond.

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