source: src/molecule_graph.cpp@ 23b830

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

class molecule implementation split up into six separate parts.

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