source: src/molecules.cpp@ 9ba9ee

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

formula typo in molecule::PrincipalAxisSystem() fixed

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