source: molecuilder/src/molecules.cpp@ 556157

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

thermostats enumerator, necessary variables included in class config, molecule::Thermostats() and ..::Constrained
Potential()

Thermostat header definitions implemented. Can be parsed from the ESPACK config file into class config
ConstrainedPotential() calculates the transformation between two given configurations my minimsing a penalty func
tional of the distance to travel per atom. This was implemented due to Michael Griebel's talk during the MultiMat

Closing meeting in order to produce some visuals. It basically mimics a "Bain Transformation". But it is not yet
perfectly implemented.

Also, MD was corrected in VerletIntegration(). However, forces are still wrong with mpqc, as the kinetic energy increases dramatically during the MD simulation.

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