source: src/molecule_graph.cpp@ 174e0e

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 174e0e was 174e0e, checked in by Frederik Heber <heber@…>, 16 years ago

Refactored molecule::DepthFirstSearchAnalysis()

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