source: src/molecule_graph.cpp@ b48ba6

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

Log() and eLog() are prepended by a DoLog()/DoeLog() construct.

  • Most of the run time (95%) is spent on verbosity that it is discarded anyway due to a low verbosity setting. However, the operator << is evaluated from the right-hand side, hence the whole message is constructed and then thrown away.
  • DoLog() and DoeLog() are new functions that check the verbosity beforehand and are used as follows: DoLog(2) && (Log() << verbose(2) << "message" << endl);

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

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