source: src/molecule_graph.cpp@ fd179f

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 fd179f was b34306, checked in by Frederik Heber <heber@…>, 15 years ago

singleton class World introduced, contains only cell_size from class molecule.

  • class World is actually code from Till Crueger from his branch StructureRefactoring.
  • has been introduced here in minimalistic form to allow molecule::cell_size to be outsourced to World::cell_size
  • access to cell_size can be obtained from anyhwere by invoking World::get()->cell_size
  • INFO: cell_size was placed in class molecule for the fragmentation procedure where the cell_size had to be individually adapted to each fragment.
  • all appearances have been changed accordingly. Where appropriate we have employed a const pointer onto cell_size.

Signed-off-by: Frederik Heber <heber@…>

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