source: src/molecule_graph.cpp@ b70721

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 Candidate_v1.7.0 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since b70721 was b70721, checked in by Frederik Heber <heber@…>, 16 years ago

New class BondGraph.

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