source: src/molecules.cpp@ a80fbdf

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since a80fbdf was a80fbdf, checked in by Frederik Heber <heber@…>, 16 years ago

class config definitions moved to their own header file.

NOTE: Tesselation of heptan was working correctly! (The config file just grew bigger and bigger that's why more and more triangles were added)

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