source: molecuilder/src/molecules.cpp@ 644ba1

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

Adaptivity fixes, MD by VerletForceIntegration introduced, MD molecule::Trajectories, atom Max::Order, no more recursive going down the fragmentation level

MD
==
molecule::Trajectories is now a map to a struct trajectory list of all the MD steps.
struct Trajectory contains STL vectors of coordinates, velocities and forces. Both are needed for the new VerletForceIntegration.
Parsing of coordinates, velocities and forces from the config file was completely rewritten:

  • in the FastParsing case, we just scan for IonType1_1 to find the last step, set the file pointer there and scan all remaining ones
  • in the other case, we create the atoms in the first step and put them in a hash for lookup on later steps and read in sequentially (with file pointer moving on).
  • This is a lot faster than the old variant.

VerletForceIntegration() implemented in a working manner with force smoothing (mean of actual and last one).
OutputTrajectoriesXYZ() now concatenates the single MD steps into one xyz file, so that the animation can be viewed with e.g. jmol or vmd
config:Deltat is now public (lazy me) and set to 1 instead of 0 initially, also Deltat is parsed accordingly (if not present, defaults to 1)
MatrixContainer::ParseMatrix from parser.cpp is used during VerletForceIntegration() to parse the forces file. Consequently, we have included parser.* in the Makefile.am.
Fix: MoleculeListClass::OutputConfigForListOfFragments() stores config file under config::configpath, before it backup'd the path twice to PathBackup.

Adaptivity
==========
Adaptivity (CheckOrderAtSite()) had compared not absolute, but real values which caused sign problems and faulty behaviour.
Adapatvity (CheckOrderAtSite()) had included atoms by Order (desired one) not by FragOrder (current one) into the list of candidates, which caused faulty behaviour.
CheckOrderAtSite() did single stepping wrong as the mask bit (last in AtomMask) was checked for true not false! Also bit was not set to false initially in FragmentMolecule().
Adaptivity: FragmentMolecule now returns 1 - continue, 2 - don't ... to tell whether we still have to continue with the adaptive cycle (is given as return value from molecuilder)
introduced atom::MaxOrder
StoreOrderAtSiteFile() now also stores the MaxOrder and ParseOrderAtSiteFromFile() parses it back into atom class

Removed Fragmentation Recursion
===============================
As we switched in the prelude of the adaptivity to a monotonous increase from order 1 to the desired one, we don't need to recursively go down each level from a given current bond order, as all these fragments have already been created on the lower orders. Consequently, FragmentBOSSANOVA does not contain NumLevels or alike anymore. This simplified the code a bit, but probably is not yet completely done. (but is working, checked on heptan).
SPFragmentGenerator() does not need Labels anymore, global ones are used for checks. Consequently, PowerSetGenerator() and FragmentSearch structure don't initialise/contain them anymore. We always compare against ...->GetTrueFather()->nr.

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