source: src/molecule_graph.cpp@ 07051c

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 07051c was 44a59b, checked in by Frederik Heber <heber@…>, 16 years ago

Renamed and rewritten CreateAdjacencyList2().

  • rename CreateAdjacencyList2() -> CreateAdjacencyListFromDbondFile()
  • initially written by Christian Neuen who was at that time not familiar with all the functions already present. The code is now shortened and tighter.

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

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