source: molecuilder/src/molecules.cpp@ 32b6dc

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

Working version of PAS transformation (tested on C-S-H cluster) and code scaffold of VolumeOfConvexEnvelope that's untested so far

PAS simply calculates inertia tensor, diagonalizes it via GSL and transforms molecule into eigenvector system such that z axis is eigenvector of biggest eigenvalue.

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