source: molecuilder/src/molecules.cpp@ e6971b

Last change on this file since e6971b was 67f102, checked in by Frederik Heber <heber@…>, 17 years ago

config::Save() and config::Load() parse MD steps into and out of molecule::Trajectories. Tested.

  • Property mode set to 100644
File size: 200.8 KB
Line 
1/** \file molecules.cpp
2 *
3 * Functions for the class molecule.
4 *
5 */
6
7#include "molecules.hpp"
8
9/************************************* Other Functions *************************************/
10
11/** Determines sum of squared distances of \a X to all \a **vectors.
12 * \param *x reference vector
13 * \param *params
14 * \return sum of square distances
15 */
16double LSQ (const gsl_vector * x, void * params)
17{
18 double sum = 0.;
19 struct LSQ_params *par = (struct LSQ_params *)params;
20 Vector **vectors = par->vectors;
21 int num = par->num;
22
23 for (int i=num;i--;) {
24 for(int j=NDIM;j--;)
25 sum += (gsl_vector_get(x,j) - (vectors[i])->x[j])*(gsl_vector_get(x,j) - (vectors[i])->x[j]);
26 }
27
28 return sum;
29};
30
31/************************************* Functions for class molecule *********************************/
32
33/** Constructor of class molecule.
34 * Initialises molecule list with correctly referenced start and end, and sets molecule::last_atom to zero.
35 */
36molecule::molecule(periodentafel *teil)
37{
38 // init atom chain list
39 start = new atom;
40 end = new atom;
41 start->father = NULL;
42 end->father = NULL;
43 link(start,end);
44 // init bond chain list
45 first = new bond(start, end, 1, -1);
46 last = new bond(start, end, 1, -1);
47 link(first,last);
48 // other stuff
49 MDSteps = 0;
50 last_atom = 0;
51 elemente = teil;
52 AtomCount = 0;
53 BondCount = 0;
54 NoNonBonds = 0;
55 NoNonHydrogen = 0;
56 NoCyclicBonds = 0;
57 ListOfBondsPerAtom = NULL;
58 NumberOfBondsPerAtom = NULL;
59 ElementCount = 0;
60 for(int i=MAX_ELEMENTS;i--;)
61 ElementsInMolecule[i] = 0;
62 cell_size[0] = cell_size[2] = cell_size[5]= 20.;
63 cell_size[1] = cell_size[3] = cell_size[4]= 0.;
64};
65
66/** Destructor of class molecule.
67 * Initialises molecule list with correctly referenced start and end, and sets molecule::last_atom to zero.
68 */
69molecule::~molecule()
70{
71 if (ListOfBondsPerAtom != NULL)
72 for(int i=AtomCount;i--;)
73 Free((void **)&ListOfBondsPerAtom[i], "molecule::~molecule: ListOfBondsPerAtom[i]");
74 Free((void **)&ListOfBondsPerAtom, "molecule::~molecule: ListOfBondsPerAtom");
75 Free((void **)&NumberOfBondsPerAtom, "molecule::~molecule: NumberOfBondsPerAtom");
76 CleanupMolecule();
77 delete(first);
78 delete(last);
79 delete(end);
80 delete(start);
81};
82
83/** Adds given atom \a *pointer from molecule list.
84 * Increases molecule::last_atom and gives last number to added atom and names it according to its element::abbrev and molecule::AtomCount
85 * \param *pointer allocated and set atom
86 * \return true - succeeded, false - atom not found in list
87 */
88bool molecule::AddAtom(atom *pointer)
89{
90 if (pointer != NULL) {
91 pointer->sort = &pointer->nr;
92 pointer->nr = last_atom++; // increase number within molecule
93 AtomCount++;
94 if (pointer->type != NULL) {
95 if (ElementsInMolecule[pointer->type->Z] == 0)
96 ElementCount++;
97 ElementsInMolecule[pointer->type->Z]++; // increase number of elements
98 if (pointer->type->Z != 1)
99 NoNonHydrogen++;
100 if (pointer->Name == NULL) {
101 Free((void **)&pointer->Name, "molecule::AddAtom: *pointer->Name");
102 pointer->Name = (char *) Malloc(sizeof(char)*6, "molecule::AddAtom: *pointer->Name");
103 sprintf(pointer->Name, "%2s%02d", pointer->type->symbol, pointer->nr+1);
104 }
105 }
106 return add(pointer, end);
107 } else
108 return false;
109};
110
111/** Adds a copy of the given atom \a *pointer from molecule list.
112 * Increases molecule::last_atom and gives last number to added atom.
113 * \param *pointer allocated and set atom
114 * \return true - succeeded, false - atom not found in list
115 */
116atom * molecule::AddCopyAtom(atom *pointer)
117{
118 if (pointer != NULL) {
119 atom *walker = new atom();
120 walker->type = pointer->type; // copy element of atom
121 walker->x.CopyVector(&pointer->x); // copy coordination
122 walker->v.CopyVector(&pointer->v); // copy velocity
123 walker->FixedIon = pointer->FixedIon;
124 walker->sort = &walker->nr;
125 walker->nr = last_atom++; // increase number within molecule
126 walker->father = pointer; //->GetTrueFather();
127 walker->Name = (char *) Malloc(sizeof(char)*strlen(pointer->Name)+1, "molecule::AddCopyAtom: *Name");
128 strcpy (walker->Name, pointer->Name);
129 add(walker, end);
130 if ((pointer->type != NULL) && (pointer->type->Z != 1))
131 NoNonHydrogen++;
132 AtomCount++;
133 return walker;
134 } else
135 return NULL;
136};
137
138/** Adds a Hydrogen atom in replacement for the given atom \a *partner in bond with a *origin.
139 * Here, we have to distinguish between single, double or triple bonds as stated by \a BondDegree, that each demand
140 * a different scheme when adding \a *replacement atom for the given one.
141 * -# Single Bond: Simply add new atom with bond distance rescaled to typical hydrogen one
142 * -# Double Bond: Here, we need the **BondList of the \a *origin atom, by scanning for the other bonds instead of
143 * *Bond, we use the through these connected atoms to determine the plane they lie in, vector::MakeNormalvector().
144 * The orthonormal vector to this plane along with the vector in *Bond direction determines the plane the two
145 * replacing hydrogens shall lie in. Now, all remains to do is take the usual hydrogen double bond angle for the
146 * element of *origin and form the sin/cos admixture of both plane vectors for the new coordinates of the two
147 * hydrogens forming this angle with *origin.
148 * -# Triple Bond: The idea is to set up a tetraoid (C1-H1-H2-H3) (however the lengths \f$b\f$ of the sides of the base
149 * triangle formed by the to be added hydrogens are not equal to the typical bond distance \f$l\f$ but have to be
150 * determined from the typical angle \f$\alpha\f$ for a hydrogen triple connected to the element of *origin):
151 * We have the height \f$d\f$ as the vector in *Bond direction (from triangle C1-H1-H2).
152 * \f[ h = l \cdot \cos{\left (\frac{\alpha}{2} \right )} \qquad b = 2l \cdot \sin{\left (\frac{\alpha}{2} \right)} \quad \rightarrow \quad d = l \cdot \sqrt{\cos^2{\left (\frac{\alpha}{2} \right)}-\frac{1}{3}\cdot\sin^2{\left (\frac{\alpha}{2}\right )}}
153 * \f]
154 * vector::GetNormalvector() creates one orthonormal vector from this *Bond vector and vector::MakeNormalvector creates
155 * the third one from the former two vectors. The latter ones form the plane of the base triangle mentioned above.
156 * The lengths for these are \f$f\f$ and \f$g\f$ (from triangle H1-H2-(center of H1-H2-H3)) with knowledge that
157 * the median lines in an isosceles triangle meet in the center point with a ratio 2:1.
158 * \f[ f = \frac{b}{\sqrt{3}} \qquad g = \frac{b}{2}
159 * \f]
160 * as the coordination of all three atoms in the coordinate system of these three vectors:
161 * \f$\pmatrix{d & f & 0}\f$, \f$\pmatrix{d & -0.5 \cdot f & g}\f$ and \f$\pmatrix{d & -0.5 \cdot f & -g}\f$.
162 *
163 * \param *out output stream for debugging
164 * \param *Bond pointer to bond between \a *origin and \a *replacement
165 * \param *TopOrigin son of \a *origin of upper level molecule (the atom added to this molecule as a copy of \a *origin)
166 * \param *origin pointer to atom which acts as the origin for scaling the added hydrogen to correct bond length
167 * \param *replacement pointer to the atom which shall be copied as a hydrogen atom in this molecule
168 * \param **BondList list of bonds \a *replacement has (necessary to determine plane for double and triple bonds)
169 * \param NumBond number of bonds in \a **BondList
170 * \param isAngstroem whether the coordination of the given atoms is in AtomicLength (false) or Angstrom(true)
171 * \return number of atoms added, if < bond::BondDegree then something went wrong
172 * \todo double and triple bonds splitting (always use the tetraeder angle!)
173 */
174bool molecule::AddHydrogenReplacementAtom(ofstream *out, bond *TopBond, atom *BottomOrigin, atom *TopOrigin, atom *TopReplacement, bond **BondList, int NumBond, bool IsAngstroem)
175{
176 double bondlength; // bond length of the bond to be replaced/cut
177 double bondangle; // bond angle of the bond to be replaced/cut
178 double BondRescale; // rescale value for the hydrogen bond length
179 bool AllWentWell = true; // flag gathering the boolean return value of molecule::AddAtom and other functions, as return value on exit
180 bond *FirstBond = NULL, *SecondBond = NULL; // Other bonds in double bond case to determine "other" plane
181 atom *FirstOtherAtom = NULL, *SecondOtherAtom = NULL, *ThirdOtherAtom = NULL; // pointer to hydrogen atoms to be added
182 double b,l,d,f,g, alpha, factors[NDIM]; // hold temporary values in triple bond case for coordination determination
183 Vector Orthovector1, Orthovector2; // temporary vectors in coordination construction
184 Vector InBondvector; // vector in direction of *Bond
185 bond *Binder = NULL;
186 double *matrix;
187
188// *out << Verbose(3) << "Begin of AddHydrogenReplacementAtom." << endl;
189 // create vector in direction of bond
190 InBondvector.CopyVector(&TopReplacement->x);
191 InBondvector.SubtractVector(&TopOrigin->x);
192 bondlength = InBondvector.Norm();
193
194 // is greater than typical bond distance? Then we have to correct periodically
195 // the problem is not the H being out of the box, but InBondvector have the wrong direction
196 // due to TopReplacement or Origin being on the wrong side!
197 if (bondlength > BondDistance) {
198// *out << Verbose(4) << "InBondvector is: ";
199// InBondvector.Output(out);
200// *out << endl;
201 Orthovector1.Zero();
202 for (int i=NDIM;i--;) {
203 l = TopReplacement->x.x[i] - TopOrigin->x.x[i];
204 if (fabs(l) > BondDistance) { // is component greater than bond distance
205 Orthovector1.x[i] = (l < 0) ? -1. : +1.;
206 } // (signs are correct, was tested!)
207 }
208 matrix = ReturnFullMatrixforSymmetric(cell_size);
209 Orthovector1.MatrixMultiplication(matrix);
210 InBondvector.SubtractVector(&Orthovector1); // subtract just the additional translation
211 Free((void **)&matrix, "molecule::AddHydrogenReplacementAtom: *matrix");
212 bondlength = InBondvector.Norm();
213// *out << Verbose(4) << "Corrected InBondvector is now: ";
214// InBondvector.Output(out);
215// *out << endl;
216 } // periodic correction finished
217
218 InBondvector.Normalize();
219 // get typical bond length and store as scale factor for later
220 BondRescale = TopOrigin->type->HBondDistance[TopBond->BondDegree-1];
221 if (BondRescale == -1) {
222 cerr << Verbose(3) << "WARNING: There is no typical bond distance for bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") of degree " << TopBond->BondDegree << "!" << endl;
223 BondRescale = bondlength;
224 } else {
225 if (!IsAngstroem)
226 BondRescale /= (1.*AtomicLengthToAngstroem);
227 }
228
229 // discern single, double and triple bonds
230 switch(TopBond->BondDegree) {
231 case 1:
232 FirstOtherAtom = new atom(); // new atom
233 FirstOtherAtom->type = elemente->FindElement(1); // element is Hydrogen
234 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
235 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
236 if (TopReplacement->type->Z == 1) { // neither rescale nor replace if it's already hydrogen
237 FirstOtherAtom->father = TopReplacement;
238 BondRescale = bondlength;
239 } else {
240 FirstOtherAtom->father = NULL; // if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father
241 }
242 InBondvector.Scale(&BondRescale); // rescale the distance vector to Hydrogen bond length
243 FirstOtherAtom->x.CopyVector(&TopOrigin->x); // set coordination to origin ...
244 FirstOtherAtom->x.AddVector(&InBondvector); // ... and add distance vector to replacement atom
245 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
246// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
247// FirstOtherAtom->x.Output(out);
248// *out << endl;
249 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
250 Binder->Cyclic = false;
251 Binder->Type = TreeEdge;
252 break;
253 case 2:
254 // determine two other bonds (warning if there are more than two other) plus valence sanity check
255 for (int i=0;i<NumBond;i++) {
256 if (BondList[i] != TopBond) {
257 if (FirstBond == NULL) {
258 FirstBond = BondList[i];
259 FirstOtherAtom = BondList[i]->GetOtherAtom(TopOrigin);
260 } else if (SecondBond == NULL) {
261 SecondBond = BondList[i];
262 SecondOtherAtom = BondList[i]->GetOtherAtom(TopOrigin);
263 } else {
264 *out << Verbose(3) << "WARNING: Detected more than four bonds for atom " << TopOrigin->Name;
265 }
266 }
267 }
268 if (SecondOtherAtom == NULL) { // then we have an atom with valence four, but only 3 bonds: one to replace and one which is TopBond (third is FirstBond)
269 SecondBond = TopBond;
270 SecondOtherAtom = TopReplacement;
271 }
272 if (FirstOtherAtom != NULL) { // then we just have this double bond and the plane does not matter at all
273// *out << Verbose(3) << "Regarding the double bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") to be constructed: Taking " << FirstOtherAtom->Name << " and " << SecondOtherAtom->Name << " along with " << TopOrigin->Name << " to determine orthogonal plane." << endl;
274
275 // determine the plane of these two with the *origin
276 AllWentWell = AllWentWell && Orthovector1.MakeNormalVector(&TopOrigin->x, &FirstOtherAtom->x, &SecondOtherAtom->x);
277 } else {
278 Orthovector1.GetOneNormalVector(&InBondvector);
279 }
280 //*out << Verbose(3)<< "Orthovector1: ";
281 //Orthovector1.Output(out);
282 //*out << endl;
283 // orthogonal vector and bond vector between origin and replacement form the new plane
284 Orthovector1.MakeNormalVector(&InBondvector);
285 Orthovector1.Normalize();
286 //*out << Verbose(3) << "ReScaleCheck: " << Orthovector1.Norm() << " and " << InBondvector.Norm() << "." << endl;
287
288 // create the two Hydrogens ...
289 FirstOtherAtom = new atom();
290 SecondOtherAtom = new atom();
291 FirstOtherAtom->type = elemente->FindElement(1);
292 SecondOtherAtom->type = elemente->FindElement(1);
293 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
294 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
295 SecondOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
296 SecondOtherAtom->FixedIon = TopReplacement->FixedIon;
297 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father
298 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father
299 bondangle = TopOrigin->type->HBondAngle[1];
300 if (bondangle == -1) {
301 *out << Verbose(3) << "WARNING: There is no typical bond angle for bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") of degree " << TopBond->BondDegree << "!" << endl;
302 bondangle = 0;
303 }
304 bondangle *= M_PI/180./2.;
305// *out << Verbose(3) << "ReScaleCheck: InBondvector ";
306// InBondvector.Output(out);
307// *out << endl;
308// *out << Verbose(3) << "ReScaleCheck: Orthovector ";
309// Orthovector1.Output(out);
310// *out << endl;
311// *out << Verbose(3) << "Half the bond angle is " << bondangle << ", sin and cos of it: " << sin(bondangle) << ", " << cos(bondangle) << endl;
312 FirstOtherAtom->x.Zero();
313 SecondOtherAtom->x.Zero();
314 for(int i=NDIM;i--;) { // rotate by half the bond angle in both directions (InBondvector is bondangle = 0 direction)
315 FirstOtherAtom->x.x[i] = InBondvector.x[i] * cos(bondangle) + Orthovector1.x[i] * (sin(bondangle));
316 SecondOtherAtom->x.x[i] = InBondvector.x[i] * cos(bondangle) + Orthovector1.x[i] * (-sin(bondangle));
317 }
318 FirstOtherAtom->x.Scale(&BondRescale); // rescale by correct BondDistance
319 SecondOtherAtom->x.Scale(&BondRescale);
320 //*out << Verbose(3) << "ReScaleCheck: " << FirstOtherAtom->x.Norm() << " and " << SecondOtherAtom->x.Norm() << "." << endl;
321 for(int i=NDIM;i--;) { // and make relative to origin atom
322 FirstOtherAtom->x.x[i] += TopOrigin->x.x[i];
323 SecondOtherAtom->x.x[i] += TopOrigin->x.x[i];
324 }
325 // ... and add to molecule
326 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
327 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom);
328// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
329// FirstOtherAtom->x.Output(out);
330// *out << endl;
331// *out << Verbose(4) << "Added " << *SecondOtherAtom << " at: ";
332// SecondOtherAtom->x.Output(out);
333// *out << endl;
334 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
335 Binder->Cyclic = false;
336 Binder->Type = TreeEdge;
337 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1);
338 Binder->Cyclic = false;
339 Binder->Type = TreeEdge;
340 break;
341 case 3:
342 // take the "usual" tetraoidal angle and add the three Hydrogen in direction of the bond (height of the tetraoid)
343 FirstOtherAtom = new atom();
344 SecondOtherAtom = new atom();
345 ThirdOtherAtom = new atom();
346 FirstOtherAtom->type = elemente->FindElement(1);
347 SecondOtherAtom->type = elemente->FindElement(1);
348 ThirdOtherAtom->type = elemente->FindElement(1);
349 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
350 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
351 SecondOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
352 SecondOtherAtom->FixedIon = TopReplacement->FixedIon;
353 ThirdOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
354 ThirdOtherAtom->FixedIon = TopReplacement->FixedIon;
355 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father
356 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father
357 ThirdOtherAtom->father = NULL; // we are just an added hydrogen with no father
358
359 // we need to vectors orthonormal the InBondvector
360 AllWentWell = AllWentWell && Orthovector1.GetOneNormalVector(&InBondvector);
361// *out << Verbose(3) << "Orthovector1: ";
362// Orthovector1.Output(out);
363// *out << endl;
364 AllWentWell = AllWentWell && Orthovector2.MakeNormalVector(&InBondvector, &Orthovector1);
365// *out << Verbose(3) << "Orthovector2: ";
366// Orthovector2.Output(out);
367// *out << endl;
368
369 // create correct coordination for the three atoms
370 alpha = (TopOrigin->type->HBondAngle[2])/180.*M_PI/2.; // retrieve triple bond angle from database
371 l = BondRescale; // desired bond length
372 b = 2.*l*sin(alpha); // base length of isosceles triangle
373 d = l*sqrt(cos(alpha)*cos(alpha) - sin(alpha)*sin(alpha)/3.); // length for InBondvector
374 f = b/sqrt(3.); // length for Orthvector1
375 g = b/2.; // length for Orthvector2
376// *out << Verbose(3) << "Bond length and half-angle: " << l << ", " << alpha << "\t (b,d,f,g) = " << b << ", " << d << ", " << f << ", " << g << ", " << endl;
377// *out << Verbose(3) << "The three Bond lengths: " << sqrt(d*d+f*f) << ", " << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g) << ", " << sqrt(d*d+(-0.5*f)*(-0.5*f)+g*g) << endl;
378 factors[0] = d;
379 factors[1] = f;
380 factors[2] = 0.;
381 FirstOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
382 factors[1] = -0.5*f;
383 factors[2] = g;
384 SecondOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
385 factors[2] = -g;
386 ThirdOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
387
388 // rescale each to correct BondDistance
389// FirstOtherAtom->x.Scale(&BondRescale);
390// SecondOtherAtom->x.Scale(&BondRescale);
391// ThirdOtherAtom->x.Scale(&BondRescale);
392
393 // and relative to *origin atom
394 FirstOtherAtom->x.AddVector(&TopOrigin->x);
395 SecondOtherAtom->x.AddVector(&TopOrigin->x);
396 ThirdOtherAtom->x.AddVector(&TopOrigin->x);
397
398 // ... and add to molecule
399 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
400 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom);
401 AllWentWell = AllWentWell && AddAtom(ThirdOtherAtom);
402// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
403// FirstOtherAtom->x.Output(out);
404// *out << endl;
405// *out << Verbose(4) << "Added " << *SecondOtherAtom << " at: ";
406// SecondOtherAtom->x.Output(out);
407// *out << endl;
408// *out << Verbose(4) << "Added " << *ThirdOtherAtom << " at: ";
409// ThirdOtherAtom->x.Output(out);
410// *out << endl;
411 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
412 Binder->Cyclic = false;
413 Binder->Type = TreeEdge;
414 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1);
415 Binder->Cyclic = false;
416 Binder->Type = TreeEdge;
417 Binder = AddBond(BottomOrigin, ThirdOtherAtom, 1);
418 Binder->Cyclic = false;
419 Binder->Type = TreeEdge;
420 break;
421 default:
422 cerr << "ERROR: BondDegree does not state single, double or triple bond!" << endl;
423 AllWentWell = false;
424 break;
425 }
426
427// *out << Verbose(3) << "End of AddHydrogenReplacementAtom." << endl;
428 return AllWentWell;
429};
430
431/** Adds given atom \a *pointer from molecule list.
432 * Increases molecule::last_atom and gives last number to added atom.
433 * \param filename name and path of xyz file
434 * \return true - succeeded, false - file not found
435 */
436bool molecule::AddXYZFile(string filename)
437{
438 istringstream *input = NULL;
439 int NumberOfAtoms = 0; // atom number in xyz read
440 int i, j; // loop variables
441 atom *Walker = NULL; // pointer to added atom
442 char shorthand[3]; // shorthand for atom name
443 ifstream xyzfile; // xyz file
444 string line; // currently parsed line
445 double x[3]; // atom coordinates
446
447 xyzfile.open(filename.c_str());
448 if (!xyzfile)
449 return false;
450
451 getline(xyzfile,line,'\n'); // Read numer of atoms in file
452 input = new istringstream(line);
453 *input >> NumberOfAtoms;
454 cout << Verbose(0) << "Parsing " << NumberOfAtoms << " atoms in file." << endl;
455 getline(xyzfile,line,'\n'); // Read comment
456 cout << Verbose(1) << "Comment: " << line << endl;
457
458 for(i=0;i<NumberOfAtoms;i++){
459 Walker = new atom;
460 getline(xyzfile,line,'\n');
461 istringstream *item = new istringstream(line);
462 //istringstream input(line);
463 //cout << Verbose(1) << "Reading: " << line << endl;
464 *item >> shorthand;
465 *item >> x[0];
466 *item >> x[1];
467 *item >> x[2];
468 Walker->type = elemente->FindElement(shorthand);
469 if (Walker->type == NULL) {
470 cerr << "Could not parse the element at line: '" << line << "', setting to H.";
471 Walker->type = elemente->FindElement(1);
472 }
473 for(j=NDIM;j--;)
474 Walker->x.x[j] = x[j];
475 AddAtom(Walker); // add to molecule
476 delete(item);
477 }
478 xyzfile.close();
479 delete(input);
480 return true;
481};
482
483/** Creates a copy of this molecule.
484 * \return copy of molecule
485 */
486molecule *molecule::CopyMolecule()
487{
488 molecule *copy = new molecule(elemente);
489 atom *CurrentAtom = NULL;
490 atom *LeftAtom = NULL, *RightAtom = NULL;
491 atom *Walker = NULL;
492
493 // copy all atoms
494 Walker = start;
495 while(Walker->next != end) {
496 Walker = Walker->next;
497 CurrentAtom = copy->AddCopyAtom(Walker);
498 }
499
500 // copy all bonds
501 bond *Binder = first;
502 bond *NewBond = NULL;
503 while(Binder->next != last) {
504 Binder = Binder->next;
505 // get the pendant atoms of current bond in the copy molecule
506 LeftAtom = copy->start;
507 while (LeftAtom->next != copy->end) {
508 LeftAtom = LeftAtom->next;
509 if (LeftAtom->father == Binder->leftatom)
510 break;
511 }
512 RightAtom = copy->start;
513 while (RightAtom->next != copy->end) {
514 RightAtom = RightAtom->next;
515 if (RightAtom->father == Binder->rightatom)
516 break;
517 }
518 NewBond = copy->AddBond(LeftAtom, RightAtom, Binder->BondDegree);
519 NewBond->Cyclic = Binder->Cyclic;
520 if (Binder->Cyclic)
521 copy->NoCyclicBonds++;
522 NewBond->Type = Binder->Type;
523 }
524 // correct fathers
525 Walker = copy->start;
526 while(Walker->next != copy->end) {
527 Walker = Walker->next;
528 if (Walker->father->father == Walker->father) // same atom in copy's father points to itself
529 Walker->father = Walker; // set father to itself (copy of a whole molecule)
530 else
531 Walker->father = Walker->father->father; // set father to original's father
532 }
533 // copy values
534 copy->CountAtoms((ofstream *)&cout);
535 copy->CountElements();
536 if (first->next != last) { // if adjaceny list is present
537 copy->BondDistance = BondDistance;
538 copy->CreateListOfBondsPerAtom((ofstream *)&cout);
539 }
540
541 return copy;
542};
543
544/** Adds a bond to a the molecule specified by two atoms, \a *first and \a *second.
545 * Also updates molecule::BondCount and molecule::NoNonBonds.
546 * \param *first first atom in bond
547 * \param *second atom in bond
548 * \return pointer to bond or NULL on failure
549 */
550bond * molecule::AddBond(atom *atom1, atom *atom2, int degree=1)
551{
552 bond *Binder = NULL;
553 if ((atom1 != NULL) && (FindAtom(atom1->nr) != NULL) && (atom2 != NULL) && (FindAtom(atom2->nr) != NULL)) {
554 Binder = new bond(atom1, atom2, degree, BondCount++);
555 if ((atom1->type != NULL) && (atom1->type->Z != 1) && (atom2->type != NULL) && (atom2->type->Z != 1))
556 NoNonBonds++;
557 add(Binder, last);
558 } else {
559 cerr << Verbose(1) << "ERROR: Could not add bond between " << atom1->Name << " and " << atom2->Name << " as one or both are not present in the molecule." << endl;
560 }
561 return Binder;
562};
563
564/** Remove bond from bond chain list.
565 * \todo Function not implemented yet
566 * \param *pointer bond pointer
567 * \return true - bound found and removed, false - bond not found/removed
568 */
569bool molecule::RemoveBond(bond *pointer)
570{
571 //cerr << Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl;
572 removewithoutcheck(pointer);
573 return true;
574};
575
576/** Remove every bond from bond chain list that atom \a *BondPartner is a constituent of.
577 * \todo Function not implemented yet
578 * \param *BondPartner atom to be removed
579 * \return true - bounds found and removed, false - bonds not found/removed
580 */
581bool molecule::RemoveBonds(atom *BondPartner)
582{
583 cerr << Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl;
584 return false;
585};
586
587/** Sets the molecule::cell_size to the components of \a *dim (rectangular box)
588 * \param *dim vector class
589 */
590void molecule::SetBoxDimension(Vector *dim)
591{
592 cell_size[0] = dim->x[0];
593 cell_size[1] = 0.;
594 cell_size[2] = dim->x[1];
595 cell_size[3] = 0.;
596 cell_size[4] = 0.;
597 cell_size[5] = dim->x[2];
598};
599
600/** Centers the molecule in the box whose lengths are defined by vector \a *BoxLengths.
601 * \param *out output stream for debugging
602 * \param *BoxLengths box lengths
603 */
604bool molecule::CenterInBox(ofstream *out, Vector *BoxLengths)
605{
606 bool status = true;
607 atom *ptr = NULL;
608 Vector *min = new Vector;
609 Vector *max = new Vector;
610
611 // gather min and max for each axis
612 ptr = start->next; // start at first in list
613 if (ptr != end) { //list not empty?
614 for (int i=NDIM;i--;) {
615 max->x[i] = ptr->x.x[i];
616 min->x[i] = ptr->x.x[i];
617 }
618 while (ptr->next != end) { // continue with second if present
619 ptr = ptr->next;
620 //ptr->Output(1,1,out);
621 for (int i=NDIM;i--;) {
622 max->x[i] = (max->x[i] < ptr->x.x[i]) ? ptr->x.x[i] : max->x[i];
623 min->x[i] = (min->x[i] > ptr->x.x[i]) ? ptr->x.x[i] : min->x[i];
624 }
625 }
626 }
627 // sanity check
628 for(int i=NDIM;i--;) {
629 if (max->x[i] - min->x[i] > BoxLengths->x[i])
630 status = false;
631 }
632 // warn if check failed
633 if (!status)
634 *out << "WARNING: molecule is bigger than defined box!" << endl;
635 else { // else center in box
636 ptr = start;
637 while (ptr->next != end) {
638 ptr = ptr->next;
639 for (int i=NDIM;i--;)
640 ptr->x.x[i] += -(max->x[i] + min->x[i])/2. + BoxLengths->x[i]/2.; // first term centers molecule at (0,0,0), second shifts to center of new box
641 }
642 }
643
644 // free and exit
645 delete(min);
646 delete(max);
647 return status;
648};
649
650/** Centers the edge of the atoms at (0,0,0).
651 * \param *out output stream for debugging
652 * \param *max coordinates of other edge, specifying box dimensions.
653 */
654void molecule::CenterEdge(ofstream *out, Vector *max)
655{
656 Vector *min = new Vector;
657
658// *out << Verbose(3) << "Begin of CenterEdge." << endl;
659 atom *ptr = start->next; // start at first in list
660 if (ptr != end) { //list not empty?
661 for (int i=NDIM;i--;) {
662 max->x[i] = ptr->x.x[i];
663 min->x[i] = ptr->x.x[i];
664 }
665 while (ptr->next != end) { // continue with second if present
666 ptr = ptr->next;
667 //ptr->Output(1,1,out);
668 for (int i=NDIM;i--;) {
669 max->x[i] = (max->x[i] < ptr->x.x[i]) ? ptr->x.x[i] : max->x[i];
670 min->x[i] = (min->x[i] > ptr->x.x[i]) ? ptr->x.x[i] : min->x[i];
671 }
672 }
673// *out << Verbose(4) << "Maximum is ";
674// max->Output(out);
675// *out << ", Minimum is ";
676// min->Output(out);
677// *out << endl;
678
679 for (int i=NDIM;i--;) {
680 min->x[i] *= -1.;
681 max->x[i] += min->x[i];
682 }
683 Translate(min);
684 }
685 delete(min);
686// *out << Verbose(3) << "End of CenterEdge." << endl;
687};
688
689/** Centers the center of the atoms at (0,0,0).
690 * \param *out output stream for debugging
691 * \param *center return vector for translation vector
692 */
693void molecule::CenterOrigin(ofstream *out, Vector *center)
694{
695 int Num = 0;
696 atom *ptr = start->next; // start at first in list
697
698 for(int i=NDIM;i--;) // zero center vector
699 center->x[i] = 0.;
700
701 if (ptr != end) { //list not empty?
702 while (ptr->next != end) { // continue with second if present
703 ptr = ptr->next;
704 Num++;
705 center->AddVector(&ptr->x);
706 }
707 center->Scale(-1./Num); // divide through total number (and sign for direction)
708 Translate(center);
709 }
710};
711
712/** Returns vector pointing to center of gravity.
713 * \param *out output stream for debugging
714 * \return pointer to center of gravity vector
715 */
716Vector * molecule::DetermineCenterOfGravity(ofstream *out)
717{
718 atom *ptr = start->next; // start at first in list
719 Vector *a = new Vector();
720 Vector tmp;
721 double Num = 0;
722
723 a->Zero();
724
725 if (ptr != end) { //list not empty?
726 while (ptr->next != end) { // continue with second if present
727 ptr = ptr->next;
728 Num += ptr->type->mass;
729 tmp.CopyVector(&ptr->x);
730 tmp.Scale(ptr->type->mass); // scale by mass
731 a->AddVector(&tmp);
732 }
733 a->Scale(-1./Num); // divide through total mass (and sign for direction)
734 }
735 *out << Verbose(1) << "Resulting center of gravity: ";
736 a->Output(out);
737 *out << endl;
738 return a;
739};
740
741/** Centers the center of gravity of the atoms at (0,0,0).
742 * \param *out output stream for debugging
743 * \param *center return vector for translation vector
744 */
745void molecule::CenterGravity(ofstream *out, Vector *center)
746{
747 if (center == NULL) {
748 DetermineCenter(*center);
749 Translate(center);
750 delete(center);
751 } else {
752 Translate(center);
753 }
754};
755
756/** Scales all atoms by \a *factor.
757 * \param *factor pointer to scaling factor
758 */
759void molecule::Scale(double **factor)
760{
761 atom *ptr = start;
762
763 while (ptr->next != end) {
764 ptr = ptr->next;
765 ptr->x.Scale(factor);
766 }
767};
768
769/** Translate all atoms by given vector.
770 * \param trans[] translation vector.
771 */
772void molecule::Translate(const Vector *trans)
773{
774 atom *ptr = start;
775
776 while (ptr->next != end) {
777 ptr = ptr->next;
778 ptr->x.Translate(trans);
779 }
780};
781
782/** Mirrors all atoms against a given plane.
783 * \param n[] normal vector of mirror plane.
784 */
785void molecule::Mirror(const Vector *n)
786{
787 atom *ptr = start;
788
789 while (ptr->next != end) {
790 ptr = ptr->next;
791 ptr->x.Mirror(n);
792 }
793};
794
795/** Determines center of molecule (yet not considering atom masses).
796 * \param Center reference to return vector
797 */
798void molecule::DetermineCenter(Vector &Center)
799{
800 atom *Walker = start;
801 bond *Binder = NULL;
802 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
803 double tmp;
804 bool flag;
805 Vector Testvector, Translationvector;
806
807 do {
808 Center.Zero();
809 flag = true;
810 while (Walker->next != end) {
811 Walker = Walker->next;
812#ifdef ADDHYDROGEN
813 if (Walker->type->Z != 1) {
814#endif
815 Testvector.CopyVector(&Walker->x);
816 Testvector.InverseMatrixMultiplication(matrix);
817 Translationvector.Zero();
818 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
819 Binder = ListOfBondsPerAtom[Walker->nr][i];
820 if (Walker->nr < Binder->GetOtherAtom(Walker)->nr) // otherwise we shift one to, the other fro and gain nothing
821 for (int j=0;j<NDIM;j++) {
822 tmp = Walker->x.x[j] - Binder->GetOtherAtom(Walker)->x.x[j];
823 if ((fabs(tmp)) > BondDistance) {
824 flag = false;
825 cout << Verbose(0) << "Hit: atom " << Walker->Name << " in bond " << *Binder << " has to be shifted due to " << tmp << "." << endl;
826 if (tmp > 0)
827 Translationvector.x[j] -= 1.;
828 else
829 Translationvector.x[j] += 1.;
830 }
831 }
832 }
833 Testvector.AddVector(&Translationvector);
834 Testvector.MatrixMultiplication(matrix);
835 Center.AddVector(&Testvector);
836 cout << Verbose(1) << "vector is: ";
837 Testvector.Output((ofstream *)&cout);
838 cout << endl;
839#ifdef ADDHYDROGEN
840 // now also change all hydrogens
841 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
842 Binder = ListOfBondsPerAtom[Walker->nr][i];
843 if (Binder->GetOtherAtom(Walker)->type->Z == 1) {
844 Testvector.CopyVector(&Binder->GetOtherAtom(Walker)->x);
845 Testvector.InverseMatrixMultiplication(matrix);
846 Testvector.AddVector(&Translationvector);
847 Testvector.MatrixMultiplication(matrix);
848 Center.AddVector(&Testvector);
849 cout << Verbose(1) << "Hydrogen vector is: ";
850 Testvector.Output((ofstream *)&cout);
851 cout << endl;
852 }
853 }
854 }
855#endif
856 }
857 } while (!flag);
858 Free((void **)&matrix, "molecule::DetermineCenter: *matrix");
859 Center.Scale(1./(double)AtomCount);
860};
861
862/** Transforms/Rotates the given molecule into its principal axis system.
863 * \param *out output stream for debugging
864 * \param DoRotate whether to rotate (true) or only to determine the PAS.
865 */
866void molecule::PrincipalAxisSystem(ofstream *out, bool DoRotate)
867{
868 atom *ptr = start; // start at first in list
869 double InertiaTensor[NDIM*NDIM];
870 Vector *CenterOfGravity = DetermineCenterOfGravity(out);
871
872 CenterGravity(out, CenterOfGravity);
873
874 // reset inertia tensor
875 for(int i=0;i<NDIM*NDIM;i++)
876 InertiaTensor[i] = 0.;
877
878 // sum up inertia tensor
879 while (ptr->next != end) {
880 ptr = ptr->next;
881 Vector x;
882 x.CopyVector(&ptr->x);
883 //x.SubtractVector(CenterOfGravity);
884 InertiaTensor[0] += ptr->type->mass*(x.x[1]*x.x[1] + x.x[2]*x.x[2]);
885 InertiaTensor[1] += ptr->type->mass*(-x.x[0]*x.x[1]);
886 InertiaTensor[2] += ptr->type->mass*(-x.x[0]*x.x[2]);
887 InertiaTensor[3] += ptr->type->mass*(-x.x[1]*x.x[0]);
888 InertiaTensor[4] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[2]*x.x[2]);
889 InertiaTensor[5] += ptr->type->mass*(-x.x[1]*x.x[2]);
890 InertiaTensor[6] += ptr->type->mass*(-x.x[2]*x.x[0]);
891 InertiaTensor[7] += ptr->type->mass*(-x.x[2]*x.x[1]);
892 InertiaTensor[8] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[1]*x.x[1]);
893 }
894 // print InertiaTensor for debugging
895 *out << "The inertia tensor is:" << endl;
896 for(int i=0;i<NDIM;i++) {
897 for(int j=0;j<NDIM;j++)
898 *out << InertiaTensor[i*NDIM+j] << " ";
899 *out << endl;
900 }
901 *out << endl;
902
903 // diagonalize to determine principal axis system
904 gsl_eigen_symmv_workspace *T = gsl_eigen_symmv_alloc(NDIM);
905 gsl_matrix_view m = gsl_matrix_view_array(InertiaTensor, NDIM, NDIM);
906 gsl_vector *eval = gsl_vector_alloc(NDIM);
907 gsl_matrix *evec = gsl_matrix_alloc(NDIM, NDIM);
908 gsl_eigen_symmv(&m.matrix, eval, evec, T);
909 gsl_eigen_symmv_free(T);
910 gsl_eigen_symmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_DESC);
911
912 for(int i=0;i<NDIM;i++) {
913 *out << Verbose(1) << "eigenvalue = " << gsl_vector_get(eval, i);
914 *out << ", eigenvector = (" << evec->data[i * evec->tda + 0] << "," << evec->data[i * evec->tda + 1] << "," << evec->data[i * evec->tda + 2] << ")" << endl;
915 }
916
917 // check whether we rotate or not
918 if (DoRotate) {
919 *out << Verbose(1) << "Transforming molecule into PAS ... ";
920 // the eigenvectors specify the transformation matrix
921 ptr = start;
922 while (ptr->next != end) {
923 ptr = ptr->next;
924 ptr->x.MatrixMultiplication(evec->data);
925 }
926 *out << "done." << endl;
927
928 // summing anew for debugging (resulting matrix has to be diagonal!)
929 // reset inertia tensor
930 for(int i=0;i<NDIM*NDIM;i++)
931 InertiaTensor[i] = 0.;
932
933 // sum up inertia tensor
934 ptr = start;
935 while (ptr->next != end) {
936 ptr = ptr->next;
937 Vector x;
938 x.CopyVector(&ptr->x);
939 //x.SubtractVector(CenterOfGravity);
940 InertiaTensor[0] += ptr->type->mass*(x.x[1]*x.x[1] + x.x[2]*x.x[2]);
941 InertiaTensor[1] += ptr->type->mass*(-x.x[0]*x.x[1]);
942 InertiaTensor[2] += ptr->type->mass*(-x.x[0]*x.x[2]);
943 InertiaTensor[3] += ptr->type->mass*(-x.x[1]*x.x[0]);
944 InertiaTensor[4] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[2]*x.x[2]);
945 InertiaTensor[5] += ptr->type->mass*(-x.x[1]*x.x[2]);
946 InertiaTensor[6] += ptr->type->mass*(-x.x[2]*x.x[0]);
947 InertiaTensor[7] += ptr->type->mass*(-x.x[2]*x.x[1]);
948 InertiaTensor[8] += ptr->type->mass*(x.x[0]*x.x[0] + x.x[1]*x.x[1]);
949 }
950 // print InertiaTensor for debugging
951 *out << "The inertia tensor is:" << endl;
952 for(int i=0;i<NDIM;i++) {
953 for(int j=0;j<NDIM;j++)
954 *out << InertiaTensor[i*NDIM+j] << " ";
955 *out << endl;
956 }
957 *out << endl;
958 }
959
960 // free everything
961 delete(CenterOfGravity);
962 gsl_vector_free(eval);
963 gsl_matrix_free(evec);
964};
965
966/** Parses nuclear forces from file and performs Verlet integration.
967 * This adds a new MD step to the config file.
968 * \param *file filename
969 * \param delta_t time step width in atomic units
970 * \return true - file found and parsed, false - file not found or imparsable
971 */
972bool molecule::VerletForceIntegration(char *file, double delta_t)
973{
974 bool status = true;
975 element *runner = elemente->start;
976 atom *walker = NULL;
977 int ElementNo, AtomNo;
978 ifstream input(file);
979 double Forcesvector[3];
980 double dummy;
981 string token;
982 size_t oldpos, newpos;
983 stringstream item;
984 int i, Ion[2];
985 double a, IonMass;
986 unsigned int size;
987
988 CountElements(); // make sure ElementsInMolecule is up to date
989
990 // check file
991 if (input == NULL) {
992 return false;
993 } else {
994 ElementNo = 0;
995 while (runner->next != elemente->end) { // go through every element
996 runner = runner->next;
997 IonMass = runner->mass;
998 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
999 ElementNo++;
1000 AtomNo = 0;
1001 walker = start;
1002 while (walker->next != end) { // go through every atom of this element
1003 walker = walker->next;
1004 if (walker->type == runner) { // if this atom fits to element
1005 AtomNo++;
1006 // parse Forcevector for this ion
1007 getline (input, token, '\n');
1008 newpos = oldpos = i = 0;
1009 while ((newpos = token.find( '\t', oldpos)) != oldpos) {
1010 i++;
1011 item.str();
1012 switch (i) {
1013 case 1:
1014 case 2:
1015 item >> Ion[i-1];
1016 break;
1017 case 6:
1018 case 7:
1019 case 8:
1020 item >> Forcesvector[i-6];
1021 break;
1022 case 3:
1023 if ((Ion[0] != ElementNo) || (Ion[1] != AtomNo))
1024 cout << "ERROR: Expected " << ElementNo << ", " << AtomNo << "but parsed " << Ion[0] << ", " << Ion[1] << "." << endl;
1025 // still parse into dummy! Hence no break here ...
1026 default:
1027 item >> dummy;
1028 }
1029 oldpos = newpos;
1030 }
1031
1032 // perform Verlet integration for this atom with position, velocity and force vector
1033
1034 // UpdateR
1035// for (int d=0; d<NDIM; d++) {
1036// R_old_old[d] = R_old[d]; // shift old values
1037// R_old[d] = R[d];
1038// R[d] += delta_t*(U[d]+a*FIon[d]); // F = m * a and s = 0.5 * a * t^2
1039// FIon_old[d] = FIon[d]; // store old force
1040// }
1041// // UpdateU
1042// a = delta_t*0.5/IonMass; // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a
1043// for (int d=0; d<NDIM; d++) {
1044// U[d] += a * (FIon[d]+FIon_old[d]);
1045// }
1046
1047
1048 // check size of vectors
1049 size = Trajectories[walker].R.size();
1050 if (size <= (unsigned int)(MDSteps)) {
1051 cout << "Increasing size for trajectory array of " << *walker << " to " << (size+10) << "." << endl;
1052 Trajectories[walker].R.resize(size+10);
1053 Trajectories[walker].U.resize(size+10);
1054 Trajectories[walker].F.resize(size+10);
1055 }
1056 // add trajectory point
1057
1058 }
1059 }
1060 }
1061 }
1062 return true;
1063 }
1064
1065 // exit
1066 return status;
1067};
1068
1069/** Align all atoms in such a manner that given vector \a *n is along z axis.
1070 * \param n[] alignment vector.
1071 */
1072void molecule::Align(Vector *n)
1073{
1074 atom *ptr = start;
1075 double alpha, tmp;
1076 Vector z_axis;
1077 z_axis.x[0] = 0.;
1078 z_axis.x[1] = 0.;
1079 z_axis.x[2] = 1.;
1080
1081 // rotate on z-x plane
1082 cout << Verbose(0) << "Begin of Aligning all atoms." << endl;
1083 alpha = atan(-n->x[0]/n->x[2]);
1084 cout << Verbose(1) << "Z-X-angle: " << alpha << " ... ";
1085 while (ptr->next != end) {
1086 ptr = ptr->next;
1087 tmp = ptr->x.x[0];
1088 ptr->x.x[0] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];
1089 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2];
1090 }
1091 // rotate n vector
1092 tmp = n->x[0];
1093 n->x[0] = cos(alpha) * tmp + sin(alpha) * n->x[2];
1094 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2];
1095 cout << Verbose(1) << "alignment vector after first rotation: ";
1096 n->Output((ofstream *)&cout);
1097 cout << endl;
1098
1099 // rotate on z-y plane
1100 ptr = start;
1101 alpha = atan(-n->x[1]/n->x[2]);
1102 cout << Verbose(1) << "Z-Y-angle: " << alpha << " ... ";
1103 while (ptr->next != end) {
1104 ptr = ptr->next;
1105 tmp = ptr->x.x[1];
1106 ptr->x.x[1] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];
1107 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2];
1108 }
1109 // rotate n vector (for consistency check)
1110 tmp = n->x[1];
1111 n->x[1] = cos(alpha) * tmp + sin(alpha) * n->x[2];
1112 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2];
1113
1114 cout << Verbose(1) << "alignment vector after second rotation: ";
1115 n->Output((ofstream *)&cout);
1116 cout << Verbose(1) << endl;
1117 cout << Verbose(0) << "End of Aligning all atoms." << endl;
1118};
1119
1120/** Removes atom from molecule list.
1121 * \param *pointer atom to be removed
1122 * \return true - succeeded, false - atom not found in list
1123 */
1124bool molecule::RemoveAtom(atom *pointer)
1125{
1126 if (ElementsInMolecule[pointer->type->Z] != 0) // this would indicate an error
1127 ElementsInMolecule[pointer->type->Z]--; // decrease number of atom of this element
1128 else
1129 cerr << "ERROR: Atom " << pointer->Name << " is of element " << pointer->type->Z << " but the entry in the table of the molecule is 0!" << endl;
1130 if (ElementsInMolecule[pointer->type->Z] == 0) // was last atom of this element?
1131 ElementCount--;
1132 return remove(pointer, start, end);
1133};
1134
1135/** Removes every atom from molecule list.
1136 * \return true - succeeded, false - atom not found in list
1137 */
1138bool molecule::CleanupMolecule()
1139{
1140 return (cleanup(start,end) && cleanup(first,last));
1141};
1142
1143/** Finds an atom specified by its continuous number.
1144 * \param Nr number of atom withim molecule
1145 * \return pointer to atom or NULL
1146 */
1147atom * molecule::FindAtom(int Nr) const{
1148 atom * walker = find(&Nr, start,end);
1149 if (walker != NULL) {
1150 //cout << Verbose(0) << "Found Atom Nr. " << walker->nr << endl;
1151 return walker;
1152 } else {
1153 cout << Verbose(0) << "Atom not found in list." << endl;
1154 return NULL;
1155 }
1156};
1157
1158/** Asks for atom number, and checks whether in list.
1159 * \param *text question before entering
1160 */
1161atom * molecule::AskAtom(string text)
1162{
1163 int No;
1164 atom *ion = NULL;
1165 do {
1166 //cout << Verbose(0) << "============Atom list==========================" << endl;
1167 //mol->Output((ofstream *)&cout);
1168 //cout << Verbose(0) << "===============================================" << endl;
1169 cout << Verbose(0) << text;
1170 cin >> No;
1171 ion = this->FindAtom(No);
1172 } while (ion == NULL);
1173 return ion;
1174};
1175
1176/** Checks if given coordinates are within cell volume.
1177 * \param *x array of coordinates
1178 * \return true - is within, false - out of cell
1179 */
1180bool molecule::CheckBounds(const Vector *x) const
1181{
1182 bool result = true;
1183 int j =-1;
1184 for (int i=0;i<NDIM;i++) {
1185 j += i+1;
1186 result = result && ((x->x[i] >= 0) && (x->x[i] < cell_size[j]));
1187 }
1188 //return result;
1189 return true; /// probably not gonna use the check no more
1190};
1191
1192/** Calculates sum over least square distance to line hidden in \a *x.
1193 * \param *x offset and direction vector
1194 * \param *params pointer to lsq_params structure
1195 * \return \f$ sum_i^N | y_i - (a + t_i b)|^2\f$
1196 */
1197double LeastSquareDistance (const gsl_vector * x, void * params)
1198{
1199 double res = 0, t;
1200 Vector a,b,c,d;
1201 struct lsq_params *par = (struct lsq_params *)params;
1202 atom *ptr = par->mol->start;
1203
1204 // initialize vectors
1205 a.x[0] = gsl_vector_get(x,0);
1206 a.x[1] = gsl_vector_get(x,1);
1207 a.x[2] = gsl_vector_get(x,2);
1208 b.x[0] = gsl_vector_get(x,3);
1209 b.x[1] = gsl_vector_get(x,4);
1210 b.x[2] = gsl_vector_get(x,5);
1211 // go through all atoms
1212 while (ptr != par->mol->end) {
1213 ptr = ptr->next;
1214 if (ptr->type == ((struct lsq_params *)params)->type) { // for specific type
1215 c.CopyVector(&ptr->x); // copy vector to temporary one
1216 c.SubtractVector(&a); // subtract offset vector
1217 t = c.ScalarProduct(&b); // get direction parameter
1218 d.CopyVector(&b); // and create vector
1219 d.Scale(&t);
1220 c.SubtractVector(&d); // ... yielding distance vector
1221 res += d.ScalarProduct((const Vector *)&d); // add squared distance
1222 }
1223 }
1224 return res;
1225};
1226
1227/** By minimizing the least square distance gains alignment vector.
1228 * \bug this is not yet working properly it seems
1229 */
1230void molecule::GetAlignvector(struct lsq_params * par) const
1231{
1232 int np = 6;
1233
1234 const gsl_multimin_fminimizer_type *T =
1235 gsl_multimin_fminimizer_nmsimplex;
1236 gsl_multimin_fminimizer *s = NULL;
1237 gsl_vector *ss;
1238 gsl_multimin_function minex_func;
1239
1240 size_t iter = 0, i;
1241 int status;
1242 double size;
1243
1244 /* Initial vertex size vector */
1245 ss = gsl_vector_alloc (np);
1246
1247 /* Set all step sizes to 1 */
1248 gsl_vector_set_all (ss, 1.0);
1249
1250 /* Starting point */
1251 par->x = gsl_vector_alloc (np);
1252 par->mol = this;
1253
1254 gsl_vector_set (par->x, 0, 0.0); // offset
1255 gsl_vector_set (par->x, 1, 0.0);
1256 gsl_vector_set (par->x, 2, 0.0);
1257 gsl_vector_set (par->x, 3, 0.0); // direction
1258 gsl_vector_set (par->x, 4, 0.0);
1259 gsl_vector_set (par->x, 5, 1.0);
1260
1261 /* Initialize method and iterate */
1262 minex_func.f = &LeastSquareDistance;
1263 minex_func.n = np;
1264 minex_func.params = (void *)par;
1265
1266 s = gsl_multimin_fminimizer_alloc (T, np);
1267 gsl_multimin_fminimizer_set (s, &minex_func, par->x, ss);
1268
1269 do
1270 {
1271 iter++;
1272 status = gsl_multimin_fminimizer_iterate(s);
1273
1274 if (status)
1275 break;
1276
1277 size = gsl_multimin_fminimizer_size (s);
1278 status = gsl_multimin_test_size (size, 1e-2);
1279
1280 if (status == GSL_SUCCESS)
1281 {
1282 printf ("converged to minimum at\n");
1283 }
1284
1285 printf ("%5d ", (int)iter);
1286 for (i = 0; i < (size_t)np; i++)
1287 {
1288 printf ("%10.3e ", gsl_vector_get (s->x, i));
1289 }
1290 printf ("f() = %7.3f size = %.3f\n", s->fval, size);
1291 }
1292 while (status == GSL_CONTINUE && iter < 100);
1293
1294 for (i=0;i<(size_t)np;i++)
1295 gsl_vector_set(par->x, i, gsl_vector_get(s->x, i));
1296 //gsl_vector_free(par->x);
1297 gsl_vector_free(ss);
1298 gsl_multimin_fminimizer_free (s);
1299};
1300
1301/** Prints molecule to *out.
1302 * \param *out output stream
1303 */
1304bool molecule::Output(ofstream *out)
1305{
1306 element *runner;
1307 atom *walker = NULL;
1308 int ElementNo, AtomNo;
1309 CountElements();
1310
1311 if (out == NULL) {
1312 return false;
1313 } else {
1314 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
1315 ElementNo = 0;
1316 runner = elemente->start;
1317 while (runner->next != elemente->end) { // go through every element
1318 runner = runner->next;
1319 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1320 ElementNo++;
1321 AtomNo = 0;
1322 walker = start;
1323 while (walker->next != end) { // go through every atom of this element
1324 walker = walker->next;
1325 if (walker->type == runner) { // if this atom fits to element
1326 AtomNo++;
1327 walker->Output(ElementNo, AtomNo, out); // removed due to trajectories
1328 }
1329 }
1330 }
1331 }
1332 return true;
1333 }
1334};
1335
1336/** Prints molecule with all atomic trajectory positions to *out.
1337 * \param *out output stream
1338 */
1339bool molecule::OutputTrajectories(ofstream *out)
1340{
1341 element *runner = NULL;
1342 atom *walker = NULL;
1343 int ElementNo, AtomNo;
1344 CountElements();
1345
1346 if (out == NULL) {
1347 return false;
1348 } else {
1349 for (int step = 0; step < MDSteps; step++) {
1350 if (step == 0) {
1351 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
1352 } else {
1353 *out << "# ====== MD step " << step << " =========" << endl;
1354 }
1355 ElementNo = 0;
1356 runner = elemente->start;
1357 while (runner->next != elemente->end) { // go through every element
1358 runner = runner->next;
1359 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1360 ElementNo++;
1361 AtomNo = 0;
1362 walker = start;
1363 while (walker->next != end) { // go through every atom of this element
1364 walker = walker->next;
1365 if (walker->type == runner) { // if this atom fits to element
1366 AtomNo++;
1367 *out << "Ion_Type" << ElementNo << "_" << AtomNo << "\t" << fixed << setprecision(9) << showpoint;
1368 *out << Trajectories[walker].R.at(step).x[0] << "\t" << Trajectories[walker].R.at(step).x[1] << "\t" << Trajectories[walker].R.at(step).x[2];
1369 *out << "\t" << walker->FixedIon;
1370 if (Trajectories[walker].U.at(step).Norm() > MYEPSILON)
1371 *out << "\t" << scientific << setprecision(6) << Trajectories[walker].U.at(step).x[0] << "\t" << Trajectories[walker].U.at(step).x[1] << "\t" << Trajectories[walker].U.at(step).x[2] << "\t";
1372 if (Trajectories[walker].F.at(step).Norm() > MYEPSILON)
1373 *out << "\t" << scientific << setprecision(6) << Trajectories[walker].F.at(step).x[0] << "\t" << Trajectories[walker].F.at(step).x[1] << "\t" << Trajectories[walker].F.at(step).x[2] << "\t";
1374 *out << " # Number in molecule " << walker->nr << endl;
1375 }
1376 }
1377 }
1378 }
1379 }
1380 return true;
1381 }
1382};
1383
1384/** Outputs contents of molecule::ListOfBondsPerAtom.
1385 * \param *out output stream
1386 */
1387void molecule::OutputListOfBonds(ofstream *out) const
1388{
1389 *out << Verbose(2) << endl << "From Contents of ListOfBondsPerAtom, all non-hydrogen atoms:" << endl;
1390 atom *Walker = start;
1391 while (Walker->next != end) {
1392 Walker = Walker->next;
1393#ifdef ADDHYDROGEN
1394 if (Walker->type->Z != 1) { // regard only non-hydrogen
1395#endif
1396 *out << Verbose(2) << "Atom " << Walker->Name << " has Bonds: "<<endl;
1397 for(int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
1398 *out << Verbose(3) << *(ListOfBondsPerAtom)[Walker->nr][j] << endl;
1399 }
1400#ifdef ADDHYDROGEN
1401 }
1402#endif
1403 }
1404 *out << endl;
1405};
1406
1407/** Output of element before the actual coordination list.
1408 * \param *out stream pointer
1409 */
1410bool molecule::Checkout(ofstream *out) const
1411{
1412 return elemente->Checkout(out, ElementsInMolecule);
1413};
1414
1415/** Prints molecule to *out as xyz file.
1416 * \param *out output stream
1417 */
1418bool molecule::OutputXYZ(ofstream *out) const
1419{
1420 atom *walker = NULL;
1421 int No = 0;
1422 time_t now;
1423
1424 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
1425 walker = start;
1426 while (walker->next != end) { // go through every atom and count
1427 walker = walker->next;
1428 No++;
1429 }
1430 if (out != NULL) {
1431 *out << No << "\n\tCreated by molecuilder on " << ctime(&now);
1432 walker = start;
1433 while (walker->next != end) { // go through every atom of this element
1434 walker = walker->next;
1435 walker->OutputXYZLine(out);
1436 }
1437 return true;
1438 } else
1439 return false;
1440};
1441
1442/** Brings molecule::AtomCount and atom::*Name up-to-date.
1443 * \param *out output stream for debugging
1444 */
1445void molecule::CountAtoms(ofstream *out)
1446{
1447 int i = 0;
1448 atom *Walker = start;
1449 while (Walker->next != end) {
1450 Walker = Walker->next;
1451 i++;
1452 }
1453 if ((AtomCount == 0) || (i != AtomCount)) {
1454 *out << Verbose(3) << "Mismatch in AtomCount " << AtomCount << " and recounted number " << i << ", renaming all." << endl;
1455 AtomCount = i;
1456
1457 // count NonHydrogen atoms and give each atom a unique name
1458 if (AtomCount != 0) {
1459 i=0;
1460 NoNonHydrogen = 0;
1461 Walker = start;
1462 while (Walker->next != end) {
1463 Walker = Walker->next;
1464 Walker->nr = i; // update number in molecule (for easier referencing in FragmentMolecule lateron)
1465 if (Walker->type->Z != 1) // count non-hydrogen atoms whilst at it
1466 NoNonHydrogen++;
1467 Free((void **)&Walker->Name, "molecule::CountAtoms: *walker->Name");
1468 Walker->Name = (char *) Malloc(sizeof(char)*6, "molecule::CountAtoms: *walker->Name");
1469 sprintf(Walker->Name, "%2s%02d", Walker->type->symbol, Walker->nr+1);
1470 *out << "Naming atom nr. " << Walker->nr << " " << Walker->Name << "." << endl;
1471 i++;
1472 }
1473 } else
1474 *out << Verbose(3) << "AtomCount is still " << AtomCount << ", thus counting nothing." << endl;
1475 }
1476};
1477
1478/** Brings molecule::ElementCount and molecule::ElementsInMolecule up-to-date.
1479 */
1480void molecule::CountElements()
1481{
1482 int i = 0;
1483 for(i=MAX_ELEMENTS;i--;)
1484 ElementsInMolecule[i] = 0;
1485 ElementCount = 0;
1486
1487 atom *walker = start;
1488 while (walker->next != end) {
1489 walker = walker->next;
1490 ElementsInMolecule[walker->type->Z]++;
1491 i++;
1492 }
1493 for(i=MAX_ELEMENTS;i--;)
1494 ElementCount += (ElementsInMolecule[i] != 0 ? 1 : 0);
1495};
1496
1497/** Counts all cyclic bonds and returns their number.
1498 * \note Hydrogen bonds can never by cyclic, thus no check for that
1499 * \param *out output stream for debugging
1500 * \return number opf cyclic bonds
1501 */
1502int molecule::CountCyclicBonds(ofstream *out)
1503{
1504 int No = 0;
1505 int *MinimumRingSize = NULL;
1506 MoleculeLeafClass *Subgraphs = NULL;
1507 bond *Binder = first;
1508 if ((Binder->next != last) && (Binder->next->Type == Undetermined)) {
1509 *out << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl;
1510 Subgraphs = DepthFirstSearchAnalysis(out, MinimumRingSize);
1511 while (Subgraphs->next != NULL) {
1512 Subgraphs = Subgraphs->next;
1513 delete(Subgraphs->previous);
1514 }
1515 delete(Subgraphs);
1516 delete[](MinimumRingSize);
1517 }
1518 while(Binder->next != last) {
1519 Binder = Binder->next;
1520 if (Binder->Cyclic)
1521 No++;
1522 }
1523 return No;
1524};
1525/** Returns Shading as a char string.
1526 * \param color the Shading
1527 * \return string of the flag
1528 */
1529string molecule::GetColor(enum Shading color)
1530{
1531 switch(color) {
1532 case white:
1533 return "white";
1534 break;
1535 case lightgray:
1536 return "lightgray";
1537 break;
1538 case darkgray:
1539 return "darkgray";
1540 break;
1541 case black:
1542 return "black";
1543 break;
1544 default:
1545 return "uncolored";
1546 break;
1547 };
1548};
1549
1550
1551/** Counts necessary number of valence electrons and returns number and SpinType.
1552 * \param configuration containing everything
1553 */
1554void molecule::CalculateOrbitals(class config &configuration)
1555{
1556 configuration.MaxPsiDouble = configuration.PsiMaxNoDown = configuration.PsiMaxNoUp = configuration.PsiType = 0;
1557 for(int i=MAX_ELEMENTS;i--;) {
1558 if (ElementsInMolecule[i] != 0) {
1559 //cout << "CalculateOrbitals: " << elemente->FindElement(i)->name << " has a valence of " << (int)elemente->FindElement(i)->Valence << " and there are " << ElementsInMolecule[i] << " of it." << endl;
1560 configuration.MaxPsiDouble += ElementsInMolecule[i]*((int)elemente->FindElement(i)->Valence);
1561 }
1562 }
1563 configuration.PsiMaxNoDown = configuration.MaxPsiDouble/2 + (configuration.MaxPsiDouble % 2);
1564 configuration.PsiMaxNoUp = configuration.MaxPsiDouble/2;
1565 configuration.MaxPsiDouble /= 2;
1566 configuration.PsiType = (configuration.PsiMaxNoDown == configuration.PsiMaxNoUp) ? 0 : 1;
1567 if ((configuration.PsiType == 1) && (configuration.ProcPEPsi < 2)) {
1568 configuration.ProcPEGamma /= 2;
1569 configuration.ProcPEPsi *= 2;
1570 } else {
1571 configuration.ProcPEGamma *= configuration.ProcPEPsi;
1572 configuration.ProcPEPsi = 1;
1573 }
1574 configuration.InitMaxMinStopStep = configuration.MaxMinStopStep = configuration.MaxPsiDouble;
1575};
1576
1577/** Creates an adjacency list of the molecule.
1578 * Generally, we use the CSD approach to bond recognition, that is the the distance
1579 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
1580 * a threshold t = 0.4 Angstroem.
1581 * To make it O(N log N) the function uses the linked-cell technique as follows:
1582 * The procedure is step-wise:
1583 * -# Remove every bond in list
1584 * -# Count the atoms in the molecule with CountAtoms()
1585 * -# partition cell into smaller linked cells of size \a bonddistance
1586 * -# put each atom into its corresponding cell
1587 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true
1588 * -# create the list of bonds via CreateListOfBondsPerAtom()
1589 * -# correct the bond degree iteratively (single->double->triple bond)
1590 * -# finally print the bond list to \a *out if desired
1591 * \param *out out stream for printing the matrix, NULL if no output
1592 * \param bonddistance length of linked cells (i.e. maximum minimal length checked)
1593 * \param IsAngstroem whether coordinate system is gauged to Angstroem or Bohr radii
1594 */
1595void molecule::CreateAdjacencyList(ofstream *out, double bonddistance, bool IsAngstroem)
1596{
1597 atom *Walker = NULL, *OtherWalker = NULL, *Candidate = NULL;
1598 int No, NoBonds, CandidateBondNo;
1599 int NumberCells, divisor[NDIM], n[NDIM], N[NDIM], index, Index, j;
1600 molecule **CellList;
1601 double distance, MinDistance, MaxDistance;
1602 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
1603 Vector x;
1604
1605 BondDistance = bonddistance; // * ((IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem);
1606 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl;
1607 // remove every bond from the list
1608 if ((first->next != last) && (last->previous != first)) { // there are bonds present
1609 cleanup(first,last);
1610 }
1611
1612 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering)
1613 CountAtoms(out);
1614 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl;
1615
1616 if (AtomCount != 0) {
1617 // 1. find divisor for each axis, such that a sphere with radius of at least bonddistance can be placed into each cell
1618 j=-1;
1619 for (int i=0;i<NDIM;i++) {
1620 j += i+1;
1621 divisor[i] = (int)floor(cell_size[j]/bonddistance); // take smaller value such that size of linked cell is at least bonddistance
1622 *out << Verbose(1) << "divisor[" << i << "] = " << divisor[i] << "." << endl;
1623 }
1624 // 2a. allocate memory for the cell list
1625 NumberCells = divisor[0]*divisor[1]*divisor[2];
1626 *out << Verbose(1) << "Allocating " << NumberCells << " cells." << endl;
1627 CellList = (molecule **) Malloc(sizeof(molecule *)*NumberCells, "molecule::CreateAdjacencyList - ** CellList");
1628 for (int i=NumberCells;i--;)
1629 CellList[i] = NULL;
1630
1631 // 2b. put all atoms into its corresponding list
1632 Walker = start;
1633 while(Walker->next != end) {
1634 Walker = Walker->next;
1635 //*out << Verbose(1) << "Current atom is " << *Walker << " with coordinates ";
1636 //Walker->x.Output(out);
1637 //*out << "." << endl;
1638 // compute the cell by the atom's coordinates
1639 j=-1;
1640 for (int i=0;i<NDIM;i++) {
1641 j += i+1;
1642 x.CopyVector(&(Walker->x));
1643 x.KeepPeriodic(out, matrix);
1644 n[i] = (int)floor(x.x[i]/cell_size[j]*(double)divisor[i]);
1645 }
1646 index = n[2] + (n[1] + n[0] * divisor[1]) * divisor[2];
1647 *out << Verbose(1) << "Atom " << *Walker << " goes into cell number [" << n[0] << "," << n[1] << "," << n[2] << "] = " << index << "." << endl;
1648 // add copy atom to this cell
1649 if (CellList[index] == NULL) // allocate molecule if not done
1650 CellList[index] = new molecule(elemente);
1651 OtherWalker = CellList[index]->AddCopyAtom(Walker); // add a copy of walker to this atom, father will be walker for later reference
1652 //*out << Verbose(1) << "Copy Atom is " << *OtherWalker << "." << endl;
1653 }
1654 //for (int i=0;i<NumberCells;i++)
1655 //*out << Verbose(1) << "Cell number " << i << ": " << CellList[i] << "." << endl;
1656
1657 // 3a. go through every cell
1658 for (N[0]=divisor[0];N[0]--;)
1659 for (N[1]=divisor[1];N[1]--;)
1660 for (N[2]=divisor[2];N[2]--;) {
1661 Index = N[2] + (N[1] + N[0] * divisor[1]) * divisor[2];
1662 if (CellList[Index] != NULL) { // if there atoms in this cell
1663 //*out << Verbose(1) << "Current cell is " << Index << "." << endl;
1664 // 3b. for every atom therein
1665 Walker = CellList[Index]->start;
1666 while (Walker->next != CellList[Index]->end) { // go through every atom
1667 Walker = Walker->next;
1668 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl;
1669 // 3c. check for possible bond between each atom in this and every one in the 27 cells
1670 for (n[0]=-1;n[0]<=1;n[0]++)
1671 for (n[1]=-1;n[1]<=1;n[1]++)
1672 for (n[2]=-1;n[2]<=1;n[2]++) {
1673 // compute the index of this comparison cell and make it periodic
1674 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];
1675 //*out << Verbose(1) << "Number of comparison cell is " << index << "." << endl;
1676 if (CellList[index] != NULL) { // if there are any atoms in this cell
1677 OtherWalker = CellList[index]->start;
1678 while(OtherWalker->next != CellList[index]->end) { // go through every atom in this cell
1679 OtherWalker = OtherWalker->next;
1680 //*out << Verbose(0) << "Current comparison atom is " << *OtherWalker << "." << endl;
1681 /// \todo periodic check is missing here!
1682 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl;
1683 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius;
1684 MinDistance *= (IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem;
1685 MaxDistance = MinDistance + BONDTHRESHOLD;
1686 MinDistance -= BONDTHRESHOLD;
1687 distance = OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size);
1688 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance*MaxDistance) && (distance >= MinDistance*MinDistance)) { // create bond if distance is smaller
1689 *out << Verbose(0) << "Adding Bond between " << *Walker << " and " << *OtherWalker << "." << endl;
1690 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount
1691 BondCount++;
1692 } else {
1693 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl;
1694 }
1695 }
1696 }
1697 }
1698 }
1699 }
1700 }
1701 // 4. free the cell again
1702 for (int i=NumberCells;i--;)
1703 if (CellList[i] != NULL) {
1704 delete(CellList[i]);
1705 }
1706 Free((void **)&CellList, "molecule::CreateAdjacencyList - ** CellList");
1707
1708 // create the adjacency list per atom
1709 CreateListOfBondsPerAtom(out);
1710
1711 // correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees,
1712 // iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene
1713 // preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of
1714 // double bonds as was expected.
1715 if (BondCount != 0) {
1716 NoCyclicBonds = 0;
1717 *out << Verbose(1) << "Correcting Bond degree of each bond ... ";
1718 do {
1719 No = 0; // No acts as breakup flag (if 1 we still continue)
1720 Walker = start;
1721 while (Walker->next != end) { // go through every atom
1722 Walker = Walker->next;
1723 // count valence of first partner
1724 NoBonds = 0;
1725 for(j=0;j<NumberOfBondsPerAtom[Walker->nr];j++)
1726 NoBonds += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
1727 *out << Verbose(3) << "Walker " << *Walker << ": " << (int)Walker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
1728 if ((int)(Walker->type->NoValenceOrbitals) > NoBonds) { // we have a mismatch, check all bonding partners for mismatch
1729 Candidate = NULL;
1730 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through each of its bond partners
1731 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
1732 // count valence of second partner
1733 NoBonds = 0;
1734 for(j=0;j<NumberOfBondsPerAtom[OtherWalker->nr];j++)
1735 NoBonds += ListOfBondsPerAtom[OtherWalker->nr][j]->BondDegree;
1736 *out << Verbose(3) << "OtherWalker " << *OtherWalker << ": " << (int)OtherWalker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
1737 if ((int)(OtherWalker->type->NoValenceOrbitals) > NoBonds) { // check if possible candidate
1738 if ((Candidate == NULL) || (NumberOfBondsPerAtom[Candidate->nr] > NumberOfBondsPerAtom[OtherWalker->nr])) { // pick the one with fewer number of bonds first
1739 Candidate = OtherWalker;
1740 CandidateBondNo = i;
1741 *out << Verbose(3) << "New candidate is " << *Candidate << "." << endl;
1742 }
1743 }
1744 }
1745 if (Candidate != NULL) {
1746 ListOfBondsPerAtom[Walker->nr][CandidateBondNo]->BondDegree++;
1747 *out << Verbose(2) << "Increased bond degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl;
1748 }
1749 }
1750 }
1751 } while (No);
1752 *out << " done." << endl;
1753 } else
1754 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl;
1755 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << bonddistance << "." << endl;
1756
1757 // output bonds for debugging (if bond chain list was correctly installed)
1758 *out << Verbose(1) << endl << "From contents of bond chain list:";
1759 bond *Binder = first;
1760 while(Binder->next != last) {
1761 Binder = Binder->next;
1762 *out << *Binder << "\t" << endl;
1763 }
1764 *out << endl;
1765 } else
1766 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl;
1767 *out << Verbose(0) << "End of CreateAdjacencyList." << endl;
1768 Free((void **)&matrix, "molecule::CreateAdjacencyList: *matrix");
1769};
1770
1771/** Performs a Depth-First search on this molecule.
1772 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
1773 * articulations points, ...
1774 * We use the algorithm from [Even, Graph Algorithms, p.62].
1775 * \param *out output stream for debugging
1776 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found
1777 * \return list of each disconnected subgraph as an individual molecule class structure
1778 */
1779MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, int *&MinimumRingSize)
1780{
1781 class StackClass<atom *> *AtomStack;
1782 AtomStack = new StackClass<atom *>(AtomCount);
1783 class StackClass<bond *> *BackEdgeStack = new StackClass<bond *> (BondCount);
1784 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
1785 MoleculeLeafClass *LeafWalker = SubGraphs;
1786 int CurrentGraphNr = 0, OldGraphNr;
1787 int ComponentNumber = 0;
1788 atom *Walker = NULL, *OtherAtom = NULL, *Root = start->next;
1789 bond *Binder = NULL;
1790 bool BackStepping = false;
1791
1792 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl;
1793
1794 ResetAllBondsToUnused();
1795 ResetAllAtomNumbers();
1796 InitComponentNumbers();
1797 BackEdgeStack->ClearStack();
1798 while (Root != end) { // if there any atoms at all
1799 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all
1800 AtomStack->ClearStack();
1801
1802 // put into new subgraph molecule and add this to list of subgraphs
1803 LeafWalker = new MoleculeLeafClass(LeafWalker);
1804 LeafWalker->Leaf = new molecule(elemente);
1805 LeafWalker->Leaf->AddCopyAtom(Root);
1806
1807 OldGraphNr = CurrentGraphNr;
1808 Walker = Root;
1809 do { // (10)
1810 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
1811 if (!BackStepping) { // if we don't just return from (8)
1812 Walker->GraphNr = CurrentGraphNr;
1813 Walker->LowpointNr = CurrentGraphNr;
1814 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl;
1815 AtomStack->Push(Walker);
1816 CurrentGraphNr++;
1817 }
1818 do { // (3) if Walker has no unused egdes, go to (5)
1819 BackStepping = false; // reset backstepping flag for (8)
1820 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
1821 Binder = FindNextUnused(Walker);
1822 if (Binder == NULL)
1823 break;
1824 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl;
1825 // (4) Mark Binder used, ...
1826 Binder->MarkUsed(black);
1827 OtherAtom = Binder->GetOtherAtom(Walker);
1828 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl;
1829 if (OtherAtom->GraphNr != -1) {
1830 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
1831 Binder->Type = BackEdge;
1832 BackEdgeStack->Push(Binder);
1833 Walker->LowpointNr = ( Walker->LowpointNr < OtherAtom->GraphNr ) ? Walker->LowpointNr : OtherAtom->GraphNr;
1834 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl;
1835 } else {
1836 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
1837 Binder->Type = TreeEdge;
1838 OtherAtom->Ancestor = Walker;
1839 Walker = OtherAtom;
1840 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl;
1841 break;
1842 }
1843 Binder = NULL;
1844 } while (1); // (3)
1845 if (Binder == NULL) {
1846 *out << Verbose(2) << "No more Unused Bonds." << endl;
1847 break;
1848 } else
1849 Binder = NULL;
1850 } while (1); // (2)
1851
1852 // 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!
1853 if ((Walker == Root) && (Binder == NULL))
1854 break;
1855
1856 // (5) if Ancestor of Walker is ...
1857 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl;
1858 if (Walker->Ancestor->GraphNr != Root->GraphNr) {
1859 // (6) (Ancestor of Walker is not Root)
1860 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
1861 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
1862 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
1863 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl;
1864 } else {
1865 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
1866 Walker->Ancestor->SeparationVertex = true;
1867 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl;
1868 SetNextComponentNumber(Walker->Ancestor, ComponentNumber);
1869 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << ComponentNumber << "." << endl;
1870 SetNextComponentNumber(Walker, ComponentNumber);
1871 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1872 do {
1873 OtherAtom = AtomStack->PopLast();
1874 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
1875 SetNextComponentNumber(OtherAtom, ComponentNumber);
1876 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1877 } while (OtherAtom != Walker);
1878 ComponentNumber++;
1879 }
1880 // (8) Walker becomes its Ancestor, go to (3)
1881 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl;
1882 Walker = Walker->Ancestor;
1883 BackStepping = true;
1884 }
1885 if (!BackStepping) { // coming from (8) want to go to (3)
1886 // (9) remove all from stack till Walker (including), these and Root form a component
1887 AtomStack->Output(out);
1888 SetNextComponentNumber(Root, ComponentNumber);
1889 *out << Verbose(3) << "(9) Root[" << Root->Name << "]'s Component is " << ComponentNumber << "." << endl;
1890 SetNextComponentNumber(Walker, ComponentNumber);
1891 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << ComponentNumber << "." << endl;
1892 do {
1893 OtherAtom = AtomStack->PopLast();
1894 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
1895 SetNextComponentNumber(OtherAtom, ComponentNumber);
1896 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1897 } while (OtherAtom != Walker);
1898 ComponentNumber++;
1899
1900 // (11) Root is separation vertex, set Walker to Root and go to (4)
1901 Walker = Root;
1902 Binder = FindNextUnused(Walker);
1903 *out << Verbose(1) << "(10) Walker is Root[" << Root->Name << "], next Unused Bond is " << Binder << "." << endl;
1904 if (Binder != NULL) { // Root is separation vertex
1905 *out << Verbose(1) << "(11) Root is a separation vertex." << endl;
1906 Walker->SeparationVertex = true;
1907 }
1908 }
1909 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
1910
1911 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
1912 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << CurrentGraphNr << "." << endl;
1913 LeafWalker->Leaf->Output(out);
1914 *out << endl;
1915
1916 // step on to next root
1917 while ((Root != end) && (Root->GraphNr != -1)) {
1918 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl;
1919 if (Root->GraphNr != -1) // if already discovered, step on
1920 Root = Root->next;
1921 }
1922 }
1923 // set cyclic bond criterium on "same LP" basis
1924 Binder = first;
1925 while(Binder->next != last) {
1926 Binder = Binder->next;
1927 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ??
1928 Binder->Cyclic = true;
1929 NoCyclicBonds++;
1930 }
1931 }
1932
1933 // analysis of the cycles (print rings, get minimum cycle length)
1934 CyclicStructureAnalysis(out, BackEdgeStack, MinimumRingSize);
1935
1936 *out << Verbose(1) << "Final graph info for each atom is:" << endl;
1937 Walker = start;
1938 while (Walker->next != end) {
1939 Walker = Walker->next;
1940 *out << Verbose(2) << "Atom " << Walker->Name << " is " << ((Walker->SeparationVertex) ? "a" : "not a") << " separation vertex, components are ";
1941 OutputComponentNumber(out, Walker);
1942 *out << " with Lowpoint " << Walker->LowpointNr << " and Graph Nr. " << Walker->GraphNr << "." << endl;
1943 }
1944
1945 *out << Verbose(1) << "Final graph info for each bond is:" << endl;
1946 Binder = first;
1947 while(Binder->next != last) {
1948 Binder = Binder->next;
1949 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
1950 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
1951 OutputComponentNumber(out, Binder->leftatom);
1952 *out << " === ";
1953 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
1954 OutputComponentNumber(out, Binder->rightatom);
1955 *out << ">." << endl;
1956 if (Binder->Cyclic) // cyclic ??
1957 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl;
1958 }
1959
1960 // free all and exit
1961 delete(AtomStack);
1962 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl;
1963 return SubGraphs;
1964};
1965
1966/** Analyses the cycles found and returns minimum of all cycle lengths.
1967 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
1968 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
1969 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
1970 * as cyclic and print out the cycles.
1971 * \param *out output stream for debugging
1972 * \param *BackEdgeStack stack with all back edges found during DFS scan
1973 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
1974 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
1975 */
1976void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize)
1977{
1978 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList");
1979 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList");
1980 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CyclicStructureAnalysis: *ColorList");
1981 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring
1982 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop)
1983 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL;
1984 bond *Binder = NULL, *BackEdge = NULL;
1985 int RingSize, NumCycles, MinRingSize = -1;
1986
1987 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
1988 for (int i=AtomCount;i--;) {
1989 PredecessorList[i] = NULL;
1990 ShortestPathList[i] = -1;
1991 ColorList[i] = white;
1992 }
1993 MinimumRingSize = new int[AtomCount];
1994 for(int i=AtomCount;i--;)
1995 MinimumRingSize[i] = AtomCount;
1996
1997
1998 *out << Verbose(1) << "Back edge list - ";
1999 BackEdgeStack->Output(out);
2000
2001 *out << Verbose(1) << "Analysing cycles ... " << endl;
2002 NumCycles = 0;
2003 while (!BackEdgeStack->IsEmpty()) {
2004 BackEdge = BackEdgeStack->PopFirst();
2005 // this is the target
2006 Root = BackEdge->leftatom;
2007 // this is the source point
2008 Walker = BackEdge->rightatom;
2009 ShortestPathList[Walker->nr] = 0;
2010 BFSStack->ClearStack(); // start with empty BFS stack
2011 BFSStack->Push(Walker);
2012 TouchedStack->Push(Walker);
2013 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
2014 OtherAtom = NULL;
2015 do { // look for Root
2016 Walker = BFSStack->PopFirst();
2017 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
2018 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2019 Binder = ListOfBondsPerAtom[Walker->nr][i];
2020 if (Binder != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
2021 OtherAtom = Binder->GetOtherAtom(Walker);
2022#ifdef ADDHYDROGEN
2023 if (OtherAtom->type->Z != 1) {
2024#endif
2025 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2026 if (ColorList[OtherAtom->nr] == white) {
2027 TouchedStack->Push(OtherAtom);
2028 ColorList[OtherAtom->nr] = lightgray;
2029 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2030 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2031 *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;
2032 //if (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
2033 *out << Verbose(3) << "Putting OtherAtom into queue." << endl;
2034 BFSStack->Push(OtherAtom);
2035 //}
2036 } else {
2037 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
2038 }
2039 if (OtherAtom == Root)
2040 break;
2041#ifdef ADDHYDROGEN
2042 } else {
2043 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl;
2044 ColorList[OtherAtom->nr] = black;
2045 }
2046#endif
2047 } else {
2048 *out << Verbose(2) << "Bond " << *Binder << " not Visiting, is the back edge." << endl;
2049 }
2050 }
2051 ColorList[Walker->nr] = black;
2052 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2053 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
2054 // step through predecessor list
2055 while (OtherAtom != BackEdge->rightatom) {
2056 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
2057 break;
2058 else
2059 OtherAtom = PredecessorList[OtherAtom->nr];
2060 }
2061 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
2062 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;\
2063 do {
2064 OtherAtom = TouchedStack->PopLast();
2065 if (PredecessorList[OtherAtom->nr] == Walker) {
2066 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl;
2067 PredecessorList[OtherAtom->nr] = NULL;
2068 ShortestPathList[OtherAtom->nr] = -1;
2069 ColorList[OtherAtom->nr] = white;
2070 BFSStack->RemoveItem(OtherAtom);
2071 }
2072 } while ((!TouchedStack->IsEmpty()) && (PredecessorList[OtherAtom->nr] == NULL));
2073 TouchedStack->Push(OtherAtom); // last was wrongly popped
2074 OtherAtom = BackEdge->rightatom; // set to not Root
2075 } else
2076 OtherAtom = Root;
2077 }
2078 } while ((!BFSStack->IsEmpty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr])));
2079
2080 if (OtherAtom == Root) {
2081 // now climb back the predecessor list and thus find the cycle members
2082 NumCycles++;
2083 RingSize = 1;
2084 Root->GetTrueFather()->IsCyclic = true;
2085 *out << Verbose(1) << "Found ring contains: ";
2086 Walker = Root;
2087 while (Walker != BackEdge->rightatom) {
2088 *out << Walker->Name << " <-> ";
2089 Walker = PredecessorList[Walker->nr];
2090 Walker->GetTrueFather()->IsCyclic = true;
2091 RingSize++;
2092 }
2093 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl;
2094 // walk through all and set MinimumRingSize
2095 Walker = Root;
2096 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
2097 while (Walker != BackEdge->rightatom) {
2098 Walker = PredecessorList[Walker->nr];
2099 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr])
2100 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
2101 }
2102 if ((RingSize < MinRingSize) || (MinRingSize == -1))
2103 MinRingSize = RingSize;
2104 } else {
2105 *out << Verbose(1) << "No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl;
2106 }
2107
2108 // now clean the lists
2109 while (!TouchedStack->IsEmpty()){
2110 Walker = TouchedStack->PopFirst();
2111 PredecessorList[Walker->nr] = NULL;
2112 ShortestPathList[Walker->nr] = -1;
2113 ColorList[Walker->nr] = white;
2114 }
2115 }
2116 if (MinRingSize != -1) {
2117 // go over all atoms
2118 Root = start;
2119 while(Root->next != end) {
2120 Root = Root->next;
2121
2122 if (MinimumRingSize[Root->GetTrueFather()->nr] == AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is
2123 Walker = Root;
2124 ShortestPathList[Walker->nr] = 0;
2125 BFSStack->ClearStack(); // start with empty BFS stack
2126 BFSStack->Push(Walker);
2127 TouchedStack->Push(Walker);
2128 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
2129 OtherAtom = Walker;
2130 while (OtherAtom != NULL) { // look for Root
2131 Walker = BFSStack->PopFirst();
2132 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
2133 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2134 Binder = ListOfBondsPerAtom[Walker->nr][i];
2135 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
2136 OtherAtom = Binder->GetOtherAtom(Walker);
2137 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2138 if (ColorList[OtherAtom->nr] == white) {
2139 TouchedStack->Push(OtherAtom);
2140 ColorList[OtherAtom->nr] = lightgray;
2141 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2142 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2143 //*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;
2144 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
2145 MinimumRingSize[Root->GetTrueFather()->nr] = ShortestPathList[OtherAtom->nr]+MinimumRingSize[OtherAtom->GetTrueFather()->nr];
2146 OtherAtom = NULL; //break;
2147 break;
2148 } else
2149 BFSStack->Push(OtherAtom);
2150 } else {
2151 //*out << Verbose(3) << "Not Adding, has already been visited." << endl;
2152 }
2153 } else {
2154 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl;
2155 }
2156 }
2157 ColorList[Walker->nr] = black;
2158 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2159 }
2160
2161 // now clean the lists
2162 while (!TouchedStack->IsEmpty()){
2163 Walker = TouchedStack->PopFirst();
2164 PredecessorList[Walker->nr] = NULL;
2165 ShortestPathList[Walker->nr] = -1;
2166 ColorList[Walker->nr] = white;
2167 }
2168 }
2169 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl;
2170 }
2171 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl;
2172 } else
2173 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
2174
2175 Free((void **)&PredecessorList, "molecule::CyclicStructureAnalysis: **PredecessorList");
2176 Free((void **)&ShortestPathList, "molecule::CyclicStructureAnalysis: **ShortestPathList");
2177 Free((void **)&ColorList, "molecule::CyclicStructureAnalysis: **ColorList");
2178 delete(BFSStack);
2179};
2180
2181/** Sets the next component number.
2182 * This is O(N) as the number of bonds per atom is bound.
2183 * \param *vertex atom whose next atom::*ComponentNr is to be set
2184 * \param nr number to use
2185 */
2186void molecule::SetNextComponentNumber(atom *vertex, int nr)
2187{
2188 int i=0;
2189 if (vertex != NULL) {
2190 for(;i<NumberOfBondsPerAtom[vertex->nr];i++) {
2191 if (vertex->ComponentNr[i] == -1) { // check if not yet used
2192 vertex->ComponentNr[i] = nr;
2193 break;
2194 }
2195 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
2196 break; // breaking here will not cause error!
2197 }
2198 if (i == NumberOfBondsPerAtom[vertex->nr])
2199 cerr << "Error: All Component entries are already occupied!" << endl;
2200 } else
2201 cerr << "Error: Given vertex is NULL!" << endl;
2202};
2203
2204/** Output a list of flags, stating whether the bond was visited or not.
2205 * \param *out output stream for debugging
2206 */
2207void molecule::OutputComponentNumber(ofstream *out, atom *vertex)
2208{
2209 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
2210 *out << vertex->ComponentNr[i] << " ";
2211};
2212
2213/** Allocates memory for all atom::*ComponentNr in this molecule and sets each entry to -1.
2214 */
2215void molecule::InitComponentNumbers()
2216{
2217 atom *Walker = start;
2218 while(Walker->next != end) {
2219 Walker = Walker->next;
2220 if (Walker->ComponentNr != NULL)
2221 Free((void **)&Walker->ComponentNr, "molecule::InitComponentNumbers: **Walker->ComponentNr");
2222 Walker->ComponentNr = (int *) Malloc(sizeof(int)*NumberOfBondsPerAtom[Walker->nr], "molecule::InitComponentNumbers: *Walker->ComponentNr");
2223 for (int i=NumberOfBondsPerAtom[Walker->nr];i--;)
2224 Walker->ComponentNr[i] = -1;
2225 }
2226};
2227
2228/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
2229 * \param *vertex atom to regard
2230 * \return bond class or NULL
2231 */
2232bond * molecule::FindNextUnused(atom *vertex)
2233{
2234 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
2235 if (ListOfBondsPerAtom[vertex->nr][i]->IsUsed() == white)
2236 return(ListOfBondsPerAtom[vertex->nr][i]);
2237 return NULL;
2238};
2239
2240/** Resets bond::Used flag of all bonds in this molecule.
2241 * \return true - success, false - -failure
2242 */
2243void molecule::ResetAllBondsToUnused()
2244{
2245 bond *Binder = first;
2246 while (Binder->next != last) {
2247 Binder = Binder->next;
2248 Binder->ResetUsed();
2249 }
2250};
2251
2252/** Resets atom::nr to -1 of all atoms in this molecule.
2253 */
2254void molecule::ResetAllAtomNumbers()
2255{
2256 atom *Walker = start;
2257 while (Walker->next != end) {
2258 Walker = Walker->next;
2259 Walker->GraphNr = -1;
2260 }
2261};
2262
2263/** Output a list of flags, stating whether the bond was visited or not.
2264 * \param *out output stream for debugging
2265 * \param *list
2266 */
2267void OutputAlreadyVisited(ofstream *out, int *list)
2268{
2269 *out << Verbose(4) << "Already Visited Bonds:\t";
2270 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " ";
2271 *out << endl;
2272};
2273
2274/** Estimates by educated guessing (using upper limit) the expected number of fragments.
2275 * The upper limit is
2276 * \f[
2277 * n = N \cdot C^k
2278 * \f]
2279 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
2280 * \param *out output stream for debugging
2281 * \param order bond order k
2282 * \return number n of fragments
2283 */
2284int molecule::GuesstimateFragmentCount(ofstream *out, int order)
2285{
2286 int c = 0;
2287 int FragmentCount;
2288 // get maximum bond degree
2289 atom *Walker = start;
2290 while (Walker->next != end) {
2291 Walker = Walker->next;
2292 c = (NumberOfBondsPerAtom[Walker->nr] > c) ? NumberOfBondsPerAtom[Walker->nr] : c;
2293 }
2294 FragmentCount = NoNonHydrogen*(1 << (c*order));
2295 *out << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl;
2296 return FragmentCount;
2297};
2298
2299/** Scans a single line for number and puts them into \a KeySet.
2300 * \param *out output stream for debugging
2301 * \param *buffer buffer to scan
2302 * \param &CurrentSet filled KeySet on return
2303 * \return true - at least one valid atom id parsed, false - CurrentSet is empty
2304 */
2305bool molecule::ScanBufferIntoKeySet(ofstream *out, char *buffer, KeySet &CurrentSet)
2306{
2307 stringstream line;
2308 int AtomNr;
2309 int status = 0;
2310
2311 line.str(buffer);
2312 while (!line.eof()) {
2313 line >> AtomNr;
2314 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
2315 CurrentSet.insert(AtomNr); // insert at end, hence in same order as in file!
2316 status++;
2317 } // else it's "-1" or else and thus must not be added
2318 }
2319 *out << Verbose(1) << "The scanned KeySet is ";
2320 for(KeySet::iterator runner = CurrentSet.begin(); runner != CurrentSet.end(); runner++) {
2321 *out << (*runner) << "\t";
2322 }
2323 *out << endl;
2324 return (status != 0);
2325};
2326
2327/** Parses the KeySet file and fills \a *FragmentList from the known molecule structure.
2328 * Does two-pass scanning:
2329 * -# Scans the keyset file and initialises a temporary graph
2330 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
2331 * Finally, the temporary graph is inserted into the given \a FragmentList for return.
2332 * \param *out output stream for debugging
2333 * \param *path path to file
2334 * \param *FragmentList empty, filled on return
2335 * \return true - parsing successfully, false - failure on parsing (FragmentList will be NULL)
2336 */
2337bool molecule::ParseKeySetFile(ofstream *out, char *path, Graph *&FragmentList)
2338{
2339 bool status = true;
2340 ifstream InputFile;
2341 stringstream line;
2342 GraphTestPair testGraphInsert;
2343 int NumberOfFragments = 0;
2344 double TEFactor;
2345 char *filename = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - filename");
2346
2347 if (FragmentList == NULL) { // check list pointer
2348 FragmentList = new Graph;
2349 }
2350
2351 // 1st pass: open file and read
2352 *out << Verbose(1) << "Parsing the KeySet file ... " << endl;
2353 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, KEYSETFILE);
2354 InputFile.open(filename);
2355 if (InputFile != NULL) {
2356 // each line represents a new fragment
2357 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - *buffer");
2358 // 1. parse keysets and insert into temp. graph
2359 while (!InputFile.eof()) {
2360 InputFile.getline(buffer, MAXSTRINGSIZE);
2361 KeySet CurrentSet;
2362 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(out, buffer, CurrentSet))) { // if at least one valid atom was added, write config
2363 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1))); // store fragment number and current factor
2364 if (!testGraphInsert.second) {
2365 cerr << "KeySet file must be corrupt as there are two equal key sets therein!" << endl;
2366 }
2367 //FragmentList->ListOfMolecules[NumberOfFragments++] = StoreFragmentFromKeySet(out, CurrentSet, IsAngstroem);
2368 }
2369 }
2370 // 2. Free and done
2371 InputFile.close();
2372 InputFile.clear();
2373 Free((void **)&buffer, "molecule::ParseKeySetFile - *buffer");
2374 *out << Verbose(1) << "done." << endl;
2375 } else {
2376 *out << Verbose(1) << "File " << filename << " not found." << endl;
2377 status = false;
2378 }
2379
2380 // 2nd pass: open TEFactors file and read
2381 *out << Verbose(1) << "Parsing the TEFactors file ... " << endl;
2382 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, TEFACTORSFILE);
2383 InputFile.open(filename);
2384 if (InputFile != NULL) {
2385 // 3. add found TEFactors to each keyset
2386 NumberOfFragments = 0;
2387 for(Graph::iterator runner = FragmentList->begin();runner != FragmentList->end(); runner++) {
2388 if (!InputFile.eof()) {
2389 InputFile >> TEFactor;
2390 (*runner).second.second = TEFactor;
2391 *out << Verbose(2) << "Setting " << ++NumberOfFragments << " fragment's TEFactor to " << (*runner).second.second << "." << endl;
2392 } else {
2393 status = false;
2394 break;
2395 }
2396 }
2397 // 4. Free and done
2398 InputFile.close();
2399 *out << Verbose(1) << "done." << endl;
2400 } else {
2401 *out << Verbose(1) << "File " << filename << " not found." << endl;
2402 status = false;
2403 }
2404
2405 // free memory
2406 Free((void **)&filename, "molecule::ParseKeySetFile - filename");
2407
2408 return status;
2409};
2410
2411/** Stores keysets and TEFactors to file.
2412 * \param *out output stream for debugging
2413 * \param KeySetList Graph with Keysets and factors
2414 * \param *path path to file
2415 * \return true - file written successfully, false - writing failed
2416 */
2417bool molecule::StoreKeySetFile(ofstream *out, Graph &KeySetList, char *path)
2418{
2419 ofstream output;
2420 bool status = true;
2421 string line;
2422
2423 // open KeySet file
2424 line = path;
2425 line.append("/");
2426 line += FRAGMENTPREFIX;
2427 line += KEYSETFILE;
2428 output.open(line.c_str(), ios::out);
2429 *out << Verbose(1) << "Saving key sets of the total graph ... ";
2430 if(output != NULL) {
2431 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) {
2432 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
2433 if (sprinter != (*runner).first.begin())
2434 output << "\t";
2435 output << *sprinter;
2436 }
2437 output << endl;
2438 }
2439 *out << "done." << endl;
2440 } else {
2441 cerr << "Unable to open " << line << " for writing keysets!" << endl;
2442 status = false;
2443 }
2444 output.close();
2445 output.clear();
2446
2447 // open TEFactors file
2448 line = path;
2449 line.append("/");
2450 line += FRAGMENTPREFIX;
2451 line += TEFACTORSFILE;
2452 output.open(line.c_str(), ios::out);
2453 *out << Verbose(1) << "Saving TEFactors of the total graph ... ";
2454 if(output != NULL) {
2455 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++)
2456 output << (*runner).second.second << endl;
2457 *out << Verbose(1) << "done." << endl;
2458 } else {
2459 *out << Verbose(1) << "failed to open " << line << "." << endl;
2460 status = false;
2461 }
2462 output.close();
2463
2464 return status;
2465};
2466
2467/** Storing the bond structure of a molecule to file.
2468 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
2469 * \param *out output stream for debugging
2470 * \param *path path to file
2471 * \return true - file written successfully, false - writing failed
2472 */
2473bool molecule::StoreAdjacencyToFile(ofstream *out, char *path)
2474{
2475 ofstream AdjacencyFile;
2476 atom *Walker = NULL;
2477 stringstream line;
2478 bool status = true;
2479
2480 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
2481 AdjacencyFile.open(line.str().c_str(), ios::out);
2482 *out << Verbose(1) << "Saving adjacency list ... ";
2483 if (AdjacencyFile != NULL) {
2484 Walker = start;
2485 while(Walker->next != end) {
2486 Walker = Walker->next;
2487 AdjacencyFile << Walker->nr << "\t";
2488 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
2489 AdjacencyFile << ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker)->nr << "\t";
2490 AdjacencyFile << endl;
2491 }
2492 AdjacencyFile.close();
2493 *out << Verbose(1) << "done." << endl;
2494 } else {
2495 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
2496 status = false;
2497 }
2498
2499 return status;
2500};
2501
2502/** Checks contents of adjacency file against bond structure in structure molecule.
2503 * \param *out output stream for debugging
2504 * \param *path path to file
2505 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
2506 * \return true - structure is equal, false - not equivalence
2507 */
2508bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms)
2509{
2510 ifstream File;
2511 stringstream filename;
2512 bool status = true;
2513 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
2514
2515 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
2516 File.open(filename.str().c_str(), ios::out);
2517 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... ";
2518 if (File != NULL) {
2519 // allocate storage structure
2520 int NonMatchNumber = 0; // will number of atoms with differing bond structure
2521 int *CurrentBonds = (int *) Malloc(sizeof(int)*8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
2522 int CurrentBondsOfAtom;
2523
2524 // Parse the file line by line and count the bonds
2525 while (!File.eof()) {
2526 File.getline(buffer, MAXSTRINGSIZE);
2527 stringstream line;
2528 line.str(buffer);
2529 int AtomNr = -1;
2530 line >> AtomNr;
2531 CurrentBondsOfAtom = -1; // we count one too far due to line end
2532 // parse into structure
2533 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
2534 while (!line.eof())
2535 line >> CurrentBonds[ ++CurrentBondsOfAtom ];
2536 // compare against present bonds
2537 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
2538 if (CurrentBondsOfAtom == NumberOfBondsPerAtom[AtomNr]) {
2539 for(int i=0;i<NumberOfBondsPerAtom[AtomNr];i++) {
2540 int id = ListOfBondsPerAtom[AtomNr][i]->GetOtherAtom(ListOfAtoms[AtomNr])->nr;
2541 int j = 0;
2542 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds
2543 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms
2544 ListOfAtoms[AtomNr] = NULL;
2545 NonMatchNumber++;
2546 status = false;
2547 //out << "[" << id << "]\t";
2548 } else {
2549 //out << id << "\t";
2550 }
2551 }
2552 //out << endl;
2553 } else {
2554 *out << "Number of bonds for Atom " << *ListOfAtoms[AtomNr] << " does not match, parsed " << CurrentBondsOfAtom << " against " << NumberOfBondsPerAtom[AtomNr] << "." << endl;
2555 status = false;
2556 }
2557 }
2558 }
2559 File.close();
2560 File.clear();
2561 if (status) { // if equal we parse the KeySetFile
2562 *out << Verbose(1) << "done: Equal." << endl;
2563 status = true;
2564 } else
2565 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
2566 Free((void **)&CurrentBonds, "molecule::CheckAdjacencyFileAgainstMolecule - **CurrentBonds");
2567 } else {
2568 *out << Verbose(1) << "Adjacency file not found." << endl;
2569 status = false;
2570 }
2571 *out << endl;
2572 Free((void **)&buffer, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
2573
2574 return status;
2575};
2576
2577/** Checks whether the OrderAtSite is still below \a Order at some site.
2578 * \param *out output stream for debugging
2579 * \param *AtomMask defines true/false per global Atom::nr to mask in/out each nuclear site, used to activate given number of site to increment order adaptively
2580 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
2581 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
2582 * \param *MinimumRingSize array of max. possible order to avoid loops
2583 * \param *path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
2584 * \return true - needs further fragmentation, false - does not need fragmentation
2585 */
2586bool molecule::CheckOrderAtSite(ofstream *out, bool *AtomMask, Graph *GlobalKeySetList, int Order, int *MinimumRingSize, char *path)
2587{
2588 atom *Walker = start;
2589 bool status = false;
2590 ifstream InputFile;
2591
2592 // initialize mask list
2593 for(int i=AtomCount;i--;)
2594 AtomMask[i] = false;
2595
2596 if (Order < 0) { // adaptive increase of BondOrder per site
2597 if (AtomMask[AtomCount] == true) // break after one step
2598 return false;
2599 // parse the EnergyPerFragment file
2600 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckOrderAtSite: *buffer");
2601 sprintf(buffer, "%s/%s%s.dat", path, FRAGMENTPREFIX, ENERGYPERFRAGMENT);
2602 InputFile.open(buffer, ios::in);
2603 if ((InputFile != NULL) && (GlobalKeySetList != NULL)) {
2604 // transmorph graph keyset list into indexed KeySetList
2605 map<int,KeySet> IndexKeySetList;
2606 for(Graph::iterator runner = GlobalKeySetList->begin(); runner != GlobalKeySetList->end(); runner++) {
2607 IndexKeySetList.insert( pair<int,KeySet>(runner->second.first,runner->first) );
2608 }
2609 int lines = 0;
2610 // count the number of lines, i.e. the number of fragments
2611 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
2612 InputFile.getline(buffer, MAXSTRINGSIZE);
2613 while(!InputFile.eof()) {
2614 InputFile.getline(buffer, MAXSTRINGSIZE);
2615 lines++;
2616 }
2617 *out << Verbose(2) << "Scanned " << lines-1 << " lines." << endl; // one endline too much
2618 InputFile.clear();
2619 InputFile.seekg(ios::beg);
2620 map<int, pair<double,int> > AdaptiveCriteriaList; // (Root No., (Value, Order)) !
2621 int No, FragOrder;
2622 double Value;
2623 // each line represents a fragment root (Atom::nr) id and its energy contribution
2624 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
2625 InputFile.getline(buffer, MAXSTRINGSIZE);
2626 while(!InputFile.eof()) {
2627 InputFile.getline(buffer, MAXSTRINGSIZE);
2628 if (strlen(buffer) > 2) {
2629 //*out << Verbose(2) << "Scanning: " << buffer;
2630 stringstream line(buffer);
2631 line >> FragOrder;
2632 line >> ws >> No;
2633 line >> ws >> Value; // skip time entry
2634 line >> ws >> Value;
2635 No -= 1; // indices start at 1 in file, not 0
2636 //*out << Verbose(2) << " - yields (" << No << "," << Value << ")" << endl;
2637
2638 // clean the list of those entries that have been superceded by higher order terms already
2639 map<int,KeySet>::iterator marker = IndexKeySetList.find(No); // find keyset to Frag No.
2640 if (marker != IndexKeySetList.end()) { // if found
2641 // as the smallest number in each set has always been the root (we use global id to keep the doubles away), seek smallest and insert into AtomMask
2642 pair <map<int, pair<double,int> >::iterator, bool> InsertedElement = AdaptiveCriteriaList.insert( make_pair(*((*marker).second.begin()), pair<double,int>( Value, Order) ));
2643 map<int, pair<double,int> >::iterator PresentItem = InsertedElement.first;
2644 if (!InsertedElement.second) { // this root is already present
2645 if ((*PresentItem).second.second < FragOrder) // if order there is lower, update entry with higher-order term
2646 //if ((*PresentItem).second.first < (*runner).first) // as higher-order terms are not always better, we skip this part (which would always include this site into adaptive increase)
2647 { // if value is smaller, update value and order
2648 (*PresentItem).second.first = Value;
2649 (*PresentItem).second.second = FragOrder;
2650 *out << Verbose(2) << "Updated element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;
2651 }
2652 } else {
2653 *out << Verbose(2) << "Inserted element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;
2654 }
2655 } else {
2656 *out << Verbose(1) << "No Fragment under No. " << No << "found." << endl;
2657 }
2658 }
2659 }
2660 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
2661 map<double, pair<int,int> > FinalRootCandidates;
2662 *out << Verbose(1) << "Root candidate list is: " << endl;
2663 for(map<int, pair<double,int> >::iterator runner = AdaptiveCriteriaList.begin(); runner != AdaptiveCriteriaList.end(); runner++) {
2664 Walker = FindAtom((*runner).first);
2665 if (Walker != NULL) {
2666 if ((*runner).second.second >= Walker->AdaptiveOrder) { // only insert if this is an "active" root site for the current order
2667 *out << Verbose(2) << "(" << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "])" << endl;
2668 FinalRootCandidates.insert( make_pair( (*runner).second.first, pair<int,int>((*runner).first, (*runner).second.second) ) );
2669 }
2670 } else {
2671 cerr << "Atom No. " << (*runner).second.first << " was not found in this molecule." << endl;
2672 }
2673 }
2674 // pick the ones still below threshold and mark as to be adaptively updated
2675 for(map<double, pair<int,int> >::iterator runner = FinalRootCandidates.upper_bound(pow(10.,Order)); runner != FinalRootCandidates.end(); runner++) {
2676 No = (*runner).second.first;
2677 Walker = FindAtom(No);
2678 //if (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]) {
2679 *out << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", setting entry " << No << " of Atom mask to true." << endl;
2680 AtomMask[No] = true;
2681 status = true;
2682 //} else
2683 //*out << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", however MinimumRingSize of " << MinimumRingSize[Walker->nr] << " does not allow further adaptive increase." << endl;
2684 }
2685 // close and done
2686 InputFile.close();
2687 InputFile.clear();
2688 } else {
2689 cerr << "Unable to parse " << buffer << " file, incrementing all." << endl;
2690 while (Walker->next != end) {
2691 Walker = Walker->next;
2692 #ifdef ADDHYDROGEN
2693 if (Walker->type->Z != 1) // skip hydrogen
2694 #endif
2695 {
2696 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms
2697 status = true;
2698 }
2699 }
2700 }
2701 Free((void **)&buffer, "molecule::CheckOrderAtSite: *buffer");
2702 // pick a given number of highest values and set AtomMask
2703 } else { // global increase of Bond Order
2704 while (Walker->next != end) {
2705 Walker = Walker->next;
2706 #ifdef ADDHYDROGEN
2707 if (Walker->type->Z != 1) // skip hydrogen
2708 #endif
2709 {
2710 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms
2711 if ((Order != 0) && (Walker->AdaptiveOrder < Order)) // && (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]))
2712 status = true;
2713 }
2714 }
2715 if ((Order == 0) && (AtomMask[AtomCount] == true)) // single stepping, just check
2716 status = true;
2717
2718 if (!status)
2719 *out << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl;
2720 }
2721
2722 // print atom mask for debugging
2723 *out << " ";
2724 for(int i=0;i<AtomCount;i++)
2725 *out << (i % 10);
2726 *out << endl << "Atom mask is: ";
2727 for(int i=0;i<AtomCount;i++)
2728 *out << (AtomMask[i] ? "t" : "f");
2729 *out << endl;
2730
2731 return status;
2732};
2733
2734/** Create a SortIndex to map from BFS labels to the sequence in which the atoms are given in the config file.
2735 * \param *out output stream for debugging
2736 * \param *&SortIndex Mapping array of size molecule::AtomCount
2737 * \return true - success, false - failure of SortIndex alloc
2738 */
2739bool molecule::CreateMappingLabelsToConfigSequence(ofstream *out, int *&SortIndex)
2740{
2741 element *runner = elemente->start;
2742 int AtomNo = 0;
2743 atom *Walker = NULL;
2744
2745 if (SortIndex != NULL) {
2746 *out << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl;
2747 return false;
2748 }
2749 SortIndex = (int *) Malloc(sizeof(int)*AtomCount, "molecule::FragmentMolecule: *SortIndex");
2750 for(int i=AtomCount;i--;)
2751 SortIndex[i] = -1;
2752 while (runner->next != elemente->end) { // go through every element
2753 runner = runner->next;
2754 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
2755 Walker = start;
2756 while (Walker->next != end) { // go through every atom of this element
2757 Walker = Walker->next;
2758 if (Walker->type->Z == runner->Z) // if this atom fits to element
2759 SortIndex[Walker->nr] = AtomNo++;
2760 }
2761 }
2762 }
2763 return true;
2764};
2765
2766/** Performs a many-body bond order analysis for a given bond order.
2767 * -# parses adjacency, keysets and orderatsite files
2768 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
2769 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
2770y contribution", and that's why this consciously not done in the following loop)
2771 * -# in a loop over all subgraphs
2772 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
2773 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
2774 * -# combines the generated molecule lists from all subgraphs
2775 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
2776 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
2777 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
2778 * subgraph in the MoleculeListClass.
2779 * \param *out output stream for debugging
2780 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
2781 * \param *configuration configuration for writing config files for each fragment
2782 */
2783void molecule::FragmentMolecule(ofstream *out, int Order, config *configuration)
2784{
2785 MoleculeListClass *BondFragments = NULL;
2786 int *SortIndex = NULL;
2787 int *MinimumRingSize = NULL;
2788 int FragmentCounter;
2789 MoleculeLeafClass *MolecularWalker = NULL;
2790 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
2791 fstream File;
2792 bool FragmentationToDo = true;
2793 Graph **FragmentList = NULL;
2794 Graph *ParsedFragmentList = NULL;
2795 Graph TotalGraph; // graph with all keysets however local numbers
2796 int TotalNumberOfKeySets = 0;
2797 atom **ListOfAtoms = NULL;
2798 atom ***ListOfLocalAtoms = NULL;
2799 bool *AtomMask = NULL;
2800
2801 *out << endl;
2802#ifdef ADDHYDROGEN
2803 *out << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl;
2804#else
2805 *out << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl;
2806#endif
2807
2808 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
2809
2810 // ===== 1. Check whether bond structure is same as stored in files ====
2811
2812 // fill the adjacency list
2813 CreateListOfBondsPerAtom(out);
2814
2815 // create lookup table for Atom::nr
2816 FragmentationToDo = FragmentationToDo && CreateFatherLookupTable(out, start, end, ListOfAtoms, AtomCount);
2817
2818 // === compare it with adjacency file ===
2819 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(out, configuration->configpath, ListOfAtoms);
2820 Free((void **)&ListOfAtoms, "molecule::FragmentMolecule - **ListOfAtoms");
2821
2822 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
2823 Subgraphs = DepthFirstSearchAnalysis(out, MinimumRingSize);
2824 // fill the bond structure of the individually stored subgraphs
2825 Subgraphs->next->FillBondStructureFromReference(out, this, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms
2826
2827 // ===== 3. if structure still valid, parse key set file and others =====
2828 FragmentationToDo = FragmentationToDo && ParseKeySetFile(out, configuration->configpath, ParsedFragmentList);
2829
2830 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
2831 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(out, configuration->configpath);
2832
2833 // =================================== Begin of FRAGMENTATION ===============================
2834 // ===== 6a. assign each keyset to its respective subgraph =====
2835 Subgraphs->next->AssignKeySetsToFragment(out, this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, (FragmentCounter = 0), false);
2836
2837 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
2838 AtomMask = new bool[AtomCount+1];
2839 while (CheckOrderAtSite(out, AtomMask, ParsedFragmentList, Order, MinimumRingSize, configuration->configpath)) {
2840 AtomMask[AtomCount] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
2841 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
2842 Subgraphs->next->FillRootStackForSubgraphs(out, RootStack, AtomMask, (FragmentCounter = 0));
2843
2844 // ===== 7. fill the bond fragment list =====
2845 FragmentCounter = 0;
2846 MolecularWalker = Subgraphs;
2847 while (MolecularWalker->next != NULL) {
2848 MolecularWalker = MolecularWalker->next;
2849 *out << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl;
2850 // output ListOfBondsPerAtom for debugging
2851 MolecularWalker->Leaf->OutputListOfBonds(out);
2852 if (MolecularWalker->Leaf->first->next != MolecularWalker->Leaf->last) {
2853
2854 // call BOSSANOVA method
2855 *out << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl;
2856 MolecularWalker->Leaf->FragmentBOSSANOVA(out, FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize);
2857 } else {
2858 cerr << "Subgraph " << MolecularWalker << " has no atoms!" << endl;
2859 }
2860 FragmentCounter++; // next fragment list
2861 }
2862 }
2863 delete[](RootStack);
2864 delete[](AtomMask);
2865 delete(ParsedFragmentList);
2866 delete[](MinimumRingSize);
2867
2868 // free the index lookup list
2869 for (int i=FragmentCounter;i--;)
2870 Free((void **)&ListOfLocalAtoms[i], "molecule::FragmentMolecule - *ListOfLocalAtoms[]");
2871 Free((void **)&ListOfLocalAtoms, "molecule::FragmentMolecule - **ListOfLocalAtoms");
2872
2873 // ==================================== End of FRAGMENTATION ============================================
2874
2875 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
2876 Subgraphs->next->TranslateIndicesToGlobalIDs(out, FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
2877
2878 // free subgraph memory again
2879 FragmentCounter = 0;
2880 if (Subgraphs != NULL) {
2881 while (Subgraphs->next != NULL) {
2882 Subgraphs = Subgraphs->next;
2883 delete(FragmentList[FragmentCounter++]);
2884 delete(Subgraphs->previous);
2885 }
2886 delete(Subgraphs);
2887 }
2888 Free((void **)&FragmentList, "molecule::FragmentMolecule - **FragmentList");
2889
2890 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
2891 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
2892 BondFragments = new MoleculeListClass(TotalGraph.size(), AtomCount);
2893 int k=0;
2894 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
2895 KeySet test = (*runner).first;
2896 *out << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl;
2897 BondFragments->ListOfMolecules[k] = StoreFragmentFromKeySet(out, test, configuration);
2898 k++;
2899 }
2900 *out << k << "/" << BondFragments->NumberOfMolecules << " fragments generated from the keysets." << endl;
2901
2902 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
2903 if (BondFragments->NumberOfMolecules != 0) {
2904 // create the SortIndex from BFS labels to order in the config file
2905 CreateMappingLabelsToConfigSequence(out, SortIndex);
2906
2907 *out << Verbose(1) << "Writing " << BondFragments->NumberOfMolecules << " possible bond fragmentation configs" << endl;
2908 if (BondFragments->OutputConfigForListOfFragments(out, configuration, SortIndex))
2909 *out << Verbose(1) << "All configs written." << endl;
2910 else
2911 *out << Verbose(1) << "Some config writing failed." << endl;
2912
2913 // store force index reference file
2914 BondFragments->StoreForcesFile(out, configuration->configpath, SortIndex);
2915
2916 // store keysets file
2917 StoreKeySetFile(out, TotalGraph, configuration->configpath);
2918
2919 // store Adjacency file
2920 StoreAdjacencyToFile(out, configuration->configpath);
2921
2922 // store Hydrogen saturation correction file
2923 BondFragments->AddHydrogenCorrection(out, configuration->configpath);
2924
2925 // store adaptive orders into file
2926 StoreOrderAtSiteFile(out, configuration->configpath);
2927
2928 // restore orbital and Stop values
2929 CalculateOrbitals(*configuration);
2930
2931 // free memory for bond part
2932 *out << Verbose(1) << "Freeing bond memory" << endl;
2933 delete(FragmentList); // remove bond molecule from memory
2934 Free((void **)&SortIndex, "molecule::FragmentMolecule: *SortIndex");
2935 } else
2936 *out << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl;
2937
2938 *out << Verbose(0) << "End of bond fragmentation." << endl;
2939};
2940
2941/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
2942 * Atoms not present in the file get "-1".
2943 * \param *out output stream for debugging
2944 * \param *path path to file ORDERATSITEFILE
2945 * \return true - file writable, false - not writable
2946 */
2947bool molecule::StoreOrderAtSiteFile(ofstream *out, char *path)
2948{
2949 stringstream line;
2950 ofstream file;
2951
2952 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
2953 file.open(line.str().c_str());
2954 *out << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl;
2955 if (file != NULL) {
2956 atom *Walker = start;
2957 while (Walker->next != end) {
2958 Walker = Walker->next;
2959 file << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << endl;
2960 *out << Verbose(2) << "Storing: " << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "." << endl;
2961 }
2962 file.close();
2963 *out << Verbose(1) << "done." << endl;
2964 return true;
2965 } else {
2966 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
2967 return false;
2968 }
2969};
2970
2971/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
2972 * Atoms not present in the file get "0".
2973 * \param *out output stream for debugging
2974 * \param *path path to file ORDERATSITEFILEe
2975 * \return true - file found and scanned, false - file not found
2976 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
2977 */
2978bool molecule::ParseOrderAtSiteFromFile(ofstream *out, char *path)
2979{
2980 unsigned char *OrderArray = (unsigned char *) Malloc(sizeof(unsigned char)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
2981 bool status;
2982 int AtomNr;
2983 stringstream line;
2984 ifstream file;
2985 int Order;
2986
2987 *out << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl;
2988 for(int i=AtomCount;i--;)
2989 OrderArray[i] = 0;
2990 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
2991 file.open(line.str().c_str());
2992 if (file != NULL) {
2993 for (int i=AtomCount;i--;) // initialise with 0
2994 OrderArray[i] = 0;
2995 while (!file.eof()) { // parse from file
2996 file >> AtomNr;
2997 file >> Order;
2998 OrderArray[AtomNr] = (unsigned char) Order;
2999 //*out << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << "." << endl;
3000 }
3001 atom *Walker = start;
3002 while (Walker->next != end) { // fill into atom classes
3003 Walker = Walker->next;
3004 Walker->AdaptiveOrder = OrderArray[Walker->nr];
3005 *out << Verbose(2) << *Walker << " gets order " << (int)Walker->AdaptiveOrder << "." << endl;
3006 }
3007 file.close();
3008 *out << Verbose(1) << "done." << endl;
3009 status = true;
3010 } else {
3011 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
3012 status = false;
3013 }
3014 Free((void **)&OrderArray, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
3015
3016 *out << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl;
3017 return status;
3018};
3019
3020/** Creates an 2d array of pointer with an entry for each atom and each bond it has.
3021 * Updates molecule::ListOfBondsPerAtom, molecule::NumberOfBondsPerAtom by parsing through
3022 * bond chain list, using molecule::AtomCount and molecule::BondCount.
3023 * Allocates memory, fills the array and exits
3024 * \param *out output stream for debugging
3025 */
3026void molecule::CreateListOfBondsPerAtom(ofstream *out)
3027{
3028 bond *Binder = NULL;
3029 atom *Walker = NULL;
3030 int TotalDegree;
3031 *out << Verbose(1) << "Begin of Creating ListOfBondsPerAtom: AtomCount = " << AtomCount << "\tBondCount = " << BondCount << "\tNoNonBonds = " << NoNonBonds << "." << endl;
3032
3033 // re-allocate memory
3034 *out << Verbose(2) << "(Re-)Allocating memory." << endl;
3035 if (ListOfBondsPerAtom != NULL) {
3036 for(int i=AtomCount;i--;)
3037 Free((void **)&ListOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom[i]");
3038 Free((void **)&ListOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom");
3039 }
3040 if (NumberOfBondsPerAtom != NULL)
3041 Free((void **)&NumberOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: NumberOfBondsPerAtom");
3042 ListOfBondsPerAtom = (bond ***) Malloc(sizeof(bond **)*AtomCount, "molecule::CreateListOfBondsPerAtom: ***ListOfBondsPerAtom");
3043 NumberOfBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfBondsPerAtom: *NumberOfBondsPerAtom");
3044
3045 // reset bond counts per atom
3046 for(int i=AtomCount;i--;)
3047 NumberOfBondsPerAtom[i] = 0;
3048 // count bonds per atom
3049 Binder = first;
3050 while (Binder->next != last) {
3051 Binder = Binder->next;
3052 NumberOfBondsPerAtom[Binder->leftatom->nr]++;
3053 NumberOfBondsPerAtom[Binder->rightatom->nr]++;
3054 }
3055 for(int i=AtomCount;i--;) {
3056 // allocate list of bonds per atom
3057 ListOfBondsPerAtom[i] = (bond **) Malloc(sizeof(bond *)*NumberOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: **ListOfBondsPerAtom[]");
3058 // clear the list again, now each NumberOfBondsPerAtom marks current free field
3059 NumberOfBondsPerAtom[i] = 0;
3060 }
3061 // fill the list
3062 Binder = first;
3063 while (Binder->next != last) {
3064 Binder = Binder->next;
3065 ListOfBondsPerAtom[Binder->leftatom->nr][NumberOfBondsPerAtom[Binder->leftatom->nr]++] = Binder;
3066 ListOfBondsPerAtom[Binder->rightatom->nr][NumberOfBondsPerAtom[Binder->rightatom->nr]++] = Binder;
3067 }
3068
3069 // output list for debugging
3070 *out << Verbose(3) << "ListOfBondsPerAtom for each atom:" << endl;
3071 Walker = start;
3072 while (Walker->next != end) {
3073 Walker = Walker->next;
3074 *out << Verbose(4) << "Atom " << Walker->Name << " with " << NumberOfBondsPerAtom[Walker->nr] << " bonds: ";
3075 TotalDegree = 0;
3076 for (int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
3077 *out << *ListOfBondsPerAtom[Walker->nr][j] << "\t";
3078 TotalDegree += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
3079 }
3080 *out << " -- TotalDegree: " << TotalDegree << endl;
3081 }
3082 *out << Verbose(1) << "End of Creating ListOfBondsPerAtom." << endl << endl;
3083};
3084
3085/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
3086 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
3087 * white and putting into queue.
3088 * \param *out output stream for debugging
3089 * \param *Mol Molecule class to add atoms to
3090 * \param **AddedAtomList list with added atom pointers, index is atom father's number
3091 * \param **AddedBondList list with added bond pointers, index is bond father's number
3092 * \param *Root root vertex for BFS
3093 * \param *Bond bond not to look beyond
3094 * \param BondOrder maximum distance for vertices to add
3095 * \param IsAngstroem lengths are in angstroem or bohrradii
3096 */
3097void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
3098{
3099 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList");
3100 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList");
3101 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList");
3102 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
3103 atom *Walker = NULL, *OtherAtom = NULL;
3104 bond *Binder = NULL;
3105
3106 // add Root if not done yet
3107 AtomStack->ClearStack();
3108 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
3109 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
3110 AtomStack->Push(Root);
3111
3112 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
3113 for (int i=AtomCount;i--;) {
3114 PredecessorList[i] = NULL;
3115 ShortestPathList[i] = -1;
3116 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited
3117 ColorList[i] = lightgray;
3118 else
3119 ColorList[i] = white;
3120 }
3121 ShortestPathList[Root->nr] = 0;
3122
3123 // and go on ... Queue always contains all lightgray vertices
3124 while (!AtomStack->IsEmpty()) {
3125 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
3126 // 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
3127 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
3128 // followed by n+1 till top of stack.
3129 Walker = AtomStack->PopFirst(); // pop oldest added
3130 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl;
3131 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
3132 Binder = ListOfBondsPerAtom[Walker->nr][i];
3133 if (Binder != NULL) { // don't look at bond equal NULL
3134 OtherAtom = Binder->GetOtherAtom(Walker);
3135 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
3136 if (ColorList[OtherAtom->nr] == white) {
3137 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)
3138 ColorList[OtherAtom->nr] = lightgray;
3139 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
3140 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
3141 *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;
3142 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance
3143 *out << Verbose(3);
3144 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
3145 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
3146 *out << "Added OtherAtom " << OtherAtom->Name;
3147 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3148 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3149 AddedBondList[Binder->nr]->Type = Binder->Type;
3150 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
3151 } 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)
3152 *out << "Not adding OtherAtom " << OtherAtom->Name;
3153 if (AddedBondList[Binder->nr] == NULL) {
3154 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3155 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3156 AddedBondList[Binder->nr]->Type = Binder->Type;
3157 *out << ", added Bond " << *(AddedBondList[Binder->nr]);
3158 } else
3159 *out << ", not added Bond ";
3160 }
3161 *out << ", putting OtherAtom into queue." << endl;
3162 AtomStack->Push(OtherAtom);
3163 } else { // out of bond order, then replace
3164 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
3165 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
3166 if (Binder == Bond)
3167 *out << Verbose(3) << "Not Queueing, is the Root bond";
3168 else if (ShortestPathList[OtherAtom->nr] >= BondOrder)
3169 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder;
3170 if (!Binder->Cyclic)
3171 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
3172 if (AddedBondList[Binder->nr] == NULL) {
3173 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
3174 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3175 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3176 AddedBondList[Binder->nr]->Type = Binder->Type;
3177 } else {
3178#ifdef ADDHYDROGEN
3179 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
3180#endif
3181 }
3182 }
3183 }
3184 } else {
3185 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
3186 // This has to be a cyclic bond, check whether it's present ...
3187 if (AddedBondList[Binder->nr] == NULL) {
3188 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) {
3189 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3190 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3191 AddedBondList[Binder->nr]->Type = Binder->Type;
3192 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
3193#ifdef ADDHYDROGEN
3194 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
3195#endif
3196 }
3197 }
3198 }
3199 }
3200 }
3201 ColorList[Walker->nr] = black;
3202 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
3203 }
3204 Free((void **)&PredecessorList, "molecule::BreadthFirstSearchAdd: **PredecessorList");
3205 Free((void **)&ShortestPathList, "molecule::BreadthFirstSearchAdd: **ShortestPathList");
3206 Free((void **)&ColorList, "molecule::BreadthFirstSearchAdd: **ColorList");
3207 delete(AtomStack);
3208};
3209
3210/** Adds bond structure to this molecule from \a Father molecule.
3211 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
3212 * with end points present in this molecule, bond is created in this molecule.
3213 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
3214 * \param *out output stream for debugging
3215 * \param *Father father molecule
3216 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
3217 * \todo not checked, not fully working probably
3218 */
3219bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
3220{
3221 atom *Walker = NULL, *OtherAtom = NULL;
3222 bool status = true;
3223 atom **ParentList = (atom **) Malloc(sizeof(atom *)*Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList");
3224
3225 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
3226
3227 // reset parent list
3228 *out << Verbose(3) << "Resetting ParentList." << endl;
3229 for (int i=Father->AtomCount;i--;)
3230 ParentList[i] = NULL;
3231
3232 // fill parent list with sons
3233 *out << Verbose(3) << "Filling Parent List." << endl;
3234 Walker = start;
3235 while (Walker->next != end) {
3236 Walker = Walker->next;
3237 ParentList[Walker->father->nr] = Walker;
3238 // Outputting List for debugging
3239 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
3240 }
3241
3242 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
3243 *out << Verbose(3) << "Creating bonds." << endl;
3244 Walker = Father->start;
3245 while (Walker->next != Father->end) {
3246 Walker = Walker->next;
3247 if (ParentList[Walker->nr] != NULL) {
3248 if (ParentList[Walker->nr]->father != Walker) {
3249 status = false;
3250 } else {
3251 for (int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) {
3252 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
3253 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
3254 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i] << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
3255 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree);
3256 }
3257 }
3258 }
3259 }
3260 }
3261
3262 Free((void **)&ParentList, "molecule::BuildInducedSubgraph: **ParentList");
3263 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
3264 return status;
3265};
3266
3267
3268/** Looks through a StackClass<atom *> and returns the likeliest removal candiate.
3269 * \param *out output stream for debugging messages
3270 * \param *&Leaf KeySet to look through
3271 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
3272 * \param index of the atom suggested for removal
3273 */
3274int molecule::LookForRemovalCandidate(ofstream *&out, KeySet *&Leaf, int *&ShortestPathList)
3275{
3276 atom *Runner = NULL;
3277 int SP, Removal;
3278
3279 *out << Verbose(2) << "Looking for removal candidate." << endl;
3280 SP = -1; //0; // not -1, so that Root is never removed
3281 Removal = -1;
3282 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
3283 Runner = FindAtom((*runner));
3284 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack
3285 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
3286 SP = ShortestPathList[(*runner)];
3287 Removal = (*runner);
3288 }
3289 }
3290 }
3291 return Removal;
3292};
3293
3294/** Stores a fragment from \a KeySet into \a molecule.
3295 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
3296 * molecule and adds missing hydrogen where bonds were cut.
3297 * \param *out output stream for debugging messages
3298 * \param &Leaflet pointer to KeySet structure
3299 * \param IsAngstroem whether we have Ansgtroem or bohrradius
3300 * \return pointer to constructed molecule
3301 */
3302molecule * molecule::StoreFragmentFromKeySet(ofstream *out, KeySet &Leaflet, bool IsAngstroem)
3303{
3304 atom *Runner = NULL, *FatherOfRunner = NULL, *OtherFather = NULL;
3305 atom **SonList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::StoreFragmentFromStack: **SonList");
3306 molecule *Leaf = new molecule(elemente);
3307 bool LonelyFlag = false;
3308 int size;
3309
3310// *out << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
3311
3312 Leaf->BondDistance = BondDistance;
3313 for(int i=NDIM*2;i--;)
3314 Leaf->cell_size[i] = cell_size[i];
3315
3316 // initialise SonList (indicates when we need to replace a bond with hydrogen instead)
3317 for(int i=AtomCount;i--;)
3318 SonList[i] = NULL;
3319
3320 // first create the minimal set of atoms from the KeySet
3321 size = 0;
3322 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
3323 FatherOfRunner = FindAtom((*runner)); // find the id
3324 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner);
3325 size++;
3326 }
3327
3328 // create the bonds between all: Make it an induced subgraph and add hydrogen
3329// *out << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
3330 Runner = Leaf->start;
3331 while (Runner->next != Leaf->end) {
3332 Runner = Runner->next;
3333 LonelyFlag = true;
3334 FatherOfRunner = Runner->father;
3335 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list
3336 // create all bonds
3337 for (int i=0;i<NumberOfBondsPerAtom[FatherOfRunner->nr];i++) { // go through every bond of father
3338 OtherFather = ListOfBondsPerAtom[FatherOfRunner->nr][i]->GetOtherAtom(FatherOfRunner);
3339// *out << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
3340 if (SonList[OtherFather->nr] != NULL) {
3341// *out << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
3342 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
3343// *out << Verbose(3) << "Adding Bond: ";
3344// *out <<
3345 Leaf->AddBond(Runner, SonList[OtherFather->nr], ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree);
3346// *out << "." << endl;
3347 //NumBonds[Runner->nr]++;
3348 } else {
3349// *out << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
3350 }
3351 LonelyFlag = false;
3352 } else {
3353// *out << ", who has no son in this fragment molecule." << endl;
3354#ifdef ADDHYDROGEN
3355 //*out << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl;
3356 Leaf->AddHydrogenReplacementAtom(out, ListOfBondsPerAtom[FatherOfRunner->nr][i], Runner, FatherOfRunner, OtherFather, ListOfBondsPerAtom[FatherOfRunner->nr],NumberOfBondsPerAtom[FatherOfRunner->nr], IsAngstroem);
3357#endif
3358 //NumBonds[Runner->nr] += ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree;
3359 }
3360 }
3361 } else {
3362 *out << Verbose(0) << "ERROR: Son " << Runner->Name << " has father " << FatherOfRunner->Name << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl;
3363 }
3364 if ((LonelyFlag) && (size > 1)) {
3365 *out << Verbose(0) << *Runner << "has got bonds only to hydrogens!" << endl;
3366 }
3367#ifdef ADDHYDROGEN
3368 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen
3369 Runner = Runner->next;
3370#endif
3371 }
3372 Leaf->CreateListOfBondsPerAtom(out);
3373 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
3374 Free((void **)&SonList, "molecule::StoreFragmentFromStack: **SonList");
3375// *out << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
3376 return Leaf;
3377};
3378
3379/** Creates \a MoleculeListClass of all unique fragments of the \a molecule containing \a Order atoms or vertices.
3380 * The picture to have in mind is that of a DFS "snake" of a certain length \a Order, i.e. as in the infamous
3381 * computer game, that winds through the connected graph representing the molecule. Color (white,
3382 * lightgray, darkgray, black) indicates whether a vertex has been discovered so far or not. Labels will help in
3383 * creating only unique fragments and not additional ones with vertices simply in different sequence.
3384 * The Predecessor is always the one that came before in discovering, needed on backstepping. And
3385 * finally, the ShortestPath is needed for removing vertices from the snake stack during the back-
3386 * stepping.
3387 * \param *out output stream for debugging
3388 * \param Order number of atoms in each fragment
3389 * \param *configuration configuration for writing config files for each fragment
3390 * \return List of all unique fragments with \a Order atoms
3391 */
3392/*
3393MoleculeListClass * molecule::CreateListOfUniqueFragmentsOfOrder(ofstream *out, int Order, config *configuration)
3394{
3395 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
3396 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
3397 int *Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
3398 enum Shading *ColorVertexList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
3399 enum Shading *ColorEdgeList = (enum Shading *) Malloc(sizeof(enum Shading)*BondCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorBondList");
3400 StackClass<atom *> *RootStack = new StackClass<atom *>(AtomCount);
3401 StackClass<atom *> *TouchedStack = new StackClass<atom *>((int)pow(4,Order)+2); // number of atoms reached from one with maximal 4 bonds plus Root itself
3402 StackClass<atom *> *SnakeStack = new StackClass<atom *>(Order+1); // equal to Order is not possible, as then the StackClass<atom *> cannot discern between full and empty stack!
3403 MoleculeLeafClass *Leaflet = NULL, *TempLeaf = NULL;
3404 MoleculeListClass *FragmentList = NULL;
3405 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Removal = NULL;
3406 bond *Binder = NULL;
3407 int RunningIndex = 0, FragmentCounter = 0;
3408
3409 *out << Verbose(1) << "Begin of CreateListOfUniqueFragmentsOfOrder." << endl;
3410
3411 // reset parent list
3412 *out << Verbose(3) << "Resetting labels, parent, predecessor, color and shortest path lists." << endl;
3413 for (int i=0;i<AtomCount;i++) { // reset all atom labels
3414 // initialise each vertex as white with no predecessor, empty queue, color lightgray, not labelled, no sons
3415 Labels[i] = -1;
3416 SonList[i] = NULL;
3417 PredecessorList[i] = NULL;
3418 ColorVertexList[i] = white;
3419 ShortestPathList[i] = -1;
3420 }
3421 for (int i=0;i<BondCount;i++)
3422 ColorEdgeList[i] = white;
3423 RootStack->ClearStack(); // clearstack and push first atom if exists
3424 TouchedStack->ClearStack();
3425 Walker = start->next;
3426 while ((Walker != end)
3427#ifdef ADDHYDROGEN
3428 && (Walker->type->Z == 1)
3429#endif
3430 ) { // search for first non-hydrogen atom
3431 *out << Verbose(4) << "Current Root candidate is " << Walker->Name << "." << endl;
3432 Walker = Walker->next;
3433 }
3434 if (Walker != end)
3435 RootStack->Push(Walker);
3436 else
3437 *out << Verbose(0) << "ERROR: Could not find an appropriate Root atom!" << endl;
3438 *out << Verbose(3) << "Root " << Walker->Name << " is on AtomStack, beginning loop through all vertices ..." << endl;
3439
3440 ///// OUTER LOOP ////////////
3441 while (!RootStack->IsEmpty()) {
3442 // get new root vertex from atom stack
3443 Root = RootStack->PopFirst();
3444 ShortestPathList[Root->nr] = 0;
3445 if (Labels[Root->nr] == -1)
3446 Labels[Root->nr] = RunningIndex++; // prevent it from getting again on AtomStack
3447 PredecessorList[Root->nr] = Root;
3448 TouchedStack->Push(Root);
3449 *out << Verbose(0) << "Root for this loop is: " << Root->Name << ".\n";
3450
3451 // clear snake stack
3452 SnakeStack->ClearStack();
3453 //SnakeStack->TestImplementation(out, start->next);
3454
3455 ///// INNER LOOP ////////////
3456 // Problems:
3457 // - what about cyclic bonds?
3458 Walker = Root;
3459 do {
3460 *out << Verbose(1) << "Current Walker is: " << Walker->Name;
3461 // initial setting of the new Walker: label, color, shortest path and put on stacks
3462 if (Labels[Walker->nr] == -1) { // give atom a unique, monotonely increasing number
3463 Labels[Walker->nr] = RunningIndex++;
3464 RootStack->Push(Walker);
3465 }
3466 *out << ", has label " << Labels[Walker->nr];
3467 if ((ColorVertexList[Walker->nr] == white) || ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white))) { // color it if newly discovered and push on stacks (and if within reach!)
3468 if ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white)) {
3469 // Binder ought to be set still from last neighbour search
3470 *out << ", coloring bond " << *Binder << " black";
3471 ColorEdgeList[Binder->nr] = black; // mark this bond as used
3472 }
3473 if (ShortestPathList[Walker->nr] == -1) {
3474 ShortestPathList[Walker->nr] = ShortestPathList[PredecessorList[Walker->nr]->nr]+1;
3475 TouchedStack->Push(Walker); // mark every atom for lists cleanup later, whose shortest path has been changed
3476 }
3477 if ((ShortestPathList[Walker->nr] < Order) && (ColorVertexList[Walker->nr] != darkgray)) { // if not already on snake stack
3478 SnakeStack->Push(Walker);
3479 ColorVertexList[Walker->nr] = darkgray; // mark as dark gray of on snake stack
3480 }
3481 }
3482 *out << ", SP of " << ShortestPathList[Walker->nr] << " and its color is " << GetColor(ColorVertexList[Walker->nr]) << "." << endl;
3483
3484 // then check the stack for a newly stumbled upon fragment
3485 if (SnakeStack->ItemCount() == Order) { // is stack full?
3486 // store the fragment if it is one and get a removal candidate
3487 Removal = StoreFragmentFromStack(out, Root, Walker, Leaflet, SnakeStack, ShortestPathList, SonList, Labels, &FragmentCounter, configuration);
3488 // remove the candidate if one was found
3489 if (Removal != NULL) {
3490 *out << Verbose(2) << "Removing item " << Removal->Name << " with SP of " << ShortestPathList[Removal->nr] << " from snake stack." << endl;
3491 SnakeStack->RemoveItem(Removal);
3492 ColorVertexList[Removal->nr] = lightgray; // return back to not on snake stack but explored marking
3493 if (Walker == Removal) { // if the current atom is to be removed, we also have to take a step back
3494 Walker = PredecessorList[Removal->nr];
3495 *out << Verbose(2) << "Stepping back to " << Walker->Name << "." << endl;
3496 }
3497 }
3498 } else
3499 Removal = NULL;
3500
3501 // finally, look for a white neighbour as the next Walker
3502 Binder = NULL;
3503 if ((Removal == NULL) || (Walker != PredecessorList[Removal->nr])) { // don't look, if a new walker has been set above
3504 *out << Verbose(2) << "Snake has currently " << SnakeStack->ItemCount() << " item(s)." << endl;
3505 OtherAtom = NULL; // this is actually not needed, every atom has at least one neighbour
3506 if (ShortestPathList[Walker->nr] < Order) {
3507 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
3508 Binder = ListOfBondsPerAtom[Walker->nr][i];
3509 *out << Verbose(2) << "Current bond is " << *Binder << ": ";
3510 OtherAtom = Binder->GetOtherAtom(Walker);
3511 if ((Labels[OtherAtom->nr] != -1) && (Labels[OtherAtom->nr] < Labels[Root->nr])) { // we don't step up to labels bigger than us
3512 *out << "Label " << Labels[OtherAtom->nr] << " is smaller than Root's " << Labels[Root->nr] << "." << endl;
3513 //ColorVertexList[OtherAtom->nr] = lightgray; // mark as explored
3514 } else { // otherwise check its colour and element
3515 if (
3516#ifdef ADDHYDROGEN
3517 (OtherAtom->type->Z != 1) &&
3518#endif
3519 (ColorEdgeList[Binder->nr] == white)) { // skip hydrogen, look for unexplored vertices
3520 *out << "Moving along " << GetColor(ColorEdgeList[Binder->nr]) << " bond " << Binder << " to " << ((ColorVertexList[OtherAtom->nr] == white) ? "unexplored" : "explored") << " item: " << OtherAtom->Name << "." << endl;
3521 // i find it currently rather sensible to always set the predecessor in order to find one's way back
3522 //if (PredecessorList[OtherAtom->nr] == NULL) {
3523 PredecessorList[OtherAtom->nr] = Walker;
3524 *out << Verbose(3) << "Setting Predecessor of " << OtherAtom->Name << " to " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
3525 //} else {
3526 // *out << Verbose(3) << "Predecessor of " << OtherAtom->Name << " is " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
3527 //}
3528 Walker = OtherAtom;
3529 break;
3530 } else {
3531 if (OtherAtom->type->Z == 1)
3532 *out << "Links to a hydrogen atom." << endl;
3533 else
3534 *out << "Bond has not white but " << GetColor(ColorEdgeList[Binder->nr]) << " color." << endl;
3535 }
3536 }
3537 }
3538 } else { // means we have stepped beyond the horizon: Return!
3539 Walker = PredecessorList[Walker->nr];
3540 OtherAtom = Walker;
3541 *out << Verbose(3) << "We have gone too far, stepping back to " << Walker->Name << "." << endl;
3542 }
3543 if (Walker != OtherAtom) { // if no white neighbours anymore, color it black
3544 *out << Verbose(2) << "Coloring " << Walker->Name << " black." << endl;
3545 ColorVertexList[Walker->nr] = black;
3546 Walker = PredecessorList[Walker->nr];
3547 }
3548 }
3549 } while ((Walker != Root) || (ColorVertexList[Root->nr] != black));
3550 *out << Verbose(2) << "Inner Looping is finished." << endl;
3551
3552 // if we reset all AtomCount atoms, we have again technically O(N^2) ...
3553 *out << Verbose(2) << "Resetting lists." << endl;
3554 Walker = NULL;
3555 Binder = NULL;
3556 while (!TouchedStack->IsEmpty()) {
3557 Walker = TouchedStack->PopLast();
3558 *out << Verbose(3) << "Re-initialising entries of " << *Walker << "." << endl;
3559 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
3560 ColorEdgeList[ListOfBondsPerAtom[Walker->nr][i]->nr] = white;
3561 PredecessorList[Walker->nr] = NULL;
3562 ColorVertexList[Walker->nr] = white;
3563 ShortestPathList[Walker->nr] = -1;
3564 }
3565 }
3566 *out << Verbose(1) << "Outer Looping over all vertices is done." << endl;
3567
3568 // copy together
3569 *out << Verbose(1) << "Copying all fragments into MoleculeList structure." << endl;
3570 FragmentList = new MoleculeListClass(FragmentCounter, AtomCount);
3571 RunningIndex = 0;
3572 while ((Leaflet != NULL) && (RunningIndex < FragmentCounter)) {
3573 FragmentList->ListOfMolecules[RunningIndex++] = Leaflet->Leaf;
3574 Leaflet->Leaf = NULL; // prevent molecule from being removed
3575 TempLeaf = Leaflet;
3576 Leaflet = Leaflet->previous;
3577 delete(TempLeaf);
3578 };
3579
3580 // free memory and exit
3581 Free((void **)&PredecessorList, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
3582 Free((void **)&ShortestPathList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
3583 Free((void **)&Labels, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
3584 Free((void **)&ColorVertexList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
3585 delete(RootStack);
3586 delete(TouchedStack);
3587 delete(SnakeStack);
3588
3589 *out << Verbose(1) << "End of CreateListOfUniqueFragmentsOfOrder." << endl;
3590 return FragmentList;
3591};
3592*/
3593
3594/** Structure containing all values in power set combination generation.
3595 */
3596struct UniqueFragments {
3597 config *configuration;
3598 atom *Root;
3599 Graph *Leaflet;
3600 KeySet *FragmentSet;
3601 int ANOVAOrder;
3602 int FragmentCounter;
3603 int CurrentIndex;
3604 int *Labels;
3605 double TEFactor;
3606 int *ShortestPathList;
3607 bool **UsedList;
3608 bond **BondsPerSPList;
3609 int *BondsPerSPCount;
3610};
3611
3612/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
3613 * -# loops over every possible combination (2^dimension of edge set)
3614 * -# inserts current set, if there's still space left
3615 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
3616ance+1
3617 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
3618 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
3619distance) and current set
3620 * \param *out output stream for debugging
3621 * \param FragmentSearch UniqueFragments structure with all values needed
3622 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
3623 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
3624 * \param SubOrder remaining number of allowed vertices to add
3625 */
3626void molecule::SPFragmentGenerator(ofstream *out, struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
3627{
3628 atom *OtherWalker = NULL;
3629 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
3630 int NumCombinations;
3631 bool bit;
3632 int bits, TouchedIndex, SubSetDimension, SP, Added;
3633 int Removal;
3634 int SpaceLeft;
3635 int *TouchedList = (int *) Malloc(sizeof(int)*(SubOrder+1), "molecule::SPFragmentGenerator: *TouchedList");
3636 bond *Binder = NULL;
3637 bond **BondsList = NULL;
3638 KeySetTestPair TestKeySetInsert;
3639
3640 NumCombinations = 1 << SetDimension;
3641
3642 // Hier muessen von 1 bis NumberOfBondsPerAtom[Walker->nr] alle Kombinationen
3643 // von Endstuecken (aus den Bonds) hinzugefᅵᅵgt werden und fᅵᅵr verbleibende ANOVAOrder
3644 // rekursiv GraphCrawler in der nᅵᅵchsten Ebene aufgerufen werden
3645
3646 *out << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
3647 *out << Verbose(1+verbosity) << "We are " << RootDistance << " away from Root, which is " << *FragmentSearch->Root << ", SubOrder is " << SubOrder << ", SetDimension is " << SetDimension << " and this means " << NumCombinations-1 << " combination(s)." << endl;
3648
3649 // initialised touched list (stores added atoms on this level)
3650 *out << Verbose(1+verbosity) << "Clearing touched list." << endl;
3651 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
3652 TouchedList[TouchedIndex] = -1;
3653 TouchedIndex = 0;
3654
3655 // create every possible combination of the endpieces
3656 *out << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
3657 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
3658 // count the set bit of i
3659 bits = 0;
3660 for (int j=SetDimension;j--;)
3661 bits += (i & (1 << j)) >> j;
3662
3663 *out << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
3664 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
3665 // --1-- add this set of the power set of bond partners to the snake stack
3666 Added = 0;
3667 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
3668 bit = ((i & (1 << j)) != 0); // mask the bit for the j-th bond
3669 if (bit) { // if bit is set, we add this bond partner
3670 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
3671 //*out << Verbose(1+verbosity) << "Current Bond is " << ListOfBondsPerAtom[Walker->nr][i] << ", checking on " << *OtherWalker << "." << endl;
3672 //if ((!FragmentSearch->UsedList[OtherWalker->nr][i]) && (FragmentSearch->Labels[OtherWalker->nr] > FragmentSearch->Labels[FragmentSearch->Root->nr])) {
3673 //*out << Verbose(2+verbosity) << "Not used so far, label " << FragmentSearch->Labels[OtherWalker->nr] << " is bigger than Root's " << FragmentSearch->Labels[FragmentSearch->Root->nr] << "." << endl;
3674 *out << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
3675 TestKeySetInsert = FragmentSearch->FragmentSet->insert(OtherWalker->nr);
3676 if (TestKeySetInsert.second) {
3677 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
3678 Added++;
3679 } else {
3680 *out << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
3681 }
3682 //FragmentSearch->UsedList[OtherWalker->nr][i] = true;
3683 //}
3684 } else {
3685 *out << Verbose(2+verbosity) << "Not adding." << endl;
3686 }
3687 }
3688
3689 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
3690 if (SpaceLeft > 0) {
3691 *out << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
3692 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
3693 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
3694 SP = RootDistance+1; // this is the next level
3695 // first count the members in the subset
3696 SubSetDimension = 0;
3697 Binder = FragmentSearch->BondsPerSPList[2*SP]; // start node for this level
3698 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) { // compare to end node of this level
3699 Binder = Binder->next;
3700 for (int k=TouchedIndex;k--;) {
3701 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
3702 SubSetDimension++;
3703 }
3704 }
3705 // then allocate and fill the list
3706 BondsList = (bond **) Malloc(sizeof(bond *)*SubSetDimension, "molecule::SPFragmentGenerator: **BondsList");
3707 SubSetDimension = 0;
3708 Binder = FragmentSearch->BondsPerSPList[2*SP];
3709 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) {
3710 Binder = Binder->next;
3711 for (int k=0;k<TouchedIndex;k++) {
3712 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
3713 BondsList[SubSetDimension++] = Binder;
3714 }
3715 }
3716 *out << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
3717 SPFragmentGenerator(out, FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
3718 Free((void **)&BondsList, "molecule::SPFragmentGenerator: **BondsList");
3719 }
3720 } else {
3721 // --2-- otherwise store the complete fragment
3722 *out << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
3723 // store fragment as a KeySet
3724 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
3725 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
3726 *out << (*runner) << " ";
3727 *out << endl;
3728 //if (!CheckForConnectedSubgraph(out, FragmentSearch->FragmentSet))
3729 //*out << Verbose(0) << "ERROR: The found fragment is not a connected subgraph!" << endl;
3730 InsertFragmentIntoGraph(out, FragmentSearch);
3731 //Removal = LookForRemovalCandidate(out, FragmentSearch->FragmentSet, FragmentSearch->ShortestPathList);
3732 //Removal = StoreFragmentFromStack(out, FragmentSearch->Root, FragmentSearch->Leaflet, FragmentSearch->FragmentStack, FragmentSearch->ShortestPathList,FragmentSearch->Labels, &FragmentSearch->FragmentCounter, FragmentSearch->configuration);
3733 }
3734
3735 // --3-- remove all added items in this level from snake stack
3736 *out << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
3737 for(int j=0;j<TouchedIndex;j++) {
3738 Removal = TouchedList[j];
3739 *out << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
3740 FragmentSearch->FragmentSet->erase(Removal);
3741 TouchedList[j] = -1;
3742 }
3743 *out << Verbose(2) << "Remaining local nr.s on snake stack are: ";
3744 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
3745 *out << (*runner) << " ";
3746 *out << endl;
3747 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
3748 } else {
3749 *out << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
3750 }
3751 }
3752 Free((void **)&TouchedList, "molecule::SPFragmentGenerator: *TouchedList");
3753 *out << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
3754};
3755
3756/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
3757 * \param *out output stream for debugging
3758 * \param *Fragment Keyset of fragment's vertices
3759 * \return true - connected, false - disconnected
3760 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
3761 */
3762bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment)
3763{
3764 atom *Walker = NULL, *Walker2 = NULL;
3765 bool BondStatus = false;
3766 int size;
3767
3768 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
3769 *out << Verbose(2) << "Disconnected atom: ";
3770
3771 // count number of atoms in graph
3772 size = 0;
3773 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
3774 size++;
3775 if (size > 1)
3776 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
3777 Walker = FindAtom(*runner);
3778 BondStatus = false;
3779 for(KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
3780 Walker2 = FindAtom(*runners);
3781 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
3782 if (ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker) == Walker2) {
3783 BondStatus = true;
3784 break;
3785 }
3786 if (BondStatus)
3787 break;
3788 }
3789 }
3790 if (!BondStatus) {
3791 *out << (*Walker) << endl;
3792 return false;
3793 }
3794 }
3795 else {
3796 *out << "none." << endl;
3797 return true;
3798 }
3799 *out << "none." << endl;
3800
3801 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
3802
3803 return true;
3804}
3805
3806/** Creates a list of all unique fragments of certain vertex size from a given graph \a Fragment for a given root vertex in the context of \a this molecule.
3807 * -# initialises UniqueFragments structure
3808 * -# fills edge list via BFS
3809 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
3810 root distance, the edge set, its dimension and the current suborder
3811 * -# Free'ing structure
3812 * Note that we may use the fact that the atoms are SP-ordered on the atomstack. I.e. when popping always the last, we first get all
3813 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
3814 * \param *out output stream for debugging
3815 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
3816 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
3817 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
3818 * \return number of inserted fragments
3819 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
3820 */
3821int molecule::PowerSetGenerator(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
3822{
3823 int SP, UniqueIndex, AtomKeyNr;
3824 atom *Walker = NULL, *OtherWalker = NULL, *Predecessor = NULL;
3825 bond *Binder = NULL;
3826 bond *CurrentEdge = NULL;
3827 bond **BondsList = NULL;
3828 int RootKeyNr = FragmentSearch.Root->nr;
3829 int Counter = FragmentSearch.FragmentCounter;
3830 int RemainingWalkers;
3831
3832 *out << endl;
3833 *out << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl;
3834
3835 // prepare Label and SP arrays of the BFS search
3836 UniqueIndex = 0;
3837 if (FragmentSearch.Labels[RootKeyNr] == -1)
3838 FragmentSearch.Labels[RootKeyNr] = UniqueIndex++;
3839 FragmentSearch.ShortestPathList[RootKeyNr] = 0;
3840
3841 // prepare root level (SP = 0) and a loop bond denoting Root
3842 for (int i=1;i<Order;i++)
3843 FragmentSearch.BondsPerSPCount[i] = 0;
3844 FragmentSearch.BondsPerSPCount[0] = 1;
3845 Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
3846 add(Binder, FragmentSearch.BondsPerSPList[1]);
3847
3848 // do a BFS search to fill the SP lists and label the found vertices
3849 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into
3850 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning
3851 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth
3852 // (EdgeinSPLevel) of this tree ...
3853 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence
3854 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction.
3855 *out << endl;
3856 *out << Verbose(0) << "Starting BFS analysis ..." << endl;
3857 for (SP = 0; SP < (Order-1); SP++) {
3858 *out << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)";
3859 if (SP > 0) {
3860 *out << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl;
3861 FragmentSearch.BondsPerSPCount[SP] = 0;
3862 } else
3863 *out << "." << endl;
3864
3865 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
3866 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP]; /// start of this SP level's list
3867 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) { /// end of this SP level's list
3868 CurrentEdge = CurrentEdge->next;
3869 RemainingWalkers--;
3870 Walker = CurrentEdge->rightatom; // rightatom is always the one more distant
3871 Predecessor = CurrentEdge->leftatom; // ... and leftatom is predecessor
3872 AtomKeyNr = Walker->nr;
3873 *out << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and label " << FragmentSearch.Labels[AtomKeyNr] << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl;
3874 // check for new sp level
3875 // go through all its bonds
3876 *out << Verbose(1) << "Going through all bonds of Walker." << endl;
3877 for (int i=0;i<NumberOfBondsPerAtom[AtomKeyNr];i++) {
3878 Binder = ListOfBondsPerAtom[AtomKeyNr][i];
3879 OtherWalker = Binder->GetOtherAtom(Walker);
3880 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end())
3881 #ifdef ADDHYDROGEN
3882 && (OtherWalker->type->Z != 1)
3883 #endif
3884 ) { // skip hydrogens and restrict to fragment
3885 *out << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *Binder << "." << endl;
3886 // set the label if not set (and push on root stack as well)
3887 if (FragmentSearch.Labels[OtherWalker->nr] == -1) {
3888 FragmentSearch.Labels[OtherWalker->nr] = UniqueIndex++;
3889 *out << Verbose(3) << "Set label to " << FragmentSearch.Labels[OtherWalker->nr] << "." << endl;
3890 } else {
3891 *out << Verbose(3) << "Label is already " << FragmentSearch.Labels[OtherWalker->nr] << "." << endl;
3892 }
3893 if ((OtherWalker != Predecessor) && (OtherWalker->nr > RootKeyNr)) { // only pass through those with label bigger than Root's
3894 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1;
3895 *out << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl;
3896 // add the bond in between to the SP list
3897 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
3898 add(Binder, FragmentSearch.BondsPerSPList[2*(SP+1)+1]);
3899 FragmentSearch.BondsPerSPCount[SP+1]++;
3900 *out << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl;
3901 } else *out << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->nr << " is smaller than that of Root " << RootKeyNr << " or this is my predecessor " << *Predecessor << "." << endl;
3902 } else *out << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
3903 }
3904 }
3905 }
3906
3907 // outputting all list for debugging
3908 *out << Verbose(0) << "Printing all found lists." << endl;
3909 for(int i=1;i<Order;i++) { // skip the root edge in the printing
3910 Binder = FragmentSearch.BondsPerSPList[2*i];
3911 *out << Verbose(1) << "Current SP level is " << i << "." << endl;
3912 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
3913 Binder = Binder->next;
3914 *out << Verbose(2) << *Binder << endl;
3915 }
3916 }
3917
3918 // creating fragments with the found edge sets (may be done in reverse order, faster)
3919 SP = -1; // the Root <-> Root edge must be subtracted!
3920 for(int i=Order;i--;) { // sum up all found edges
3921 Binder = FragmentSearch.BondsPerSPList[2*i];
3922 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
3923 Binder = Binder->next;
3924 SP ++;
3925 }
3926 }
3927 *out << Verbose(0) << "Total number of edges is " << SP << "." << endl;
3928 if (SP >= (Order-1)) {
3929 // start with root (push on fragment stack)
3930 *out << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->nr << "." << endl;
3931 FragmentSearch.FragmentSet->clear();
3932 *out << Verbose(0) << "Preparing subset for this root and calling generator." << endl;
3933 // prepare the subset and call the generator
3934 BondsList = (bond **) Malloc(sizeof(bond *)*FragmentSearch.BondsPerSPCount[0], "molecule::PowerSetGenerator: **BondsList");
3935 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond
3936
3937 SPFragmentGenerator(out, &FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
3938
3939 Free((void **)&BondsList, "molecule::PowerSetGenerator: **BondsList");
3940 } else {
3941 *out << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl;
3942 }
3943
3944 // as FragmentSearch structure is used only once, we don't have to clean it anymore
3945 // remove root from stack
3946 *out << Verbose(0) << "Removing root again from stack." << endl;
3947 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr);
3948
3949 // free'ing the bonds lists
3950 *out << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl;
3951 for(int i=Order;i--;) {
3952 *out << Verbose(1) << "Current SP level is " << i << ": ";
3953 Binder = FragmentSearch.BondsPerSPList[2*i];
3954 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
3955 Binder = Binder->next;
3956 // *out << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local
3957 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1;
3958 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1;
3959 }
3960 // delete added bonds
3961 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]);
3962 // also start and end node
3963 *out << "cleaned." << endl;
3964 }
3965
3966 // return list
3967 *out << Verbose(0) << "End of PowerSetGenerator." << endl;
3968 return (FragmentSearch.FragmentCounter - Counter);
3969};
3970
3971/** Corrects the nuclei position if the fragment was created over the cell borders.
3972 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
3973 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
3974 * and re-add the bond. Looping on the distance check.
3975 * \param *out ofstream for debugging messages
3976 */
3977void molecule::ScanForPeriodicCorrection(ofstream *out)
3978{
3979 bond *Binder = NULL;
3980 bond *OtherBinder = NULL;
3981 atom *Walker = NULL;
3982 atom *OtherWalker = NULL;
3983 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
3984 enum Shading *ColorList = NULL;
3985 double tmp;
3986 Vector Translationvector;
3987 //class StackClass<atom *> *CompStack = NULL;
3988 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
3989 bool flag = true;
3990
3991 *out << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl;
3992
3993 ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::ScanForPeriodicCorrection: *ColorList");
3994 while (flag) {
3995 // remove bonds that are beyond bonddistance
3996 for(int i=NDIM;i--;)
3997 Translationvector.x[i] = 0.;
3998 // scan all bonds
3999 Binder = first;
4000 flag = false;
4001 while ((!flag) && (Binder->next != last)) {
4002 Binder = Binder->next;
4003 for (int i=NDIM;i--;) {
4004 tmp = fabs(Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]);
4005 //*out << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
4006 if (tmp > BondDistance) {
4007 OtherBinder = Binder->next; // note down binding partner for later re-insertion
4008 unlink(Binder); // unlink bond
4009 //*out << Verbose(2) << "Correcting at bond " << *Binder << "." << endl;
4010 flag = true;
4011 break;
4012 }
4013 }
4014 }
4015 if (flag) {
4016 // create translation vector from their periodically modified distance
4017 for (int i=NDIM;i--;) {
4018 tmp = Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i];
4019 if (fabs(tmp) > BondDistance)
4020 Translationvector.x[i] = (tmp < 0) ? +1. : -1.;
4021 }
4022 Translationvector.MatrixMultiplication(matrix);
4023 *out << Verbose(3) << "Translation vector is ";
4024 Translationvector.Output(out);
4025 *out << endl;
4026 // apply to all atoms of first component via BFS
4027 for (int i=AtomCount;i--;)
4028 ColorList[i] = white;
4029 AtomStack->Push(Binder->leftatom);
4030 while (!AtomStack->IsEmpty()) {
4031 Walker = AtomStack->PopFirst();
4032 //*out << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
4033 ColorList[Walker->nr] = black; // mark as explored
4034 Walker->x.AddVector(&Translationvector); // translate
4035 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through all binding partners
4036 if (ListOfBondsPerAtom[Walker->nr][i] != Binder) {
4037 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
4038 if (ColorList[OtherWalker->nr] == white) {
4039 AtomStack->Push(OtherWalker); // push if yet unexplored
4040 }
4041 }
4042 }
4043 }
4044 // re-add bond
4045 link(Binder, OtherBinder);
4046 } else {
4047 *out << Verbose(3) << "No corrections for this fragment." << endl;
4048 }
4049 //delete(CompStack);
4050 }
4051
4052 // free allocated space from ReturnFullMatrixforSymmetric()
4053 delete(AtomStack);
4054 Free((void **)&ColorList, "molecule::ScanForPeriodicCorrection: *ColorList");
4055 Free((void **)&matrix, "molecule::ScanForPeriodicCorrection: *matrix");
4056 *out << Verbose(2) << "End of ScanForPeriodicCorrection." << endl;
4057};
4058
4059/** Blows the 6-dimensional \a cell_size array up to a full NDIM by NDIM matrix.
4060 * \param *symm 6-dim array of unique symmetric matrix components
4061 * \return allocated NDIM*NDIM array with the symmetric matrix
4062 */
4063double * molecule::ReturnFullMatrixforSymmetric(double *symm)
4064{
4065 double *matrix = (double *) Malloc(sizeof(double)*NDIM*NDIM, "molecule::ReturnFullMatrixforSymmetric: *matrix");
4066 matrix[0] = symm[0];
4067 matrix[1] = symm[1];
4068 matrix[2] = symm[3];
4069 matrix[3] = symm[1];
4070 matrix[4] = symm[2];
4071 matrix[5] = symm[4];
4072 matrix[6] = symm[3];
4073 matrix[7] = symm[4];
4074 matrix[8] = symm[5];
4075 return matrix;
4076};
4077
4078bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
4079{
4080 //cout << "my check is used." << endl;
4081 if (SubgraphA.size() < SubgraphB.size()) {
4082 return true;
4083 } else {
4084 if (SubgraphA.size() > SubgraphB.size()) {
4085 return false;
4086 } else {
4087 KeySet::iterator IteratorA = SubgraphA.begin();
4088 KeySet::iterator IteratorB = SubgraphB.begin();
4089 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
4090 if ((*IteratorA) < (*IteratorB))
4091 return true;
4092 else if ((*IteratorA) > (*IteratorB)) {
4093 return false;
4094 } // else, go on to next index
4095 IteratorA++;
4096 IteratorB++;
4097 } // end of while loop
4098 }// end of check in case of equal sizes
4099 }
4100 return false; // if we reach this point, they are equal
4101};
4102
4103//bool operator < (KeySet SubgraphA, KeySet SubgraphB)
4104//{
4105// return KeyCompare(SubgraphA, SubgraphB);
4106//};
4107
4108/** Checking whether KeySet is not already present in Graph, if so just adds factor.
4109 * \param *out output stream for debugging
4110 * \param &set KeySet to insert
4111 * \param &graph Graph to insert into
4112 * \param *counter pointer to unique fragment count
4113 * \param factor energy factor for the fragment
4114 */
4115inline void InsertFragmentIntoGraph(ofstream *out, struct UniqueFragments *Fragment)
4116{
4117 GraphTestPair testGraphInsert;
4118
4119 testGraphInsert = Fragment->Leaflet->insert(GraphPair (*Fragment->FragmentSet,pair<int,double>(Fragment->FragmentCounter,Fragment->TEFactor))); // store fragment number and current factor
4120 if (testGraphInsert.second) {
4121 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " successfully inserted." << endl;
4122 Fragment->FragmentCounter++;
4123 } else {
4124 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
4125 ((*(testGraphInsert.first)).second).second += Fragment->TEFactor; // increase the "created" counter
4126 *out << Verbose(2) << "New factor is " << ((*(testGraphInsert.first)).second).second << "." << endl;
4127 }
4128};
4129//void inline InsertIntoGraph(ofstream *out, KeyStack &stack, Graph &graph, int *counter, double factor)
4130//{
4131// // copy stack contents to set and call overloaded function again
4132// KeySet set;
4133// for(KeyStack::iterator runner = stack.begin(); runner != stack.begin(); runner++)
4134// set.insert((*runner));
4135// InsertIntoGraph(out, set, graph, counter, factor);
4136//};
4137
4138/** Inserts each KeySet in \a graph2 into \a graph1.
4139 * \param *out output stream for debugging
4140 * \param graph1 first (dest) graph
4141 * \param graph2 second (source) graph
4142 * \param *counter keyset counter that gets increased
4143 */
4144inline void InsertGraphIntoGraph(ofstream *out, Graph &graph1, Graph &graph2, int *counter)
4145{
4146 GraphTestPair testGraphInsert;
4147
4148 for(Graph::iterator runner = graph2.begin(); runner != graph2.end(); runner++) {
4149 testGraphInsert = graph1.insert(GraphPair ((*runner).first,pair<int,double>((*counter)++,((*runner).second).second))); // store fragment number and current factor
4150 if (testGraphInsert.second) {
4151 *out << Verbose(2) << "KeySet " << (*counter)-1 << " successfully inserted." << endl;
4152 } else {
4153 *out << Verbose(2) << "KeySet " << (*counter)-1 << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
4154 ((*(testGraphInsert.first)).second).second += (*runner).second.second;
4155 *out << Verbose(2) << "New factor is " << (*(testGraphInsert.first)).second.second << "." << endl;
4156 }
4157 }
4158};
4159
4160
4161/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
4162 * -# constructs a complete keyset of the molecule
4163 * -# In a loop over all possible roots from the given rootstack
4164 * -# increases order of root site
4165 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
4166 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
4167as the restricted one and each site in the set as the root)
4168 * -# these are merged into a fragment list of keysets
4169 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
4170 * Important only is that we create all fragments, it is not important if we create them more than once
4171 * as these copies are filtered out via use of the hash table (KeySet).
4172 * \param *out output stream for debugging
4173 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
4174 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
4175 * \param *MinimumRingSize minimum ring size for each atom (molecule::Atomcount)
4176 * \return pointer to Graph list
4177 */
4178void molecule::FragmentBOSSANOVA(ofstream *out, Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize)
4179{
4180 Graph ***FragmentLowerOrdersList = NULL;
4181 int NumLevels, NumMolecules, TotalNumMolecules = 0, *NumMoleculesOfOrder = NULL;
4182 int counter = 0, Order;
4183 int UpgradeCount = RootStack.size();
4184 KeyStack FragmentRootStack;
4185 int RootKeyNr, RootNr;
4186 struct UniqueFragments FragmentSearch;
4187
4188 *out << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl;
4189
4190 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
4191 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
4192 NumMoleculesOfOrder = (int *) Malloc(sizeof(int)*UpgradeCount, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
4193 FragmentLowerOrdersList = (Graph ***) Malloc(sizeof(Graph **)*UpgradeCount, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
4194
4195 // initialise the fragments structure
4196 FragmentSearch.ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *ShortestPathList");
4197 FragmentSearch.Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *Labels");
4198 FragmentSearch.FragmentCounter = 0;
4199 FragmentSearch.FragmentSet = new KeySet;
4200 FragmentSearch.Root = FindAtom(RootKeyNr);
4201 for (int i=AtomCount;i--;) {
4202 FragmentSearch.Labels[i] = -1;
4203 FragmentSearch.ShortestPathList[i] = -1;
4204 }
4205
4206 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
4207 atom *Walker = start;
4208 KeySet CompleteMolecule;
4209 while (Walker->next != end) {
4210 Walker = Walker->next;
4211 CompleteMolecule.insert(Walker->GetTrueFather()->nr);
4212 }
4213
4214 // this can easily be seen: if Order is 5, then the number of levels for each lower order is the total sum of the number of levels above, as
4215 // each has to be split up. E.g. for the second level we have one from 5th, one from 4th, two from 3th (which in turn is one from 5th, one from 4th),
4216 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
4217 // with the order along the cells as this: 5433222211111111 for BondOrder 5 needing 16=pow(2,5-1) cells (only we use bit-shifting which is faster)
4218 RootNr = 0; // counts through the roots in RootStack
4219 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
4220 RootKeyNr = RootStack.front();
4221 RootStack.pop_front();
4222 Walker = FindAtom(RootKeyNr);
4223 // check cyclic lengths
4224 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) {
4225 // *out << Verbose(0) << "Bond order " << Walker->GetTrueFather()->AdaptiveOrder << " of Root " << *Walker << " greater than or equal to Minimum Ring size of " << MinimumRingSize << " found is not allowed." << endl;
4226 //} else
4227 {
4228 // increase adaptive order by one
4229 Walker->GetTrueFather()->AdaptiveOrder++;
4230 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
4231
4232 // initialise Order-dependent entries of UniqueFragments structure
4233 FragmentSearch.BondsPerSPList = (bond **) Malloc(sizeof(bond *)*Order*2, "molecule::PowerSetGenerator: ***BondsPerSPList");
4234 FragmentSearch.BondsPerSPCount = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *BondsPerSPCount");
4235 for (int i=Order;i--;) {
4236 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node
4237 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node
4238 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two
4239 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i];
4240 FragmentSearch.BondsPerSPCount[i] = 0;
4241 }
4242
4243 // allocate memory for all lower level orders in this 1D-array of ptrs
4244 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
4245 FragmentLowerOrdersList[RootNr] = (Graph **) Malloc(sizeof(Graph *)*NumLevels, "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
4246 for (int i=0;i<NumLevels;i++)
4247 FragmentLowerOrdersList[RootNr][i] = NULL;
4248
4249 // create top order where nothing is reduced
4250 *out << Verbose(0) << "==============================================================================================================" << endl;
4251 *out << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", NumLevels is " << NumLevels << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl;
4252
4253 // Create list of Graphs of current Bond Order (i.e. F_{ij})
4254 FragmentLowerOrdersList[RootNr][0] = new Graph;
4255 FragmentSearch.TEFactor = 1.;
4256 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
4257 FragmentSearch.Root = Walker;
4258 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(out, Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
4259 *out << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
4260 if (NumMoleculesOfOrder[RootNr] != 0) {
4261 NumMolecules = 0;
4262
4263 if ((NumLevels >> 1) > 0) {
4264 // create lower order fragments
4265 *out << Verbose(0) << "Creating list of unique fragments of lower Bond Order terms to be subtracted." << endl;
4266 Order = Walker->AdaptiveOrder;
4267 for (int source=0;source<(NumLevels >> 1);source++) { // 1-terms don't need any more splitting, that's why only half is gone through (shift again)
4268 // step down to next order at (virtual) boundary of powers of 2 in array
4269 while (source >= (1 << (Walker->AdaptiveOrder-Order))) // (int)pow(2,Walker->AdaptiveOrder-Order))
4270 Order--;
4271 *out << Verbose(0) << "Current Order is: " << Order << "." << endl;
4272 for (int SubOrder=Order-1;SubOrder>0;SubOrder--) {
4273 int dest = source + (1 << (Walker->AdaptiveOrder-(SubOrder+1)));
4274 *out << Verbose(0) << "--------------------------------------------------------------------------------------------------------------" << endl;
4275 *out << Verbose(0) << "Current SubOrder is: " << SubOrder << " with source " << source << " to destination " << dest << "." << endl;
4276
4277 // every molecule is split into a list of again (Order - 1) molecules, while counting all molecules
4278 //*out << Verbose(1) << "Splitting the " << (*FragmentLowerOrdersList[RootNr][source]).size() << " molecules of the " << source << "th cell in the array." << endl;
4279 //NumMolecules = 0;
4280 FragmentLowerOrdersList[RootNr][dest] = new Graph;
4281 for(Graph::iterator runner = (*FragmentLowerOrdersList[RootNr][source]).begin();runner != (*FragmentLowerOrdersList[RootNr][source]).end(); runner++) {
4282 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
4283 Graph TempFragmentList;
4284 FragmentSearch.TEFactor = -(*runner).second.second;
4285 FragmentSearch.Leaflet = &TempFragmentList; // set to insertion graph
4286 FragmentSearch.Root = FindAtom(*sprinter);
4287 NumMoleculesOfOrder[RootNr] += PowerSetGenerator(out, SubOrder, FragmentSearch, (*runner).first);
4288 // insert new keysets FragmentList into FragmentLowerOrdersList[Walker->AdaptiveOrder-1][dest]
4289 *out << Verbose(1) << "Merging resulting key sets with those present in destination " << dest << "." << endl;
4290 InsertGraphIntoGraph(out, *FragmentLowerOrdersList[RootNr][dest], TempFragmentList, &NumMolecules);
4291 }
4292 }
4293 *out << Verbose(1) << "Number of resulting molecules for SubOrder " << SubOrder << " is: " << NumMolecules << "." << endl;
4294 }
4295 }
4296 }
4297 } else {
4298 *out << Verbose(1) << "Hence, we don't dive into SubOrders ... " << endl;
4299 }
4300 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
4301 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
4302 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
4303 *out << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
4304 RootStack.push_back(RootKeyNr); // put back on stack
4305 RootNr++;
4306
4307 // free Order-dependent entries of UniqueFragments structure for next loop cycle
4308 Free((void **)&FragmentSearch.BondsPerSPCount, "molecule::PowerSetGenerator: *BondsPerSPCount");
4309 for (int i=Order;i--;) {
4310 delete(FragmentSearch.BondsPerSPList[2*i]);
4311 delete(FragmentSearch.BondsPerSPList[2*i+1]);
4312 }
4313 Free((void **)&FragmentSearch.BondsPerSPList, "molecule::PowerSetGenerator: ***BondsPerSPList");
4314 }
4315 }
4316 *out << Verbose(0) << "==============================================================================================================" << endl;
4317 *out << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl;
4318 *out << Verbose(0) << "==============================================================================================================" << endl;
4319
4320 // cleanup FragmentSearch structure
4321 Free((void **)&FragmentSearch.ShortestPathList, "molecule::PowerSetGenerator: *ShortestPathList");
4322 Free((void **)&FragmentSearch.Labels, "molecule::PowerSetGenerator: *Labels");
4323 delete(FragmentSearch.FragmentSet);
4324
4325 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
4326 // 5433222211111111
4327 // 43221111
4328 // 3211
4329 // 21
4330 // 1
4331
4332 // Subsequently, we combine all into a single list (FragmentList)
4333
4334 *out << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl;
4335 if (FragmentList == NULL) {
4336 FragmentList = new Graph;
4337 counter = 0;
4338 } else {
4339 counter = FragmentList->size();
4340 }
4341 RootNr = 0;
4342 while (!RootStack.empty()) {
4343 RootKeyNr = RootStack.front();
4344 RootStack.pop_front();
4345 Walker = FindAtom(RootKeyNr);
4346 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
4347 for(int i=0;i<NumLevels;i++) {
4348 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
4349 InsertGraphIntoGraph(out, *FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
4350 delete(FragmentLowerOrdersList[RootNr][i]);
4351 }
4352 }
4353 Free((void **)&FragmentLowerOrdersList[RootNr], "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
4354 RootNr++;
4355 }
4356 Free((void **)&FragmentLowerOrdersList, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
4357 Free((void **)&NumMoleculesOfOrder, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
4358
4359 *out << Verbose(0) << "End of FragmentBOSSANOVA." << endl;
4360};
4361
4362/** Comparison function for GSL heapsort on distances in two molecules.
4363 * \param *a
4364 * \param *b
4365 * \return <0, \a *a less than \a *b, ==0 if equal, >0 \a *a greater than \a *b
4366 */
4367inline int CompareDoubles (const void * a, const void * b)
4368{
4369 if (*(double *)a > *(double *)b)
4370 return -1;
4371 else if (*(double *)a < *(double *)b)
4372 return 1;
4373 else
4374 return 0;
4375};
4376
4377/** Determines whether two molecules actually contain the same atoms and coordination.
4378 * \param *out output stream for debugging
4379 * \param *OtherMolecule the molecule to compare this one to
4380 * \param threshold upper limit of difference when comparing the coordination.
4381 * \return NULL - not equal, otherwise an allocated (molecule::AtomCount) permutation map of the atom numbers (which corresponds to which)
4382 */
4383int * molecule::IsEqualToWithinThreshold(ofstream *out, molecule *OtherMolecule, double threshold)
4384{
4385 int flag;
4386 double *Distances = NULL, *OtherDistances = NULL;
4387 Vector CenterOfGravity, OtherCenterOfGravity;
4388 size_t *PermMap = NULL, *OtherPermMap = NULL;
4389 int *PermutationMap = NULL;
4390 atom *Walker = NULL;
4391 bool result = true; // status of comparison
4392
4393 *out << Verbose(3) << "Begin of IsEqualToWithinThreshold." << endl;
4394 /// first count both their atoms and elements and update lists thereby ...
4395 //*out << Verbose(0) << "Counting atoms, updating list" << endl;
4396 CountAtoms(out);
4397 OtherMolecule->CountAtoms(out);
4398 CountElements();
4399 OtherMolecule->CountElements();
4400
4401 /// ... and compare:
4402 /// -# AtomCount
4403 if (result) {
4404 if (AtomCount != OtherMolecule->AtomCount) {
4405 *out << Verbose(4) << "AtomCounts don't match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
4406 result = false;
4407 } else *out << Verbose(4) << "AtomCounts match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
4408 }
4409 /// -# ElementCount
4410 if (result) {
4411 if (ElementCount != OtherMolecule->ElementCount) {
4412 *out << Verbose(4) << "ElementCount don't match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
4413 result = false;
4414 } else *out << Verbose(4) << "ElementCount match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
4415 }
4416 /// -# ElementsInMolecule
4417 if (result) {
4418 for (flag=MAX_ELEMENTS;flag--;) {
4419 //*out << Verbose(5) << "Element " << flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl;
4420 if (ElementsInMolecule[flag] != OtherMolecule->ElementsInMolecule[flag])
4421 break;
4422 }
4423 if (flag < MAX_ELEMENTS) {
4424 *out << Verbose(4) << "ElementsInMolecule don't match." << endl;
4425 result = false;
4426 } else *out << Verbose(4) << "ElementsInMolecule match." << endl;
4427 }
4428 /// then determine and compare center of gravity for each molecule ...
4429 if (result) {
4430 *out << Verbose(5) << "Calculating Centers of Gravity" << endl;
4431 DetermineCenter(CenterOfGravity);
4432 OtherMolecule->DetermineCenter(OtherCenterOfGravity);
4433 *out << Verbose(5) << "Center of Gravity: ";
4434 CenterOfGravity.Output(out);
4435 *out << endl << Verbose(5) << "Other Center of Gravity: ";
4436 OtherCenterOfGravity.Output(out);
4437 *out << endl;
4438 if (CenterOfGravity.Distance(&OtherCenterOfGravity) > threshold) {
4439 *out << Verbose(4) << "Centers of gravity don't match." << endl;
4440 result = false;
4441 }
4442 }
4443
4444 /// ... then make a list with the euclidian distance to this center for each atom of both molecules
4445 if (result) {
4446 *out << Verbose(5) << "Calculating distances" << endl;
4447 Distances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: Distances");
4448 OtherDistances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: OtherDistances");
4449 Walker = start;
4450 while (Walker->next != end) {
4451 Walker = Walker->next;
4452 Distances[Walker->nr] = CenterOfGravity.Distance(&Walker->x);
4453 }
4454 Walker = OtherMolecule->start;
4455 while (Walker->next != OtherMolecule->end) {
4456 Walker = Walker->next;
4457 OtherDistances[Walker->nr] = OtherCenterOfGravity.Distance(&Walker->x);
4458 }
4459
4460 /// ... sort each list (using heapsort (o(N log N)) from GSL)
4461 *out << Verbose(5) << "Sorting distances" << endl;
4462 PermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermMap");
4463 OtherPermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
4464 gsl_heapsort_index (PermMap, Distances, AtomCount, sizeof(double), CompareDoubles);
4465 gsl_heapsort_index (OtherPermMap, OtherDistances, AtomCount, sizeof(double), CompareDoubles);
4466 PermutationMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermutationMap");
4467 *out << Verbose(5) << "Combining Permutation Maps" << endl;
4468 for(int i=AtomCount;i--;)
4469 PermutationMap[PermMap[i]] = (int) OtherPermMap[i];
4470
4471 /// ... and compare them step by step, whether the difference is individiually(!) below \a threshold for all
4472 *out << Verbose(4) << "Comparing distances" << endl;
4473 flag = 0;
4474 for (int i=0;i<AtomCount;i++) {
4475 *out << Verbose(5) << "Distances: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " << threshold << endl;
4476 if (fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) > threshold)
4477 flag = 1;
4478 }
4479 Free((void **)&PermMap, "molecule::IsEqualToWithinThreshold: *PermMap");
4480 Free((void **)&OtherPermMap, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
4481
4482 /// free memory
4483 Free((void **)&Distances, "molecule::IsEqualToWithinThreshold: Distances");
4484 Free((void **)&OtherDistances, "molecule::IsEqualToWithinThreshold: OtherDistances");
4485 if (flag) { // if not equal
4486 Free((void **)&PermutationMap, "molecule::IsEqualToWithinThreshold: *PermutationMap");
4487 result = false;
4488 }
4489 }
4490 /// return pointer to map if all distances were below \a threshold
4491 *out << Verbose(3) << "End of IsEqualToWithinThreshold." << endl;
4492 if (result) {
4493 *out << Verbose(3) << "Result: Equal." << endl;
4494 return PermutationMap;
4495 } else {
4496 *out << Verbose(3) << "Result: Not equal." << endl;
4497 return NULL;
4498 }
4499};
4500
4501/** Returns an index map for two father-son-molecules.
4502 * The map tells which atom in this molecule corresponds to which one in the other molecul with their fathers.
4503 * \param *out output stream for debugging
4504 * \param *OtherMolecule corresponding molecule with fathers
4505 * \return allocated map of size molecule::AtomCount with map
4506 * \todo make this with a good sort O(n), not O(n^2)
4507 */
4508int * molecule::GetFatherSonAtomicMap(ofstream *out, molecule *OtherMolecule)
4509{
4510 atom *Walker = NULL, *OtherWalker = NULL;
4511 *out << Verbose(3) << "Begin of GetFatherAtomicMap." << endl;
4512 int *AtomicMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::GetAtomicMap: *AtomicMap"); //Calloc
4513 for (int i=AtomCount;i--;)
4514 AtomicMap[i] = -1;
4515 if (OtherMolecule == this) { // same molecule
4516 for (int i=AtomCount;i--;) // no need as -1 means already that there is trivial correspondence
4517 AtomicMap[i] = i;
4518 *out << Verbose(4) << "Map is trivial." << endl;
4519 } else {
4520 *out << Verbose(4) << "Map is ";
4521 Walker = start;
4522 while (Walker->next != end) {
4523 Walker = Walker->next;
4524 if (Walker->father == NULL) {
4525 AtomicMap[Walker->nr] = -2;
4526 } else {
4527 OtherWalker = OtherMolecule->start;
4528 while (OtherWalker->next != OtherMolecule->end) {
4529 OtherWalker = OtherWalker->next;
4530 //for (int i=0;i<AtomCount;i++) { // search atom
4531 //for (int j=0;j<OtherMolecule->AtomCount;j++) {
4532 //*out << Verbose(4) << "Comparing father " << Walker->father << " with the other one " << OtherWalker->father << "." << endl;
4533 if (Walker->father == OtherWalker)
4534 AtomicMap[Walker->nr] = OtherWalker->nr;
4535 }
4536 }
4537 *out << AtomicMap[Walker->nr] << "\t";
4538 }
4539 *out << endl;
4540 }
4541 *out << Verbose(3) << "End of GetFatherAtomicMap." << endl;
4542 return AtomicMap;
4543};
4544
Note: See TracBrowser for help on using the repository browser.