source: src/molecule_graph.cpp@ 3839e5

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 3839e5 was 4e10f5, checked in by Tillmann Crueger <crueger@…>, 14 years ago

Merge branch 'stable' into StructureRefactoring

Conflicts:

src/Actions/WorldAction/CenterOnEdgeAction.cpp
src/Actions/WorldAction/ChangeBoxAction.cpp
src/Actions/WorldAction/RepeatBoxAction.cpp
src/Actions/WorldAction/ScaleBoxAction.cpp
src/World.cpp
src/boundary.cpp

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