source: molecuilder/src/molecules.cpp@ 47548d

Last change on this file since 47548d was 47548d, checked in by Frederik Heber <heber@…>, 16 years ago

Merge branch 'AtomRemoval'

Conflicts:

molecuilder/src/builder.cpp
molecuilder/src/molecules.cpp

merges:

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