source: molecuilder/src/molecules.cpp@ c99adf

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

Constrained Molecular Dynamics: two new functions molecule::ConstrainedPotential(), molecule::MinimiseConstrainedPotential()

Constrained Molecular Dynamics scaffold implemented (so far it does nothing):

  • config::DoConstrainedMD contains the target step (i.e. config::DoConstrainedMD = 2 will do a constraint motion from step 1 to step 2), 0 means no constrained motion, is parsed in config::load(), def

ault is 0

ajectory distance, equal target (last two are pure penalties). Implemented, not tested.

  • Property mode set to 100644
File size: 214.9 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 \tfrac{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 *permutation gives target index 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 */
1027double molecule::ConstrainedPotential(ofstream *out, int *permutation, int startstep, int endstep, double *constants, bool IsAngstroem)
1028{
1029 double result = 0., tmp;
1030 atom *Walker = NULL, *Runner = NULL, *Sprinter = NULL;
1031 Vector trajectory1, trajectory2, normal, TestVector;
1032 gsl_matrix *A = gsl_matrix_alloc(NDIM,NDIM);
1033 gsl_vector *x = gsl_vector_alloc(NDIM);
1034
1035 // go through every atom
1036 Walker = start;
1037 while (Walker->next != end) {
1038 Walker = Walker->next;
1039 // first term: distance to target
1040 Runner = FindAtom(permutation[Walker->nr]); // find target point
1041 result += constants[0] * (Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(endstep)));
1042
1043 // second term: sum of distances to other trajectories
1044 Runner = start;
1045 while (Runner->next != end) {
1046 Runner = Runner->next;
1047 // determine normalized trajectories direction vector (n1, n2)
1048 Sprinter = FindAtom(permutation[Walker->nr]); // find target point
1049 trajectory1.CopyVector(&Trajectories[Sprinter].R.at(endstep));
1050 trajectory1.SubtractVector(&Trajectories[Walker].R.at(startstep));
1051 trajectory1.Normalize();
1052 Sprinter = FindAtom(permutation[Runner->nr]); // find target point
1053 trajectory2.CopyVector(&Trajectories[Sprinter].R.at(endstep));
1054 trajectory2.SubtractVector(&Trajectories[Runner].R.at(startstep));
1055 trajectory2.Normalize();
1056 // check whether they're linear dependent
1057 if (fabs(trajectory1.ScalarProduct(&trajectory2)/trajectory1.Norm()/trajectory2.Norm() - 1.) < MYEPSILON) {
1058 *out << "Both trajectories of " << *Walker << " and " << *Runner << " are linear dependent: ";
1059 *out << trajectory1;
1060 *out << " and ";
1061 *out << trajectory2 << endl;
1062 tmp = Trajectories[Walker].R.at(startstep).Distance(&Trajectories[Runner].R.at(startstep));
1063 } else { // determine distance by finding minimum distance
1064 *out << "Both trajectories of " << *Walker << " and " << *Runner << " are linear independent." << endl;
1065 // determine normal vector for both
1066 normal.MakeNormalVector(&trajectory1, &trajectory2);
1067 // setup matrix
1068 for (int i=NDIM;i--;) {
1069 gsl_matrix_set(A, 0, i, trajectory1.x[i]);
1070 gsl_matrix_set(A, 1, i, trajectory2.x[i]);
1071 gsl_matrix_set(A, 2, i, normal.x[i]);
1072 gsl_vector_set(x,i, (Trajectories[Walker].R.at(startstep).x[i] - Trajectories[Runner].R.at(startstep).x[i]));
1073 }
1074 // solve the linear system by Householder transformations
1075 gsl_linalg_HH_svx(A, x);
1076 // distance from last component
1077 tmp = gsl_vector_get(x,2);
1078 // test whether we really have the intersection (by checking on c_1 and c_2)
1079 TestVector.CopyVector(&Trajectories[Runner].R.at(startstep));
1080 trajectory2.Scale(gsl_vector_get(x,1));
1081 TestVector.AddVector(&trajectory2);
1082 normal.Scale(gsl_vector_get(x,2));
1083 TestVector.AddVector(&normal);
1084 TestVector.SubtractVector(&Trajectories[Walker].R.at(startstep));
1085 trajectory1.Scale(gsl_vector_get(x,0));
1086 TestVector.SubtractVector(&trajectory1);
1087 if (TestVector.Norm() < MYEPSILON) {
1088 *out << "Test: ok.\tDistance of " << tmp << " is correct." << endl;
1089 } else {
1090 *out << "Test: failed.\tDifference in intersection is ";
1091 *out << TestVector;
1092 *out << "." << endl;
1093 }
1094 }
1095 // add up
1096 result += constants[1] * 1./tmp;
1097 }
1098
1099 // third term: penalty for equal targets
1100 Runner = start;
1101 while (Runner->next != end) {
1102 Runner = Runner->next;
1103 if ((permutation[Walker->nr] == permutation[Runner->nr]) && (Walker->nr < Runner->nr)) {
1104 Sprinter = FindAtom(permutation[Walker->nr]);
1105 *out << *Walker << " and " << *Runner << " are heading to the same target at ";
1106 *out << Trajectories[Sprinter].R.at(endstep);
1107 *out << ", penalting." << endl;
1108 result += constants[2];
1109 }
1110 }
1111 }
1112
1113 return result;
1114};
1115
1116/** Minimises the extra potential for constrained molecular dynamics and gives forces and the constrained potential energy.
1117 * We do the following:
1118 * -# First, we minimise the potential, see molecule::ConstrainedPotential()
1119 * -# Then, we calculate the forces by taking the spatial derivative, where we scale the potential to such a degree,
1120 * that the total force is always pointing in direction of the constraint force (ensuring that we move in the
1121 * right direction).
1122 * -# Finally, we calculate the potential energy and return.
1123 * \param *out output stream for debugging
1124 * \param *Force ForceMatrix containing force vectors from the external energy functional minimisation.
1125 * \param targetstep target step between which and the predecessor we perform the constrained MD
1126 * \sa molecule::VerletForceIntegration()
1127 * \return potential energy
1128 */
1129double molecule::MinimiseConstrainedPotential(ofstream *out, ForceMatrix *Force, int targetstep)
1130{
1131 double potential = 0.;
1132 // Minimise the potential
1133
1134 // evaluate forces
1135
1136 // evaluate potential and return
1137 return potential;
1138};
1139
1140/** Parses nuclear forces from file and performs Verlet integration.
1141 * Note that we assume the parsed forces to be in atomic units (hence, if coordinates are in angstroem, we
1142 * have to transform them).
1143 * This adds a new MD step to the config file.
1144 * \param *out output stream for debugging
1145 * \param *file filename
1146 * \param delta_t time step width in atomic units
1147 * \param IsAngstroem whether coordinates are in angstroem (true) or bohrradius (false)
1148 * \param DoConstrained whether we perform a constrained (>0, target step in molecule::trajectories) or unconstrained (0) molecular dynamics, \sa molecule::MinimiseConstrainedPotential()
1149 * \return true - file found and parsed, false - file not found or imparsable
1150 */
1151bool molecule::VerletForceIntegration(ofstream *out, char *file, double delta_t, bool IsAngstroem, int DoConstrained)
1152{
1153 element *runner = elemente->start;
1154 atom *walker = NULL;
1155 int AtomNo;
1156 ifstream input(file);
1157 string token;
1158 stringstream item;
1159 double a, IonMass, Vector[NDIM], ConstrainedPotentialEnergy;
1160 ForceMatrix Force;
1161
1162 CountElements(); // make sure ElementsInMolecule is up to date
1163
1164 // check file
1165 if (input == NULL) {
1166 return false;
1167 } else {
1168 // parse file into ForceMatrix
1169 if (!Force.ParseMatrix(file, 0,0,0)) {
1170 cerr << "Could not parse Force Matrix file " << file << "." << endl;
1171 return false;
1172 }
1173 if (Force.RowCounter[0] != AtomCount) {
1174 cerr << "Mismatch between number of atoms in file " << Force.RowCounter[0] << " and in molecule " << AtomCount << "." << endl;
1175 return false;
1176 }
1177 // correct Forces
1178 for(int d=0;d<NDIM;d++)
1179 Vector[d] = 0.;
1180 for(int i=0;i<AtomCount;i++)
1181 for(int d=0;d<NDIM;d++) {
1182 Vector[d] += Force.Matrix[0][i][d+5];
1183 }
1184 for(int i=0;i<AtomCount;i++)
1185 for(int d=0;d<NDIM;d++) {
1186 Force.Matrix[0][i][d+5] -= Vector[d]/(double)AtomCount;
1187 }
1188 // solve a constrained potential if we are meant to
1189 if (DoConstrained) {
1190 ConstrainedPotentialEnergy = MinimiseConstrainedPotential(out, &Force, DoConstrained);
1191 }
1192
1193 // and perform Verlet integration for each atom with position, velocity and force vector
1194 runner = elemente->start;
1195 while (runner->next != elemente->end) { // go through every element
1196 runner = runner->next;
1197 IonMass = runner->mass;
1198 a = delta_t*0.5/IonMass; // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a
1199 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1200 AtomNo = 0;
1201 walker = start;
1202 while (walker->next != end) { // go through every atom of this element
1203 walker = walker->next;
1204 if (walker->type == runner) { // if this atom fits to element
1205 // check size of vectors
1206 if (Trajectories[walker].R.size() <= (unsigned int)(MDSteps)) {
1207 //out << "Increasing size for trajectory array of " << *walker << " to " << (size+10) << "." << endl;
1208 Trajectories[walker].R.resize(MDSteps+10);
1209 Trajectories[walker].U.resize(MDSteps+10);
1210 Trajectories[walker].F.resize(MDSteps+10);
1211 }
1212
1213 // Update R (and F)
1214 for (int d=0; d<NDIM; d++) {
1215 Trajectories[walker].F.at(MDSteps).x[d] = -Force.Matrix[0][AtomNo][d+5]*(IsAngstroem ? AtomicLengthToAngstroem : 1.);
1216 Trajectories[walker].R.at(MDSteps).x[d] = Trajectories[walker].R.at(MDSteps-1).x[d];
1217 Trajectories[walker].R.at(MDSteps).x[d] += delta_t*(Trajectories[walker].U.at(MDSteps-1).x[d]);
1218 Trajectories[walker].R.at(MDSteps).x[d] += delta_t*a*(Trajectories[walker].F.at(MDSteps).x[d]); // F = m * a and s = 0.5 * F/m * t^2 = F * a * t
1219 }
1220 // Update U
1221 for (int d=0; d<NDIM; d++) {
1222 Trajectories[walker].U.at(MDSteps).x[d] = Trajectories[walker].U.at(MDSteps-1).x[d];
1223 Trajectories[walker].U.at(MDSteps).x[d] += a * (Trajectories[walker].F.at(MDSteps).x[d]+Trajectories[walker].F.at(MDSteps-1).x[d]);
1224 }
1225// out << "Integrated position&velocity of step " << (MDSteps) << ": (";
1226// for (int d=0;d<NDIM;d++)
1227// out << Trajectories[walker].R.at(MDSteps).x[d] << " "; // next step
1228// out << ")\t(";
1229// for (int d=0;d<NDIM;d++)
1230// cout << Trajectories[walker].U.at(MDSteps).x[d] << " "; // next step
1231// out << ")" << endl;
1232 // next atom
1233 AtomNo++;
1234 }
1235 }
1236 }
1237 }
1238 }
1239// // correct velocities (rather momenta) so that center of mass remains motionless
1240// for(int d=0;d<NDIM;d++)
1241// Vector[d] = 0.;
1242// IonMass = 0.;
1243// walker = start;
1244// while (walker->next != end) { // go through every atom
1245// walker = walker->next;
1246// IonMass += walker->type->mass; // sum up total mass
1247// for(int d=0;d<NDIM;d++) {
1248// Vector[d] += Trajectories[walker].U.at(MDSteps).x[d]*walker->type->mass;
1249// }
1250// }
1251// walker = start;
1252// while (walker->next != end) { // go through every atom of this element
1253// walker = walker->next;
1254// for(int d=0;d<NDIM;d++) {
1255// Trajectories[walker].U.at(MDSteps).x[d] -= Vector[d]*walker->type->mass/IonMass;
1256// }
1257// }
1258 MDSteps++;
1259
1260
1261 // exit
1262 return true;
1263};
1264
1265/** Align all atoms in such a manner that given vector \a *n is along z axis.
1266 * \param n[] alignment vector.
1267 */
1268void molecule::Align(Vector *n)
1269{
1270 atom *ptr = start;
1271 double alpha, tmp;
1272 Vector z_axis;
1273 z_axis.x[0] = 0.;
1274 z_axis.x[1] = 0.;
1275 z_axis.x[2] = 1.;
1276
1277 // rotate on z-x plane
1278 cout << Verbose(0) << "Begin of Aligning all atoms." << endl;
1279 alpha = atan(-n->x[0]/n->x[2]);
1280 cout << Verbose(1) << "Z-X-angle: " << alpha << " ... ";
1281 while (ptr->next != end) {
1282 ptr = ptr->next;
1283 tmp = ptr->x.x[0];
1284 ptr->x.x[0] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];
1285 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2];
1286 for (int j=0;j<MDSteps;j++) {
1287 tmp = Trajectories[ptr].R.at(j).x[0];
1288 Trajectories[ptr].R.at(j).x[0] = cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2];
1289 Trajectories[ptr].R.at(j).x[2] = -sin(alpha) * tmp + cos(alpha) * Trajectories[ptr].R.at(j).x[2];
1290 }
1291 }
1292 // rotate n vector
1293 tmp = n->x[0];
1294 n->x[0] = cos(alpha) * tmp + sin(alpha) * n->x[2];
1295 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2];
1296 cout << Verbose(1) << "alignment vector after first rotation: ";
1297 n->Output((ofstream *)&cout);
1298 cout << endl;
1299
1300 // rotate on z-y plane
1301 ptr = start;
1302 alpha = atan(-n->x[1]/n->x[2]);
1303 cout << Verbose(1) << "Z-Y-angle: " << alpha << " ... ";
1304 while (ptr->next != end) {
1305 ptr = ptr->next;
1306 tmp = ptr->x.x[1];
1307 ptr->x.x[1] = cos(alpha) * tmp + sin(alpha) * ptr->x.x[2];
1308 ptr->x.x[2] = -sin(alpha) * tmp + cos(alpha) * ptr->x.x[2];
1309 for (int j=0;j<MDSteps;j++) {
1310 tmp = Trajectories[ptr].R.at(j).x[1];
1311 Trajectories[ptr].R.at(j).x[1] = cos(alpha) * tmp + sin(alpha) * Trajectories[ptr].R.at(j).x[2];
1312 Trajectories[ptr].R.at(j).x[2] = -sin(alpha) * tmp + cos(alpha) * Trajectories[ptr].R.at(j).x[2];
1313 }
1314 }
1315 // rotate n vector (for consistency check)
1316 tmp = n->x[1];
1317 n->x[1] = cos(alpha) * tmp + sin(alpha) * n->x[2];
1318 n->x[2] = -sin(alpha) * tmp + cos(alpha) * n->x[2];
1319
1320 cout << Verbose(1) << "alignment vector after second rotation: ";
1321 n->Output((ofstream *)&cout);
1322 cout << Verbose(1) << endl;
1323 cout << Verbose(0) << "End of Aligning all atoms." << endl;
1324};
1325
1326/** Removes atom from molecule list.
1327 * \param *pointer atom to be removed
1328 * \return true - succeeded, false - atom not found in list
1329 */
1330bool molecule::RemoveAtom(atom *pointer)
1331{
1332 if (ElementsInMolecule[pointer->type->Z] != 0) // this would indicate an error
1333 ElementsInMolecule[pointer->type->Z]--; // decrease number of atom of this element
1334 else
1335 cerr << "ERROR: Atom " << pointer->Name << " is of element " << pointer->type->Z << " but the entry in the table of the molecule is 0!" << endl;
1336 if (ElementsInMolecule[pointer->type->Z] == 0) // was last atom of this element?
1337 ElementCount--;
1338 Trajectories.erase(pointer);
1339 return remove(pointer, start, end);
1340};
1341
1342/** Removes every atom from molecule list.
1343 * \return true - succeeded, false - atom not found in list
1344 */
1345bool molecule::CleanupMolecule()
1346{
1347 return (cleanup(start,end) && cleanup(first,last));
1348};
1349
1350/** Finds an atom specified by its continuous number.
1351 * \param Nr number of atom withim molecule
1352 * \return pointer to atom or NULL
1353 */
1354atom * molecule::FindAtom(int Nr) const{
1355 atom * walker = find(&Nr, start,end);
1356 if (walker != NULL) {
1357 //cout << Verbose(0) << "Found Atom Nr. " << walker->nr << endl;
1358 return walker;
1359 } else {
1360 cout << Verbose(0) << "Atom not found in list." << endl;
1361 return NULL;
1362 }
1363};
1364
1365/** Asks for atom number, and checks whether in list.
1366 * \param *text question before entering
1367 */
1368atom * molecule::AskAtom(string text)
1369{
1370 int No;
1371 atom *ion = NULL;
1372 do {
1373 //cout << Verbose(0) << "============Atom list==========================" << endl;
1374 //mol->Output((ofstream *)&cout);
1375 //cout << Verbose(0) << "===============================================" << endl;
1376 cout << Verbose(0) << text;
1377 cin >> No;
1378 ion = this->FindAtom(No);
1379 } while (ion == NULL);
1380 return ion;
1381};
1382
1383/** Checks if given coordinates are within cell volume.
1384 * \param *x array of coordinates
1385 * \return true - is within, false - out of cell
1386 */
1387bool molecule::CheckBounds(const Vector *x) const
1388{
1389 bool result = true;
1390 int j =-1;
1391 for (int i=0;i<NDIM;i++) {
1392 j += i+1;
1393 result = result && ((x->x[i] >= 0) && (x->x[i] < cell_size[j]));
1394 }
1395 //return result;
1396 return true; /// probably not gonna use the check no more
1397};
1398
1399/** Calculates sum over least square distance to line hidden in \a *x.
1400 * \param *x offset and direction vector
1401 * \param *params pointer to lsq_params structure
1402 * \return \f$ sum_i^N | y_i - (a + t_i b)|^2\f$
1403 */
1404double LeastSquareDistance (const gsl_vector * x, void * params)
1405{
1406 double res = 0, t;
1407 Vector a,b,c,d;
1408 struct lsq_params *par = (struct lsq_params *)params;
1409 atom *ptr = par->mol->start;
1410
1411 // initialize vectors
1412 a.x[0] = gsl_vector_get(x,0);
1413 a.x[1] = gsl_vector_get(x,1);
1414 a.x[2] = gsl_vector_get(x,2);
1415 b.x[0] = gsl_vector_get(x,3);
1416 b.x[1] = gsl_vector_get(x,4);
1417 b.x[2] = gsl_vector_get(x,5);
1418 // go through all atoms
1419 while (ptr != par->mol->end) {
1420 ptr = ptr->next;
1421 if (ptr->type == ((struct lsq_params *)params)->type) { // for specific type
1422 c.CopyVector(&ptr->x); // copy vector to temporary one
1423 c.SubtractVector(&a); // subtract offset vector
1424 t = c.ScalarProduct(&b); // get direction parameter
1425 d.CopyVector(&b); // and create vector
1426 d.Scale(&t);
1427 c.SubtractVector(&d); // ... yielding distance vector
1428 res += d.ScalarProduct((const Vector *)&d); // add squared distance
1429 }
1430 }
1431 return res;
1432};
1433
1434/** By minimizing the least square distance gains alignment vector.
1435 * \bug this is not yet working properly it seems
1436 */
1437void molecule::GetAlignvector(struct lsq_params * par) const
1438{
1439 int np = 6;
1440
1441 const gsl_multimin_fminimizer_type *T =
1442 gsl_multimin_fminimizer_nmsimplex;
1443 gsl_multimin_fminimizer *s = NULL;
1444 gsl_vector *ss;
1445 gsl_multimin_function minex_func;
1446
1447 size_t iter = 0, i;
1448 int status;
1449 double size;
1450
1451 /* Initial vertex size vector */
1452 ss = gsl_vector_alloc (np);
1453
1454 /* Set all step sizes to 1 */
1455 gsl_vector_set_all (ss, 1.0);
1456
1457 /* Starting point */
1458 par->x = gsl_vector_alloc (np);
1459 par->mol = this;
1460
1461 gsl_vector_set (par->x, 0, 0.0); // offset
1462 gsl_vector_set (par->x, 1, 0.0);
1463 gsl_vector_set (par->x, 2, 0.0);
1464 gsl_vector_set (par->x, 3, 0.0); // direction
1465 gsl_vector_set (par->x, 4, 0.0);
1466 gsl_vector_set (par->x, 5, 1.0);
1467
1468 /* Initialize method and iterate */
1469 minex_func.f = &LeastSquareDistance;
1470 minex_func.n = np;
1471 minex_func.params = (void *)par;
1472
1473 s = gsl_multimin_fminimizer_alloc (T, np);
1474 gsl_multimin_fminimizer_set (s, &minex_func, par->x, ss);
1475
1476 do
1477 {
1478 iter++;
1479 status = gsl_multimin_fminimizer_iterate(s);
1480
1481 if (status)
1482 break;
1483
1484 size = gsl_multimin_fminimizer_size (s);
1485 status = gsl_multimin_test_size (size, 1e-2);
1486
1487 if (status == GSL_SUCCESS)
1488 {
1489 printf ("converged to minimum at\n");
1490 }
1491
1492 printf ("%5d ", (int)iter);
1493 for (i = 0; i < (size_t)np; i++)
1494 {
1495 printf ("%10.3e ", gsl_vector_get (s->x, i));
1496 }
1497 printf ("f() = %7.3f size = %.3f\n", s->fval, size);
1498 }
1499 while (status == GSL_CONTINUE && iter < 100);
1500
1501 for (i=0;i<(size_t)np;i++)
1502 gsl_vector_set(par->x, i, gsl_vector_get(s->x, i));
1503 //gsl_vector_free(par->x);
1504 gsl_vector_free(ss);
1505 gsl_multimin_fminimizer_free (s);
1506};
1507
1508/** Prints molecule to *out.
1509 * \param *out output stream
1510 */
1511bool molecule::Output(ofstream *out)
1512{
1513 element *runner;
1514 atom *walker = NULL;
1515 int ElementNo, AtomNo;
1516 CountElements();
1517
1518 if (out == NULL) {
1519 return false;
1520 } else {
1521 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
1522 ElementNo = 0;
1523 runner = elemente->start;
1524 while (runner->next != elemente->end) { // go through every element
1525 runner = runner->next;
1526 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1527 ElementNo++;
1528 AtomNo = 0;
1529 walker = start;
1530 while (walker->next != end) { // go through every atom of this element
1531 walker = walker->next;
1532 if (walker->type == runner) { // if this atom fits to element
1533 AtomNo++;
1534 walker->Output(ElementNo, AtomNo, out); // removed due to trajectories
1535 }
1536 }
1537 }
1538 }
1539 return true;
1540 }
1541};
1542
1543/** Prints molecule with all atomic trajectory positions to *out.
1544 * \param *out output stream
1545 */
1546bool molecule::OutputTrajectories(ofstream *out)
1547{
1548 element *runner = NULL;
1549 atom *walker = NULL;
1550 int ElementNo, AtomNo;
1551 CountElements();
1552
1553 if (out == NULL) {
1554 return false;
1555 } else {
1556 for (int step = 0; step < MDSteps; step++) {
1557 if (step == 0) {
1558 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
1559 } else {
1560 *out << "# ====== MD step " << step << " =========" << endl;
1561 }
1562 ElementNo = 0;
1563 runner = elemente->start;
1564 while (runner->next != elemente->end) { // go through every element
1565 runner = runner->next;
1566 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
1567 ElementNo++;
1568 AtomNo = 0;
1569 walker = start;
1570 while (walker->next != end) { // go through every atom of this element
1571 walker = walker->next;
1572 if (walker->type == runner) { // if this atom fits to element
1573 AtomNo++;
1574 *out << "Ion_Type" << ElementNo << "_" << AtomNo << "\t" << fixed << setprecision(9) << showpoint;
1575 *out << Trajectories[walker].R.at(step).x[0] << "\t" << Trajectories[walker].R.at(step).x[1] << "\t" << Trajectories[walker].R.at(step).x[2];
1576 *out << "\t" << walker->FixedIon;
1577 if (Trajectories[walker].U.at(step).Norm() > MYEPSILON)
1578 *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";
1579 if (Trajectories[walker].F.at(step).Norm() > MYEPSILON)
1580 *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";
1581 *out << "\t# Number in molecule " << walker->nr << endl;
1582 }
1583 }
1584 }
1585 }
1586 }
1587 return true;
1588 }
1589};
1590
1591/** Outputs contents of molecule::ListOfBondsPerAtom.
1592 * \param *out output stream
1593 */
1594void molecule::OutputListOfBonds(ofstream *out) const
1595{
1596 *out << Verbose(2) << endl << "From Contents of ListOfBondsPerAtom, all non-hydrogen atoms:" << endl;
1597 atom *Walker = start;
1598 while (Walker->next != end) {
1599 Walker = Walker->next;
1600#ifdef ADDHYDROGEN
1601 if (Walker->type->Z != 1) { // regard only non-hydrogen
1602#endif
1603 *out << Verbose(2) << "Atom " << Walker->Name << " has Bonds: "<<endl;
1604 for(int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
1605 *out << Verbose(3) << *(ListOfBondsPerAtom)[Walker->nr][j] << endl;
1606 }
1607#ifdef ADDHYDROGEN
1608 }
1609#endif
1610 }
1611 *out << endl;
1612};
1613
1614/** Output of element before the actual coordination list.
1615 * \param *out stream pointer
1616 */
1617bool molecule::Checkout(ofstream *out) const
1618{
1619 return elemente->Checkout(out, ElementsInMolecule);
1620};
1621
1622/** Prints molecule with all its trajectories to *out as xyz file.
1623 * \param *out output stream
1624 */
1625bool molecule::OutputTrajectoriesXYZ(ofstream *out)
1626{
1627 atom *walker = NULL;
1628 int No = 0;
1629 time_t now;
1630
1631 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
1632 walker = start;
1633 while (walker->next != end) { // go through every atom and count
1634 walker = walker->next;
1635 No++;
1636 }
1637 if (out != NULL) {
1638 for (int step=0;step<MDSteps;step++) {
1639 *out << No << "\n\tCreated by molecuilder, step " << step << ", on " << ctime(&now);
1640 walker = start;
1641 while (walker->next != end) { // go through every atom of this element
1642 walker = walker->next;
1643 *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;
1644 }
1645 }
1646 return true;
1647 } else
1648 return false;
1649};
1650
1651/** Prints molecule to *out as xyz file.
1652* \param *out output stream
1653 */
1654bool molecule::OutputXYZ(ofstream *out) const
1655{
1656 atom *walker = NULL;
1657 int No = 0;
1658 time_t now;
1659
1660 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
1661 walker = start;
1662 while (walker->next != end) { // go through every atom and count
1663 walker = walker->next;
1664 No++;
1665 }
1666 if (out != NULL) {
1667 *out << No << "\n\tCreated by molecuilder on " << ctime(&now);
1668 walker = start;
1669 while (walker->next != end) { // go through every atom of this element
1670 walker = walker->next;
1671 walker->OutputXYZLine(out);
1672 }
1673 return true;
1674 } else
1675 return false;
1676};
1677
1678/** Brings molecule::AtomCount and atom::*Name up-to-date.
1679 * \param *out output stream for debugging
1680 */
1681void molecule::CountAtoms(ofstream *out)
1682{
1683 int i = 0;
1684 atom *Walker = start;
1685 while (Walker->next != end) {
1686 Walker = Walker->next;
1687 i++;
1688 }
1689 if ((AtomCount == 0) || (i != AtomCount)) {
1690 *out << Verbose(3) << "Mismatch in AtomCount " << AtomCount << " and recounted number " << i << ", renaming all." << endl;
1691 AtomCount = i;
1692
1693 // count NonHydrogen atoms and give each atom a unique name
1694 if (AtomCount != 0) {
1695 i=0;
1696 NoNonHydrogen = 0;
1697 Walker = start;
1698 while (Walker->next != end) {
1699 Walker = Walker->next;
1700 Walker->nr = i; // update number in molecule (for easier referencing in FragmentMolecule lateron)
1701 if (Walker->type->Z != 1) // count non-hydrogen atoms whilst at it
1702 NoNonHydrogen++;
1703 Free((void **)&Walker->Name, "molecule::CountAtoms: *walker->Name");
1704 Walker->Name = (char *) Malloc(sizeof(char)*6, "molecule::CountAtoms: *walker->Name");
1705 sprintf(Walker->Name, "%2s%02d", Walker->type->symbol, Walker->nr+1);
1706 *out << "Naming atom nr. " << Walker->nr << " " << Walker->Name << "." << endl;
1707 i++;
1708 }
1709 } else
1710 *out << Verbose(3) << "AtomCount is still " << AtomCount << ", thus counting nothing." << endl;
1711 }
1712};
1713
1714/** Brings molecule::ElementCount and molecule::ElementsInMolecule up-to-date.
1715 */
1716void molecule::CountElements()
1717{
1718 int i = 0;
1719 for(i=MAX_ELEMENTS;i--;)
1720 ElementsInMolecule[i] = 0;
1721 ElementCount = 0;
1722
1723 atom *walker = start;
1724 while (walker->next != end) {
1725 walker = walker->next;
1726 ElementsInMolecule[walker->type->Z]++;
1727 i++;
1728 }
1729 for(i=MAX_ELEMENTS;i--;)
1730 ElementCount += (ElementsInMolecule[i] != 0 ? 1 : 0);
1731};
1732
1733/** Counts all cyclic bonds and returns their number.
1734 * \note Hydrogen bonds can never by cyclic, thus no check for that
1735 * \param *out output stream for debugging
1736 * \return number opf cyclic bonds
1737 */
1738int molecule::CountCyclicBonds(ofstream *out)
1739{
1740 int No = 0;
1741 int *MinimumRingSize = NULL;
1742 MoleculeLeafClass *Subgraphs = NULL;
1743 bond *Binder = first;
1744 if ((Binder->next != last) && (Binder->next->Type == Undetermined)) {
1745 *out << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl;
1746 Subgraphs = DepthFirstSearchAnalysis(out, MinimumRingSize);
1747 while (Subgraphs->next != NULL) {
1748 Subgraphs = Subgraphs->next;
1749 delete(Subgraphs->previous);
1750 }
1751 delete(Subgraphs);
1752 delete[](MinimumRingSize);
1753 }
1754 while(Binder->next != last) {
1755 Binder = Binder->next;
1756 if (Binder->Cyclic)
1757 No++;
1758 }
1759 return No;
1760};
1761/** Returns Shading as a char string.
1762 * \param color the Shading
1763 * \return string of the flag
1764 */
1765string molecule::GetColor(enum Shading color)
1766{
1767 switch(color) {
1768 case white:
1769 return "white";
1770 break;
1771 case lightgray:
1772 return "lightgray";
1773 break;
1774 case darkgray:
1775 return "darkgray";
1776 break;
1777 case black:
1778 return "black";
1779 break;
1780 default:
1781 return "uncolored";
1782 break;
1783 };
1784};
1785
1786
1787/** Counts necessary number of valence electrons and returns number and SpinType.
1788 * \param configuration containing everything
1789 */
1790void molecule::CalculateOrbitals(class config &configuration)
1791{
1792 configuration.MaxPsiDouble = configuration.PsiMaxNoDown = configuration.PsiMaxNoUp = configuration.PsiType = 0;
1793 for(int i=MAX_ELEMENTS;i--;) {
1794 if (ElementsInMolecule[i] != 0) {
1795 //cout << "CalculateOrbitals: " << elemente->FindElement(i)->name << " has a valence of " << (int)elemente->FindElement(i)->Valence << " and there are " << ElementsInMolecule[i] << " of it." << endl;
1796 configuration.MaxPsiDouble += ElementsInMolecule[i]*((int)elemente->FindElement(i)->Valence);
1797 }
1798 }
1799 configuration.PsiMaxNoDown = configuration.MaxPsiDouble/2 + (configuration.MaxPsiDouble % 2);
1800 configuration.PsiMaxNoUp = configuration.MaxPsiDouble/2;
1801 configuration.MaxPsiDouble /= 2;
1802 configuration.PsiType = (configuration.PsiMaxNoDown == configuration.PsiMaxNoUp) ? 0 : 1;
1803 if ((configuration.PsiType == 1) && (configuration.ProcPEPsi < 2)) {
1804 configuration.ProcPEGamma /= 2;
1805 configuration.ProcPEPsi *= 2;
1806 } else {
1807 configuration.ProcPEGamma *= configuration.ProcPEPsi;
1808 configuration.ProcPEPsi = 1;
1809 }
1810 configuration.InitMaxMinStopStep = configuration.MaxMinStopStep = configuration.MaxPsiDouble;
1811};
1812
1813/** Creates an adjacency list of the molecule.
1814 * Generally, we use the CSD approach to bond recognition, that is the the distance
1815 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
1816 * a threshold t = 0.4 Angstroem.
1817 * To make it O(N log N) the function uses the linked-cell technique as follows:
1818 * The procedure is step-wise:
1819 * -# Remove every bond in list
1820 * -# Count the atoms in the molecule with CountAtoms()
1821 * -# partition cell into smaller linked cells of size \a bonddistance
1822 * -# put each atom into its corresponding cell
1823 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true
1824 * -# create the list of bonds via CreateListOfBondsPerAtom()
1825 * -# correct the bond degree iteratively (single->double->triple bond)
1826 * -# finally print the bond list to \a *out if desired
1827 * \param *out out stream for printing the matrix, NULL if no output
1828 * \param bonddistance length of linked cells (i.e. maximum minimal length checked)
1829 * \param IsAngstroem whether coordinate system is gauged to Angstroem or Bohr radii
1830 */
1831void molecule::CreateAdjacencyList(ofstream *out, double bonddistance, bool IsAngstroem)
1832{
1833 atom *Walker = NULL, *OtherWalker = NULL, *Candidate = NULL;
1834 int No, NoBonds, CandidateBondNo;
1835 int NumberCells, divisor[NDIM], n[NDIM], N[NDIM], index, Index, j;
1836 molecule **CellList;
1837 double distance, MinDistance, MaxDistance;
1838 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
1839 Vector x;
1840
1841 BondDistance = bonddistance; // * ((IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem);
1842 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl;
1843 // remove every bond from the list
1844 if ((first->next != last) && (last->previous != first)) { // there are bonds present
1845 cleanup(first,last);
1846 }
1847
1848 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering)
1849 CountAtoms(out);
1850 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl;
1851
1852 if (AtomCount != 0) {
1853 // 1. find divisor for each axis, such that a sphere with radius of at least bonddistance can be placed into each cell
1854 j=-1;
1855 for (int i=0;i<NDIM;i++) {
1856 j += i+1;
1857 divisor[i] = (int)floor(cell_size[j]/bonddistance); // take smaller value such that size of linked cell is at least bonddistance
1858 *out << Verbose(1) << "divisor[" << i << "] = " << divisor[i] << "." << endl;
1859 }
1860 // 2a. allocate memory for the cell list
1861 NumberCells = divisor[0]*divisor[1]*divisor[2];
1862 *out << Verbose(1) << "Allocating " << NumberCells << " cells." << endl;
1863 CellList = (molecule **) Malloc(sizeof(molecule *)*NumberCells, "molecule::CreateAdjacencyList - ** CellList");
1864 for (int i=NumberCells;i--;)
1865 CellList[i] = NULL;
1866
1867 // 2b. put all atoms into its corresponding list
1868 Walker = start;
1869 while(Walker->next != end) {
1870 Walker = Walker->next;
1871 //*out << Verbose(1) << "Current atom is " << *Walker << " with coordinates ";
1872 //Walker->x.Output(out);
1873 //*out << "." << endl;
1874 // compute the cell by the atom's coordinates
1875 j=-1;
1876 for (int i=0;i<NDIM;i++) {
1877 j += i+1;
1878 x.CopyVector(&(Walker->x));
1879 x.KeepPeriodic(out, matrix);
1880 n[i] = (int)floor(x.x[i]/cell_size[j]*(double)divisor[i]);
1881 }
1882 index = n[2] + (n[1] + n[0] * divisor[1]) * divisor[2];
1883 *out << Verbose(1) << "Atom " << *Walker << " goes into cell number [" << n[0] << "," << n[1] << "," << n[2] << "] = " << index << "." << endl;
1884 // add copy atom to this cell
1885 if (CellList[index] == NULL) // allocate molecule if not done
1886 CellList[index] = new molecule(elemente);
1887 OtherWalker = CellList[index]->AddCopyAtom(Walker); // add a copy of walker to this atom, father will be walker for later reference
1888 //*out << Verbose(1) << "Copy Atom is " << *OtherWalker << "." << endl;
1889 }
1890 //for (int i=0;i<NumberCells;i++)
1891 //*out << Verbose(1) << "Cell number " << i << ": " << CellList[i] << "." << endl;
1892
1893 // 3a. go through every cell
1894 for (N[0]=divisor[0];N[0]--;)
1895 for (N[1]=divisor[1];N[1]--;)
1896 for (N[2]=divisor[2];N[2]--;) {
1897 Index = N[2] + (N[1] + N[0] * divisor[1]) * divisor[2];
1898 if (CellList[Index] != NULL) { // if there atoms in this cell
1899 //*out << Verbose(1) << "Current cell is " << Index << "." << endl;
1900 // 3b. for every atom therein
1901 Walker = CellList[Index]->start;
1902 while (Walker->next != CellList[Index]->end) { // go through every atom
1903 Walker = Walker->next;
1904 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl;
1905 // 3c. check for possible bond between each atom in this and every one in the 27 cells
1906 for (n[0]=-1;n[0]<=1;n[0]++)
1907 for (n[1]=-1;n[1]<=1;n[1]++)
1908 for (n[2]=-1;n[2]<=1;n[2]++) {
1909 // compute the index of this comparison cell and make it periodic
1910 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];
1911 //*out << Verbose(1) << "Number of comparison cell is " << index << "." << endl;
1912 if (CellList[index] != NULL) { // if there are any atoms in this cell
1913 OtherWalker = CellList[index]->start;
1914 while(OtherWalker->next != CellList[index]->end) { // go through every atom in this cell
1915 OtherWalker = OtherWalker->next;
1916 //*out << Verbose(0) << "Current comparison atom is " << *OtherWalker << "." << endl;
1917 /// \todo periodic check is missing here!
1918 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl;
1919 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius;
1920 MinDistance *= (IsAngstroem) ? 1. : 1./AtomicLengthToAngstroem;
1921 MaxDistance = MinDistance + BONDTHRESHOLD;
1922 MinDistance -= BONDTHRESHOLD;
1923 distance = OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size);
1924 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance*MaxDistance) && (distance >= MinDistance*MinDistance)) { // create bond if distance is smaller
1925 *out << Verbose(0) << "Adding Bond between " << *Walker << " and " << *OtherWalker << "." << endl;
1926 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount
1927 BondCount++;
1928 } else {
1929 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl;
1930 }
1931 }
1932 }
1933 }
1934 }
1935 }
1936 }
1937 // 4. free the cell again
1938 for (int i=NumberCells;i--;)
1939 if (CellList[i] != NULL) {
1940 delete(CellList[i]);
1941 }
1942 Free((void **)&CellList, "molecule::CreateAdjacencyList - ** CellList");
1943
1944 // create the adjacency list per atom
1945 CreateListOfBondsPerAtom(out);
1946
1947 // correct Bond degree of each bond by checking both bond partners for a mismatch between valence and current sum of bond degrees,
1948 // iteratively increase the one first where the other bond partner has the fewest number of bonds (i.e. in general bonds oxygene
1949 // preferred over carbon bonds). Beforehand, we had picked the first mismatching partner, which lead to oxygenes with single instead of
1950 // double bonds as was expected.
1951 if (BondCount != 0) {
1952 NoCyclicBonds = 0;
1953 *out << Verbose(1) << "Correcting Bond degree of each bond ... ";
1954 do {
1955 No = 0; // No acts as breakup flag (if 1 we still continue)
1956 Walker = start;
1957 while (Walker->next != end) { // go through every atom
1958 Walker = Walker->next;
1959 // count valence of first partner
1960 NoBonds = 0;
1961 for(j=0;j<NumberOfBondsPerAtom[Walker->nr];j++)
1962 NoBonds += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
1963 *out << Verbose(3) << "Walker " << *Walker << ": " << (int)Walker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
1964 if ((int)(Walker->type->NoValenceOrbitals) > NoBonds) { // we have a mismatch, check all bonding partners for mismatch
1965 Candidate = NULL;
1966 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through each of its bond partners
1967 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
1968 // count valence of second partner
1969 NoBonds = 0;
1970 for(j=0;j<NumberOfBondsPerAtom[OtherWalker->nr];j++)
1971 NoBonds += ListOfBondsPerAtom[OtherWalker->nr][j]->BondDegree;
1972 *out << Verbose(3) << "OtherWalker " << *OtherWalker << ": " << (int)OtherWalker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
1973 if ((int)(OtherWalker->type->NoValenceOrbitals) > NoBonds) { // check if possible candidate
1974 if ((Candidate == NULL) || (NumberOfBondsPerAtom[Candidate->nr] > NumberOfBondsPerAtom[OtherWalker->nr])) { // pick the one with fewer number of bonds first
1975 Candidate = OtherWalker;
1976 CandidateBondNo = i;
1977 *out << Verbose(3) << "New candidate is " << *Candidate << "." << endl;
1978 }
1979 }
1980 }
1981 if (Candidate != NULL) {
1982 ListOfBondsPerAtom[Walker->nr][CandidateBondNo]->BondDegree++;
1983 *out << Verbose(2) << "Increased bond degree for bond " << *ListOfBondsPerAtom[Walker->nr][CandidateBondNo] << "." << endl;
1984 }
1985 }
1986 }
1987 } while (No);
1988 *out << " done." << endl;
1989 } else
1990 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl;
1991 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << bonddistance << "." << endl;
1992
1993 // output bonds for debugging (if bond chain list was correctly installed)
1994 *out << Verbose(1) << endl << "From contents of bond chain list:";
1995 bond *Binder = first;
1996 while(Binder->next != last) {
1997 Binder = Binder->next;
1998 *out << *Binder << "\t" << endl;
1999 }
2000 *out << endl;
2001 } else
2002 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl;
2003 *out << Verbose(0) << "End of CreateAdjacencyList." << endl;
2004 Free((void **)&matrix, "molecule::CreateAdjacencyList: *matrix");
2005};
2006
2007/** Performs a Depth-First search on this molecule.
2008 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
2009 * articulations points, ...
2010 * We use the algorithm from [Even, Graph Algorithms, p.62].
2011 * \param *out output stream for debugging
2012 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found
2013 * \return list of each disconnected subgraph as an individual molecule class structure
2014 */
2015MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, int *&MinimumRingSize)
2016{
2017 class StackClass<atom *> *AtomStack;
2018 AtomStack = new StackClass<atom *>(AtomCount);
2019 class StackClass<bond *> *BackEdgeStack = new StackClass<bond *> (BondCount);
2020 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
2021 MoleculeLeafClass *LeafWalker = SubGraphs;
2022 int CurrentGraphNr = 0, OldGraphNr;
2023 int ComponentNumber = 0;
2024 atom *Walker = NULL, *OtherAtom = NULL, *Root = start->next;
2025 bond *Binder = NULL;
2026 bool BackStepping = false;
2027
2028 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl;
2029
2030 ResetAllBondsToUnused();
2031 ResetAllAtomNumbers();
2032 InitComponentNumbers();
2033 BackEdgeStack->ClearStack();
2034 while (Root != end) { // if there any atoms at all
2035 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all
2036 AtomStack->ClearStack();
2037
2038 // put into new subgraph molecule and add this to list of subgraphs
2039 LeafWalker = new MoleculeLeafClass(LeafWalker);
2040 LeafWalker->Leaf = new molecule(elemente);
2041 LeafWalker->Leaf->AddCopyAtom(Root);
2042
2043 OldGraphNr = CurrentGraphNr;
2044 Walker = Root;
2045 do { // (10)
2046 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
2047 if (!BackStepping) { // if we don't just return from (8)
2048 Walker->GraphNr = CurrentGraphNr;
2049 Walker->LowpointNr = CurrentGraphNr;
2050 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl;
2051 AtomStack->Push(Walker);
2052 CurrentGraphNr++;
2053 }
2054 do { // (3) if Walker has no unused egdes, go to (5)
2055 BackStepping = false; // reset backstepping flag for (8)
2056 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
2057 Binder = FindNextUnused(Walker);
2058 if (Binder == NULL)
2059 break;
2060 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl;
2061 // (4) Mark Binder used, ...
2062 Binder->MarkUsed(black);
2063 OtherAtom = Binder->GetOtherAtom(Walker);
2064 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl;
2065 if (OtherAtom->GraphNr != -1) {
2066 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
2067 Binder->Type = BackEdge;
2068 BackEdgeStack->Push(Binder);
2069 Walker->LowpointNr = ( Walker->LowpointNr < OtherAtom->GraphNr ) ? Walker->LowpointNr : OtherAtom->GraphNr;
2070 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl;
2071 } else {
2072 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
2073 Binder->Type = TreeEdge;
2074 OtherAtom->Ancestor = Walker;
2075 Walker = OtherAtom;
2076 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl;
2077 break;
2078 }
2079 Binder = NULL;
2080 } while (1); // (3)
2081 if (Binder == NULL) {
2082 *out << Verbose(2) << "No more Unused Bonds." << endl;
2083 break;
2084 } else
2085 Binder = NULL;
2086 } while (1); // (2)
2087
2088 // 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!
2089 if ((Walker == Root) && (Binder == NULL))
2090 break;
2091
2092 // (5) if Ancestor of Walker is ...
2093 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl;
2094 if (Walker->Ancestor->GraphNr != Root->GraphNr) {
2095 // (6) (Ancestor of Walker is not Root)
2096 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
2097 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
2098 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
2099 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl;
2100 } else {
2101 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
2102 Walker->Ancestor->SeparationVertex = true;
2103 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl;
2104 SetNextComponentNumber(Walker->Ancestor, ComponentNumber);
2105 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << ComponentNumber << "." << endl;
2106 SetNextComponentNumber(Walker, ComponentNumber);
2107 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << ComponentNumber << "." << endl;
2108 do {
2109 OtherAtom = AtomStack->PopLast();
2110 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
2111 SetNextComponentNumber(OtherAtom, ComponentNumber);
2112 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
2113 } while (OtherAtom != Walker);
2114 ComponentNumber++;
2115 }
2116 // (8) Walker becomes its Ancestor, go to (3)
2117 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl;
2118 Walker = Walker->Ancestor;
2119 BackStepping = true;
2120 }
2121 if (!BackStepping) { // coming from (8) want to go to (3)
2122 // (9) remove all from stack till Walker (including), these and Root form a component
2123 AtomStack->Output(out);
2124 SetNextComponentNumber(Root, ComponentNumber);
2125 *out << Verbose(3) << "(9) Root[" << Root->Name << "]'s Component is " << ComponentNumber << "." << endl;
2126 SetNextComponentNumber(Walker, ComponentNumber);
2127 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << ComponentNumber << "." << endl;
2128 do {
2129 OtherAtom = AtomStack->PopLast();
2130 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
2131 SetNextComponentNumber(OtherAtom, ComponentNumber);
2132 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
2133 } while (OtherAtom != Walker);
2134 ComponentNumber++;
2135
2136 // (11) Root is separation vertex, set Walker to Root and go to (4)
2137 Walker = Root;
2138 Binder = FindNextUnused(Walker);
2139 *out << Verbose(1) << "(10) Walker is Root[" << Root->Name << "], next Unused Bond is " << Binder << "." << endl;
2140 if (Binder != NULL) { // Root is separation vertex
2141 *out << Verbose(1) << "(11) Root is a separation vertex." << endl;
2142 Walker->SeparationVertex = true;
2143 }
2144 }
2145 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
2146
2147 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
2148 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << CurrentGraphNr << "." << endl;
2149 LeafWalker->Leaf->Output(out);
2150 *out << endl;
2151
2152 // step on to next root
2153 while ((Root != end) && (Root->GraphNr != -1)) {
2154 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl;
2155 if (Root->GraphNr != -1) // if already discovered, step on
2156 Root = Root->next;
2157 }
2158 }
2159 // set cyclic bond criterium on "same LP" basis
2160 Binder = first;
2161 while(Binder->next != last) {
2162 Binder = Binder->next;
2163 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ??
2164 Binder->Cyclic = true;
2165 NoCyclicBonds++;
2166 }
2167 }
2168
2169 // analysis of the cycles (print rings, get minimum cycle length)
2170 CyclicStructureAnalysis(out, BackEdgeStack, MinimumRingSize);
2171
2172 *out << Verbose(1) << "Final graph info for each atom is:" << endl;
2173 Walker = start;
2174 while (Walker->next != end) {
2175 Walker = Walker->next;
2176 *out << Verbose(2) << "Atom " << Walker->Name << " is " << ((Walker->SeparationVertex) ? "a" : "not a") << " separation vertex, components are ";
2177 OutputComponentNumber(out, Walker);
2178 *out << " with Lowpoint " << Walker->LowpointNr << " and Graph Nr. " << Walker->GraphNr << "." << endl;
2179 }
2180
2181 *out << Verbose(1) << "Final graph info for each bond is:" << endl;
2182 Binder = first;
2183 while(Binder->next != last) {
2184 Binder = Binder->next;
2185 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
2186 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
2187 OutputComponentNumber(out, Binder->leftatom);
2188 *out << " === ";
2189 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
2190 OutputComponentNumber(out, Binder->rightatom);
2191 *out << ">." << endl;
2192 if (Binder->Cyclic) // cyclic ??
2193 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl;
2194 }
2195
2196 // free all and exit
2197 delete(AtomStack);
2198 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl;
2199 return SubGraphs;
2200};
2201
2202/** Analyses the cycles found and returns minimum of all cycle lengths.
2203 * We begin with a list of Back edges found during DepthFirstSearchAnalysis(). We go through this list - one end is the Root,
2204 * the other our initial Walker - and do a Breadth First Search for the Root. We mark down each Predecessor and as soon as
2205 * we have found the Root via BFS, we may climb back the closed cycle via the Predecessors. Thereby we mark atoms and bonds
2206 * as cyclic and print out the cycles.
2207 * \param *out output stream for debugging
2208 * \param *BackEdgeStack stack with all back edges found during DFS scan
2209 * \param *&MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found, if set is maximum search distance
2210 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
2211 */
2212void molecule::CyclicStructureAnalysis(ofstream *out, class StackClass<bond *> * BackEdgeStack, int *&MinimumRingSize)
2213{
2214 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CyclicStructureAnalysis: **PredecessorList");
2215 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CyclicStructureAnalysis: *ShortestPathList");
2216 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CyclicStructureAnalysis: *ColorList");
2217 class StackClass<atom *> *BFSStack = new StackClass<atom *> (AtomCount); // will hold the current ring
2218 class StackClass<atom *> *TouchedStack = new StackClass<atom *> (AtomCount); // contains all "touched" atoms (that need to be reset after BFS loop)
2219 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL;
2220 bond *Binder = NULL, *BackEdge = NULL;
2221 int RingSize, NumCycles, MinRingSize = -1;
2222
2223 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
2224 for (int i=AtomCount;i--;) {
2225 PredecessorList[i] = NULL;
2226 ShortestPathList[i] = -1;
2227 ColorList[i] = white;
2228 }
2229 MinimumRingSize = new int[AtomCount];
2230 for(int i=AtomCount;i--;)
2231 MinimumRingSize[i] = AtomCount;
2232
2233
2234 *out << Verbose(1) << "Back edge list - ";
2235 BackEdgeStack->Output(out);
2236
2237 *out << Verbose(1) << "Analysing cycles ... " << endl;
2238 NumCycles = 0;
2239 while (!BackEdgeStack->IsEmpty()) {
2240 BackEdge = BackEdgeStack->PopFirst();
2241 // this is the target
2242 Root = BackEdge->leftatom;
2243 // this is the source point
2244 Walker = BackEdge->rightatom;
2245 ShortestPathList[Walker->nr] = 0;
2246 BFSStack->ClearStack(); // start with empty BFS stack
2247 BFSStack->Push(Walker);
2248 TouchedStack->Push(Walker);
2249 *out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
2250 OtherAtom = NULL;
2251 do { // look for Root
2252 Walker = BFSStack->PopFirst();
2253 *out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
2254 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2255 Binder = ListOfBondsPerAtom[Walker->nr][i];
2256 if (Binder != BackEdge) { // only walk along DFS spanning tree (otherwise we always find SP of one being backedge Binder)
2257 OtherAtom = Binder->GetOtherAtom(Walker);
2258#ifdef ADDHYDROGEN
2259 if (OtherAtom->type->Z != 1) {
2260#endif
2261 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2262 if (ColorList[OtherAtom->nr] == white) {
2263 TouchedStack->Push(OtherAtom);
2264 ColorList[OtherAtom->nr] = lightgray;
2265 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2266 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2267 *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;
2268 //if (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr]) { // Check for maximum distance
2269 *out << Verbose(3) << "Putting OtherAtom into queue." << endl;
2270 BFSStack->Push(OtherAtom);
2271 //}
2272 } else {
2273 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
2274 }
2275 if (OtherAtom == Root)
2276 break;
2277#ifdef ADDHYDROGEN
2278 } else {
2279 *out << Verbose(2) << "Skipping hydrogen atom " << *OtherAtom << "." << endl;
2280 ColorList[OtherAtom->nr] = black;
2281 }
2282#endif
2283 } else {
2284 *out << Verbose(2) << "Bond " << *Binder << " not Visiting, is the back edge." << endl;
2285 }
2286 }
2287 ColorList[Walker->nr] = black;
2288 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2289 if (OtherAtom == Root) { // if we have found the root, check whether this cycle wasn't already found beforehand
2290 // step through predecessor list
2291 while (OtherAtom != BackEdge->rightatom) {
2292 if (!OtherAtom->GetTrueFather()->IsCyclic) // if one bond in the loop is not marked as cyclic, we haven't found this cycle yet
2293 break;
2294 else
2295 OtherAtom = PredecessorList[OtherAtom->nr];
2296 }
2297 if (OtherAtom == BackEdge->rightatom) { // if each atom in found cycle is cyclic, loop's been found before already
2298 *out << Verbose(3) << "This cycle was already found before, skipping and removing seeker from search." << endl;\
2299 do {
2300 OtherAtom = TouchedStack->PopLast();
2301 if (PredecessorList[OtherAtom->nr] == Walker) {
2302 *out << Verbose(4) << "Removing " << *OtherAtom << " from lists and stacks." << endl;
2303 PredecessorList[OtherAtom->nr] = NULL;
2304 ShortestPathList[OtherAtom->nr] = -1;
2305 ColorList[OtherAtom->nr] = white;
2306 BFSStack->RemoveItem(OtherAtom);
2307 }
2308 } while ((!TouchedStack->IsEmpty()) && (PredecessorList[OtherAtom->nr] == NULL));
2309 TouchedStack->Push(OtherAtom); // last was wrongly popped
2310 OtherAtom = BackEdge->rightatom; // set to not Root
2311 } else
2312 OtherAtom = Root;
2313 }
2314 } while ((!BFSStack->IsEmpty()) && (OtherAtom != Root) && (OtherAtom != NULL)); // || (ShortestPathList[OtherAtom->nr] < MinimumRingSize[Walker->GetTrueFather()->nr])));
2315
2316 if (OtherAtom == Root) {
2317 // now climb back the predecessor list and thus find the cycle members
2318 NumCycles++;
2319 RingSize = 1;
2320 Root->GetTrueFather()->IsCyclic = true;
2321 *out << Verbose(1) << "Found ring contains: ";
2322 Walker = Root;
2323 while (Walker != BackEdge->rightatom) {
2324 *out << Walker->Name << " <-> ";
2325 Walker = PredecessorList[Walker->nr];
2326 Walker->GetTrueFather()->IsCyclic = true;
2327 RingSize++;
2328 }
2329 *out << Walker->Name << " with a length of " << RingSize << "." << endl << endl;
2330 // walk through all and set MinimumRingSize
2331 Walker = Root;
2332 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
2333 while (Walker != BackEdge->rightatom) {
2334 Walker = PredecessorList[Walker->nr];
2335 if (RingSize < MinimumRingSize[Walker->GetTrueFather()->nr])
2336 MinimumRingSize[Walker->GetTrueFather()->nr] = RingSize;
2337 }
2338 if ((RingSize < MinRingSize) || (MinRingSize == -1))
2339 MinRingSize = RingSize;
2340 } else {
2341 *out << Verbose(1) << "No ring containing " << *Root << " with length equal to or smaller than " << MinimumRingSize[Walker->GetTrueFather()->nr] << " found." << endl;
2342 }
2343
2344 // now clean the lists
2345 while (!TouchedStack->IsEmpty()){
2346 Walker = TouchedStack->PopFirst();
2347 PredecessorList[Walker->nr] = NULL;
2348 ShortestPathList[Walker->nr] = -1;
2349 ColorList[Walker->nr] = white;
2350 }
2351 }
2352 if (MinRingSize != -1) {
2353 // go over all atoms
2354 Root = start;
2355 while(Root->next != end) {
2356 Root = Root->next;
2357
2358 if (MinimumRingSize[Root->GetTrueFather()->nr] == AtomCount) { // check whether MinimumRingSize is set, if not BFS to next where it is
2359 Walker = Root;
2360 ShortestPathList[Walker->nr] = 0;
2361 BFSStack->ClearStack(); // start with empty BFS stack
2362 BFSStack->Push(Walker);
2363 TouchedStack->Push(Walker);
2364 //*out << Verbose(1) << "---------------------------------------------------------------------------------------------------------" << endl;
2365 OtherAtom = Walker;
2366 while (OtherAtom != NULL) { // look for Root
2367 Walker = BFSStack->PopFirst();
2368 //*out << Verbose(2) << "Current Walker is " << *Walker << ", we look for SP to Root " << *Root << "." << endl;
2369 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2370 Binder = ListOfBondsPerAtom[Walker->nr][i];
2371 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
2372 OtherAtom = Binder->GetOtherAtom(Walker);
2373 //*out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2374 if (ColorList[OtherAtom->nr] == white) {
2375 TouchedStack->Push(OtherAtom);
2376 ColorList[OtherAtom->nr] = lightgray;
2377 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2378 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2379 //*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;
2380 if (OtherAtom->GetTrueFather()->IsCyclic) { // if the other atom is connected to a ring
2381 MinimumRingSize[Root->GetTrueFather()->nr] = ShortestPathList[OtherAtom->nr]+MinimumRingSize[OtherAtom->GetTrueFather()->nr];
2382 OtherAtom = NULL; //break;
2383 break;
2384 } else
2385 BFSStack->Push(OtherAtom);
2386 } else {
2387 //*out << Verbose(3) << "Not Adding, has already been visited." << endl;
2388 }
2389 } else {
2390 //*out << Verbose(3) << "Not Visiting, is a back edge." << endl;
2391 }
2392 }
2393 ColorList[Walker->nr] = black;
2394 //*out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2395 }
2396
2397 // now clean the lists
2398 while (!TouchedStack->IsEmpty()){
2399 Walker = TouchedStack->PopFirst();
2400 PredecessorList[Walker->nr] = NULL;
2401 ShortestPathList[Walker->nr] = -1;
2402 ColorList[Walker->nr] = white;
2403 }
2404 }
2405 *out << Verbose(1) << "Minimum ring size of " << *Root << " is " << MinimumRingSize[Root->GetTrueFather()->nr] << "." << endl;
2406 }
2407 *out << Verbose(1) << "Minimum ring size is " << MinRingSize << ", over " << NumCycles << " cycles total." << endl;
2408 } else
2409 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
2410
2411 Free((void **)&PredecessorList, "molecule::CyclicStructureAnalysis: **PredecessorList");
2412 Free((void **)&ShortestPathList, "molecule::CyclicStructureAnalysis: **ShortestPathList");
2413 Free((void **)&ColorList, "molecule::CyclicStructureAnalysis: **ColorList");
2414 delete(BFSStack);
2415};
2416
2417/** Sets the next component number.
2418 * This is O(N) as the number of bonds per atom is bound.
2419 * \param *vertex atom whose next atom::*ComponentNr is to be set
2420 * \param nr number to use
2421 */
2422void molecule::SetNextComponentNumber(atom *vertex, int nr)
2423{
2424 int i=0;
2425 if (vertex != NULL) {
2426 for(;i<NumberOfBondsPerAtom[vertex->nr];i++) {
2427 if (vertex->ComponentNr[i] == -1) { // check if not yet used
2428 vertex->ComponentNr[i] = nr;
2429 break;
2430 }
2431 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
2432 break; // breaking here will not cause error!
2433 }
2434 if (i == NumberOfBondsPerAtom[vertex->nr])
2435 cerr << "Error: All Component entries are already occupied!" << endl;
2436 } else
2437 cerr << "Error: Given vertex is NULL!" << endl;
2438};
2439
2440/** Output a list of flags, stating whether the bond was visited or not.
2441 * \param *out output stream for debugging
2442 */
2443void molecule::OutputComponentNumber(ofstream *out, atom *vertex)
2444{
2445 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
2446 *out << vertex->ComponentNr[i] << " ";
2447};
2448
2449/** Allocates memory for all atom::*ComponentNr in this molecule and sets each entry to -1.
2450 */
2451void molecule::InitComponentNumbers()
2452{
2453 atom *Walker = start;
2454 while(Walker->next != end) {
2455 Walker = Walker->next;
2456 if (Walker->ComponentNr != NULL)
2457 Free((void **)&Walker->ComponentNr, "molecule::InitComponentNumbers: **Walker->ComponentNr");
2458 Walker->ComponentNr = (int *) Malloc(sizeof(int)*NumberOfBondsPerAtom[Walker->nr], "molecule::InitComponentNumbers: *Walker->ComponentNr");
2459 for (int i=NumberOfBondsPerAtom[Walker->nr];i--;)
2460 Walker->ComponentNr[i] = -1;
2461 }
2462};
2463
2464/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
2465 * \param *vertex atom to regard
2466 * \return bond class or NULL
2467 */
2468bond * molecule::FindNextUnused(atom *vertex)
2469{
2470 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
2471 if (ListOfBondsPerAtom[vertex->nr][i]->IsUsed() == white)
2472 return(ListOfBondsPerAtom[vertex->nr][i]);
2473 return NULL;
2474};
2475
2476/** Resets bond::Used flag of all bonds in this molecule.
2477 * \return true - success, false - -failure
2478 */
2479void molecule::ResetAllBondsToUnused()
2480{
2481 bond *Binder = first;
2482 while (Binder->next != last) {
2483 Binder = Binder->next;
2484 Binder->ResetUsed();
2485 }
2486};
2487
2488/** Resets atom::nr to -1 of all atoms in this molecule.
2489 */
2490void molecule::ResetAllAtomNumbers()
2491{
2492 atom *Walker = start;
2493 while (Walker->next != end) {
2494 Walker = Walker->next;
2495 Walker->GraphNr = -1;
2496 }
2497};
2498
2499/** Output a list of flags, stating whether the bond was visited or not.
2500 * \param *out output stream for debugging
2501 * \param *list
2502 */
2503void OutputAlreadyVisited(ofstream *out, int *list)
2504{
2505 *out << Verbose(4) << "Already Visited Bonds:\t";
2506 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " ";
2507 *out << endl;
2508};
2509
2510/** Estimates by educated guessing (using upper limit) the expected number of fragments.
2511 * The upper limit is
2512 * \f[
2513 * n = N \cdot C^k
2514 * \f]
2515 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
2516 * \param *out output stream for debugging
2517 * \param order bond order k
2518 * \return number n of fragments
2519 */
2520int molecule::GuesstimateFragmentCount(ofstream *out, int order)
2521{
2522 int c = 0;
2523 int FragmentCount;
2524 // get maximum bond degree
2525 atom *Walker = start;
2526 while (Walker->next != end) {
2527 Walker = Walker->next;
2528 c = (NumberOfBondsPerAtom[Walker->nr] > c) ? NumberOfBondsPerAtom[Walker->nr] : c;
2529 }
2530 FragmentCount = NoNonHydrogen*(1 << (c*order));
2531 *out << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl;
2532 return FragmentCount;
2533};
2534
2535/** Scans a single line for number and puts them into \a KeySet.
2536 * \param *out output stream for debugging
2537 * \param *buffer buffer to scan
2538 * \param &CurrentSet filled KeySet on return
2539 * \return true - at least one valid atom id parsed, false - CurrentSet is empty
2540 */
2541bool molecule::ScanBufferIntoKeySet(ofstream *out, char *buffer, KeySet &CurrentSet)
2542{
2543 stringstream line;
2544 int AtomNr;
2545 int status = 0;
2546
2547 line.str(buffer);
2548 while (!line.eof()) {
2549 line >> AtomNr;
2550 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
2551 CurrentSet.insert(AtomNr); // insert at end, hence in same order as in file!
2552 status++;
2553 } // else it's "-1" or else and thus must not be added
2554 }
2555 *out << Verbose(1) << "The scanned KeySet is ";
2556 for(KeySet::iterator runner = CurrentSet.begin(); runner != CurrentSet.end(); runner++) {
2557 *out << (*runner) << "\t";
2558 }
2559 *out << endl;
2560 return (status != 0);
2561};
2562
2563/** Parses the KeySet file and fills \a *FragmentList from the known molecule structure.
2564 * Does two-pass scanning:
2565 * -# Scans the keyset file and initialises a temporary graph
2566 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
2567 * Finally, the temporary graph is inserted into the given \a FragmentList for return.
2568 * \param *out output stream for debugging
2569 * \param *path path to file
2570 * \param *FragmentList empty, filled on return
2571 * \return true - parsing successfully, false - failure on parsing (FragmentList will be NULL)
2572 */
2573bool molecule::ParseKeySetFile(ofstream *out, char *path, Graph *&FragmentList)
2574{
2575 bool status = true;
2576 ifstream InputFile;
2577 stringstream line;
2578 GraphTestPair testGraphInsert;
2579 int NumberOfFragments = 0;
2580 double TEFactor;
2581 char *filename = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - filename");
2582
2583 if (FragmentList == NULL) { // check list pointer
2584 FragmentList = new Graph;
2585 }
2586
2587 // 1st pass: open file and read
2588 *out << Verbose(1) << "Parsing the KeySet file ... " << endl;
2589 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, KEYSETFILE);
2590 InputFile.open(filename);
2591 if (InputFile != NULL) {
2592 // each line represents a new fragment
2593 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - *buffer");
2594 // 1. parse keysets and insert into temp. graph
2595 while (!InputFile.eof()) {
2596 InputFile.getline(buffer, MAXSTRINGSIZE);
2597 KeySet CurrentSet;
2598 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(out, buffer, CurrentSet))) { // if at least one valid atom was added, write config
2599 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1))); // store fragment number and current factor
2600 if (!testGraphInsert.second) {
2601 cerr << "KeySet file must be corrupt as there are two equal key sets therein!" << endl;
2602 }
2603 //FragmentList->ListOfMolecules[NumberOfFragments++] = StoreFragmentFromKeySet(out, CurrentSet, IsAngstroem);
2604 }
2605 }
2606 // 2. Free and done
2607 InputFile.close();
2608 InputFile.clear();
2609 Free((void **)&buffer, "molecule::ParseKeySetFile - *buffer");
2610 *out << Verbose(1) << "done." << endl;
2611 } else {
2612 *out << Verbose(1) << "File " << filename << " not found." << endl;
2613 status = false;
2614 }
2615
2616 // 2nd pass: open TEFactors file and read
2617 *out << Verbose(1) << "Parsing the TEFactors file ... " << endl;
2618 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, TEFACTORSFILE);
2619 InputFile.open(filename);
2620 if (InputFile != NULL) {
2621 // 3. add found TEFactors to each keyset
2622 NumberOfFragments = 0;
2623 for(Graph::iterator runner = FragmentList->begin();runner != FragmentList->end(); runner++) {
2624 if (!InputFile.eof()) {
2625 InputFile >> TEFactor;
2626 (*runner).second.second = TEFactor;
2627 *out << Verbose(2) << "Setting " << ++NumberOfFragments << " fragment's TEFactor to " << (*runner).second.second << "." << endl;
2628 } else {
2629 status = false;
2630 break;
2631 }
2632 }
2633 // 4. Free and done
2634 InputFile.close();
2635 *out << Verbose(1) << "done." << endl;
2636 } else {
2637 *out << Verbose(1) << "File " << filename << " not found." << endl;
2638 status = false;
2639 }
2640
2641 // free memory
2642 Free((void **)&filename, "molecule::ParseKeySetFile - filename");
2643
2644 return status;
2645};
2646
2647/** Stores keysets and TEFactors to file.
2648 * \param *out output stream for debugging
2649 * \param KeySetList Graph with Keysets and factors
2650 * \param *path path to file
2651 * \return true - file written successfully, false - writing failed
2652 */
2653bool molecule::StoreKeySetFile(ofstream *out, Graph &KeySetList, char *path)
2654{
2655 ofstream output;
2656 bool status = true;
2657 string line;
2658
2659 // open KeySet file
2660 line = path;
2661 line.append("/");
2662 line += FRAGMENTPREFIX;
2663 line += KEYSETFILE;
2664 output.open(line.c_str(), ios::out);
2665 *out << Verbose(1) << "Saving key sets of the total graph ... ";
2666 if(output != NULL) {
2667 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) {
2668 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
2669 if (sprinter != (*runner).first.begin())
2670 output << "\t";
2671 output << *sprinter;
2672 }
2673 output << endl;
2674 }
2675 *out << "done." << endl;
2676 } else {
2677 cerr << "Unable to open " << line << " for writing keysets!" << endl;
2678 status = false;
2679 }
2680 output.close();
2681 output.clear();
2682
2683 // open TEFactors file
2684 line = path;
2685 line.append("/");
2686 line += FRAGMENTPREFIX;
2687 line += TEFACTORSFILE;
2688 output.open(line.c_str(), ios::out);
2689 *out << Verbose(1) << "Saving TEFactors of the total graph ... ";
2690 if(output != NULL) {
2691 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++)
2692 output << (*runner).second.second << endl;
2693 *out << Verbose(1) << "done." << endl;
2694 } else {
2695 *out << Verbose(1) << "failed to open " << line << "." << endl;
2696 status = false;
2697 }
2698 output.close();
2699
2700 return status;
2701};
2702
2703/** Storing the bond structure of a molecule to file.
2704 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
2705 * \param *out output stream for debugging
2706 * \param *path path to file
2707 * \return true - file written successfully, false - writing failed
2708 */
2709bool molecule::StoreAdjacencyToFile(ofstream *out, char *path)
2710{
2711 ofstream AdjacencyFile;
2712 atom *Walker = NULL;
2713 stringstream line;
2714 bool status = true;
2715
2716 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
2717 AdjacencyFile.open(line.str().c_str(), ios::out);
2718 *out << Verbose(1) << "Saving adjacency list ... ";
2719 if (AdjacencyFile != NULL) {
2720 Walker = start;
2721 while(Walker->next != end) {
2722 Walker = Walker->next;
2723 AdjacencyFile << Walker->nr << "\t";
2724 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
2725 AdjacencyFile << ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker)->nr << "\t";
2726 AdjacencyFile << endl;
2727 }
2728 AdjacencyFile.close();
2729 *out << Verbose(1) << "done." << endl;
2730 } else {
2731 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
2732 status = false;
2733 }
2734
2735 return status;
2736};
2737
2738/** Checks contents of adjacency file against bond structure in structure molecule.
2739 * \param *out output stream for debugging
2740 * \param *path path to file
2741 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
2742 * \return true - structure is equal, false - not equivalence
2743 */
2744bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms)
2745{
2746 ifstream File;
2747 stringstream filename;
2748 bool status = true;
2749 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
2750
2751 filename << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
2752 File.open(filename.str().c_str(), ios::out);
2753 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... ";
2754 if (File != NULL) {
2755 // allocate storage structure
2756 int NonMatchNumber = 0; // will number of atoms with differing bond structure
2757 int *CurrentBonds = (int *) Malloc(sizeof(int)*8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
2758 int CurrentBondsOfAtom;
2759
2760 // Parse the file line by line and count the bonds
2761 while (!File.eof()) {
2762 File.getline(buffer, MAXSTRINGSIZE);
2763 stringstream line;
2764 line.str(buffer);
2765 int AtomNr = -1;
2766 line >> AtomNr;
2767 CurrentBondsOfAtom = -1; // we count one too far due to line end
2768 // parse into structure
2769 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
2770 while (!line.eof())
2771 line >> CurrentBonds[ ++CurrentBondsOfAtom ];
2772 // compare against present bonds
2773 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
2774 if (CurrentBondsOfAtom == NumberOfBondsPerAtom[AtomNr]) {
2775 for(int i=0;i<NumberOfBondsPerAtom[AtomNr];i++) {
2776 int id = ListOfBondsPerAtom[AtomNr][i]->GetOtherAtom(ListOfAtoms[AtomNr])->nr;
2777 int j = 0;
2778 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds
2779 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms
2780 ListOfAtoms[AtomNr] = NULL;
2781 NonMatchNumber++;
2782 status = false;
2783 //out << "[" << id << "]\t";
2784 } else {
2785 //out << id << "\t";
2786 }
2787 }
2788 //out << endl;
2789 } else {
2790 *out << "Number of bonds for Atom " << *ListOfAtoms[AtomNr] << " does not match, parsed " << CurrentBondsOfAtom << " against " << NumberOfBondsPerAtom[AtomNr] << "." << endl;
2791 status = false;
2792 }
2793 }
2794 }
2795 File.close();
2796 File.clear();
2797 if (status) { // if equal we parse the KeySetFile
2798 *out << Verbose(1) << "done: Equal." << endl;
2799 status = true;
2800 } else
2801 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
2802 Free((void **)&CurrentBonds, "molecule::CheckAdjacencyFileAgainstMolecule - **CurrentBonds");
2803 } else {
2804 *out << Verbose(1) << "Adjacency file not found." << endl;
2805 status = false;
2806 }
2807 *out << endl;
2808 Free((void **)&buffer, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
2809
2810 return status;
2811};
2812
2813/** Checks whether the OrderAtSite is still below \a Order at some site.
2814 * \param *out output stream for debugging
2815 * \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
2816 * \param *GlobalKeySetList list of keysets with global ids (valid in "this" molecule) needed for adaptive increase
2817 * \param Order desired Order if positive, desired exponent in threshold criteria if negative (0 is single-step)
2818 * \param *MinimumRingSize array of max. possible order to avoid loops
2819 * \param *path path to ENERGYPERFRAGMENT file (may be NULL if Order is non-negative)
2820 * \return true - needs further fragmentation, false - does not need fragmentation
2821 */
2822bool molecule::CheckOrderAtSite(ofstream *out, bool *AtomMask, Graph *GlobalKeySetList, int Order, int *MinimumRingSize, char *path)
2823{
2824 atom *Walker = start;
2825 bool status = false;
2826 ifstream InputFile;
2827
2828 // initialize mask list
2829 for(int i=AtomCount;i--;)
2830 AtomMask[i] = false;
2831
2832 if (Order < 0) { // adaptive increase of BondOrder per site
2833 if (AtomMask[AtomCount] == true) // break after one step
2834 return false;
2835 // parse the EnergyPerFragment file
2836 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckOrderAtSite: *buffer");
2837 sprintf(buffer, "%s/%s%s.dat", path, FRAGMENTPREFIX, ENERGYPERFRAGMENT);
2838 InputFile.open(buffer, ios::in);
2839 if ((InputFile != NULL) && (GlobalKeySetList != NULL)) {
2840 // transmorph graph keyset list into indexed KeySetList
2841 map<int,KeySet> IndexKeySetList;
2842 for(Graph::iterator runner = GlobalKeySetList->begin(); runner != GlobalKeySetList->end(); runner++) {
2843 IndexKeySetList.insert( pair<int,KeySet>(runner->second.first,runner->first) );
2844 }
2845 int lines = 0;
2846 // count the number of lines, i.e. the number of fragments
2847 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
2848 InputFile.getline(buffer, MAXSTRINGSIZE);
2849 while(!InputFile.eof()) {
2850 InputFile.getline(buffer, MAXSTRINGSIZE);
2851 lines++;
2852 }
2853 //*out << Verbose(2) << "Scanned " << lines-1 << " lines." << endl; // one endline too much
2854 InputFile.clear();
2855 InputFile.seekg(ios::beg);
2856 map<int, pair<double,int> > AdaptiveCriteriaList; // (Root No., (Value, Order)) !
2857 int No, FragOrder;
2858 double Value;
2859 // each line represents a fragment root (Atom::nr) id and its energy contribution
2860 InputFile.getline(buffer, MAXSTRINGSIZE); // skip comment lines
2861 InputFile.getline(buffer, MAXSTRINGSIZE);
2862 while(!InputFile.eof()) {
2863 InputFile.getline(buffer, MAXSTRINGSIZE);
2864 if (strlen(buffer) > 2) {
2865 //*out << Verbose(2) << "Scanning: " << buffer << endl;
2866 stringstream line(buffer);
2867 line >> FragOrder;
2868 line >> ws >> No;
2869 line >> ws >> Value; // skip time entry
2870 line >> ws >> Value;
2871 No -= 1; // indices start at 1 in file, not 0
2872 //*out << Verbose(2) << " - yields (" << No << "," << Value << ", " << FragOrder << ")" << endl;
2873
2874 // clean the list of those entries that have been superceded by higher order terms already
2875 map<int,KeySet>::iterator marker = IndexKeySetList.find(No); // find keyset to Frag No.
2876 if (marker != IndexKeySetList.end()) { // if found
2877 Value *= 1 + MYEPSILON*(*((*marker).second.begin())); // in case of equal energies this makes em not equal without changing anything actually
2878 // 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
2879 pair <map<int, pair<double,int> >::iterator, bool> InsertedElement = AdaptiveCriteriaList.insert( make_pair(*((*marker).second.begin()), pair<double,int>( fabs(Value), FragOrder) ));
2880 map<int, pair<double,int> >::iterator PresentItem = InsertedElement.first;
2881 if (!InsertedElement.second) { // this root is already present
2882 if ((*PresentItem).second.second < FragOrder) // if order there is lower, update entry with higher-order term
2883 //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)
2884 { // if value is smaller, update value and order
2885 (*PresentItem).second.first = fabs(Value);
2886 (*PresentItem).second.second = FragOrder;
2887 *out << Verbose(2) << "Updated element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;
2888 } else {
2889 *out << Verbose(2) << "Did not update element " << (*PresentItem).first << " as " << FragOrder << " is less than or equal to " << (*PresentItem).second.second << "." << endl;
2890 }
2891 } else {
2892 *out << Verbose(2) << "Inserted element (" << (*PresentItem).first << ",[" << (*PresentItem).second.first << "," << (*PresentItem).second.second << "])." << endl;
2893 }
2894 } else {
2895 *out << Verbose(1) << "No Fragment under No. " << No << "found." << endl;
2896 }
2897 }
2898 }
2899 // then map back onto (Value, (Root Nr., Order)) (i.e. sorted by value to pick the highest ones)
2900 map<double, pair<int,int> > FinalRootCandidates;
2901 *out << Verbose(1) << "Root candidate list is: " << endl;
2902 for(map<int, pair<double,int> >::iterator runner = AdaptiveCriteriaList.begin(); runner != AdaptiveCriteriaList.end(); runner++) {
2903 Walker = FindAtom((*runner).first);
2904 if (Walker != NULL) {
2905 //if ((*runner).second.second >= Walker->AdaptiveOrder) { // only insert if this is an "active" root site for the current order
2906 if (!Walker->MaxOrder) {
2907 *out << Verbose(2) << "(" << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "])" << endl;
2908 FinalRootCandidates.insert( make_pair( (*runner).second.first, pair<int,int>((*runner).first, (*runner).second.second) ) );
2909 } else {
2910 *out << Verbose(2) << "Excluding (" << *Walker << ", " << (*runner).first << ",[" << (*runner).second.first << "," << (*runner).second.second << "]), as it has reached its maximum order." << endl;
2911 }
2912 } else {
2913 cerr << "Atom No. " << (*runner).second.first << " was not found in this molecule." << endl;
2914 }
2915 }
2916 // pick the ones still below threshold and mark as to be adaptively updated
2917 for(map<double, pair<int,int> >::iterator runner = FinalRootCandidates.upper_bound(pow(10.,Order)); runner != FinalRootCandidates.end(); runner++) {
2918 No = (*runner).second.first;
2919 Walker = FindAtom(No);
2920 //if (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]) {
2921 *out << Verbose(2) << "Root " << No << " is still above threshold (10^{" << Order <<"}: " << runner->first << ", setting entry " << No << " of Atom mask to true." << endl;
2922 AtomMask[No] = true;
2923 status = true;
2924 //} else
2925 //*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;
2926 }
2927 // close and done
2928 InputFile.close();
2929 InputFile.clear();
2930 } else {
2931 cerr << "Unable to parse " << buffer << " file, incrementing all." << endl;
2932 while (Walker->next != end) {
2933 Walker = Walker->next;
2934 #ifdef ADDHYDROGEN
2935 if (Walker->type->Z != 1) // skip hydrogen
2936 #endif
2937 {
2938 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms
2939 status = true;
2940 }
2941 }
2942 }
2943 Free((void **)&buffer, "molecule::CheckOrderAtSite: *buffer");
2944 // pick a given number of highest values and set AtomMask
2945 } else { // global increase of Bond Order
2946 while (Walker->next != end) {
2947 Walker = Walker->next;
2948 #ifdef ADDHYDROGEN
2949 if (Walker->type->Z != 1) // skip hydrogen
2950 #endif
2951 {
2952 AtomMask[Walker->nr] = true; // include all (non-hydrogen) atoms
2953 if ((Order != 0) && (Walker->AdaptiveOrder < Order)) // && (Walker->AdaptiveOrder < MinimumRingSize[Walker->nr]))
2954 status = true;
2955 }
2956 }
2957 if ((Order == 0) && (AtomMask[AtomCount] == false)) // single stepping, just check
2958 status = true;
2959
2960 if (!status) {
2961 if (Order == 0)
2962 *out << Verbose(1) << "Single stepping done." << endl;
2963 else
2964 *out << Verbose(1) << "Order at every site is already equal or above desired order " << Order << "." << endl;
2965 }
2966 }
2967
2968 // print atom mask for debugging
2969 *out << " ";
2970 for(int i=0;i<AtomCount;i++)
2971 *out << (i % 10);
2972 *out << endl << "Atom mask is: ";
2973 for(int i=0;i<AtomCount;i++)
2974 *out << (AtomMask[i] ? "t" : "f");
2975 *out << endl;
2976
2977 return status;
2978};
2979
2980/** Create a SortIndex to map from atomic labels to the sequence in which the atoms are given in the config file.
2981 * \param *out output stream for debugging
2982 * \param *&SortIndex Mapping array of size molecule::AtomCount
2983 * \return true - success, false - failure of SortIndex alloc
2984 */
2985bool molecule::CreateMappingLabelsToConfigSequence(ofstream *out, int *&SortIndex)
2986{
2987 element *runner = elemente->start;
2988 int AtomNo = 0;
2989 atom *Walker = NULL;
2990
2991 if (SortIndex != NULL) {
2992 *out << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl;
2993 return false;
2994 }
2995 SortIndex = (int *) Malloc(sizeof(int)*AtomCount, "molecule::FragmentMolecule: *SortIndex");
2996 for(int i=AtomCount;i--;)
2997 SortIndex[i] = -1;
2998 while (runner->next != elemente->end) { // go through every element
2999 runner = runner->next;
3000 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
3001 Walker = start;
3002 while (Walker->next != end) { // go through every atom of this element
3003 Walker = Walker->next;
3004 if (Walker->type->Z == runner->Z) // if this atom fits to element
3005 SortIndex[Walker->nr] = AtomNo++;
3006 }
3007 }
3008 }
3009 return true;
3010};
3011
3012/** Performs a many-body bond order analysis for a given bond order.
3013 * -# parses adjacency, keysets and orderatsite files
3014 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
3015 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
3016y contribution", and that's why this consciously not done in the following loop)
3017 * -# in a loop over all subgraphs
3018 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
3019 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
3020 * -# combines the generated molecule lists from all subgraphs
3021 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
3022 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
3023 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
3024 * subgraph in the MoleculeListClass.
3025 * \param *out output stream for debugging
3026 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
3027 * \param *configuration configuration for writing config files for each fragment
3028 * \return 1 - continue, 2 - stop (no fragmentation occured)
3029 */
3030int molecule::FragmentMolecule(ofstream *out, int Order, config *configuration)
3031{
3032 MoleculeListClass *BondFragments = NULL;
3033 int *SortIndex = NULL;
3034 int *MinimumRingSize = NULL;
3035 int FragmentCounter;
3036 MoleculeLeafClass *MolecularWalker = NULL;
3037 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
3038 fstream File;
3039 bool FragmentationToDo = true;
3040 bool CheckOrder = false;
3041 Graph **FragmentList = NULL;
3042 Graph *ParsedFragmentList = NULL;
3043 Graph TotalGraph; // graph with all keysets however local numbers
3044 int TotalNumberOfKeySets = 0;
3045 atom **ListOfAtoms = NULL;
3046 atom ***ListOfLocalAtoms = NULL;
3047 bool *AtomMask = NULL;
3048
3049 *out << endl;
3050#ifdef ADDHYDROGEN
3051 *out << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl;
3052#else
3053 *out << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl;
3054#endif
3055
3056 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
3057
3058 // ===== 1. Check whether bond structure is same as stored in files ====
3059
3060 // fill the adjacency list
3061 CreateListOfBondsPerAtom(out);
3062
3063 // create lookup table for Atom::nr
3064 FragmentationToDo = FragmentationToDo && CreateFatherLookupTable(out, start, end, ListOfAtoms, AtomCount);
3065
3066 // === compare it with adjacency file ===
3067 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(out, configuration->configpath, ListOfAtoms);
3068 Free((void **)&ListOfAtoms, "molecule::FragmentMolecule - **ListOfAtoms");
3069
3070 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
3071 Subgraphs = DepthFirstSearchAnalysis(out, MinimumRingSize);
3072 // fill the bond structure of the individually stored subgraphs
3073 Subgraphs->next->FillBondStructureFromReference(out, this, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms
3074
3075 // ===== 3. if structure still valid, parse key set file and others =====
3076 FragmentationToDo = FragmentationToDo && ParseKeySetFile(out, configuration->configpath, ParsedFragmentList);
3077
3078 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
3079 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(out, configuration->configpath);
3080
3081 // =================================== Begin of FRAGMENTATION ===============================
3082 // ===== 6a. assign each keyset to its respective subgraph =====
3083 Subgraphs->next->AssignKeySetsToFragment(out, this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, (FragmentCounter = 0), false);
3084
3085 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
3086 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
3087 AtomMask = new bool[AtomCount+1];
3088 AtomMask[AtomCount] = false;
3089 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
3090 while ((CheckOrder = CheckOrderAtSite(out, AtomMask, ParsedFragmentList, Order, MinimumRingSize, configuration->configpath))) {
3091 FragmentationToDo = FragmentationToDo || CheckOrder;
3092 AtomMask[AtomCount] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
3093 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
3094 Subgraphs->next->FillRootStackForSubgraphs(out, RootStack, AtomMask, (FragmentCounter = 0));
3095
3096 // ===== 7. fill the bond fragment list =====
3097 FragmentCounter = 0;
3098 MolecularWalker = Subgraphs;
3099 while (MolecularWalker->next != NULL) {
3100 MolecularWalker = MolecularWalker->next;
3101 *out << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl;
3102 // output ListOfBondsPerAtom for debugging
3103 MolecularWalker->Leaf->OutputListOfBonds(out);
3104 if (MolecularWalker->Leaf->first->next != MolecularWalker->Leaf->last) {
3105
3106 // call BOSSANOVA method
3107 *out << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl;
3108 MolecularWalker->Leaf->FragmentBOSSANOVA(out, FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize);
3109 } else {
3110 cerr << "Subgraph " << MolecularWalker << " has no atoms!" << endl;
3111 }
3112 FragmentCounter++; // next fragment list
3113 }
3114 }
3115 delete[](RootStack);
3116 delete[](AtomMask);
3117 delete(ParsedFragmentList);
3118 delete[](MinimumRingSize);
3119
3120 // free the index lookup list
3121 for (int i=FragmentCounter;i--;)
3122 Free((void **)&ListOfLocalAtoms[i], "molecule::FragmentMolecule - *ListOfLocalAtoms[]");
3123 Free((void **)&ListOfLocalAtoms, "molecule::FragmentMolecule - **ListOfLocalAtoms");
3124
3125 // ==================================== End of FRAGMENTATION ============================================
3126
3127 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
3128 Subgraphs->next->TranslateIndicesToGlobalIDs(out, FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
3129
3130 // free subgraph memory again
3131 FragmentCounter = 0;
3132 if (Subgraphs != NULL) {
3133 while (Subgraphs->next != NULL) {
3134 Subgraphs = Subgraphs->next;
3135 delete(FragmentList[FragmentCounter++]);
3136 delete(Subgraphs->previous);
3137 }
3138 delete(Subgraphs);
3139 }
3140 Free((void **)&FragmentList, "molecule::FragmentMolecule - **FragmentList");
3141
3142 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
3143 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
3144 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
3145 BondFragments = new MoleculeListClass(TotalGraph.size(), AtomCount);
3146 int k=0;
3147 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
3148 KeySet test = (*runner).first;
3149 *out << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl;
3150 BondFragments->ListOfMolecules[k] = StoreFragmentFromKeySet(out, test, configuration);
3151 k++;
3152 }
3153 *out << k << "/" << BondFragments->NumberOfMolecules << " fragments generated from the keysets." << endl;
3154
3155 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
3156 if (BondFragments->NumberOfMolecules != 0) {
3157 // create the SortIndex from BFS labels to order in the config file
3158 CreateMappingLabelsToConfigSequence(out, SortIndex);
3159
3160 *out << Verbose(1) << "Writing " << BondFragments->NumberOfMolecules << " possible bond fragmentation configs" << endl;
3161 if (BondFragments->OutputConfigForListOfFragments(out, configuration, SortIndex))
3162 *out << Verbose(1) << "All configs written." << endl;
3163 else
3164 *out << Verbose(1) << "Some config writing failed." << endl;
3165
3166 // store force index reference file
3167 BondFragments->StoreForcesFile(out, configuration->configpath, SortIndex);
3168
3169 // store keysets file
3170 StoreKeySetFile(out, TotalGraph, configuration->configpath);
3171
3172 // store Adjacency file
3173 StoreAdjacencyToFile(out, configuration->configpath);
3174
3175 // store Hydrogen saturation correction file
3176 BondFragments->AddHydrogenCorrection(out, configuration->configpath);
3177
3178 // store adaptive orders into file
3179 StoreOrderAtSiteFile(out, configuration->configpath);
3180
3181 // restore orbital and Stop values
3182 CalculateOrbitals(*configuration);
3183
3184 // free memory for bond part
3185 *out << Verbose(1) << "Freeing bond memory" << endl;
3186 delete(FragmentList); // remove bond molecule from memory
3187 Free((void **)&SortIndex, "molecule::FragmentMolecule: *SortIndex");
3188 } else
3189 *out << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl;
3190 //} else
3191 // *out << Verbose(1) << "No fragments to store." << endl;
3192 *out << Verbose(0) << "End of bond fragmentation." << endl;
3193
3194 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
3195};
3196
3197/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
3198 * Atoms not present in the file get "-1".
3199 * \param *out output stream for debugging
3200 * \param *path path to file ORDERATSITEFILE
3201 * \return true - file writable, false - not writable
3202 */
3203bool molecule::StoreOrderAtSiteFile(ofstream *out, char *path)
3204{
3205 stringstream line;
3206 ofstream file;
3207
3208 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
3209 file.open(line.str().c_str());
3210 *out << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl;
3211 if (file != NULL) {
3212 atom *Walker = start;
3213 while (Walker->next != end) {
3214 Walker = Walker->next;
3215 file << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << endl;
3216 *out << Verbose(2) << "Storing: " << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << "." << endl;
3217 }
3218 file.close();
3219 *out << Verbose(1) << "done." << endl;
3220 return true;
3221 } else {
3222 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
3223 return false;
3224 }
3225};
3226
3227/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
3228 * Atoms not present in the file get "0".
3229 * \param *out output stream for debugging
3230 * \param *path path to file ORDERATSITEFILEe
3231 * \return true - file found and scanned, false - file not found
3232 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
3233 */
3234bool molecule::ParseOrderAtSiteFromFile(ofstream *out, char *path)
3235{
3236 unsigned char *OrderArray = (unsigned char *) Malloc(sizeof(unsigned char)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
3237 bool *MaxArray = (bool *) Malloc(sizeof(bool)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
3238 bool status;
3239 int AtomNr, value;
3240 stringstream line;
3241 ifstream file;
3242
3243 *out << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl;
3244 for(int i=AtomCount;i--;)
3245 OrderArray[i] = 0;
3246 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
3247 file.open(line.str().c_str());
3248 if (file != NULL) {
3249 for (int i=AtomCount;i--;) { // initialise with 0
3250 OrderArray[i] = 0;
3251 MaxArray[i] = 0;
3252 }
3253 while (!file.eof()) { // parse from file
3254 AtomNr = -1;
3255 file >> AtomNr;
3256 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
3257 file >> value;
3258 OrderArray[AtomNr] = value;
3259 file >> value;
3260 MaxArray[AtomNr] = value;
3261 //*out << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
3262 }
3263 }
3264 atom *Walker = start;
3265 while (Walker->next != end) { // fill into atom classes
3266 Walker = Walker->next;
3267 Walker->AdaptiveOrder = OrderArray[Walker->nr];
3268 Walker->MaxOrder = MaxArray[Walker->nr];
3269 *out << Verbose(2) << *Walker << " gets order " << (int)Walker->AdaptiveOrder << " and is " << (!Walker->MaxOrder ? "not " : " ") << "maxed." << endl;
3270 }
3271 file.close();
3272 *out << Verbose(1) << "done." << endl;
3273 status = true;
3274 } else {
3275 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
3276 status = false;
3277 }
3278 Free((void **)&OrderArray, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
3279 Free((void **)&MaxArray, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
3280
3281 *out << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl;
3282 return status;
3283};
3284
3285/** Creates an 2d array of pointer with an entry for each atom and each bond it has.
3286 * Updates molecule::ListOfBondsPerAtom, molecule::NumberOfBondsPerAtom by parsing through
3287 * bond chain list, using molecule::AtomCount and molecule::BondCount.
3288 * Allocates memory, fills the array and exits
3289 * \param *out output stream for debugging
3290 */
3291void molecule::CreateListOfBondsPerAtom(ofstream *out)
3292{
3293 bond *Binder = NULL;
3294 atom *Walker = NULL;
3295 int TotalDegree;
3296 *out << Verbose(1) << "Begin of Creating ListOfBondsPerAtom: AtomCount = " << AtomCount << "\tBondCount = " << BondCount << "\tNoNonBonds = " << NoNonBonds << "." << endl;
3297
3298 // re-allocate memory
3299 *out << Verbose(2) << "(Re-)Allocating memory." << endl;
3300 if (ListOfBondsPerAtom != NULL) {
3301 for(int i=AtomCount;i--;)
3302 Free((void **)&ListOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom[i]");
3303 Free((void **)&ListOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom");
3304 }
3305 if (NumberOfBondsPerAtom != NULL)
3306 Free((void **)&NumberOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: NumberOfBondsPerAtom");
3307 ListOfBondsPerAtom = (bond ***) Malloc(sizeof(bond **)*AtomCount, "molecule::CreateListOfBondsPerAtom: ***ListOfBondsPerAtom");
3308 NumberOfBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfBondsPerAtom: *NumberOfBondsPerAtom");
3309
3310 // reset bond counts per atom
3311 for(int i=AtomCount;i--;)
3312 NumberOfBondsPerAtom[i] = 0;
3313 // count bonds per atom
3314 Binder = first;
3315 while (Binder->next != last) {
3316 Binder = Binder->next;
3317 NumberOfBondsPerAtom[Binder->leftatom->nr]++;
3318 NumberOfBondsPerAtom[Binder->rightatom->nr]++;
3319 }
3320 for(int i=AtomCount;i--;) {
3321 // allocate list of bonds per atom
3322 ListOfBondsPerAtom[i] = (bond **) Malloc(sizeof(bond *)*NumberOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: **ListOfBondsPerAtom[]");
3323 // clear the list again, now each NumberOfBondsPerAtom marks current free field
3324 NumberOfBondsPerAtom[i] = 0;
3325 }
3326 // fill the list
3327 Binder = first;
3328 while (Binder->next != last) {
3329 Binder = Binder->next;
3330 ListOfBondsPerAtom[Binder->leftatom->nr][NumberOfBondsPerAtom[Binder->leftatom->nr]++] = Binder;
3331 ListOfBondsPerAtom[Binder->rightatom->nr][NumberOfBondsPerAtom[Binder->rightatom->nr]++] = Binder;
3332 }
3333
3334 // output list for debugging
3335 *out << Verbose(3) << "ListOfBondsPerAtom for each atom:" << endl;
3336 Walker = start;
3337 while (Walker->next != end) {
3338 Walker = Walker->next;
3339 *out << Verbose(4) << "Atom " << Walker->Name << " with " << NumberOfBondsPerAtom[Walker->nr] << " bonds: ";
3340 TotalDegree = 0;
3341 for (int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
3342 *out << *ListOfBondsPerAtom[Walker->nr][j] << "\t";
3343 TotalDegree += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
3344 }
3345 *out << " -- TotalDegree: " << TotalDegree << endl;
3346 }
3347 *out << Verbose(1) << "End of Creating ListOfBondsPerAtom." << endl << endl;
3348};
3349
3350/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
3351 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
3352 * white and putting into queue.
3353 * \param *out output stream for debugging
3354 * \param *Mol Molecule class to add atoms to
3355 * \param **AddedAtomList list with added atom pointers, index is atom father's number
3356 * \param **AddedBondList list with added bond pointers, index is bond father's number
3357 * \param *Root root vertex for BFS
3358 * \param *Bond bond not to look beyond
3359 * \param BondOrder maximum distance for vertices to add
3360 * \param IsAngstroem lengths are in angstroem or bohrradii
3361 */
3362void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
3363{
3364 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList");
3365 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList");
3366 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList");
3367 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
3368 atom *Walker = NULL, *OtherAtom = NULL;
3369 bond *Binder = NULL;
3370
3371 // add Root if not done yet
3372 AtomStack->ClearStack();
3373 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
3374 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
3375 AtomStack->Push(Root);
3376
3377 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
3378 for (int i=AtomCount;i--;) {
3379 PredecessorList[i] = NULL;
3380 ShortestPathList[i] = -1;
3381 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited
3382 ColorList[i] = lightgray;
3383 else
3384 ColorList[i] = white;
3385 }
3386 ShortestPathList[Root->nr] = 0;
3387
3388 // and go on ... Queue always contains all lightgray vertices
3389 while (!AtomStack->IsEmpty()) {
3390 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
3391 // 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
3392 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
3393 // followed by n+1 till top of stack.
3394 Walker = AtomStack->PopFirst(); // pop oldest added
3395 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl;
3396 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
3397 Binder = ListOfBondsPerAtom[Walker->nr][i];
3398 if (Binder != NULL) { // don't look at bond equal NULL
3399 OtherAtom = Binder->GetOtherAtom(Walker);
3400 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
3401 if (ColorList[OtherAtom->nr] == white) {
3402 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)
3403 ColorList[OtherAtom->nr] = lightgray;
3404 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
3405 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
3406 *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;
3407 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance
3408 *out << Verbose(3);
3409 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
3410 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
3411 *out << "Added OtherAtom " << OtherAtom->Name;
3412 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3413 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3414 AddedBondList[Binder->nr]->Type = Binder->Type;
3415 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
3416 } 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)
3417 *out << "Not adding OtherAtom " << OtherAtom->Name;
3418 if (AddedBondList[Binder->nr] == NULL) {
3419 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3420 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3421 AddedBondList[Binder->nr]->Type = Binder->Type;
3422 *out << ", added Bond " << *(AddedBondList[Binder->nr]);
3423 } else
3424 *out << ", not added Bond ";
3425 }
3426 *out << ", putting OtherAtom into queue." << endl;
3427 AtomStack->Push(OtherAtom);
3428 } else { // out of bond order, then replace
3429 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
3430 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
3431 if (Binder == Bond)
3432 *out << Verbose(3) << "Not Queueing, is the Root bond";
3433 else if (ShortestPathList[OtherAtom->nr] >= BondOrder)
3434 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder;
3435 if (!Binder->Cyclic)
3436 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
3437 if (AddedBondList[Binder->nr] == NULL) {
3438 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
3439 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3440 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3441 AddedBondList[Binder->nr]->Type = Binder->Type;
3442 } else {
3443#ifdef ADDHYDROGEN
3444 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
3445#endif
3446 }
3447 }
3448 }
3449 } else {
3450 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
3451 // This has to be a cyclic bond, check whether it's present ...
3452 if (AddedBondList[Binder->nr] == NULL) {
3453 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) {
3454 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
3455 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
3456 AddedBondList[Binder->nr]->Type = Binder->Type;
3457 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
3458#ifdef ADDHYDROGEN
3459 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
3460#endif
3461 }
3462 }
3463 }
3464 }
3465 }
3466 ColorList[Walker->nr] = black;
3467 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
3468 }
3469 Free((void **)&PredecessorList, "molecule::BreadthFirstSearchAdd: **PredecessorList");
3470 Free((void **)&ShortestPathList, "molecule::BreadthFirstSearchAdd: **ShortestPathList");
3471 Free((void **)&ColorList, "molecule::BreadthFirstSearchAdd: **ColorList");
3472 delete(AtomStack);
3473};
3474
3475/** Adds bond structure to this molecule from \a Father molecule.
3476 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
3477 * with end points present in this molecule, bond is created in this molecule.
3478 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
3479 * \param *out output stream for debugging
3480 * \param *Father father molecule
3481 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
3482 * \todo not checked, not fully working probably
3483 */
3484bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
3485{
3486 atom *Walker = NULL, *OtherAtom = NULL;
3487 bool status = true;
3488 atom **ParentList = (atom **) Malloc(sizeof(atom *)*Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList");
3489
3490 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
3491
3492 // reset parent list
3493 *out << Verbose(3) << "Resetting ParentList." << endl;
3494 for (int i=Father->AtomCount;i--;)
3495 ParentList[i] = NULL;
3496
3497 // fill parent list with sons
3498 *out << Verbose(3) << "Filling Parent List." << endl;
3499 Walker = start;
3500 while (Walker->next != end) {
3501 Walker = Walker->next;
3502 ParentList[Walker->father->nr] = Walker;
3503 // Outputting List for debugging
3504 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
3505 }
3506
3507 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
3508 *out << Verbose(3) << "Creating bonds." << endl;
3509 Walker = Father->start;
3510 while (Walker->next != Father->end) {
3511 Walker = Walker->next;
3512 if (ParentList[Walker->nr] != NULL) {
3513 if (ParentList[Walker->nr]->father != Walker) {
3514 status = false;
3515 } else {
3516 for (int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) {
3517 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
3518 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
3519 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i] << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
3520 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree);
3521 }
3522 }
3523 }
3524 }
3525 }
3526
3527 Free((void **)&ParentList, "molecule::BuildInducedSubgraph: **ParentList");
3528 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
3529 return status;
3530};
3531
3532
3533/** Looks through a StackClass<atom *> and returns the likeliest removal candiate.
3534 * \param *out output stream for debugging messages
3535 * \param *&Leaf KeySet to look through
3536 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
3537 * \param index of the atom suggested for removal
3538 */
3539int molecule::LookForRemovalCandidate(ofstream *&out, KeySet *&Leaf, int *&ShortestPathList)
3540{
3541 atom *Runner = NULL;
3542 int SP, Removal;
3543
3544 *out << Verbose(2) << "Looking for removal candidate." << endl;
3545 SP = -1; //0; // not -1, so that Root is never removed
3546 Removal = -1;
3547 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
3548 Runner = FindAtom((*runner));
3549 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack
3550 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
3551 SP = ShortestPathList[(*runner)];
3552 Removal = (*runner);
3553 }
3554 }
3555 }
3556 return Removal;
3557};
3558
3559/** Stores a fragment from \a KeySet into \a molecule.
3560 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
3561 * molecule and adds missing hydrogen where bonds were cut.
3562 * \param *out output stream for debugging messages
3563 * \param &Leaflet pointer to KeySet structure
3564 * \param IsAngstroem whether we have Ansgtroem or bohrradius
3565 * \return pointer to constructed molecule
3566 */
3567molecule * molecule::StoreFragmentFromKeySet(ofstream *out, KeySet &Leaflet, bool IsAngstroem)
3568{
3569 atom *Runner = NULL, *FatherOfRunner = NULL, *OtherFather = NULL;
3570 atom **SonList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::StoreFragmentFromStack: **SonList");
3571 molecule *Leaf = new molecule(elemente);
3572 bool LonelyFlag = false;
3573 int size;
3574
3575// *out << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
3576
3577 Leaf->BondDistance = BondDistance;
3578 for(int i=NDIM*2;i--;)
3579 Leaf->cell_size[i] = cell_size[i];
3580
3581 // initialise SonList (indicates when we need to replace a bond with hydrogen instead)
3582 for(int i=AtomCount;i--;)
3583 SonList[i] = NULL;
3584
3585 // first create the minimal set of atoms from the KeySet
3586 size = 0;
3587 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
3588 FatherOfRunner = FindAtom((*runner)); // find the id
3589 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner);
3590 size++;
3591 }
3592
3593 // create the bonds between all: Make it an induced subgraph and add hydrogen
3594// *out << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
3595 Runner = Leaf->start;
3596 while (Runner->next != Leaf->end) {
3597 Runner = Runner->next;
3598 LonelyFlag = true;
3599 FatherOfRunner = Runner->father;
3600 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list
3601 // create all bonds
3602 for (int i=0;i<NumberOfBondsPerAtom[FatherOfRunner->nr];i++) { // go through every bond of father
3603 OtherFather = ListOfBondsPerAtom[FatherOfRunner->nr][i]->GetOtherAtom(FatherOfRunner);
3604// *out << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
3605 if (SonList[OtherFather->nr] != NULL) {
3606// *out << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
3607 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
3608// *out << Verbose(3) << "Adding Bond: ";
3609// *out <<
3610 Leaf->AddBond(Runner, SonList[OtherFather->nr], ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree);
3611// *out << "." << endl;
3612 //NumBonds[Runner->nr]++;
3613 } else {
3614// *out << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
3615 }
3616 LonelyFlag = false;
3617 } else {
3618// *out << ", who has no son in this fragment molecule." << endl;
3619#ifdef ADDHYDROGEN
3620 //*out << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl;
3621 Leaf->AddHydrogenReplacementAtom(out, ListOfBondsPerAtom[FatherOfRunner->nr][i], Runner, FatherOfRunner, OtherFather, ListOfBondsPerAtom[FatherOfRunner->nr],NumberOfBondsPerAtom[FatherOfRunner->nr], IsAngstroem);
3622#endif
3623 //NumBonds[Runner->nr] += ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree;
3624 }
3625 }
3626 } else {
3627 *out << Verbose(0) << "ERROR: Son " << Runner->Name << " has father " << FatherOfRunner->Name << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl;
3628 }
3629 if ((LonelyFlag) && (size > 1)) {
3630 *out << Verbose(0) << *Runner << "has got bonds only to hydrogens!" << endl;
3631 }
3632#ifdef ADDHYDROGEN
3633 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen
3634 Runner = Runner->next;
3635#endif
3636 }
3637 Leaf->CreateListOfBondsPerAtom(out);
3638 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
3639 Free((void **)&SonList, "molecule::StoreFragmentFromStack: **SonList");
3640// *out << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
3641 return Leaf;
3642};
3643
3644/** Creates \a MoleculeListClass of all unique fragments of the \a molecule containing \a Order atoms or vertices.
3645 * The picture to have in mind is that of a DFS "snake" of a certain length \a Order, i.e. as in the infamous
3646 * computer game, that winds through the connected graph representing the molecule. Color (white,
3647 * lightgray, darkgray, black) indicates whether a vertex has been discovered so far or not. Labels will help in
3648 * creating only unique fragments and not additional ones with vertices simply in different sequence.
3649 * The Predecessor is always the one that came before in discovering, needed on backstepping. And
3650 * finally, the ShortestPath is needed for removing vertices from the snake stack during the back-
3651 * stepping.
3652 * \param *out output stream for debugging
3653 * \param Order number of atoms in each fragment
3654 * \param *configuration configuration for writing config files for each fragment
3655 * \return List of all unique fragments with \a Order atoms
3656 */
3657/*
3658MoleculeListClass * molecule::CreateListOfUniqueFragmentsOfOrder(ofstream *out, int Order, config *configuration)
3659{
3660 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
3661 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
3662 int *Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
3663 enum Shading *ColorVertexList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
3664 enum Shading *ColorEdgeList = (enum Shading *) Malloc(sizeof(enum Shading)*BondCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorBondList");
3665 StackClass<atom *> *RootStack = new StackClass<atom *>(AtomCount);
3666 StackClass<atom *> *TouchedStack = new StackClass<atom *>((int)pow(4,Order)+2); // number of atoms reached from one with maximal 4 bonds plus Root itself
3667 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!
3668 MoleculeLeafClass *Leaflet = NULL, *TempLeaf = NULL;
3669 MoleculeListClass *FragmentList = NULL;
3670 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Removal = NULL;
3671 bond *Binder = NULL;
3672 int RunningIndex = 0, FragmentCounter = 0;
3673
3674 *out << Verbose(1) << "Begin of CreateListOfUniqueFragmentsOfOrder." << endl;
3675
3676 // reset parent list
3677 *out << Verbose(3) << "Resetting labels, parent, predecessor, color and shortest path lists." << endl;
3678 for (int i=0;i<AtomCount;i++) { // reset all atom labels
3679 // initialise each vertex as white with no predecessor, empty queue, color lightgray, not labelled, no sons
3680 Labels[i] = -1;
3681 SonList[i] = NULL;
3682 PredecessorList[i] = NULL;
3683 ColorVertexList[i] = white;
3684 ShortestPathList[i] = -1;
3685 }
3686 for (int i=0;i<BondCount;i++)
3687 ColorEdgeList[i] = white;
3688 RootStack->ClearStack(); // clearstack and push first atom if exists
3689 TouchedStack->ClearStack();
3690 Walker = start->next;
3691 while ((Walker != end)
3692#ifdef ADDHYDROGEN
3693 && (Walker->type->Z == 1)
3694#endif
3695 ) { // search for first non-hydrogen atom
3696 *out << Verbose(4) << "Current Root candidate is " << Walker->Name << "." << endl;
3697 Walker = Walker->next;
3698 }
3699 if (Walker != end)
3700 RootStack->Push(Walker);
3701 else
3702 *out << Verbose(0) << "ERROR: Could not find an appropriate Root atom!" << endl;
3703 *out << Verbose(3) << "Root " << Walker->Name << " is on AtomStack, beginning loop through all vertices ..." << endl;
3704
3705 ///// OUTER LOOP ////////////
3706 while (!RootStack->IsEmpty()) {
3707 // get new root vertex from atom stack
3708 Root = RootStack->PopFirst();
3709 ShortestPathList[Root->nr] = 0;
3710 if (Labels[Root->nr] == -1)
3711 Labels[Root->nr] = RunningIndex++; // prevent it from getting again on AtomStack
3712 PredecessorList[Root->nr] = Root;
3713 TouchedStack->Push(Root);
3714 *out << Verbose(0) << "Root for this loop is: " << Root->Name << ".\n";
3715
3716 // clear snake stack
3717 SnakeStack->ClearStack();
3718 //SnakeStack->TestImplementation(out, start->next);
3719
3720 ///// INNER LOOP ////////////
3721 // Problems:
3722 // - what about cyclic bonds?
3723 Walker = Root;
3724 do {
3725 *out << Verbose(1) << "Current Walker is: " << Walker->Name;
3726 // initial setting of the new Walker: label, color, shortest path and put on stacks
3727 if (Labels[Walker->nr] == -1) { // give atom a unique, monotonely increasing number
3728 Labels[Walker->nr] = RunningIndex++;
3729 RootStack->Push(Walker);
3730 }
3731 *out << ", has label " << Labels[Walker->nr];
3732 if ((ColorVertexList[Walker->nr] == white) || ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white))) { // color it if newly discovered and push on stacks (and if within reach!)
3733 if ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white)) {
3734 // Binder ought to be set still from last neighbour search
3735 *out << ", coloring bond " << *Binder << " black";
3736 ColorEdgeList[Binder->nr] = black; // mark this bond as used
3737 }
3738 if (ShortestPathList[Walker->nr] == -1) {
3739 ShortestPathList[Walker->nr] = ShortestPathList[PredecessorList[Walker->nr]->nr]+1;
3740 TouchedStack->Push(Walker); // mark every atom for lists cleanup later, whose shortest path has been changed
3741 }
3742 if ((ShortestPathList[Walker->nr] < Order) && (ColorVertexList[Walker->nr] != darkgray)) { // if not already on snake stack
3743 SnakeStack->Push(Walker);
3744 ColorVertexList[Walker->nr] = darkgray; // mark as dark gray of on snake stack
3745 }
3746 }
3747 *out << ", SP of " << ShortestPathList[Walker->nr] << " and its color is " << GetColor(ColorVertexList[Walker->nr]) << "." << endl;
3748
3749 // then check the stack for a newly stumbled upon fragment
3750 if (SnakeStack->ItemCount() == Order) { // is stack full?
3751 // store the fragment if it is one and get a removal candidate
3752 Removal = StoreFragmentFromStack(out, Root, Walker, Leaflet, SnakeStack, ShortestPathList, SonList, Labels, &FragmentCounter, configuration);
3753 // remove the candidate if one was found
3754 if (Removal != NULL) {
3755 *out << Verbose(2) << "Removing item " << Removal->Name << " with SP of " << ShortestPathList[Removal->nr] << " from snake stack." << endl;
3756 SnakeStack->RemoveItem(Removal);
3757 ColorVertexList[Removal->nr] = lightgray; // return back to not on snake stack but explored marking
3758 if (Walker == Removal) { // if the current atom is to be removed, we also have to take a step back
3759 Walker = PredecessorList[Removal->nr];
3760 *out << Verbose(2) << "Stepping back to " << Walker->Name << "." << endl;
3761 }
3762 }
3763 } else
3764 Removal = NULL;
3765
3766 // finally, look for a white neighbour as the next Walker
3767 Binder = NULL;
3768 if ((Removal == NULL) || (Walker != PredecessorList[Removal->nr])) { // don't look, if a new walker has been set above
3769 *out << Verbose(2) << "Snake has currently " << SnakeStack->ItemCount() << " item(s)." << endl;
3770 OtherAtom = NULL; // this is actually not needed, every atom has at least one neighbour
3771 if (ShortestPathList[Walker->nr] < Order) {
3772 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
3773 Binder = ListOfBondsPerAtom[Walker->nr][i];
3774 *out << Verbose(2) << "Current bond is " << *Binder << ": ";
3775 OtherAtom = Binder->GetOtherAtom(Walker);
3776 if ((Labels[OtherAtom->nr] != -1) && (Labels[OtherAtom->nr] < Labels[Root->nr])) { // we don't step up to labels bigger than us
3777 *out << "Label " << Labels[OtherAtom->nr] << " is smaller than Root's " << Labels[Root->nr] << "." << endl;
3778 //ColorVertexList[OtherAtom->nr] = lightgray; // mark as explored
3779 } else { // otherwise check its colour and element
3780 if (
3781#ifdef ADDHYDROGEN
3782 (OtherAtom->type->Z != 1) &&
3783#endif
3784 (ColorEdgeList[Binder->nr] == white)) { // skip hydrogen, look for unexplored vertices
3785 *out << "Moving along " << GetColor(ColorEdgeList[Binder->nr]) << " bond " << Binder << " to " << ((ColorVertexList[OtherAtom->nr] == white) ? "unexplored" : "explored") << " item: " << OtherAtom->Name << "." << endl;
3786 // i find it currently rather sensible to always set the predecessor in order to find one's way back
3787 //if (PredecessorList[OtherAtom->nr] == NULL) {
3788 PredecessorList[OtherAtom->nr] = Walker;
3789 *out << Verbose(3) << "Setting Predecessor of " << OtherAtom->Name << " to " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
3790 //} else {
3791 // *out << Verbose(3) << "Predecessor of " << OtherAtom->Name << " is " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
3792 //}
3793 Walker = OtherAtom;
3794 break;
3795 } else {
3796 if (OtherAtom->type->Z == 1)
3797 *out << "Links to a hydrogen atom." << endl;
3798 else
3799 *out << "Bond has not white but " << GetColor(ColorEdgeList[Binder->nr]) << " color." << endl;
3800 }
3801 }
3802 }
3803 } else { // means we have stepped beyond the horizon: Return!
3804 Walker = PredecessorList[Walker->nr];
3805 OtherAtom = Walker;
3806 *out << Verbose(3) << "We have gone too far, stepping back to " << Walker->Name << "." << endl;
3807 }
3808 if (Walker != OtherAtom) { // if no white neighbours anymore, color it black
3809 *out << Verbose(2) << "Coloring " << Walker->Name << " black." << endl;
3810 ColorVertexList[Walker->nr] = black;
3811 Walker = PredecessorList[Walker->nr];
3812 }
3813 }
3814 } while ((Walker != Root) || (ColorVertexList[Root->nr] != black));
3815 *out << Verbose(2) << "Inner Looping is finished." << endl;
3816
3817 // if we reset all AtomCount atoms, we have again technically O(N^2) ...
3818 *out << Verbose(2) << "Resetting lists." << endl;
3819 Walker = NULL;
3820 Binder = NULL;
3821 while (!TouchedStack->IsEmpty()) {
3822 Walker = TouchedStack->PopLast();
3823 *out << Verbose(3) << "Re-initialising entries of " << *Walker << "." << endl;
3824 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
3825 ColorEdgeList[ListOfBondsPerAtom[Walker->nr][i]->nr] = white;
3826 PredecessorList[Walker->nr] = NULL;
3827 ColorVertexList[Walker->nr] = white;
3828 ShortestPathList[Walker->nr] = -1;
3829 }
3830 }
3831 *out << Verbose(1) << "Outer Looping over all vertices is done." << endl;
3832
3833 // copy together
3834 *out << Verbose(1) << "Copying all fragments into MoleculeList structure." << endl;
3835 FragmentList = new MoleculeListClass(FragmentCounter, AtomCount);
3836 RunningIndex = 0;
3837 while ((Leaflet != NULL) && (RunningIndex < FragmentCounter)) {
3838 FragmentList->ListOfMolecules[RunningIndex++] = Leaflet->Leaf;
3839 Leaflet->Leaf = NULL; // prevent molecule from being removed
3840 TempLeaf = Leaflet;
3841 Leaflet = Leaflet->previous;
3842 delete(TempLeaf);
3843 };
3844
3845 // free memory and exit
3846 Free((void **)&PredecessorList, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
3847 Free((void **)&ShortestPathList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
3848 Free((void **)&Labels, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
3849 Free((void **)&ColorVertexList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
3850 delete(RootStack);
3851 delete(TouchedStack);
3852 delete(SnakeStack);
3853
3854 *out << Verbose(1) << "End of CreateListOfUniqueFragmentsOfOrder." << endl;
3855 return FragmentList;
3856};
3857*/
3858
3859/** Structure containing all values in power set combination generation.
3860 */
3861struct UniqueFragments {
3862 config *configuration;
3863 atom *Root;
3864 Graph *Leaflet;
3865 KeySet *FragmentSet;
3866 int ANOVAOrder;
3867 int FragmentCounter;
3868 int CurrentIndex;
3869 double TEFactor;
3870 int *ShortestPathList;
3871 bool **UsedList;
3872 bond **BondsPerSPList;
3873 int *BondsPerSPCount;
3874};
3875
3876/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
3877 * -# loops over every possible combination (2^dimension of edge set)
3878 * -# inserts current set, if there's still space left
3879 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
3880ance+1
3881 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
3882 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
3883distance) and current set
3884 * \param *out output stream for debugging
3885 * \param FragmentSearch UniqueFragments structure with all values needed
3886 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
3887 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
3888 * \param SubOrder remaining number of allowed vertices to add
3889 */
3890void molecule::SPFragmentGenerator(ofstream *out, struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
3891{
3892 atom *OtherWalker = NULL;
3893 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
3894 int NumCombinations;
3895 bool bit;
3896 int bits, TouchedIndex, SubSetDimension, SP, Added;
3897 int Removal;
3898 int SpaceLeft;
3899 int *TouchedList = (int *) Malloc(sizeof(int)*(SubOrder+1), "molecule::SPFragmentGenerator: *TouchedList");
3900 bond *Binder = NULL;
3901 bond **BondsList = NULL;
3902 KeySetTestPair TestKeySetInsert;
3903
3904 NumCombinations = 1 << SetDimension;
3905
3906 // Hier muessen von 1 bis NumberOfBondsPerAtom[Walker->nr] alle Kombinationen
3907 // von Endstuecken (aus den Bonds) hinzugefᅵᅵgt werden und fᅵᅵr verbleibende ANOVAOrder
3908 // rekursiv GraphCrawler in der nᅵᅵchsten Ebene aufgerufen werden
3909
3910 *out << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
3911 *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;
3912
3913 // initialised touched list (stores added atoms on this level)
3914 *out << Verbose(1+verbosity) << "Clearing touched list." << endl;
3915 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
3916 TouchedList[TouchedIndex] = -1;
3917 TouchedIndex = 0;
3918
3919 // create every possible combination of the endpieces
3920 *out << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
3921 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
3922 // count the set bit of i
3923 bits = 0;
3924 for (int j=SetDimension;j--;)
3925 bits += (i & (1 << j)) >> j;
3926
3927 *out << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
3928 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
3929 // --1-- add this set of the power set of bond partners to the snake stack
3930 Added = 0;
3931 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
3932 bit = ((i & (1 << j)) != 0); // mask the bit for the j-th bond
3933 if (bit) { // if bit is set, we add this bond partner
3934 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
3935 //*out << Verbose(1+verbosity) << "Current Bond is " << ListOfBondsPerAtom[Walker->nr][i] << ", checking on " << *OtherWalker << "." << endl;
3936 *out << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
3937 TestKeySetInsert = FragmentSearch->FragmentSet->insert(OtherWalker->nr);
3938 if (TestKeySetInsert.second) {
3939 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
3940 Added++;
3941 } else {
3942 *out << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
3943 }
3944 //FragmentSearch->UsedList[OtherWalker->nr][i] = true;
3945 //}
3946 } else {
3947 *out << Verbose(2+verbosity) << "Not adding." << endl;
3948 }
3949 }
3950
3951 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
3952 if (SpaceLeft > 0) {
3953 *out << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
3954 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
3955 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
3956 SP = RootDistance+1; // this is the next level
3957 // first count the members in the subset
3958 SubSetDimension = 0;
3959 Binder = FragmentSearch->BondsPerSPList[2*SP]; // start node for this level
3960 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) { // compare to end node of this level
3961 Binder = Binder->next;
3962 for (int k=TouchedIndex;k--;) {
3963 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
3964 SubSetDimension++;
3965 }
3966 }
3967 // then allocate and fill the list
3968 BondsList = (bond **) Malloc(sizeof(bond *)*SubSetDimension, "molecule::SPFragmentGenerator: **BondsList");
3969 SubSetDimension = 0;
3970 Binder = FragmentSearch->BondsPerSPList[2*SP];
3971 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) {
3972 Binder = Binder->next;
3973 for (int k=0;k<TouchedIndex;k++) {
3974 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
3975 BondsList[SubSetDimension++] = Binder;
3976 }
3977 }
3978 *out << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
3979 SPFragmentGenerator(out, FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
3980 Free((void **)&BondsList, "molecule::SPFragmentGenerator: **BondsList");
3981 }
3982 } else {
3983 // --2-- otherwise store the complete fragment
3984 *out << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
3985 // store fragment as a KeySet
3986 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
3987 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
3988 *out << (*runner) << " ";
3989 *out << endl;
3990 //if (!CheckForConnectedSubgraph(out, FragmentSearch->FragmentSet))
3991 //*out << Verbose(0) << "ERROR: The found fragment is not a connected subgraph!" << endl;
3992 InsertFragmentIntoGraph(out, FragmentSearch);
3993 //Removal = LookForRemovalCandidate(out, FragmentSearch->FragmentSet, FragmentSearch->ShortestPathList);
3994 //Removal = StoreFragmentFromStack(out, FragmentSearch->Root, FragmentSearch->Leaflet, FragmentSearch->FragmentStack, FragmentSearch->ShortestPathList, &FragmentSearch->FragmentCounter, FragmentSearch->configuration);
3995 }
3996
3997 // --3-- remove all added items in this level from snake stack
3998 *out << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
3999 for(int j=0;j<TouchedIndex;j++) {
4000 Removal = TouchedList[j];
4001 *out << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
4002 FragmentSearch->FragmentSet->erase(Removal);
4003 TouchedList[j] = -1;
4004 }
4005 *out << Verbose(2) << "Remaining local nr.s on snake stack are: ";
4006 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
4007 *out << (*runner) << " ";
4008 *out << endl;
4009 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
4010 } else {
4011 *out << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
4012 }
4013 }
4014 Free((void **)&TouchedList, "molecule::SPFragmentGenerator: *TouchedList");
4015 *out << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
4016};
4017
4018/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
4019 * \param *out output stream for debugging
4020 * \param *Fragment Keyset of fragment's vertices
4021 * \return true - connected, false - disconnected
4022 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
4023 */
4024bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment)
4025{
4026 atom *Walker = NULL, *Walker2 = NULL;
4027 bool BondStatus = false;
4028 int size;
4029
4030 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
4031 *out << Verbose(2) << "Disconnected atom: ";
4032
4033 // count number of atoms in graph
4034 size = 0;
4035 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
4036 size++;
4037 if (size > 1)
4038 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
4039 Walker = FindAtom(*runner);
4040 BondStatus = false;
4041 for(KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
4042 Walker2 = FindAtom(*runners);
4043 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
4044 if (ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker) == Walker2) {
4045 BondStatus = true;
4046 break;
4047 }
4048 if (BondStatus)
4049 break;
4050 }
4051 }
4052 if (!BondStatus) {
4053 *out << (*Walker) << endl;
4054 return false;
4055 }
4056 }
4057 else {
4058 *out << "none." << endl;
4059 return true;
4060 }
4061 *out << "none." << endl;
4062
4063 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
4064
4065 return true;
4066}
4067
4068/** 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.
4069 * -# initialises UniqueFragments structure
4070 * -# fills edge list via BFS
4071 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
4072 root distance, the edge set, its dimension and the current suborder
4073 * -# Free'ing structure
4074 * 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
4075 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
4076 * \param *out output stream for debugging
4077 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
4078 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
4079 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
4080 * \return number of inserted fragments
4081 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
4082 */
4083int molecule::PowerSetGenerator(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
4084{
4085 int SP, AtomKeyNr;
4086 atom *Walker = NULL, *OtherWalker = NULL, *Predecessor = NULL;
4087 bond *Binder = NULL;
4088 bond *CurrentEdge = NULL;
4089 bond **BondsList = NULL;
4090 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->nr;
4091 int Counter = FragmentSearch.FragmentCounter;
4092 int RemainingWalkers;
4093
4094 *out << endl;
4095 *out << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl;
4096
4097 // prepare Label and SP arrays of the BFS search
4098 FragmentSearch.ShortestPathList[FragmentSearch.Root->nr] = 0;
4099
4100 // prepare root level (SP = 0) and a loop bond denoting Root
4101 for (int i=1;i<Order;i++)
4102 FragmentSearch.BondsPerSPCount[i] = 0;
4103 FragmentSearch.BondsPerSPCount[0] = 1;
4104 Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
4105 add(Binder, FragmentSearch.BondsPerSPList[1]);
4106
4107 // do a BFS search to fill the SP lists and label the found vertices
4108 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into
4109 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning
4110 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth
4111 // (EdgeinSPLevel) of this tree ...
4112 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence
4113 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction.
4114 *out << endl;
4115 *out << Verbose(0) << "Starting BFS analysis ..." << endl;
4116 for (SP = 0; SP < (Order-1); SP++) {
4117 *out << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)";
4118 if (SP > 0) {
4119 *out << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl;
4120 FragmentSearch.BondsPerSPCount[SP] = 0;
4121 } else
4122 *out << "." << endl;
4123
4124 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
4125 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP]; /// start of this SP level's list
4126 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) { /// end of this SP level's list
4127 CurrentEdge = CurrentEdge->next;
4128 RemainingWalkers--;
4129 Walker = CurrentEdge->rightatom; // rightatom is always the one more distant
4130 Predecessor = CurrentEdge->leftatom; // ... and leftatom is predecessor
4131 AtomKeyNr = Walker->nr;
4132 *out << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl;
4133 // check for new sp level
4134 // go through all its bonds
4135 *out << Verbose(1) << "Going through all bonds of Walker." << endl;
4136 for (int i=0;i<NumberOfBondsPerAtom[AtomKeyNr];i++) {
4137 Binder = ListOfBondsPerAtom[AtomKeyNr][i];
4138 OtherWalker = Binder->GetOtherAtom(Walker);
4139 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end())
4140 #ifdef ADDHYDROGEN
4141 && (OtherWalker->type->Z != 1)
4142 #endif
4143 ) { // skip hydrogens and restrict to fragment
4144 *out << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *Binder << "." << endl;
4145 // set the label if not set (and push on root stack as well)
4146 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->nr > RootKeyNr)) { // only pass through those with label bigger than Root's
4147 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1;
4148 *out << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl;
4149 // add the bond in between to the SP list
4150 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
4151 add(Binder, FragmentSearch.BondsPerSPList[2*(SP+1)+1]);
4152 FragmentSearch.BondsPerSPCount[SP+1]++;
4153 *out << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl;
4154 } else {
4155 if (OtherWalker != Predecessor)
4156 *out << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->nr << " is smaller than that of Root " << RootKeyNr << "." << endl;
4157 else
4158 *out << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl;
4159 }
4160 } else *out << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
4161 }
4162 }
4163 }
4164
4165 // outputting all list for debugging
4166 *out << Verbose(0) << "Printing all found lists." << endl;
4167 for(int i=1;i<Order;i++) { // skip the root edge in the printing
4168 Binder = FragmentSearch.BondsPerSPList[2*i];
4169 *out << Verbose(1) << "Current SP level is " << i << "." << endl;
4170 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4171 Binder = Binder->next;
4172 *out << Verbose(2) << *Binder << endl;
4173 }
4174 }
4175
4176 // creating fragments with the found edge sets (may be done in reverse order, faster)
4177 SP = -1; // the Root <-> Root edge must be subtracted!
4178 for(int i=Order;i--;) { // sum up all found edges
4179 Binder = FragmentSearch.BondsPerSPList[2*i];
4180 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4181 Binder = Binder->next;
4182 SP ++;
4183 }
4184 }
4185 *out << Verbose(0) << "Total number of edges is " << SP << "." << endl;
4186 if (SP >= (Order-1)) {
4187 // start with root (push on fragment stack)
4188 *out << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->nr << "." << endl;
4189 FragmentSearch.FragmentSet->clear();
4190 *out << Verbose(0) << "Preparing subset for this root and calling generator." << endl;
4191 // prepare the subset and call the generator
4192 BondsList = (bond **) Malloc(sizeof(bond *)*FragmentSearch.BondsPerSPCount[0], "molecule::PowerSetGenerator: **BondsList");
4193 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond
4194
4195 SPFragmentGenerator(out, &FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
4196
4197 Free((void **)&BondsList, "molecule::PowerSetGenerator: **BondsList");
4198 } else {
4199 *out << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl;
4200 }
4201
4202 // as FragmentSearch structure is used only once, we don't have to clean it anymore
4203 // remove root from stack
4204 *out << Verbose(0) << "Removing root again from stack." << endl;
4205 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr);
4206
4207 // free'ing the bonds lists
4208 *out << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl;
4209 for(int i=Order;i--;) {
4210 *out << Verbose(1) << "Current SP level is " << i << ": ";
4211 Binder = FragmentSearch.BondsPerSPList[2*i];
4212 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4213 Binder = Binder->next;
4214 // *out << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local
4215 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1;
4216 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1;
4217 }
4218 // delete added bonds
4219 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]);
4220 // also start and end node
4221 *out << "cleaned." << endl;
4222 }
4223
4224 // return list
4225 *out << Verbose(0) << "End of PowerSetGenerator." << endl;
4226 return (FragmentSearch.FragmentCounter - Counter);
4227};
4228
4229/** Corrects the nuclei position if the fragment was created over the cell borders.
4230 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
4231 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
4232 * and re-add the bond. Looping on the distance check.
4233 * \param *out ofstream for debugging messages
4234 */
4235void molecule::ScanForPeriodicCorrection(ofstream *out)
4236{
4237 bond *Binder = NULL;
4238 bond *OtherBinder = NULL;
4239 atom *Walker = NULL;
4240 atom *OtherWalker = NULL;
4241 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
4242 enum Shading *ColorList = NULL;
4243 double tmp;
4244 Vector Translationvector;
4245 //class StackClass<atom *> *CompStack = NULL;
4246 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
4247 bool flag = true;
4248
4249 *out << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl;
4250
4251 ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::ScanForPeriodicCorrection: *ColorList");
4252 while (flag) {
4253 // remove bonds that are beyond bonddistance
4254 for(int i=NDIM;i--;)
4255 Translationvector.x[i] = 0.;
4256 // scan all bonds
4257 Binder = first;
4258 flag = false;
4259 while ((!flag) && (Binder->next != last)) {
4260 Binder = Binder->next;
4261 for (int i=NDIM;i--;) {
4262 tmp = fabs(Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]);
4263 //*out << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
4264 if (tmp > BondDistance) {
4265 OtherBinder = Binder->next; // note down binding partner for later re-insertion
4266 unlink(Binder); // unlink bond
4267 *out << Verbose(2) << "Correcting at bond " << *Binder << "." << endl;
4268 flag = true;
4269 break;
4270 }
4271 }
4272 }
4273 if (flag) {
4274 // create translation vector from their periodically modified distance
4275 for (int i=NDIM;i--;) {
4276 tmp = Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i];
4277 if (fabs(tmp) > BondDistance)
4278 Translationvector.x[i] = (tmp < 0) ? +1. : -1.;
4279 }
4280 Translationvector.MatrixMultiplication(matrix);
4281 //*out << Verbose(3) << "Translation vector is ";
4282 Translationvector.Output(out);
4283 *out << endl;
4284 // apply to all atoms of first component via BFS
4285 for (int i=AtomCount;i--;)
4286 ColorList[i] = white;
4287 AtomStack->Push(Binder->leftatom);
4288 while (!AtomStack->IsEmpty()) {
4289 Walker = AtomStack->PopFirst();
4290 //*out << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
4291 ColorList[Walker->nr] = black; // mark as explored
4292 Walker->x.AddVector(&Translationvector); // translate
4293 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through all binding partners
4294 if (ListOfBondsPerAtom[Walker->nr][i] != Binder) {
4295 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
4296 if (ColorList[OtherWalker->nr] == white) {
4297 AtomStack->Push(OtherWalker); // push if yet unexplored
4298 }
4299 }
4300 }
4301 }
4302 // re-add bond
4303 link(Binder, OtherBinder);
4304 } else {
4305 *out << Verbose(3) << "No corrections for this fragment." << endl;
4306 }
4307 //delete(CompStack);
4308 }
4309
4310 // free allocated space from ReturnFullMatrixforSymmetric()
4311 delete(AtomStack);
4312 Free((void **)&ColorList, "molecule::ScanForPeriodicCorrection: *ColorList");
4313 Free((void **)&matrix, "molecule::ScanForPeriodicCorrection: *matrix");
4314 *out << Verbose(2) << "End of ScanForPeriodicCorrection." << endl;
4315};
4316
4317/** Blows the 6-dimensional \a cell_size array up to a full NDIM by NDIM matrix.
4318 * \param *symm 6-dim array of unique symmetric matrix components
4319 * \return allocated NDIM*NDIM array with the symmetric matrix
4320 */
4321double * molecule::ReturnFullMatrixforSymmetric(double *symm)
4322{
4323 double *matrix = (double *) Malloc(sizeof(double)*NDIM*NDIM, "molecule::ReturnFullMatrixforSymmetric: *matrix");
4324 matrix[0] = symm[0];
4325 matrix[1] = symm[1];
4326 matrix[2] = symm[3];
4327 matrix[3] = symm[1];
4328 matrix[4] = symm[2];
4329 matrix[5] = symm[4];
4330 matrix[6] = symm[3];
4331 matrix[7] = symm[4];
4332 matrix[8] = symm[5];
4333 return matrix;
4334};
4335
4336bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
4337{
4338 //cout << "my check is used." << endl;
4339 if (SubgraphA.size() < SubgraphB.size()) {
4340 return true;
4341 } else {
4342 if (SubgraphA.size() > SubgraphB.size()) {
4343 return false;
4344 } else {
4345 KeySet::iterator IteratorA = SubgraphA.begin();
4346 KeySet::iterator IteratorB = SubgraphB.begin();
4347 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
4348 if ((*IteratorA) < (*IteratorB))
4349 return true;
4350 else if ((*IteratorA) > (*IteratorB)) {
4351 return false;
4352 } // else, go on to next index
4353 IteratorA++;
4354 IteratorB++;
4355 } // end of while loop
4356 }// end of check in case of equal sizes
4357 }
4358 return false; // if we reach this point, they are equal
4359};
4360
4361//bool operator < (KeySet SubgraphA, KeySet SubgraphB)
4362//{
4363// return KeyCompare(SubgraphA, SubgraphB);
4364//};
4365
4366/** Checking whether KeySet is not already present in Graph, if so just adds factor.
4367 * \param *out output stream for debugging
4368 * \param &set KeySet to insert
4369 * \param &graph Graph to insert into
4370 * \param *counter pointer to unique fragment count
4371 * \param factor energy factor for the fragment
4372 */
4373inline void InsertFragmentIntoGraph(ofstream *out, struct UniqueFragments *Fragment)
4374{
4375 GraphTestPair testGraphInsert;
4376
4377 testGraphInsert = Fragment->Leaflet->insert(GraphPair (*Fragment->FragmentSet,pair<int,double>(Fragment->FragmentCounter,Fragment->TEFactor))); // store fragment number and current factor
4378 if (testGraphInsert.second) {
4379 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " successfully inserted." << endl;
4380 Fragment->FragmentCounter++;
4381 } else {
4382 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
4383 ((*(testGraphInsert.first)).second).second += Fragment->TEFactor; // increase the "created" counter
4384 *out << Verbose(2) << "New factor is " << ((*(testGraphInsert.first)).second).second << "." << endl;
4385 }
4386};
4387//void inline InsertIntoGraph(ofstream *out, KeyStack &stack, Graph &graph, int *counter, double factor)
4388//{
4389// // copy stack contents to set and call overloaded function again
4390// KeySet set;
4391// for(KeyStack::iterator runner = stack.begin(); runner != stack.begin(); runner++)
4392// set.insert((*runner));
4393// InsertIntoGraph(out, set, graph, counter, factor);
4394//};
4395
4396/** Inserts each KeySet in \a graph2 into \a graph1.
4397 * \param *out output stream for debugging
4398 * \param graph1 first (dest) graph
4399 * \param graph2 second (source) graph
4400 * \param *counter keyset counter that gets increased
4401 */
4402inline void InsertGraphIntoGraph(ofstream *out, Graph &graph1, Graph &graph2, int *counter)
4403{
4404 GraphTestPair testGraphInsert;
4405
4406 for(Graph::iterator runner = graph2.begin(); runner != graph2.end(); runner++) {
4407 testGraphInsert = graph1.insert(GraphPair ((*runner).first,pair<int,double>((*counter)++,((*runner).second).second))); // store fragment number and current factor
4408 if (testGraphInsert.second) {
4409 *out << Verbose(2) << "KeySet " << (*counter)-1 << " successfully inserted." << endl;
4410 } else {
4411 *out << Verbose(2) << "KeySet " << (*counter)-1 << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
4412 ((*(testGraphInsert.first)).second).second += (*runner).second.second;
4413 *out << Verbose(2) << "New factor is " << (*(testGraphInsert.first)).second.second << "." << endl;
4414 }
4415 }
4416};
4417
4418
4419/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
4420 * -# constructs a complete keyset of the molecule
4421 * -# In a loop over all possible roots from the given rootstack
4422 * -# increases order of root site
4423 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
4424 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
4425as the restricted one and each site in the set as the root)
4426 * -# these are merged into a fragment list of keysets
4427 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
4428 * Important only is that we create all fragments, it is not important if we create them more than once
4429 * as these copies are filtered out via use of the hash table (KeySet).
4430 * \param *out output stream for debugging
4431 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
4432 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
4433 * \param *MinimumRingSize minimum ring size for each atom (molecule::Atomcount)
4434 * \return pointer to Graph list
4435 */
4436void molecule::FragmentBOSSANOVA(ofstream *out, Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize)
4437{
4438 Graph ***FragmentLowerOrdersList = NULL;
4439 int NumLevels, NumMolecules, TotalNumMolecules = 0, *NumMoleculesOfOrder = NULL;
4440 int counter = 0, Order;
4441 int UpgradeCount = RootStack.size();
4442 KeyStack FragmentRootStack;
4443 int RootKeyNr, RootNr;
4444 struct UniqueFragments FragmentSearch;
4445
4446 *out << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl;
4447
4448 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
4449 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
4450 NumMoleculesOfOrder = (int *) Malloc(sizeof(int)*UpgradeCount, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
4451 FragmentLowerOrdersList = (Graph ***) Malloc(sizeof(Graph **)*UpgradeCount, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
4452
4453 // initialise the fragments structure
4454 FragmentSearch.ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *ShortestPathList");
4455 FragmentSearch.FragmentCounter = 0;
4456 FragmentSearch.FragmentSet = new KeySet;
4457 FragmentSearch.Root = FindAtom(RootKeyNr);
4458 for (int i=AtomCount;i--;) {
4459 FragmentSearch.ShortestPathList[i] = -1;
4460 }
4461
4462 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
4463 atom *Walker = start;
4464 KeySet CompleteMolecule;
4465 while (Walker->next != end) {
4466 Walker = Walker->next;
4467 CompleteMolecule.insert(Walker->GetTrueFather()->nr);
4468 }
4469
4470 // 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
4471 // 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),
4472 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
4473 // 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)
4474 RootNr = 0; // counts through the roots in RootStack
4475 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
4476 RootKeyNr = RootStack.front();
4477 RootStack.pop_front();
4478 Walker = FindAtom(RootKeyNr);
4479 // check cyclic lengths
4480 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) {
4481 // *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;
4482 //} else
4483 {
4484 // increase adaptive order by one
4485 Walker->GetTrueFather()->AdaptiveOrder++;
4486 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
4487
4488 // initialise Order-dependent entries of UniqueFragments structure
4489 FragmentSearch.BondsPerSPList = (bond **) Malloc(sizeof(bond *)*Order*2, "molecule::PowerSetGenerator: ***BondsPerSPList");
4490 FragmentSearch.BondsPerSPCount = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *BondsPerSPCount");
4491 for (int i=Order;i--;) {
4492 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node
4493 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node
4494 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two
4495 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i];
4496 FragmentSearch.BondsPerSPCount[i] = 0;
4497 }
4498
4499 // allocate memory for all lower level orders in this 1D-array of ptrs
4500 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
4501 FragmentLowerOrdersList[RootNr] = (Graph **) Malloc(sizeof(Graph *)*NumLevels, "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
4502 for (int i=0;i<NumLevels;i++)
4503 FragmentLowerOrdersList[RootNr][i] = NULL;
4504
4505 // create top order where nothing is reduced
4506 *out << Verbose(0) << "==============================================================================================================" << endl;
4507 *out << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl; // , NumLevels is " << NumLevels << "
4508
4509 // Create list of Graphs of current Bond Order (i.e. F_{ij})
4510 FragmentLowerOrdersList[RootNr][0] = new Graph;
4511 FragmentSearch.TEFactor = 1.;
4512 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
4513 FragmentSearch.Root = Walker;
4514 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(out, Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
4515 *out << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
4516 if (NumMoleculesOfOrder[RootNr] != 0) {
4517 NumMolecules = 0;
4518
4519 // we don't have to dive into suborders! These keysets are all already created on lower orders!
4520 // this was all ancient stuff, when we still depended on the TEFactors (and for those the suborders were needed)
4521
4522// if ((NumLevels >> 1) > 0) {
4523// // create lower order fragments
4524// *out << Verbose(0) << "Creating list of unique fragments of lower Bond Order terms to be subtracted." << endl;
4525// Order = Walker->AdaptiveOrder;
4526// 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)
4527// // step down to next order at (virtual) boundary of powers of 2 in array
4528// while (source >= (1 << (Walker->AdaptiveOrder-Order))) // (int)pow(2,Walker->AdaptiveOrder-Order))
4529// Order--;
4530// *out << Verbose(0) << "Current Order is: " << Order << "." << endl;
4531// for (int SubOrder=Order-1;SubOrder>0;SubOrder--) {
4532// int dest = source + (1 << (Walker->AdaptiveOrder-(SubOrder+1)));
4533// *out << Verbose(0) << "--------------------------------------------------------------------------------------------------------------" << endl;
4534// *out << Verbose(0) << "Current SubOrder is: " << SubOrder << " with source " << source << " to destination " << dest << "." << endl;
4535//
4536// // every molecule is split into a list of again (Order - 1) molecules, while counting all molecules
4537// //*out << Verbose(1) << "Splitting the " << (*FragmentLowerOrdersList[RootNr][source]).size() << " molecules of the " << source << "th cell in the array." << endl;
4538// //NumMolecules = 0;
4539// FragmentLowerOrdersList[RootNr][dest] = new Graph;
4540// for(Graph::iterator runner = (*FragmentLowerOrdersList[RootNr][source]).begin();runner != (*FragmentLowerOrdersList[RootNr][source]).end(); runner++) {
4541// for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
4542// Graph TempFragmentList;
4543// FragmentSearch.TEFactor = -(*runner).second.second;
4544// FragmentSearch.Leaflet = &TempFragmentList; // set to insertion graph
4545// FragmentSearch.Root = FindAtom(*sprinter);
4546// NumMoleculesOfOrder[RootNr] += PowerSetGenerator(out, SubOrder, FragmentSearch, (*runner).first);
4547// // insert new keysets FragmentList into FragmentLowerOrdersList[Walker->AdaptiveOrder-1][dest]
4548// *out << Verbose(1) << "Merging resulting key sets with those present in destination " << dest << "." << endl;
4549// InsertGraphIntoGraph(out, *FragmentLowerOrdersList[RootNr][dest], TempFragmentList, &NumMolecules);
4550// }
4551// }
4552// *out << Verbose(1) << "Number of resulting molecules for SubOrder " << SubOrder << " is: " << NumMolecules << "." << endl;
4553// }
4554// }
4555// }
4556 } else {
4557 Walker->GetTrueFather()->MaxOrder = true;
4558// *out << Verbose(1) << "Hence, we don't dive into SubOrders ... " << endl;
4559 }
4560 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
4561 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
4562 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
4563// *out << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
4564 RootStack.push_back(RootKeyNr); // put back on stack
4565 RootNr++;
4566
4567 // free Order-dependent entries of UniqueFragments structure for next loop cycle
4568 Free((void **)&FragmentSearch.BondsPerSPCount, "molecule::PowerSetGenerator: *BondsPerSPCount");
4569 for (int i=Order;i--;) {
4570 delete(FragmentSearch.BondsPerSPList[2*i]);
4571 delete(FragmentSearch.BondsPerSPList[2*i+1]);
4572 }
4573 Free((void **)&FragmentSearch.BondsPerSPList, "molecule::PowerSetGenerator: ***BondsPerSPList");
4574 }
4575 }
4576 *out << Verbose(0) << "==============================================================================================================" << endl;
4577 *out << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl;
4578 *out << Verbose(0) << "==============================================================================================================" << endl;
4579
4580 // cleanup FragmentSearch structure
4581 Free((void **)&FragmentSearch.ShortestPathList, "molecule::PowerSetGenerator: *ShortestPathList");
4582 delete(FragmentSearch.FragmentSet);
4583
4584 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
4585 // 5433222211111111
4586 // 43221111
4587 // 3211
4588 // 21
4589 // 1
4590
4591 // Subsequently, we combine all into a single list (FragmentList)
4592
4593 *out << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl;
4594 if (FragmentList == NULL) {
4595 FragmentList = new Graph;
4596 counter = 0;
4597 } else {
4598 counter = FragmentList->size();
4599 }
4600 RootNr = 0;
4601 while (!RootStack.empty()) {
4602 RootKeyNr = RootStack.front();
4603 RootStack.pop_front();
4604 Walker = FindAtom(RootKeyNr);
4605 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
4606 for(int i=0;i<NumLevels;i++) {
4607 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
4608 InsertGraphIntoGraph(out, *FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
4609 delete(FragmentLowerOrdersList[RootNr][i]);
4610 }
4611 }
4612 Free((void **)&FragmentLowerOrdersList[RootNr], "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
4613 RootNr++;
4614 }
4615 Free((void **)&FragmentLowerOrdersList, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
4616 Free((void **)&NumMoleculesOfOrder, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
4617
4618 *out << Verbose(0) << "End of FragmentBOSSANOVA." << endl;
4619};
4620
4621/** Comparison function for GSL heapsort on distances in two molecules.
4622 * \param *a
4623 * \param *b
4624 * \return <0, \a *a less than \a *b, ==0 if equal, >0 \a *a greater than \a *b
4625 */
4626inline int CompareDoubles (const void * a, const void * b)
4627{
4628 if (*(double *)a > *(double *)b)
4629 return -1;
4630 else if (*(double *)a < *(double *)b)
4631 return 1;
4632 else
4633 return 0;
4634};
4635
4636/** Determines whether two molecules actually contain the same atoms and coordination.
4637 * \param *out output stream for debugging
4638 * \param *OtherMolecule the molecule to compare this one to
4639 * \param threshold upper limit of difference when comparing the coordination.
4640 * \return NULL - not equal, otherwise an allocated (molecule::AtomCount) permutation map of the atom numbers (which corresponds to which)
4641 */
4642int * molecule::IsEqualToWithinThreshold(ofstream *out, molecule *OtherMolecule, double threshold)
4643{
4644 int flag;
4645 double *Distances = NULL, *OtherDistances = NULL;
4646 Vector CenterOfGravity, OtherCenterOfGravity;
4647 size_t *PermMap = NULL, *OtherPermMap = NULL;
4648 int *PermutationMap = NULL;
4649 atom *Walker = NULL;
4650 bool result = true; // status of comparison
4651
4652 *out << Verbose(3) << "Begin of IsEqualToWithinThreshold." << endl;
4653 /// first count both their atoms and elements and update lists thereby ...
4654 //*out << Verbose(0) << "Counting atoms, updating list" << endl;
4655 CountAtoms(out);
4656 OtherMolecule->CountAtoms(out);
4657 CountElements();
4658 OtherMolecule->CountElements();
4659
4660 /// ... and compare:
4661 /// -# AtomCount
4662 if (result) {
4663 if (AtomCount != OtherMolecule->AtomCount) {
4664 *out << Verbose(4) << "AtomCounts don't match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
4665 result = false;
4666 } else *out << Verbose(4) << "AtomCounts match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
4667 }
4668 /// -# ElementCount
4669 if (result) {
4670 if (ElementCount != OtherMolecule->ElementCount) {
4671 *out << Verbose(4) << "ElementCount don't match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
4672 result = false;
4673 } else *out << Verbose(4) << "ElementCount match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
4674 }
4675 /// -# ElementsInMolecule
4676 if (result) {
4677 for (flag=MAX_ELEMENTS;flag--;) {
4678 //*out << Verbose(5) << "Element " << flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl;
4679 if (ElementsInMolecule[flag] != OtherMolecule->ElementsInMolecule[flag])
4680 break;
4681 }
4682 if (flag < MAX_ELEMENTS) {
4683 *out << Verbose(4) << "ElementsInMolecule don't match." << endl;
4684 result = false;
4685 } else *out << Verbose(4) << "ElementsInMolecule match." << endl;
4686 }
4687 /// then determine and compare center of gravity for each molecule ...
4688 if (result) {
4689 *out << Verbose(5) << "Calculating Centers of Gravity" << endl;
4690 DetermineCenter(CenterOfGravity);
4691 OtherMolecule->DetermineCenter(OtherCenterOfGravity);
4692 *out << Verbose(5) << "Center of Gravity: ";
4693 CenterOfGravity.Output(out);
4694 *out << endl << Verbose(5) << "Other Center of Gravity: ";
4695 OtherCenterOfGravity.Output(out);
4696 *out << endl;
4697 if (CenterOfGravity.Distance(&OtherCenterOfGravity) > threshold) {
4698 *out << Verbose(4) << "Centers of gravity don't match." << endl;
4699 result = false;
4700 }
4701 }
4702
4703 /// ... then make a list with the euclidian distance to this center for each atom of both molecules
4704 if (result) {
4705 *out << Verbose(5) << "Calculating distances" << endl;
4706 Distances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: Distances");
4707 OtherDistances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: OtherDistances");
4708 Walker = start;
4709 while (Walker->next != end) {
4710 Walker = Walker->next;
4711 Distances[Walker->nr] = CenterOfGravity.Distance(&Walker->x);
4712 }
4713 Walker = OtherMolecule->start;
4714 while (Walker->next != OtherMolecule->end) {
4715 Walker = Walker->next;
4716 OtherDistances[Walker->nr] = OtherCenterOfGravity.Distance(&Walker->x);
4717 }
4718
4719 /// ... sort each list (using heapsort (o(N log N)) from GSL)
4720 *out << Verbose(5) << "Sorting distances" << endl;
4721 PermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermMap");
4722 OtherPermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
4723 gsl_heapsort_index (PermMap, Distances, AtomCount, sizeof(double), CompareDoubles);
4724 gsl_heapsort_index (OtherPermMap, OtherDistances, AtomCount, sizeof(double), CompareDoubles);
4725 PermutationMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermutationMap");
4726 *out << Verbose(5) << "Combining Permutation Maps" << endl;
4727 for(int i=AtomCount;i--;)
4728 PermutationMap[PermMap[i]] = (int) OtherPermMap[i];
4729
4730 /// ... and compare them step by step, whether the difference is individiually(!) below \a threshold for all
4731 *out << Verbose(4) << "Comparing distances" << endl;
4732 flag = 0;
4733 for (int i=0;i<AtomCount;i++) {
4734 *out << Verbose(5) << "Distances: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " << threshold << endl;
4735 if (fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) > threshold)
4736 flag = 1;
4737 }
4738 Free((void **)&PermMap, "molecule::IsEqualToWithinThreshold: *PermMap");
4739 Free((void **)&OtherPermMap, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
4740
4741 /// free memory
4742 Free((void **)&Distances, "molecule::IsEqualToWithinThreshold: Distances");
4743 Free((void **)&OtherDistances, "molecule::IsEqualToWithinThreshold: OtherDistances");
4744 if (flag) { // if not equal
4745 Free((void **)&PermutationMap, "molecule::IsEqualToWithinThreshold: *PermutationMap");
4746 result = false;
4747 }
4748 }
4749 /// return pointer to map if all distances were below \a threshold
4750 *out << Verbose(3) << "End of IsEqualToWithinThreshold." << endl;
4751 if (result) {
4752 *out << Verbose(3) << "Result: Equal." << endl;
4753 return PermutationMap;
4754 } else {
4755 *out << Verbose(3) << "Result: Not equal." << endl;
4756 return NULL;
4757 }
4758};
4759
4760/** Returns an index map for two father-son-molecules.
4761 * The map tells which atom in this molecule corresponds to which one in the other molecul with their fathers.
4762 * \param *out output stream for debugging
4763 * \param *OtherMolecule corresponding molecule with fathers
4764 * \return allocated map of size molecule::AtomCount with map
4765 * \todo make this with a good sort O(n), not O(n^2)
4766 */
4767int * molecule::GetFatherSonAtomicMap(ofstream *out, molecule *OtherMolecule)
4768{
4769 atom *Walker = NULL, *OtherWalker = NULL;
4770 *out << Verbose(3) << "Begin of GetFatherAtomicMap." << endl;
4771 int *AtomicMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::GetAtomicMap: *AtomicMap"); //Calloc
4772 for (int i=AtomCount;i--;)
4773 AtomicMap[i] = -1;
4774 if (OtherMolecule == this) { // same molecule
4775 for (int i=AtomCount;i--;) // no need as -1 means already that there is trivial correspondence
4776 AtomicMap[i] = i;
4777 *out << Verbose(4) << "Map is trivial." << endl;
4778 } else {
4779 *out << Verbose(4) << "Map is ";
4780 Walker = start;
4781 while (Walker->next != end) {
4782 Walker = Walker->next;
4783 if (Walker->father == NULL) {
4784 AtomicMap[Walker->nr] = -2;
4785 } else {
4786 OtherWalker = OtherMolecule->start;
4787 while (OtherWalker->next != OtherMolecule->end) {
4788 OtherWalker = OtherWalker->next;
4789 //for (int i=0;i<AtomCount;i++) { // search atom
4790 //for (int j=0;j<OtherMolecule->AtomCount;j++) {
4791 //*out << Verbose(4) << "Comparing father " << Walker->father << " with the other one " << OtherWalker->father << "." << endl;
4792 if (Walker->father == OtherWalker)
4793 AtomicMap[Walker->nr] = OtherWalker->nr;
4794 }
4795 }
4796 *out << AtomicMap[Walker->nr] << "\t";
4797 }
4798 *out << endl;
4799 }
4800 *out << Verbose(3) << "End of GetFatherAtomicMap." << endl;
4801 return AtomicMap;
4802};
4803
4804/** Stores the temperature evaluated from velocities in molecule::Trajectories.
4805 * We simply use the formula equivaleting temperature and kinetic energy:
4806 * \f$k_B T = \sum_i m_i v_i^2\f$
4807 * \param *out output stream for debugging
4808 * \param startstep first MD step in molecule::Trajectories
4809 * \param endstep last plus one MD step in molecule::Trajectories
4810 * \param *output output stream of temperature file
4811 * \return file written (true), failure on writing file (false)
4812 */
4813bool molecule::OutputTemperatureFromTrajectories(ofstream *out, int startstep, int endstep, ofstream *output)
4814{
4815 double temperature;
4816 atom *Walker = NULL;
4817 // test stream
4818 if (output == NULL)
4819 return false;
4820 else
4821 *output << "# Step Temperature [K] Temperature [a.u.]" << endl;
4822 for (int step=startstep;step < endstep; step++) { // loop over all time steps
4823 temperature = 0.;
4824 Walker = start;
4825 while (Walker->next != end) {
4826 Walker = Walker->next;
4827 for (int i=NDIM;i--;)
4828 temperature += Walker->type->mass * Trajectories[Walker].U.at(step).x[i]* Trajectories[Walker].U.at(step).x[i];
4829 }
4830 *output << step << "\t" << temperature*AtomicEnergyToKelvin << "\t" << temperature << endl;
4831 }
4832 return true;
4833};
Note: See TracBrowser for help on using the repository browser.