source: src/molecule_graph.cpp@ 735b1c

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

ParticleInfo::ParticleInfo_nr is protected and accessed via getter/setter.

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