source: src/molecules.cpp@ 03e57a

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 03e57a was 03e57a, checked in by Frederik Heber <heber@…>, 16 years ago

Smaller FIXES to molecule class

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