source: src/molecule_graph.cpp@ 05a97c

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 05a97c was 05a97c, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Replaced some error conditions with ASSERTs

  • Property mode set to 100644
File size: 60.9 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 "Helpers/Assert.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 ASSERT(Walker,"Could not find an atom with the ID given in dbond file");
76 OtherWalker = FindAtom(atom2);
77 ASSERT(OtherWalker,"Could not find an atom with the ID given in dbond file");
78 AddBond(Walker, OtherWalker); //Add the bond between the two atoms with respective indices.
79 }
80}
81;
82
83/** Creates an adjacency list of the molecule.
84 * Generally, we use the CSD approach to bond recognition, that is the the distance
85 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
86 * a threshold t = 0.4 Angstroem.
87 * To make it O(N log N) the function uses the linked-cell technique as follows:
88 * The procedure is step-wise:
89 * -# Remove every bond in list
90 * -# Count the atoms in the molecule with CountAtoms()
91 * -# partition cell into smaller linked cells of size \a bonddistance
92 * -# put each atom into its corresponding cell
93 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true
94 * -# correct the bond degree iteratively (single->double->triple bond)
95 * -# finally print the bond list to \a *out if desired
96 * \param *out out stream for printing the matrix, NULL if no output
97 * \param bonddistance length of linked cells (i.e. maximum minimal length checked)
98 * \param IsAngstroem whether coordinate system is gauged to Angstroem or Bohr radii
99 * \param *minmaxdistance function to give upper and lower bound on whether particle is bonded to some other
100 * \param *BG BondGraph with the member function above or NULL, if just standard covalent should be used.
101 */
102void molecule::CreateAdjacencyList(double bonddistance, bool IsAngstroem, void (BondGraph::*minmaxdistance)(BondedParticle * const , BondedParticle * const , double &, double &, bool), BondGraph *BG)
103{
104 atom *Walker = NULL;
105 atom *OtherWalker = NULL;
106 int n[NDIM];
107 double MinDistance, MaxDistance;
108 LinkedCell *LC = NULL;
109 bool free_BG = false;
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 Log() << Verbose(1) << "AtomCount " << getAtomCount() << " and bonddistance is " << bonddistance << "." << endl;
130
131 if ((getAtomCount() > 1) && (bonddistance > 1.)) {
132 Log() << Verbose(2) << "Creating Linked Cell structure ... " << endl;
133 LC = new LinkedCell(this, bonddistance);
134
135 // create a list to map Tesselpoint::nr to atom *
136 Log() << Verbose(2) << "Creating TesselPoint to atom map ... " << endl;
137
138 // set numbers for atoms that can later be used
139 int i=0;
140 for(internal_iterator iter = atoms.begin();iter!= atoms.end(); ++iter){
141 (*iter)->nr = i++;
142 }
143
144 // 3a. go through every cell
145 Log() << Verbose(2) << "Celling ... " << endl;
146 for (LC->n[0] = 0; LC->n[0] < LC->N[0]; LC->n[0]++)
147 for (LC->n[1] = 0; LC->n[1] < LC->N[1]; LC->n[1]++)
148 for (LC->n[2] = 0; LC->n[2] < LC->N[2]; LC->n[2]++) {
149 const LinkedNodes *List = LC->GetCurrentCell();
150 //Log() << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << " containing " << List->size() << " points." << endl;
151 if (List != NULL) {
152 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
153 Walker = dynamic_cast<atom*>(*Runner);
154 ASSERT(Walker,"Tesselpoint that was not an atom retrieved from LinkedNode");
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 = dynamic_cast<atom*>(*OtherRunner);
166 ASSERT(OtherWalker,"TesselPoint that was not an atom retrieved from LinkedNode");
167 //Log() << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl;
168 (BG->*minmaxdistance)(Walker, OtherWalker, MinDistance, MaxDistance, IsAngstroem);
169 const double distance = OtherWalker->x.PeriodicDistanceSquared(&(Walker->x), cell_size);
170 const bool status = (distance <= MaxDistance * MaxDistance) && (distance >= MinDistance * MinDistance);
171 if ((OtherWalker->father->nr > Walker->father->nr) && (status)) { // create bond if distance is smaller
172 //Log() << Verbose(1) << "Adding Bond between " << *Walker << " and " << *OtherWalker << " in distance " << sqrt(distance) << "." << endl;
173 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount
174 } else {
175 //Log() << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl;
176 }
177 }
178 }
179 }
180 }
181 }
182 }
183 }
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 " << getAtomCount() << ", 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 " << getAtomCount() << " 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->getAtomCount());
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 for (molecule::const_iterator iter = begin(); iter != end();) {
501 DFS.Root = *iter;
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 ((iter != end()) && ((*iter)->GraphNr != -1)) {
542 //Log() << Verbose(1) << "Current next subgraph root candidate is " << (*iter)->Name << "." << endl;
543 if ((*iter)->GraphNr != -1) // if already discovered, step on
544 iter++;
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 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
848 Root = *iter;
849
850 if (MinimumRingSize[Root->GetTrueFather()->nr] == mol->getAtomCount()) { // check whether MinimumRingSize is set, if not BFS to next where it is
851 Walker = Root;
852
853 //Log() << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
854 CyclicStructureAnalysis_BFSToNextCycle(Root, Walker, MinimumRingSize, mol->getAtomCount());
855
856 }
857 Log() << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl;
858 }
859 Log() << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl;
860 } else
861 Log() << Verbose(1) << "No rings were detected in the molecular structure." << endl;
862}
863;
864
865/** Analyses the cycles found and returns minimum of all cycle lengths.
866 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
867 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
868 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
869 * as cyclic and print out the cycles.
870 * \param *out output stream for debugging
871 * \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!
872 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
873 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
874 */
875void molecule::CyclicStructureAnalysis(class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize) const
876{
877 struct BFSAccounting BFS;
878 atom *Walker = NULL;
879 atom *OtherAtom = NULL;
880 bond *BackEdge = NULL;
881 int NumCycles = 0;
882 int MinRingSize = -1;
883
884 InitializeBFSAccounting(BFS, getAtomCount());
885
886 //Log() << Verbose(1) << "Back edge list - ";
887 //BackEdgeStack->Output(out);
888
889 Log() << Verbose(1) << "Analysing cycles ... " << endl;
890 NumCycles = 0;
891 while (!BackEdgeStack->IsEmpty()) {
892 BackEdge = BackEdgeStack->PopFirst();
893 // this is the target
894 BFS.Root = BackEdge->leftatom;
895 // this is the source point
896 Walker = BackEdge->rightatom;
897
898 ResetBFSAccounting(Walker, BFS);
899
900 Log() << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
901 OtherAtom = NULL;
902 CyclicStructureAnalysis_CyclicBFSFromRootToRoot(BackEdge, BFS);
903
904 CyclicStructureAnalysis_RetrieveCycleMembers(OtherAtom, BackEdge, BFS, MinimumRingSize, MinRingSize);
905
906 CleanBFSAccounting(BFS);
907 }
908 FinalizeBFSAccounting(BFS);
909
910 CyclicStructureAnalysis_AssignRingSizetoNonCycleMembers(MinimumRingSize, MinRingSize, NumCycles, this);
911};
912
913/** Sets the next component number.
914 * This is O(N) as the number of bonds per atom is bound.
915 * \param *vertex atom whose next atom::*ComponentNr is to be set
916 * \param nr number to use
917 */
918void molecule::SetNextComponentNumber(atom *vertex, int nr) const
919{
920 size_t i = 0;
921 if (vertex != NULL) {
922 for (; i < vertex->ListOfBonds.size(); i++) {
923 if (vertex->ComponentNr[i] == -1) { // check if not yet used
924 vertex->ComponentNr[i] = nr;
925 break;
926 } else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
927 break; // breaking here will not cause error!
928 }
929 if (i == vertex->ListOfBonds.size()) {
930 eLog() << Verbose(0) << "Error: All Component entries are already occupied!" << endl;
931 performCriticalExit();
932 }
933 } else {
934 eLog() << Verbose(0) << "Error: Given vertex is NULL!" << endl;
935 performCriticalExit();
936 }
937}
938;
939
940/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
941 * \param *vertex atom to regard
942 * \return bond class or NULL
943 */
944bond * molecule::FindNextUnused(atom *vertex) const
945{
946 for (BondList::const_iterator Runner = vertex->ListOfBonds.begin(); Runner != vertex->ListOfBonds.end(); (++Runner))
947 if ((*Runner)->IsUsed() == white)
948 return ((*Runner));
949 return NULL;
950}
951;
952
953/** Resets bond::Used flag of all bonds in this molecule.
954 * \return true - success, false - -failure
955 */
956void molecule::ResetAllBondsToUnused() const
957{
958 bond *Binder = first;
959 while (Binder->next != last) {
960 Binder = Binder->next;
961 Binder->ResetUsed();
962 }
963}
964;
965
966/** Output a list of flags, stating whether the bond was visited or not.
967 * \param *out output stream for debugging
968 * \param *list
969 */
970void OutputAlreadyVisited(int *list)
971{
972 Log() << Verbose(4) << "Already Visited Bonds:\t";
973 for (int i = 1; i <= list[0]; i++)
974 Log() << Verbose(0) << list[i] << " ";
975 Log() << Verbose(0) << endl;
976}
977;
978
979/** Storing the bond structure of a molecule to file.
980 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
981 * \param *out output stream for debugging
982 * \param *path path to file
983 * \return true - file written successfully, false - writing failed
984 */
985bool molecule::StoreAdjacencyToFile(char *path)
986{
987 ofstream AdjacencyFile;
988 stringstream line;
989 bool status = true;
990
991 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
992 AdjacencyFile.open(line.str().c_str(), ios::out);
993 Log() << Verbose(1) << "Saving adjacency list ... ";
994 if (AdjacencyFile != NULL) {
995 AdjacencyFile << "m\tn" << endl;
996 ActOnAllAtoms(&atom::OutputAdjacency, &AdjacencyFile);
997 AdjacencyFile.close();
998 Log() << Verbose(1) << "done." << endl;
999 } else {
1000 Log() << Verbose(1) << "failed to open file " << line.str() << "." << endl;
1001 status = false;
1002 }
1003
1004 return status;
1005}
1006;
1007
1008/** Storing the bond structure of a molecule to file.
1009 * Simply stores Atom::nr and then the Atom::nr of all bond partners, one per line.
1010 * \param *out output stream for debugging
1011 * \param *path path to file
1012 * \return true - file written successfully, false - writing failed
1013 */
1014bool molecule::StoreBondsToFile(char *path)
1015{
1016 ofstream BondFile;
1017 stringstream line;
1018 bool status = true;
1019
1020 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
1021 BondFile.open(line.str().c_str(), ios::out);
1022 Log() << Verbose(1) << "Saving adjacency list ... ";
1023 if (BondFile != NULL) {
1024 BondFile << "m\tn" << endl;
1025 ActOnAllAtoms(&atom::OutputBonds, &BondFile);
1026 BondFile.close();
1027 Log() << Verbose(1) << "done." << endl;
1028 } else {
1029 Log() << Verbose(1) << "failed to open file " << line.str() << "." << endl;
1030 status = false;
1031 }
1032
1033 return status;
1034}
1035;
1036
1037bool CheckAdjacencyFileAgainstMolecule_Init(char *path, ifstream &File, int *&CurrentBonds)
1038{
1039 stringstream filename;
1040 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
1041 File.open(filename.str().c_str(), ios::out);
1042 Log() << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... ";
1043 if (File == NULL)
1044 return false;
1045
1046 // allocate storage structure
1047 CurrentBonds = Calloc<int> (8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
1048 return true;
1049}
1050;
1051
1052void CheckAdjacencyFileAgainstMolecule_Finalize(ifstream &File, int *&CurrentBonds)
1053{
1054 File.close();
1055 File.clear();
1056 Free(&CurrentBonds);
1057}
1058;
1059
1060void CheckAdjacencyFileAgainstMolecule_CompareBonds(bool &status, int &NonMatchNumber, atom *&Walker, size_t &CurrentBondsOfAtom, int AtomNr, int *&CurrentBonds, atom **ListOfAtoms)
1061{
1062 size_t j = 0;
1063 int id = -1;
1064
1065 //Log() << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
1066 if (CurrentBondsOfAtom == Walker->ListOfBonds.size()) {
1067 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1068 id = (*Runner)->GetOtherAtom(Walker)->nr;
1069 j = 0;
1070 for (; (j < CurrentBondsOfAtom) && (CurrentBonds[j++] != id);)
1071 ; // check against all parsed bonds
1072 if (CurrentBonds[j - 1] != id) { // no match ? Then mark in ListOfAtoms
1073 ListOfAtoms[AtomNr] = NULL;
1074 NonMatchNumber++;
1075 status = false;
1076 //Log() << Verbose(0) << "[" << id << "]\t";
1077 } else {
1078 //Log() << Verbose(0) << id << "\t";
1079 }
1080 }
1081 //Log() << Verbose(0) << endl;
1082 } else {
1083 Log() << Verbose(0) << "Number of bonds for Atom " << *Walker << " does not match, parsed " << CurrentBondsOfAtom << " against " << Walker->ListOfBonds.size() << "." << endl;
1084 status = false;
1085 }
1086}
1087;
1088
1089/** Checks contents of adjacency file against bond structure in structure molecule.
1090 * \param *out output stream for debugging
1091 * \param *path path to file
1092 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
1093 * \return true - structure is equal, false - not equivalence
1094 */
1095bool molecule::CheckAdjacencyFileAgainstMolecule(char *path, atom **ListOfAtoms)
1096{
1097 ifstream File;
1098 bool status = true;
1099 atom *Walker = NULL;
1100 char *buffer = NULL;
1101 int *CurrentBonds = NULL;
1102 int NonMatchNumber = 0; // will number of atoms with differing bond structure
1103 size_t CurrentBondsOfAtom = -1;
1104
1105 if (!CheckAdjacencyFileAgainstMolecule_Init(path, File, CurrentBonds)) {
1106 Log() << Verbose(1) << "Adjacency file not found." << endl;
1107 return true;
1108 }
1109
1110 buffer = Malloc<char> (MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
1111 // Parse the file line by line and count the bonds
1112 while (!File.eof()) {
1113 File.getline(buffer, MAXSTRINGSIZE);
1114 stringstream line;
1115 line.str(buffer);
1116 int AtomNr = -1;
1117 line >> AtomNr;
1118 CurrentBondsOfAtom = -1; // we count one too far due to line end
1119 // parse into structure
1120 if ((AtomNr >= 0) && (AtomNr < getAtomCount())) {
1121 Walker = ListOfAtoms[AtomNr];
1122 while (!line.eof())
1123 line >> CurrentBonds[++CurrentBondsOfAtom];
1124 // compare against present bonds
1125 CheckAdjacencyFileAgainstMolecule_CompareBonds(status, NonMatchNumber, Walker, CurrentBondsOfAtom, AtomNr, CurrentBonds, ListOfAtoms);
1126 }
1127 }
1128 Free(&buffer);
1129 CheckAdjacencyFileAgainstMolecule_Finalize(File, CurrentBonds);
1130
1131 if (status) { // if equal we parse the KeySetFile
1132 Log() << Verbose(1) << "done: Equal." << endl;
1133 } else
1134 Log() << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
1135 return status;
1136}
1137;
1138
1139/** Picks from a global stack with all back edges the ones in the fragment.
1140 * \param *out output stream for debugging
1141 * \param **ListOfLocalAtoms array of father atom::nr to local atom::nr (reverse of atom::father)
1142 * \param *ReferenceStack stack with all the back egdes
1143 * \param *LocalStack stack to be filled
1144 * \return true - everything ok, false - ReferenceStack was empty
1145 */
1146bool molecule::PickLocalBackEdges(atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack) const
1147{
1148 bool status = true;
1149 if (ReferenceStack->IsEmpty()) {
1150 Log() << Verbose(1) << "ReferenceStack is empty!" << endl;
1151 return false;
1152 }
1153 bond *Binder = ReferenceStack->PopFirst();
1154 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
1155 atom *Walker = NULL, *OtherAtom = NULL;
1156 ReferenceStack->Push(Binder);
1157
1158 do { // go through all bonds and push local ones
1159 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule
1160 if (Walker != NULL) // if this Walker exists in the subgraph ...
1161 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1162 OtherAtom = (*Runner)->GetOtherAtom(Walker);
1163 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->nr]) { // found the bond
1164 LocalStack->Push((*Runner));
1165 Log() << Verbose(3) << "Found local edge " << *(*Runner) << "." << endl;
1166 break;
1167 }
1168 }
1169 Binder = ReferenceStack->PopFirst(); // loop the stack for next item
1170 Log() << Verbose(3) << "Current candidate edge " << Binder << "." << endl;
1171 ReferenceStack->Push(Binder);
1172 } while (FirstBond != Binder);
1173
1174 return status;
1175}
1176;
1177
1178void BreadthFirstSearchAdd_Init(struct BFSAccounting &BFS, atom *&Root, int AtomCount, int BondOrder, atom **AddedAtomList = NULL)
1179{
1180 BFS.AtomCount = AtomCount;
1181 BFS.BondOrder = BondOrder;
1182 BFS.PredecessorList = Calloc<atom*> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: **PredecessorList");
1183 BFS.ShortestPathList = Calloc<int> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ShortestPathList");
1184 BFS.ColorList = Malloc<enum Shading> (AtomCount, "molecule::BreadthFirstSearchAdd_Init: *ColorList");
1185 BFS.BFSStack = new StackClass<atom *> (AtomCount);
1186
1187 BFS.Root = Root;
1188 BFS.BFSStack->ClearStack();
1189 BFS.BFSStack->Push(Root);
1190
1191 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
1192 for (int i = AtomCount; i--;) {
1193 BFS.ShortestPathList[i] = -1;
1194 if ((AddedAtomList != NULL) && (AddedAtomList[i] != NULL)) // mark already present atoms (i.e. Root and maybe others) as visited
1195 BFS.ColorList[i] = lightgray;
1196 else
1197 BFS.ColorList[i] = white;
1198 }
1199 //BFS.ShortestPathList[Root->nr] = 0; //is set due to Calloc()
1200}
1201;
1202
1203void BreadthFirstSearchAdd_Free(struct BFSAccounting &BFS)
1204{
1205 Free(&BFS.PredecessorList);
1206 Free(&BFS.ShortestPathList);
1207 Free(&BFS.ColorList);
1208 delete (BFS.BFSStack);
1209 BFS.AtomCount = 0;
1210}
1211;
1212
1213void BreadthFirstSearchAdd_UnvisitedNode(molecule *Mol, struct BFSAccounting &BFS, atom *&Walker, atom *&OtherAtom, bond *&Binder, bond *&Bond, atom **&AddedAtomList, bond **&AddedBondList, bool IsAngstroem)
1214{
1215 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)
1216 BFS.ColorList[OtherAtom->nr] = lightgray;
1217 BFS.PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
1218 BFS.ShortestPathList[OtherAtom->nr] = BFS.ShortestPathList[Walker->nr] + 1;
1219 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;
1220 if ((((BFS.ShortestPathList[OtherAtom->nr] < BFS.BondOrder) && (Binder != Bond)))) { // Check for maximum distance
1221 Log() << Verbose(3);
1222 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
1223 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
1224 Log() << Verbose(0) << "Added OtherAtom " << OtherAtom->Name;
1225 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder);
1226 Log() << Verbose(0) << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
1227 } 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)
1228 Log() << Verbose(0) << "Not adding OtherAtom " << OtherAtom->Name;
1229 if (AddedBondList[Binder->nr] == NULL) {
1230 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder);
1231 Log() << Verbose(0) << ", added Bond " << *(AddedBondList[Binder->nr]);
1232 } else
1233 Log() << Verbose(0) << ", not added Bond ";
1234 }
1235 Log() << Verbose(0) << ", putting OtherAtom into queue." << endl;
1236 BFS.BFSStack->Push(OtherAtom);
1237 } else { // out of bond order, then replace
1238 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
1239 BFS.ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
1240 if (Binder == Bond)
1241 Log() << Verbose(3) << "Not Queueing, is the Root bond";
1242 else if (BFS.ShortestPathList[OtherAtom->nr] >= BFS.BondOrder)
1243 Log() << Verbose(3) << "Not Queueing, is out of Bond Count of " << BFS.BondOrder;
1244 if (!Binder->Cyclic)
1245 Log() << Verbose(0) << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
1246 if (AddedBondList[Binder->nr] == NULL) {
1247 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
1248 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder);
1249 } else {
1250#ifdef ADDHYDROGEN
1251 if (!Mol->AddHydrogenReplacementAtom(Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, IsAngstroem))
1252 exit(1);
1253#endif
1254 }
1255 }
1256 }
1257}
1258;
1259
1260void BreadthFirstSearchAdd_VisitedNode(molecule *Mol, struct BFSAccounting &BFS, atom *&Walker, atom *&OtherAtom, bond *&Binder, bond *&Bond, atom **&AddedAtomList, bond **&AddedBondList, bool IsAngstroem)
1261{
1262 Log() << Verbose(3) << "Not Adding, has already been visited." << endl;
1263 // This has to be a cyclic bond, check whether it's present ...
1264 if (AddedBondList[Binder->nr] == NULL) {
1265 if ((Binder != Bond) && (Binder->Cyclic) && (((BFS.ShortestPathList[Walker->nr] + 1) < BFS.BondOrder))) {
1266 AddedBondList[Binder->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder);
1267 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
1268#ifdef ADDHYDROGEN
1269 if(!Mol->AddHydrogenReplacementAtom(Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, IsAngstroem))
1270 exit(1);
1271#endif
1272 }
1273 }
1274}
1275;
1276
1277/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
1278 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
1279 * white and putting into queue.
1280 * \param *out output stream for debugging
1281 * \param *Mol Molecule class to add atoms to
1282 * \param **AddedAtomList list with added atom pointers, index is atom father's number
1283 * \param **AddedBondList list with added bond pointers, index is bond father's number
1284 * \param *Root root vertex for BFS
1285 * \param *Bond bond not to look beyond
1286 * \param BondOrder maximum distance for vertices to add
1287 * \param IsAngstroem lengths are in angstroem or bohrradii
1288 */
1289void molecule::BreadthFirstSearchAdd(molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
1290{
1291 struct BFSAccounting BFS;
1292 atom *Walker = NULL, *OtherAtom = NULL;
1293 bond *Binder = NULL;
1294
1295 // add Root if not done yet
1296 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
1297 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
1298
1299 BreadthFirstSearchAdd_Init(BFS, Root, BondOrder, getAtomCount(), AddedAtomList);
1300
1301 // and go on ... Queue always contains all lightgray vertices
1302 while (!BFS.BFSStack->IsEmpty()) {
1303 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
1304 // 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
1305 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
1306 // followed by n+1 till top of stack.
1307 Walker = BFS.BFSStack->PopFirst(); // pop oldest added
1308 Log() << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << Walker->ListOfBonds.size() << " bonds." << endl;
1309 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1310 if ((*Runner) != NULL) { // don't look at bond equal NULL
1311 Binder = (*Runner);
1312 OtherAtom = (*Runner)->GetOtherAtom(Walker);
1313 Log() << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *(*Runner) << "." << endl;
1314 if (BFS.ColorList[OtherAtom->nr] == white) {
1315 BreadthFirstSearchAdd_UnvisitedNode(Mol, BFS, Walker, OtherAtom, Binder, Bond, AddedAtomList, AddedBondList, IsAngstroem);
1316 } else {
1317 BreadthFirstSearchAdd_VisitedNode(Mol, BFS, Walker, OtherAtom, Binder, Bond, AddedAtomList, AddedBondList, IsAngstroem);
1318 }
1319 }
1320 }
1321 BFS.ColorList[Walker->nr] = black;
1322 Log() << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
1323 }
1324 BreadthFirstSearchAdd_Free(BFS);
1325}
1326;
1327
1328/** Adds a bond as a copy to a given one
1329 * \param *left leftatom of new bond
1330 * \param *right rightatom of new bond
1331 * \param *CopyBond rest of fields in bond are copied from this
1332 * \return pointer to new bond
1333 */
1334bond * molecule::CopyBond(atom *left, atom *right, bond *CopyBond)
1335{
1336 bond *Binder = AddBond(left, right, CopyBond->BondDegree);
1337 Binder->Cyclic = CopyBond->Cyclic;
1338 Binder->Type = CopyBond->Type;
1339 return Binder;
1340}
1341;
1342
1343void BuildInducedSubgraph_Init(atom **&ParentList, int AtomCount)
1344{
1345 // reset parent list
1346 ParentList = Calloc<atom*> (AtomCount, "molecule::BuildInducedSubgraph_Init: **ParentList");
1347 Log() << Verbose(3) << "Resetting ParentList." << endl;
1348}
1349;
1350
1351void BuildInducedSubgraph_FillParentList(const molecule *mol, const molecule *Father, atom **&ParentList)
1352{
1353 // fill parent list with sons
1354 Log() << Verbose(3) << "Filling Parent List." << endl;
1355 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
1356 ParentList[(*iter)->father->nr] = (*iter);
1357 // Outputting List for debugging
1358 Log() << Verbose(4) << "Son[" << (*iter)->father->nr << "] of " << (*iter)->father << " is " << ParentList[(*iter)->father->nr] << "." << endl;
1359 }
1360
1361}
1362;
1363
1364void BuildInducedSubgraph_Finalize(atom **&ParentList)
1365{
1366 Free(&ParentList);
1367}
1368;
1369
1370bool BuildInducedSubgraph_CreateBondsFromParent(molecule *mol, const molecule *Father, atom **&ParentList)
1371{
1372 bool status = true;
1373 atom *OtherAtom = NULL;
1374 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
1375 Log() << Verbose(3) << "Creating bonds." << endl;
1376 for (molecule::const_iterator iter = Father->begin(); iter != Father->end(); ++iter) {
1377 if (ParentList[(*iter)->nr] != NULL) {
1378 if (ParentList[(*iter)->nr]->father != (*iter)) {
1379 status = false;
1380 } else {
1381 for (BondList::const_iterator Runner = (*iter)->ListOfBonds.begin(); Runner != (*iter)->ListOfBonds.end(); (++Runner)) {
1382 OtherAtom = (*Runner)->GetOtherAtom((*iter));
1383 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
1384 Log() << Verbose(4) << "Endpoints of Bond " << (*Runner) << " are both present: " << ParentList[(*iter)->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
1385 mol->AddBond(ParentList[(*iter)->nr], ParentList[OtherAtom->nr], (*Runner)->BondDegree);
1386 }
1387 }
1388 }
1389 }
1390 }
1391 return status;
1392}
1393;
1394
1395/** Adds bond structure to this molecule from \a Father molecule.
1396 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
1397 * with end points present in this molecule, bond is created in this molecule.
1398 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
1399 * \param *out output stream for debugging
1400 * \param *Father father molecule
1401 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
1402 * \todo not checked, not fully working probably
1403 */
1404bool molecule::BuildInducedSubgraph(const molecule *Father)
1405{
1406 bool status = true;
1407 atom **ParentList = NULL;
1408
1409 Log() << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
1410 BuildInducedSubgraph_Init(ParentList, Father->getAtomCount());
1411 BuildInducedSubgraph_FillParentList(this, Father, ParentList);
1412 status = BuildInducedSubgraph_CreateBondsFromParent(this, Father, ParentList);
1413 BuildInducedSubgraph_Finalize(ParentList);
1414 Log() << Verbose(2) << "End of BuildInducedSubgraph." << endl;
1415 return status;
1416}
1417;
1418
1419/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
1420 * \param *out output stream for debugging
1421 * \param *Fragment Keyset of fragment's vertices
1422 * \return true - connected, false - disconnected
1423 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
1424 */
1425bool molecule::CheckForConnectedSubgraph(KeySet *Fragment)
1426{
1427 atom *Walker = NULL, *Walker2 = NULL;
1428 bool BondStatus = false;
1429 int size;
1430
1431 Log() << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
1432 Log() << Verbose(2) << "Disconnected atom: ";
1433
1434 // count number of atoms in graph
1435 size = 0;
1436 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
1437 size++;
1438 if (size > 1)
1439 for (KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
1440 Walker = FindAtom(*runner);
1441 BondStatus = false;
1442 for (KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
1443 Walker2 = FindAtom(*runners);
1444 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1445 if ((*Runner)->GetOtherAtom(Walker) == Walker2) {
1446 BondStatus = true;
1447 break;
1448 }
1449 if (BondStatus)
1450 break;
1451 }
1452 }
1453 if (!BondStatus) {
1454 Log() << Verbose(0) << (*Walker) << endl;
1455 return false;
1456 }
1457 }
1458 else {
1459 Log() << Verbose(0) << "none." << endl;
1460 return true;
1461 }
1462 Log() << Verbose(0) << "none." << endl;
1463
1464 Log() << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
1465
1466 return true;
1467}
Note: See TracBrowser for help on using the repository browser.