source: src/molecule_graph.cpp@ db6bf74

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

forward declarations used to untangle interdependet classes.

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