source: src/molecule_graph.cpp@ df8b19

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

Removed ResetAllAtomNumbers(), replaced by templated SetAtomValueToValue().

  • Property mode set to 100644
File size: 52.5 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();
[df8b19]389 SetAtomValueToValue( -1, &atom::GraphNr );
[2cc75c3]390 ActOnAllAtoms( &atom::InitComponentNr );
[cee0b57]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
[ef9aae]496/** initialise each vertex as white with no predecessor, empty queue, color Root lightgray.
497 *
498 */
499void InitializeAccounting(atom **&PredecessorList, int *&ShortestPathList, enum Shading *&ColorList, int AtomCount)
500{
501 for (int i=AtomCount;i--;) {
502 PredecessorList[i] = NULL;
503 ShortestPathList[i] = -1;
504 ColorList[i] = white;
505 }
506};
507
508void ResetAccounting(atom *&Walker, class StackClass<atom *> *&TouchedStack, int *&ShortestPathList, class StackClass<atom *> *&BFSStack)
509{
510 ShortestPathList[Walker->nr] = 0;
511 BFSStack->ClearStack(); // start with empty BFS stack
512 BFSStack->Push(Walker);
513 TouchedStack->Push(Walker);
514};
515
516void CyclicBFSFromRootToRoot(ofstream *out, atom *&Root, bond *&BackEdge, class StackClass<atom *> *&TouchedStack, int *&ShortestPathList, atom **&PredecessorList, class StackClass<atom *> *&BFSStack, enum Shading *&ColorList)
517{
518 atom *Walker = NULL;
519 atom *OtherAtom = NULL;
520 do { // look for Root
521 Walker = BFSStack->PopFirst();
522 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
523 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
524 if ((*Runner) != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
525 OtherAtom = (*Runner)->GetOtherAtom(Walker);
526 #ifdef ADDHYDROGEN
527 if (OtherAtom->type->Z != 1) {
528 #endif
529 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *(*Runner) << "." << endl;
530 if (ColorList[OtherAtom->nr] == white) {
531 TouchedStack->Push(OtherAtom);
532 ColorList[OtherAtom->nr] = lightgray;
533 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
534 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
535 *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;
536 //if (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
537 *out << Verbose(3) << "Putting OtherAtom into queue." << endl;
538 BFSStack->Push(OtherAtom);
539 //}
540 } else {
541 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
542 }
543 if (OtherAtom == Root)
544 break;
545 #ifdef ADDHYDROGEN
546 } else {
547 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl;
548 ColorList[OtherAtom->nr] = black;
549 }
550 #endif
551 } else {
552 *out << Verbose(2) << "Bond " << *(*Runner) << " not Visiting, is the back edge." << endl;
553 }
554 }
555 ColorList[Walker->nr] = black;
556 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
557 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
558 // step through predecessor list
559 while (OtherAtom != BackEdge->rightatom) {
560 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
561 break;
562 else
563 OtherAtom = PredecessorList[OtherAtom->nr];
564 }
565 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
566 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;\
567 do {
568 OtherAtom = TouchedStack->PopLast();
569 if (PredecessorList[OtherAtom->nr] == Walker) {
570 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl;
571 PredecessorList[OtherAtom->nr] = NULL;
572 ShortestPathList[OtherAtom->nr] = -1;
573 ColorList[OtherAtom->nr] = white;
574 BFSStack->RemoveItem(OtherAtom);
575 }
576 } while ((!TouchedStack->IsEmpty()) && (PredecessorList[OtherAtom->nr] == NULL));
577 TouchedStack->Push(OtherAtom); // last was wrongly popped
578 OtherAtom = BackEdge->rightatom; // set to not Root
579 } else
580 OtherAtom = Root;
581 }
582 } while ((!BFSStack->IsEmpty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr])));
583};
584
585void RetrieveCycleMembers(ofstream *out, atom *&Root, atom *&OtherAtom, bond *&BackEdge, atom **&PredecessorList, int *&MinimumRingSize, int &MinRingSize)
586{
587 atom *Walker = NULL;
588 int NumCycles = 0;
589 int RingSize = -1;
590
591 if (OtherAtom == Root) {
592 // now climb back the predecessor list and thus find the cycle members
593 NumCycles++;
594 RingSize = 1;
595 Root->GetTrueFather()->IsCyclic = true;
596 *out << Verbose(1) << "Found ring contains: ";
597 Walker = Root;
598 while (Walker != BackEdge->rightatom) {
599 *out << Walker->Name << " <-> ";
600 Walker = PredecessorList[Walker->nr];
601 Walker->GetTrueFather()->IsCyclic = true;
602 RingSize++;
603 }
604 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl;
605 // walk through all and set MinimumRingSize
606 Walker = Root;
607 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
608 while (Walker != BackEdge->rightatom) {
609 Walker = PredecessorList[Walker->nr];
610 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr])
611 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
612 }
613 if ((RingSize < MinRingSize) || (MinRingSize == -1))
614 MinRingSize = RingSize;
615 } else {
616 *out << Verbose(1) << "No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl;
617 }
618};
619
620void CleanAccounting(class StackClass<atom *> *&TouchedStack, atom **&PredecessorList, int *&ShortestPathList, enum Shading *&ColorList)
621{
622 atom *Walker = NULL;
623 while (!TouchedStack->IsEmpty()){
624 Walker = TouchedStack->PopFirst();
625 PredecessorList[Walker->nr] = NULL;
626 ShortestPathList[Walker->nr] = -1;
627 ColorList[Walker->nr] = white;
628 }
629};
630
631
632void BFSToNextCycle(ofstream *out, atom *&Root, atom *&Walker, bond *&BackEdge, int *&MinimumRingSize, int AtomCount)
633{
634 atom **PredecessorList = Malloc<atom*>(AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList");
635 int *ShortestPathList = Malloc<int>(AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList");
636 enum Shading *ColorList = Malloc<enum Shading>(AtomCount, "molecule::CyclicStructureAnalysis: *ColorList");
637 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring
638 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop)
639 atom *OtherAtom = Walker;
640
641 InitializeAccounting(PredecessorList, ShortestPathList, ColorList, AtomCount);
642
643 ResetAccounting(Walker, TouchedStack, ShortestPathList, BFSStack);
644 while (OtherAtom != NULL) { // look for Root
645 Walker = BFSStack->PopFirst();
646 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
647 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
648 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
649 OtherAtom = (*Runner)->GetOtherAtom(Walker);
650 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
651 if (ColorList[OtherAtom->nr] == white) {
652 TouchedStack->Push(OtherAtom);
653 ColorList[OtherAtom->nr] = lightgray;
654 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
655 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
656 //*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;
657 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
658 MinimumRingSize[Root->GetTrueFather()->nr] = ShortestPathList[OtherAtom->nr]+MinimumRingSize[OtherAtom->GetTrueFather()->nr];
659 OtherAtom = NULL; //break;
660 break;
661 } else
662 BFSStack->Push(OtherAtom);
663 } else {
664 //*out << Verbose(3) << "Not Adding, has already been visited." << endl;
665 }
666 } else {
667 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl;
668 }
669 }
670 ColorList[Walker->nr] = black;
671 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
672 }
673 //CleanAccountingLists(TouchedStack, PredecessorList, ShortestPathList, ColorList);
674
675 Free(&PredecessorList);
676 Free(&ShortestPathList);
677 Free(&ColorList);
678 delete(BFSStack);
679};
680
681void AssignRingSizetoNonCycleMembers(ofstream *out, int *&MinimumRingSize, int &MinRingSize, int &NumCycles, molecule *mol, bond *&BackEdge)
682{
683 atom *Root= NULL;
684 atom *Walker = NULL;
685 if (MinRingSize != -1) { // if rings are present
686 // go over all atoms
687 Root = mol->start;
688 while(Root->next != mol->end) {
689 Root = Root->next;
690
691 if (MinimumRingSize[Root->GetTrueFather()->nr] == mol->AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is
692 Walker = Root;
693
694 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
695 BFSToNextCycle(out, Root, Walker, BackEdge, MinimumRingSize, mol->AtomCount);
696
697 }
698 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl;
699 }
700 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl;
701 } else
702 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
703};
704
[cee0b57]705/** Analyses the cycles found and returns minimum of all cycle lengths.
706 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
707 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
708 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
709 * as cyclic and print out the cycles.
710 * \param *out output stream for debugging
711 * \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!
712 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
713 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
714 */
715void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize)
716{
717 atom **PredecessorList = Malloc<atom*>(AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList");
718 int *ShortestPathList = Malloc<int>(AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList");
719 enum Shading *ColorList = Malloc<enum Shading>(AtomCount, "molecule::CyclicStructureAnalysis: *ColorList");
720 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring
721 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop)
[ef9aae]722 atom *Walker = NULL;
723 atom *OtherAtom = NULL;
724 atom *Root = NULL;
725 bond *BackEdge = NULL;
726 int NumCycles = 0;
727 int MinRingSize = -1;
[cee0b57]728
[ef9aae]729 InitializeAccounting(PredecessorList, ShortestPathList, ColorList, AtomCount);
[cee0b57]730
731 *out << Verbose(1) << "Back edge list - ";
732 BackEdgeStack->Output(out);
733
734 *out << Verbose(1) << "Analysing cycles ... " << endl;
735 NumCycles = 0;
736 while (!BackEdgeStack->IsEmpty()) {
737 BackEdge = BackEdgeStack->PopFirst();
738 // this is the target
739 Root = BackEdge->leftatom;
740 // this is the source point
741 Walker = BackEdge->rightatom;
742
[ef9aae]743 ResetAccounting(Walker, TouchedStack, ShortestPathList, BFSStack);
[cee0b57]744
[ef9aae]745 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
746 OtherAtom = NULL;
747 CyclicBFSFromRootToRoot(out, Root, BackEdge, TouchedStack, ShortestPathList, PredecessorList, BFSStack, ColorList);
[cee0b57]748
[ef9aae]749 RetrieveCycleMembers(out, Root, OtherAtom, BackEdge, PredecessorList, MinimumRingSize, MinRingSize);
[cee0b57]750
[ef9aae]751 CleanAccounting(TouchedStack, PredecessorList, ShortestPathList, ColorList);
752 }
[cee0b57]753 Free(&PredecessorList);
754 Free(&ShortestPathList);
755 Free(&ColorList);
756 delete(BFSStack);
[ef9aae]757
758 AssignRingSizetoNonCycleMembers(out, MinimumRingSize, MinRingSize, NumCycles, this, BackEdge);
759
[cee0b57]760};
761
762/** Sets the next component number.
763 * This is O(N) as the number of bonds per atom is bound.
764 * \param *vertex atom whose next atom::*ComponentNr is to be set
765 * \param nr number to use
766 */
767void molecule::SetNextComponentNumber(atom *vertex, int nr)
768{
[266237]769 size_t i=0;
[cee0b57]770 if (vertex != NULL) {
[266237]771 for(;i<vertex->ListOfBonds.size();i++) {
[cee0b57]772 if (vertex->ComponentNr[i] == -1) { // check if not yet used
773 vertex->ComponentNr[i] = nr;
774 break;
775 }
776 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
777 break; // breaking here will not cause error!
778 }
[266237]779 if (i == vertex->ListOfBonds.size())
[cee0b57]780 cerr << "Error: All Component entries are already occupied!" << endl;
781 } else
782 cerr << "Error: Given vertex is NULL!" << endl;
783};
784
785/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
786 * \param *vertex atom to regard
787 * \return bond class or NULL
788 */
789bond * molecule::FindNextUnused(atom *vertex)
790{
[266237]791 for (BondList::const_iterator Runner = vertex->ListOfBonds.begin(); Runner != vertex->ListOfBonds.end(); (++Runner))
792 if ((*Runner)->IsUsed() == white)
793 return((*Runner));
[cee0b57]794 return NULL;
795};
796
797/** Resets bond::Used flag of all bonds in this molecule.
798 * \return true - success, false - -failure
799 */
800void molecule::ResetAllBondsToUnused()
801{
802 bond *Binder = first;
803 while (Binder->next != last) {
804 Binder = Binder->next;
805 Binder->ResetUsed();
806 }
807};
808
809/** Output a list of flags, stating whether the bond was visited or not.
810 * \param *out output stream for debugging
811 * \param *list
812 */
813void OutputAlreadyVisited(ofstream *out, int *list)
814{
815 *out << Verbose(4) << "Already Visited Bonds:\t";
816 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " ";
817 *out << endl;
818};
819
820
821/** Storing the bond structure of a molecule to file.
822 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
823 * \param *out output stream for debugging
824 * \param *path path to file
825 * \return true - file written successfully, false - writing failed
826 */
827bool molecule::StoreAdjacencyToFile(ofstream *out, char *path)
828{
829 ofstream AdjacencyFile;
830 stringstream line;
831 bool status = true;
832
833 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
834 AdjacencyFile.open(line.str().c_str(), ios::out);
835 *out << Verbose(1) << "Saving adjacency list ... ";
836 if (AdjacencyFile != NULL) {
[266237]837 ActOnAllAtoms( &atom::OutputAdjacency, &AdjacencyFile );
[cee0b57]838 AdjacencyFile.close();
839 *out << Verbose(1) << "done." << endl;
840 } else {
841 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
842 status = false;
843 }
844
845 return status;
846};
847
848/** Checks contents of adjacency file against bond structure in structure molecule.
849 * \param *out output stream for debugging
850 * \param *path path to file
851 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
852 * \return true - structure is equal, false - not equivalence
853 */
854bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms)
855{
856 ifstream File;
857 stringstream filename;
858 bool status = true;
[266237]859 atom *Walker = NULL;
[cee0b57]860 char *buffer = Malloc<char>(MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
861
862 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
863 File.open(filename.str().c_str(), ios::out);
864 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... ";
865 if (File != NULL) {
866 // allocate storage structure
867 int NonMatchNumber = 0; // will number of atoms with differing bond structure
868 int *CurrentBonds = Malloc<int>(8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
[266237]869 size_t CurrentBondsOfAtom;
[cee0b57]870
871 // Parse the file line by line and count the bonds
872 while (!File.eof()) {
873 File.getline(buffer, MAXSTRINGSIZE);
874 stringstream line;
875 line.str(buffer);
876 int AtomNr = -1;
877 line >> AtomNr;
878 CurrentBondsOfAtom = -1; // we count one too far due to line end
879 // parse into structure
880 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
[266237]881 Walker = ListOfAtoms[AtomNr];
[cee0b57]882 while (!line.eof())
883 line >> CurrentBonds[ ++CurrentBondsOfAtom ];
884 // compare against present bonds
885 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
[266237]886 if (CurrentBondsOfAtom == Walker->ListOfBonds.size()) {
887 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
888 int id = (*Runner)->GetOtherAtom(Walker)->nr;
889 size_t j = 0;
[cee0b57]890 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds
891 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms
892 ListOfAtoms[AtomNr] = NULL;
893 NonMatchNumber++;
894 status = false;
895 //out << "[" << id << "]\t";
896 } else {
897 //out << id << "\t";
898 }
899 }
900 //out << endl;
901 } else {
[266237]902 *out << "Number of bonds for Atom " << *Walker << " does not match, parsed " << CurrentBondsOfAtom << " against " << Walker->ListOfBonds.size() << "." << endl;
[cee0b57]903 status = false;
904 }
905 }
906 }
907 File.close();
908 File.clear();
909 if (status) { // if equal we parse the KeySetFile
910 *out << Verbose(1) << "done: Equal." << endl;
911 status = true;
912 } else
913 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
914 Free(&CurrentBonds);
915 } else {
916 *out << Verbose(1) << "Adjacency file not found." << endl;
917 status = false;
918 }
919 *out << endl;
920 Free(&buffer);
921
922 return status;
923};
924
925
926/** Picks from a global stack with all back edges the ones in the fragment.
927 * \param *out output stream for debugging
928 * \param **ListOfLocalAtoms array of father atom::nr to local atom::nr (reverse of atom::father)
929 * \param *ReferenceStack stack with all the back egdes
930 * \param *LocalStack stack to be filled
931 * \return true - everything ok, false - ReferenceStack was empty
932 */
933bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack)
934{
935 bool status = true;
936 if (ReferenceStack->IsEmpty()) {
937 cerr << "ReferenceStack is empty!" << endl;
938 return false;
939 }
940 bond *Binder = ReferenceStack->PopFirst();
941 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
942 atom *Walker = NULL, *OtherAtom = NULL;
943 ReferenceStack->Push(Binder);
944
945 do { // go through all bonds and push local ones
946 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule
947 if (Walker != NULL) // if this Walker exists in the subgraph ...
[266237]948 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
949 OtherAtom = (*Runner)->GetOtherAtom(Walker);
950 if (OtherAtom == ListOfLocalAtoms[(*Runner)->rightatom->nr]) { // found the bond
951 LocalStack->Push((*Runner));
952 *out << Verbose(3) << "Found local edge " << *(*Runner) << "." << endl;
[cee0b57]953 break;
954 }
955 }
956 Binder = ReferenceStack->PopFirst(); // loop the stack for next item
957 *out << Verbose(3) << "Current candidate edge " << Binder << "." << endl;
958 ReferenceStack->Push(Binder);
959 } while (FirstBond != Binder);
960
961 return status;
962};
963
964
965/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
966 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
967 * white and putting into queue.
968 * \param *out output stream for debugging
969 * \param *Mol Molecule class to add atoms to
970 * \param **AddedAtomList list with added atom pointers, index is atom father's number
971 * \param **AddedBondList list with added bond pointers, index is bond father's number
972 * \param *Root root vertex for BFS
973 * \param *Bond bond not to look beyond
974 * \param BondOrder maximum distance for vertices to add
975 * \param IsAngstroem lengths are in angstroem or bohrradii
976 */
977void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
978{
979 atom **PredecessorList = Malloc<atom*>(AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList");
980 int *ShortestPathList = Malloc<int>(AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList");
981 enum Shading *ColorList = Malloc<enum Shading>(AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList");
982 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
983 atom *Walker = NULL, *OtherAtom = NULL;
984
985 // add Root if not done yet
986 AtomStack->ClearStack();
987 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
988 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
989 AtomStack->Push(Root);
990
991 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
992 for (int i=AtomCount;i--;) {
993 PredecessorList[i] = NULL;
994 ShortestPathList[i] = -1;
995 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited
996 ColorList[i] = lightgray;
997 else
998 ColorList[i] = white;
999 }
1000 ShortestPathList[Root->nr] = 0;
1001
1002 // and go on ... Queue always contains all lightgray vertices
1003 while (!AtomStack->IsEmpty()) {
1004 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
1005 // 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
1006 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
1007 // followed by n+1 till top of stack.
1008 Walker = AtomStack->PopFirst(); // pop oldest added
[266237]1009 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << Walker->ListOfBonds.size() << " bonds." << endl;
1010 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1011 if ((*Runner) != NULL) { // don't look at bond equal NULL
1012 OtherAtom = (*Runner)->GetOtherAtom(Walker);
1013 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *(*Runner) << "." << endl;
[cee0b57]1014 if (ColorList[OtherAtom->nr] == white) {
[266237]1015 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]1016 ColorList[OtherAtom->nr] = lightgray;
1017 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
1018 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
1019 *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]1020 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && ((*Runner) != Bond))) ) { // Check for maximum distance
[cee0b57]1021 *out << Verbose(3);
1022 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
1023 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
1024 *out << "Added OtherAtom " << OtherAtom->Name;
[266237]1025 AddedBondList[(*Runner)->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], (*Runner));
1026 *out << " and bond " << *(AddedBondList[(*Runner)->nr]) << ", ";
[cee0b57]1027 } 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)
1028 *out << "Not adding OtherAtom " << OtherAtom->Name;
[266237]1029 if (AddedBondList[(*Runner)->nr] == NULL) {
1030 AddedBondList[(*Runner)->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], (*Runner));
1031 *out << ", added Bond " << *(AddedBondList[(*Runner)->nr]);
[cee0b57]1032 } else
1033 *out << ", not added Bond ";
1034 }
1035 *out << ", putting OtherAtom into queue." << endl;
1036 AtomStack->Push(OtherAtom);
1037 } else { // out of bond order, then replace
[266237]1038 if ((AddedAtomList[OtherAtom->nr] == NULL) && ((*Runner)->Cyclic))
[cee0b57]1039 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
[266237]1040 if ((*Runner) == Bond)
[cee0b57]1041 *out << Verbose(3) << "Not Queueing, is the Root bond";
1042 else if (ShortestPathList[OtherAtom->nr] >= BondOrder)
1043 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder;
[266237]1044 if (!(*Runner)->Cyclic)
[cee0b57]1045 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
[266237]1046 if (AddedBondList[(*Runner)->nr] == NULL) {
[cee0b57]1047 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
[266237]1048 AddedBondList[(*Runner)->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], (*Runner));
[cee0b57]1049 } else {
1050#ifdef ADDHYDROGEN
[266237]1051 if (!Mol->AddHydrogenReplacementAtom(out, (*Runner), AddedAtomList[Walker->nr], Walker, OtherAtom, IsAngstroem))
[cee0b57]1052 exit(1);
1053#endif
1054 }
1055 }
1056 }
1057 } else {
1058 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
1059 // This has to be a cyclic bond, check whether it's present ...
[266237]1060 if (AddedBondList[(*Runner)->nr] == NULL) {
1061 if (((*Runner) != Bond) && ((*Runner)->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) {
1062 AddedBondList[(*Runner)->nr] = Mol->CopyBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], (*Runner));
[cee0b57]1063 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
1064#ifdef ADDHYDROGEN
[266237]1065 if(!Mol->AddHydrogenReplacementAtom(out, (*Runner), AddedAtomList[Walker->nr], Walker, OtherAtom, IsAngstroem))
[cee0b57]1066 exit(1);
1067#endif
1068 }
1069 }
1070 }
1071 }
1072 }
1073 ColorList[Walker->nr] = black;
1074 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
1075 }
1076 Free(&PredecessorList);
1077 Free(&ShortestPathList);
1078 Free(&ColorList);
1079 delete(AtomStack);
1080};
1081
[266237]1082/** Adds a bond as a copy to a given one
1083 * \param *left leftatom of new bond
1084 * \param *right rightatom of new bond
1085 * \param *CopyBond rest of fields in bond are copied from this
1086 * \return pointer to new bond
1087 */
1088bond * molecule::CopyBond(atom *left, atom *right, bond *CopyBond)
1089{
1090 bond *Binder = AddBond(left, right, CopyBond->BondDegree);
1091 Binder->Cyclic = CopyBond->Cyclic;
1092 Binder->Type = CopyBond->Type;
1093 return Binder;
1094};
1095
1096
[cee0b57]1097/** Adds bond structure to this molecule from \a Father molecule.
1098 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
1099 * with end points present in this molecule, bond is created in this molecule.
1100 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
1101 * \param *out output stream for debugging
1102 * \param *Father father molecule
1103 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
1104 * \todo not checked, not fully working probably
1105 */
1106bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
1107{
1108 atom *Walker = NULL, *OtherAtom = NULL;
1109 bool status = true;
1110 atom **ParentList = Malloc<atom*>(Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList");
1111
1112 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
1113
1114 // reset parent list
1115 *out << Verbose(3) << "Resetting ParentList." << endl;
1116 for (int i=Father->AtomCount;i--;)
1117 ParentList[i] = NULL;
1118
1119 // fill parent list with sons
1120 *out << Verbose(3) << "Filling Parent List." << endl;
1121 Walker = start;
1122 while (Walker->next != end) {
1123 Walker = Walker->next;
1124 ParentList[Walker->father->nr] = Walker;
1125 // Outputting List for debugging
1126 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
1127 }
1128
1129 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
1130 *out << Verbose(3) << "Creating bonds." << endl;
1131 Walker = Father->start;
1132 while (Walker->next != Father->end) {
1133 Walker = Walker->next;
1134 if (ParentList[Walker->nr] != NULL) {
1135 if (ParentList[Walker->nr]->father != Walker) {
1136 status = false;
1137 } else {
[266237]1138 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1139 OtherAtom = (*Runner)->GetOtherAtom(Walker);
[cee0b57]1140 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
[266237]1141 *out << Verbose(4) << "Endpoints of Bond " << (*Runner) << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
1142 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], (*Runner)->BondDegree);
[cee0b57]1143 }
1144 }
1145 }
1146 }
1147 }
1148
1149 Free(&ParentList);
1150 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
1151 return status;
1152};
1153
1154
1155/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
1156 * \param *out output stream for debugging
1157 * \param *Fragment Keyset of fragment's vertices
1158 * \return true - connected, false - disconnected
1159 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
1160 */
1161bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment)
1162{
1163 atom *Walker = NULL, *Walker2 = NULL;
1164 bool BondStatus = false;
1165 int size;
1166
1167 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
1168 *out << Verbose(2) << "Disconnected atom: ";
1169
1170 // count number of atoms in graph
1171 size = 0;
1172 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
1173 size++;
1174 if (size > 1)
1175 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
1176 Walker = FindAtom(*runner);
1177 BondStatus = false;
1178 for(KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
1179 Walker2 = FindAtom(*runners);
[266237]1180 for (BondList::const_iterator Runner = Walker->ListOfBonds.begin(); Runner != Walker->ListOfBonds.end(); (++Runner)) {
1181 if ((*Runner)->GetOtherAtom(Walker) == Walker2) {
[cee0b57]1182 BondStatus = true;
1183 break;
1184 }
1185 if (BondStatus)
1186 break;
1187 }
1188 }
1189 if (!BondStatus) {
1190 *out << (*Walker) << endl;
1191 return false;
1192 }
1193 }
1194 else {
1195 *out << "none." << endl;
1196 return true;
1197 }
1198 *out << "none." << endl;
1199
1200 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
1201
1202 return true;
1203}
Note: See TracBrowser for help on using the repository browser.