source: src/molecules.cpp@ 54a746

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 54a746 was 54a746, checked in by Frederik Heber <heber@…>, 15 years ago

Incorporation of Unit test on class Vector.

  • new file leastsquaremin.[ch]pp has least square minimisation which is otherwise unclean between classes molecules and Vector

Unit test (later tests rely on good results of earlier ones)

changes to class Vector:

  • Vector::IsNull() -> IsZero()
  • new function Vector::IsOne() similar to IsZero()
  • BUGFIX: Vector::IsNULL() (thx to unit test :)
  • Tesselation::getAngle() changed due to above rename
  • Property mode set to 100755
File size: 247.9 KB
Line 
1/** \file molecules.cpp
2 *
3 * Functions for the class molecule.
4 *
5 */
6
7#include "config.hpp"
8#include "molecules.hpp"
9
10/************************************* 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}$ 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 */
3725bool molecule::CreateMappingLabelsToConfigSequence(ofstream *out, int *&SortIndex)
3726{
3727 element *runner = elemente->start;
3728 int AtomNo = 0;
3729 atom *Walker = NULL;
3730
3731 if (SortIndex != NULL) {
3732 *out << Verbose(1) << "SortIndex is " << SortIndex << " and not NULL as expected." << endl;
3733 return false;
3734 }
3735 SortIndex = (int *) Malloc(sizeof(int)*AtomCount, "molecule::FragmentMolecule: *SortIndex");
3736 for(int i=AtomCount;i--;)
3737 SortIndex[i] = -1;
3738 while (runner->next != elemente->end) { // go through every element
3739 runner = runner->next;
3740 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
3741 Walker = start;
3742 while (Walker->next != end) { // go through every atom of this element
3743 Walker = Walker->next;
3744 if (Walker->type->Z == runner->Z) // if this atom fits to element
3745 SortIndex[Walker->nr] = AtomNo++;
3746 }
3747 }
3748 }
3749 return true;
3750};
3751
3752/** Performs a many-body bond order analysis for a given bond order.
3753 * -# parses adjacency, keysets and orderatsite files
3754 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
3755 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
3756y contribution", and that's why this consciously not done in the following loop)
3757 * -# in a loop over all subgraphs
3758 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
3759 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
3760 * -# combines the generated molecule lists from all subgraphs
3761 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
3762 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
3763 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
3764 * subgraph in the MoleculeListClass.
3765 * \param *out output stream for debugging
3766 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
3767 * \param *configuration configuration for writing config files for each fragment
3768 * \return 1 - continue, 2 - stop (no fragmentation occured)
3769 */
3770int molecule::FragmentMolecule(ofstream *out, int Order, config *configuration)
3771{
3772 MoleculeListClass *BondFragments = NULL;
3773 int *SortIndex = NULL;
3774 int *MinimumRingSize = new int[AtomCount];
3775 int FragmentCounter;
3776 MoleculeLeafClass *MolecularWalker = NULL;
3777 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
3778 fstream File;
3779 bool FragmentationToDo = true;
3780 class StackClass<bond *> *BackEdgeStack = NULL, *LocalBackEdgeStack = NULL;
3781 bool CheckOrder = false;
3782 Graph **FragmentList = NULL;
3783 Graph *ParsedFragmentList = NULL;
3784 Graph TotalGraph; // graph with all keysets however local numbers
3785 int TotalNumberOfKeySets = 0;
3786 atom **ListOfAtoms = NULL;
3787 atom ***ListOfLocalAtoms = NULL;
3788 bool *AtomMask = NULL;
3789
3790 *out << endl;
3791#ifdef ADDHYDROGEN
3792 *out << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl;
3793#else
3794 *out << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl;
3795#endif
3796
3797 // ++++++++++++++++++++++++++++ INITIAL STUFF: Bond structure analysis, file parsing, ... ++++++++++++++++++++++++++++++++++++++++++
3798
3799 // ===== 1. Check whether bond structure is same as stored in files ====
3800
3801 // fill the adjacency list
3802 CreateListOfBondsPerAtom(out);
3803
3804 // create lookup table for Atom::nr
3805 FragmentationToDo = FragmentationToDo && CreateFatherLookupTable(out, start, end, ListOfAtoms, AtomCount);
3806
3807 // === compare it with adjacency file ===
3808 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(out, configuration->configpath, ListOfAtoms);
3809 Free((void **)&ListOfAtoms, "molecule::FragmentMolecule - **ListOfAtoms");
3810
3811 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
3812 Subgraphs = DepthFirstSearchAnalysis(out, BackEdgeStack);
3813 // fill the bond structure of the individually stored subgraphs
3814 Subgraphs->next->FillBondStructureFromReference(out, this, (FragmentCounter = 0), ListOfLocalAtoms, false); // we want to keep the created ListOfLocalAtoms
3815 // analysis of the cycles (print rings, get minimum cycle length) for each subgraph
3816 for(int i=AtomCount;i--;)
3817 MinimumRingSize[i] = AtomCount;
3818 MolecularWalker = Subgraphs;
3819 FragmentCounter = 0;
3820 while (MolecularWalker->next != NULL) {
3821 MolecularWalker = MolecularWalker->next;
3822 *out << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl;
3823 LocalBackEdgeStack = new StackClass<bond *> (MolecularWalker->Leaf->BondCount);
3824// // check the list of local atoms for debugging
3825// *out << Verbose(0) << "ListOfLocalAtoms for this subgraph is:" << endl;
3826// for (int i=0;i<AtomCount;i++)
3827// if (ListOfLocalAtoms[FragmentCounter][i] == NULL)
3828// *out << "\tNULL";
3829// else
3830// *out << "\t" << ListOfLocalAtoms[FragmentCounter][i]->Name;
3831 *out << Verbose(0) << "Gathering local back edges for subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl;
3832 MolecularWalker->Leaf->PickLocalBackEdges(out, ListOfLocalAtoms[FragmentCounter++], BackEdgeStack, LocalBackEdgeStack);
3833 *out << Verbose(0) << "Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl;
3834 MolecularWalker->Leaf->CyclicStructureAnalysis(out, LocalBackEdgeStack, MinimumRingSize);
3835 *out << Verbose(0) << "Done with Analysing the cycles of subgraph " << MolecularWalker->Leaf << " with nr. " << FragmentCounter << "." << endl;
3836 delete(LocalBackEdgeStack);
3837 }
3838
3839 // ===== 3. if structure still valid, parse key set file and others =====
3840 FragmentationToDo = FragmentationToDo && ParseKeySetFile(out, configuration->configpath, ParsedFragmentList);
3841
3842 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
3843 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(out, configuration->configpath);
3844
3845 // =================================== Begin of FRAGMENTATION ===============================
3846 // ===== 6a. assign each keyset to its respective subgraph =====
3847 Subgraphs->next->AssignKeySetsToFragment(out, this, ParsedFragmentList, ListOfLocalAtoms, FragmentList, (FragmentCounter = 0), true);
3848
3849 // ===== 6b. prepare and go into the adaptive (Order<0), single-step (Order==0) or incremental (Order>0) cycle
3850 KeyStack *RootStack = new KeyStack[Subgraphs->next->Count()];
3851 AtomMask = new bool[AtomCount+1];
3852 AtomMask[AtomCount] = false;
3853 FragmentationToDo = false; // if CheckOrderAtSite just ones recommends fragmentation, we will save fragments afterwards
3854 while ((CheckOrder = CheckOrderAtSite(out, AtomMask, ParsedFragmentList, Order, MinimumRingSize, configuration->configpath))) {
3855 FragmentationToDo = FragmentationToDo || CheckOrder;
3856 AtomMask[AtomCount] = true; // last plus one entry is used as marker that we have been through this loop once already in CheckOrderAtSite()
3857 // ===== 6b. fill RootStack for each subgraph (second adaptivity check) =====
3858 Subgraphs->next->FillRootStackForSubgraphs(out, RootStack, AtomMask, (FragmentCounter = 0));
3859
3860 // ===== 7. fill the bond fragment list =====
3861 FragmentCounter = 0;
3862 MolecularWalker = Subgraphs;
3863 while (MolecularWalker->next != NULL) {
3864 MolecularWalker = MolecularWalker->next;
3865 *out << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl;
3866 //MolecularWalker->Leaf->OutputListOfBonds(out); // output ListOfBondsPerAtom for debugging
3867 if (MolecularWalker->Leaf->first->next != MolecularWalker->Leaf->last) {
3868 // call BOSSANOVA method
3869 *out << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl;
3870 MolecularWalker->Leaf->FragmentBOSSANOVA(out, FragmentList[FragmentCounter], RootStack[FragmentCounter], MinimumRingSize);
3871 } else {
3872 cerr << "Subgraph " << MolecularWalker << " has no atoms!" << endl;
3873 }
3874 FragmentCounter++; // next fragment list
3875 }
3876 }
3877 delete[](RootStack);
3878 delete[](AtomMask);
3879 delete(ParsedFragmentList);
3880 delete[](MinimumRingSize);
3881
3882
3883 // ==================================== End of FRAGMENTATION ============================================
3884
3885 // ===== 8a. translate list into global numbers (i.e. ones that are valid in "this" molecule, not in MolecularWalker->Leaf)
3886 Subgraphs->next->TranslateIndicesToGlobalIDs(out, FragmentList, (FragmentCounter = 0), TotalNumberOfKeySets, TotalGraph);
3887
3888 // free subgraph memory again
3889 FragmentCounter = 0;
3890 if (Subgraphs != NULL) {
3891 while (Subgraphs->next != NULL) {
3892 Subgraphs = Subgraphs->next;
3893 delete(FragmentList[FragmentCounter++]);
3894 delete(Subgraphs->previous);
3895 }
3896 delete(Subgraphs);
3897 }
3898 Free((void **)&FragmentList, "molecule::FragmentMolecule - **FragmentList");
3899
3900 // ===== 8b. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
3901 //if (FragmentationToDo) { // we should always store the fragments again as coordination might have changed slightly without changing bond structure
3902 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
3903 BondFragments = new MoleculeListClass();
3904 int k=0;
3905 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
3906 KeySet test = (*runner).first;
3907 *out << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl;
3908 BondFragments->insert(StoreFragmentFromKeySet(out, test, configuration));
3909 k++;
3910 }
3911 *out << k << "/" << BondFragments->ListOfMolecules.size() << " fragments generated from the keysets." << endl;
3912
3913 // ===== 9. Save fragments' configuration and keyset files et al to disk ===
3914 if (BondFragments->ListOfMolecules.size() != 0) {
3915 // create the SortIndex from BFS labels to order in the config file
3916 CreateMappingLabelsToConfigSequence(out, SortIndex);
3917
3918 *out << Verbose(1) << "Writing " << BondFragments->ListOfMolecules.size() << " possible bond fragmentation configs" << endl;
3919 if (BondFragments->OutputConfigForListOfFragments(out, configuration, SortIndex))
3920 *out << Verbose(1) << "All configs written." << endl;
3921 else
3922 *out << Verbose(1) << "Some config writing failed." << endl;
3923
3924 // store force index reference file
3925 BondFragments->StoreForcesFile(out, configuration->configpath, SortIndex);
3926
3927 // store keysets file
3928 StoreKeySetFile(out, TotalGraph, configuration->configpath);
3929
3930 // store Adjacency file
3931 StoreAdjacencyToFile(out, configuration->configpath);
3932
3933 // store Hydrogen saturation correction file
3934 BondFragments->AddHydrogenCorrection(out, configuration->configpath);
3935
3936 // store adaptive orders into file
3937 StoreOrderAtSiteFile(out, configuration->configpath);
3938
3939 // restore orbital and Stop values
3940 CalculateOrbitals(*configuration);
3941
3942 // free memory for bond part
3943 *out << Verbose(1) << "Freeing bond memory" << endl;
3944 delete(FragmentList); // remove bond molecule from memory
3945 Free((void **)&SortIndex, "molecule::FragmentMolecule: *SortIndex");
3946 } else
3947 *out << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl;
3948 //} else
3949 // *out << Verbose(1) << "No fragments to store." << endl;
3950 *out << Verbose(0) << "End of bond fragmentation." << endl;
3951
3952 return ((int)(!FragmentationToDo)+1); // 1 - continue, 2 - stop (no fragmentation occured)
3953};
3954
3955
3956/** Picks from a global stack with all back edges the ones in the fragment.
3957 * \param *out output stream for debugging
3958 * \param **ListOfLocalAtoms array of father atom::nr to local atom::nr (reverse of atom::father)
3959 * \param *ReferenceStack stack with all the back egdes
3960 * \param *LocalStack stack to be filled
3961 * \return true - everything ok, false - ReferenceStack was empty
3962 */
3963bool molecule::PickLocalBackEdges(ofstream *out, atom **ListOfLocalAtoms, class StackClass<bond *> *&ReferenceStack, class StackClass<bond *> *&LocalStack)
3964{
3965 bool status = true;
3966 if (ReferenceStack->IsEmpty()) {
3967 cerr << "ReferenceStack is empty!" << endl;
3968 return false;
3969 }
3970 bond *Binder = ReferenceStack->PopFirst();
3971 bond *FirstBond = Binder; // mark the first bond, so that we don't loop through the stack indefinitely
3972 atom *Walker = NULL, *OtherAtom = NULL;
3973 ReferenceStack->Push(Binder);
3974
3975 do { // go through all bonds and push local ones
3976 Walker = ListOfLocalAtoms[Binder->leftatom->nr]; // get one atom in the reference molecule
3977 if (Walker != NULL) // if this Walker exists in the subgraph ...
3978 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through the local list of bonds
3979 OtherAtom = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
3980 if (OtherAtom == ListOfLocalAtoms[Binder->rightatom->nr]) { // found the bond
3981 LocalStack->Push(ListOfBondsPerAtom[Walker->nr][i]);
3982 *out << Verbose(3) << "Found local edge " << *(ListOfBondsPerAtom[Walker->nr][i]) << "." << endl;
3983 break;
3984 }
3985 }
3986 Binder = ReferenceStack->PopFirst(); // loop the stack for next item
3987 *out << Verbose(3) << "Current candidate edge " << Binder << "." << endl;
3988 ReferenceStack->Push(Binder);
3989 } while (FirstBond != Binder);
3990
3991 return status;
3992};
3993
3994/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
3995 * Atoms not present in the file get "-1".
3996 * \param *out output stream for debugging
3997 * \param *path path to file ORDERATSITEFILE
3998 * \return true - file writable, false - not writable
3999 */
4000bool molecule::StoreOrderAtSiteFile(ofstream *out, char *path)
4001{
4002 stringstream line;
4003 ofstream file;
4004
4005 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
4006 file.open(line.str().c_str());
4007 *out << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl;
4008 if (file != NULL) {
4009 atom *Walker = start;
4010 while (Walker->next != end) {
4011 Walker = Walker->next;
4012 file << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << endl;
4013 *out << Verbose(2) << "Storing: " << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "\t" << (int)Walker->MaxOrder << "." << endl;
4014 }
4015 file.close();
4016 *out << Verbose(1) << "done." << endl;
4017 return true;
4018 } else {
4019 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
4020 return false;
4021 }
4022};
4023
4024/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
4025 * Atoms not present in the file get "0".
4026 * \param *out output stream for debugging
4027 * \param *path path to file ORDERATSITEFILEe
4028 * \return true - file found and scanned, false - file not found
4029 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
4030 */
4031bool molecule::ParseOrderAtSiteFromFile(ofstream *out, char *path)
4032{
4033 unsigned char *OrderArray = (unsigned char *) Malloc(sizeof(unsigned char)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
4034 bool *MaxArray = (bool *) Malloc(sizeof(bool)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
4035 bool status;
4036 int AtomNr, value;
4037 stringstream line;
4038 ifstream file;
4039
4040 *out << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl;
4041 for(int i=AtomCount;i--;)
4042 OrderArray[i] = 0;
4043 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
4044 file.open(line.str().c_str());
4045 if (file != NULL) {
4046 for (int i=AtomCount;i--;) { // initialise with 0
4047 OrderArray[i] = 0;
4048 MaxArray[i] = 0;
4049 }
4050 while (!file.eof()) { // parse from file
4051 AtomNr = -1;
4052 file >> AtomNr;
4053 if (AtomNr != -1) { // test whether we really parsed something (this is necessary, otherwise last atom is set twice and to 0 on second time)
4054 file >> value;
4055 OrderArray[AtomNr] = value;
4056 file >> value;
4057 MaxArray[AtomNr] = value;
4058 //*out << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << " and max order set to " << (int)MaxArray[AtomNr] << "." << endl;
4059 }
4060 }
4061 atom *Walker = start;
4062 while (Walker->next != end) { // fill into atom classes
4063 Walker = Walker->next;
4064 Walker->AdaptiveOrder = OrderArray[Walker->nr];
4065 Walker->MaxOrder = MaxArray[Walker->nr];
4066 *out << Verbose(2) << *Walker << " gets order " << (int)Walker->AdaptiveOrder << " and is " << (!Walker->MaxOrder ? "not " : " ") << "maxed." << endl;
4067 }
4068 file.close();
4069 *out << Verbose(1) << "done." << endl;
4070 status = true;
4071 } else {
4072 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
4073 status = false;
4074 }
4075 Free((void **)&OrderArray, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
4076 Free((void **)&MaxArray, "molecule::ParseOrderAtSiteFromFile - *MaxArray");
4077
4078 *out << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl;
4079 return status;
4080};
4081
4082/** Creates an 2d array of pointer with an entry for each atom and each bond it has.
4083 * Updates molecule::ListOfBondsPerAtom, molecule::NumberOfBondsPerAtom by parsing through
4084 * bond chain list, using molecule::AtomCount and molecule::BondCount.
4085 * Allocates memory, fills the array and exits
4086 * \param *out output stream for debugging
4087 */
4088void molecule::CreateListOfBondsPerAtom(ofstream *out)
4089{
4090 bond *Binder = NULL;
4091 atom *Walker = NULL;
4092 int TotalDegree;
4093 *out << Verbose(1) << "Begin of Creating ListOfBondsPerAtom: AtomCount = " << AtomCount << "\tBondCount = " << BondCount << "\tNoNonBonds = " << NoNonBonds << "." << endl;
4094
4095 // re-allocate memory
4096 *out << Verbose(2) << "(Re-)Allocating memory." << endl;
4097 if (ListOfBondsPerAtom != NULL) {
4098 for(int i=AtomCount;i--;)
4099 Free((void **)&ListOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom[i]");
4100 Free((void **)&ListOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom");
4101 }
4102 if (NumberOfBondsPerAtom != NULL)
4103 Free((void **)&NumberOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: NumberOfBondsPerAtom");
4104 ListOfBondsPerAtom = (bond ***) Malloc(sizeof(bond **)*AtomCount, "molecule::CreateListOfBondsPerAtom: ***ListOfBondsPerAtom");
4105 NumberOfBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfBondsPerAtom: *NumberOfBondsPerAtom");
4106
4107 // reset bond counts per atom
4108 for(int i=AtomCount;i--;)
4109 NumberOfBondsPerAtom[i] = 0;
4110 // count bonds per atom
4111 Binder = first;
4112 while (Binder->next != last) {
4113 Binder = Binder->next;
4114 NumberOfBondsPerAtom[Binder->leftatom->nr]++;
4115 NumberOfBondsPerAtom[Binder->rightatom->nr]++;
4116 }
4117 for(int i=AtomCount;i--;) {
4118 // allocate list of bonds per atom
4119 ListOfBondsPerAtom[i] = (bond **) Malloc(sizeof(bond *)*NumberOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: **ListOfBondsPerAtom[]");
4120 // clear the list again, now each NumberOfBondsPerAtom marks current free field
4121 NumberOfBondsPerAtom[i] = 0;
4122 }
4123 // fill the list
4124 Binder = first;
4125 while (Binder->next != last) {
4126 Binder = Binder->next;
4127 ListOfBondsPerAtom[Binder->leftatom->nr][NumberOfBondsPerAtom[Binder->leftatom->nr]++] = Binder;
4128 ListOfBondsPerAtom[Binder->rightatom->nr][NumberOfBondsPerAtom[Binder->rightatom->nr]++] = Binder;
4129 }
4130
4131 // output list for debugging
4132 *out << Verbose(3) << "ListOfBondsPerAtom for each atom:" << endl;
4133 Walker = start;
4134 while (Walker->next != end) {
4135 Walker = Walker->next;
4136 *out << Verbose(4) << "Atom " << Walker->Name << "/" << Walker->nr << " with " << NumberOfBondsPerAtom[Walker->nr] << " bonds: ";
4137 TotalDegree = 0;
4138 for (int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
4139 *out << *ListOfBondsPerAtom[Walker->nr][j] << "\t";
4140 TotalDegree += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
4141 }
4142 *out << " -- TotalDegree: " << TotalDegree << endl;
4143 }
4144 *out << Verbose(1) << "End of Creating ListOfBondsPerAtom." << endl << endl;
4145};
4146
4147/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
4148 * Gray vertices are always enqueued in an StackClass<atom *> FIFO queue, the rest is usual BFS with adding vertices found was
4149 * white and putting into queue.
4150 * \param *out output stream for debugging
4151 * \param *Mol Molecule class to add atoms to
4152 * \param **AddedAtomList list with added atom pointers, index is atom father's number
4153 * \param **AddedBondList list with added bond pointers, index is bond father's number
4154 * \param *Root root vertex for BFS
4155 * \param *Bond bond not to look beyond
4156 * \param BondOrder maximum distance for vertices to add
4157 * \param IsAngstroem lengths are in angstroem or bohrradii
4158 */
4159void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
4160{
4161 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList");
4162 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList");
4163 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList");
4164 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
4165 atom *Walker = NULL, *OtherAtom = NULL;
4166 bond *Binder = NULL;
4167
4168 // add Root if not done yet
4169 AtomStack->ClearStack();
4170 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
4171 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
4172 AtomStack->Push(Root);
4173
4174 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
4175 for (int i=AtomCount;i--;) {
4176 PredecessorList[i] = NULL;
4177 ShortestPathList[i] = -1;
4178 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited
4179 ColorList[i] = lightgray;
4180 else
4181 ColorList[i] = white;
4182 }
4183 ShortestPathList[Root->nr] = 0;
4184
4185 // and go on ... Queue always contains all lightgray vertices
4186 while (!AtomStack->IsEmpty()) {
4187 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
4188 // 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
4189 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
4190 // followed by n+1 till top of stack.
4191 Walker = AtomStack->PopFirst(); // pop oldest added
4192 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl;
4193 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
4194 Binder = ListOfBondsPerAtom[Walker->nr][i];
4195 if (Binder != NULL) { // don't look at bond equal NULL
4196 OtherAtom = Binder->GetOtherAtom(Walker);
4197 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
4198 if (ColorList[OtherAtom->nr] == white) {
4199 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)
4200 ColorList[OtherAtom->nr] = lightgray;
4201 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
4202 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
4203 *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;
4204 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance
4205 *out << Verbose(3);
4206 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
4207 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
4208 *out << "Added OtherAtom " << OtherAtom->Name;
4209 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
4210 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
4211 AddedBondList[Binder->nr]->Type = Binder->Type;
4212 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
4213 } 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)
4214 *out << "Not adding OtherAtom " << OtherAtom->Name;
4215 if (AddedBondList[Binder->nr] == NULL) {
4216 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
4217 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
4218 AddedBondList[Binder->nr]->Type = Binder->Type;
4219 *out << ", added Bond " << *(AddedBondList[Binder->nr]);
4220 } else
4221 *out << ", not added Bond ";
4222 }
4223 *out << ", putting OtherAtom into queue." << endl;
4224 AtomStack->Push(OtherAtom);
4225 } else { // out of bond order, then replace
4226 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
4227 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
4228 if (Binder == Bond)
4229 *out << Verbose(3) << "Not Queueing, is the Root bond";
4230 else if (ShortestPathList[OtherAtom->nr] >= BondOrder)
4231 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder;
4232 if (!Binder->Cyclic)
4233 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
4234 if (AddedBondList[Binder->nr] == NULL) {
4235 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
4236 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
4237 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
4238 AddedBondList[Binder->nr]->Type = Binder->Type;
4239 } else {
4240#ifdef ADDHYDROGEN
4241 if (!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem))
4242 exit(1);
4243#endif
4244 }
4245 }
4246 }
4247 } else {
4248 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
4249 // This has to be a cyclic bond, check whether it's present ...
4250 if (AddedBondList[Binder->nr] == NULL) {
4251 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) {
4252 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
4253 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
4254 AddedBondList[Binder->nr]->Type = Binder->Type;
4255 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
4256#ifdef ADDHYDROGEN
4257 if(!Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem))
4258 exit(1);
4259#endif
4260 }
4261 }
4262 }
4263 }
4264 }
4265 ColorList[Walker->nr] = black;
4266 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
4267 }
4268 Free((void **)&PredecessorList, "molecule::BreadthFirstSearchAdd: **PredecessorList");
4269 Free((void **)&ShortestPathList, "molecule::BreadthFirstSearchAdd: **ShortestPathList");
4270 Free((void **)&ColorList, "molecule::BreadthFirstSearchAdd: **ColorList");
4271 delete(AtomStack);
4272};
4273
4274/** Adds bond structure to this molecule from \a Father molecule.
4275 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
4276 * with end points present in this molecule, bond is created in this molecule.
4277 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
4278 * \param *out output stream for debugging
4279 * \param *Father father molecule
4280 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
4281 * \todo not checked, not fully working probably
4282 */
4283bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
4284{
4285 atom *Walker = NULL, *OtherAtom = NULL;
4286 bool status = true;
4287 atom **ParentList = (atom **) Malloc(sizeof(atom *)*Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList");
4288
4289 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
4290
4291 // reset parent list
4292 *out << Verbose(3) << "Resetting ParentList." << endl;
4293 for (int i=Father->AtomCount;i--;)
4294 ParentList[i] = NULL;
4295
4296 // fill parent list with sons
4297 *out << Verbose(3) << "Filling Parent List." << endl;
4298 Walker = start;
4299 while (Walker->next != end) {
4300 Walker = Walker->next;
4301 ParentList[Walker->father->nr] = Walker;
4302 // Outputting List for debugging
4303 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
4304 }
4305
4306 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
4307 *out << Verbose(3) << "Creating bonds." << endl;
4308 Walker = Father->start;
4309 while (Walker->next != Father->end) {
4310 Walker = Walker->next;
4311 if (ParentList[Walker->nr] != NULL) {
4312 if (ParentList[Walker->nr]->father != Walker) {
4313 status = false;
4314 } else {
4315 for (int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) {
4316 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
4317 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
4318 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i] << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
4319 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree);
4320 }
4321 }
4322 }
4323 }
4324 }
4325
4326 Free((void **)&ParentList, "molecule::BuildInducedSubgraph: **ParentList");
4327 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
4328 return status;
4329};
4330
4331
4332/** Looks through a StackClass<atom *> and returns the likeliest removal candiate.
4333 * \param *out output stream for debugging messages
4334 * \param *&Leaf KeySet to look through
4335 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
4336 * \param index of the atom suggested for removal
4337 */
4338int molecule::LookForRemovalCandidate(ofstream *&out, KeySet *&Leaf, int *&ShortestPathList)
4339{
4340 atom *Runner = NULL;
4341 int SP, Removal;
4342
4343 *out << Verbose(2) << "Looking for removal candidate." << endl;
4344 SP = -1; //0; // not -1, so that Root is never removed
4345 Removal = -1;
4346 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
4347 Runner = FindAtom((*runner));
4348 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack
4349 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
4350 SP = ShortestPathList[(*runner)];
4351 Removal = (*runner);
4352 }
4353 }
4354 }
4355 return Removal;
4356};
4357
4358/** Stores a fragment from \a KeySet into \a molecule.
4359 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
4360 * molecule and adds missing hydrogen where bonds were cut.
4361 * \param *out output stream for debugging messages
4362 * \param &Leaflet pointer to KeySet structure
4363 * \param IsAngstroem whether we have Ansgtroem or bohrradius
4364 * \return pointer to constructed molecule
4365 */
4366molecule * molecule::StoreFragmentFromKeySet(ofstream *out, KeySet &Leaflet, bool IsAngstroem)
4367{
4368 atom *Runner = NULL, *FatherOfRunner = NULL, *OtherFather = NULL;
4369 atom **SonList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::StoreFragmentFromStack: **SonList");
4370 molecule *Leaf = new molecule(elemente);
4371 bool LonelyFlag = false;
4372 int size;
4373
4374// *out << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
4375
4376 Leaf->BondDistance = BondDistance;
4377 for(int i=NDIM*2;i--;)
4378 Leaf->cell_size[i] = cell_size[i];
4379
4380 // initialise SonList (indicates when we need to replace a bond with hydrogen instead)
4381 for(int i=AtomCount;i--;)
4382 SonList[i] = NULL;
4383
4384 // first create the minimal set of atoms from the KeySet
4385 size = 0;
4386 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
4387 FatherOfRunner = FindAtom((*runner)); // find the id
4388 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner);
4389 size++;
4390 }
4391
4392 // create the bonds between all: Make it an induced subgraph and add hydrogen
4393// *out << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
4394 Runner = Leaf->start;
4395 while (Runner->next != Leaf->end) {
4396 Runner = Runner->next;
4397 LonelyFlag = true;
4398 FatherOfRunner = Runner->father;
4399 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list
4400 // create all bonds
4401 for (int i=0;i<NumberOfBondsPerAtom[FatherOfRunner->nr];i++) { // go through every bond of father
4402 OtherFather = ListOfBondsPerAtom[FatherOfRunner->nr][i]->GetOtherAtom(FatherOfRunner);
4403// *out << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
4404 if (SonList[OtherFather->nr] != NULL) {
4405// *out << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
4406 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
4407// *out << Verbose(3) << "Adding Bond: ";
4408// *out <<
4409 Leaf->AddBond(Runner, SonList[OtherFather->nr], ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree);
4410// *out << "." << endl;
4411 //NumBonds[Runner->nr]++;
4412 } else {
4413// *out << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
4414 }
4415 LonelyFlag = false;
4416 } else {
4417// *out << ", who has no son in this fragment molecule." << endl;
4418#ifdef ADDHYDROGEN
4419 //*out << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl;
4420 if(!Leaf->AddHydrogenReplacementAtom(out, ListOfBondsPerAtom[FatherOfRunner->nr][i], Runner, FatherOfRunner, OtherFather, ListOfBondsPerAtom[FatherOfRunner->nr],NumberOfBondsPerAtom[FatherOfRunner->nr], IsAngstroem))
4421 exit(1);
4422#endif
4423 //NumBonds[Runner->nr] += ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree;
4424 }
4425 }
4426 } else {
4427 *out << Verbose(0) << "ERROR: Son " << Runner->Name << " has father " << FatherOfRunner->Name << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl;
4428 }
4429 if ((LonelyFlag) && (size > 1)) {
4430 *out << Verbose(0) << *Runner << "has got bonds only to hydrogens!" << endl;
4431 }
4432#ifdef ADDHYDROGEN
4433 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen
4434 Runner = Runner->next;
4435#endif
4436 }
4437 Leaf->CreateListOfBondsPerAtom(out);
4438 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
4439 Free((void **)&SonList, "molecule::StoreFragmentFromStack: **SonList");
4440// *out << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
4441 return Leaf;
4442};
4443
4444/** Creates \a MoleculeListClass of all unique fragments of the \a molecule containing \a Order atoms or vertices.
4445 * The picture to have in mind is that of a DFS "snake" of a certain length \a Order, i.e. as in the infamous
4446 * computer game, that winds through the connected graph representing the molecule. Color (white,
4447 * lightgray, darkgray, black) indicates whether a vertex has been discovered so far or not. Labels will help in
4448 * creating only unique fragments and not additional ones with vertices simply in different sequence.
4449 * The Predecessor is always the one that came before in discovering, needed on backstepping. And
4450 * finally, the ShortestPath is needed for removing vertices from the snake stack during the back-
4451 * stepping.
4452 * \param *out output stream for debugging
4453 * \param Order number of atoms in each fragment
4454 * \param *configuration configuration for writing config files for each fragment
4455 * \return List of all unique fragments with \a Order atoms
4456 */
4457/*
4458MoleculeListClass * molecule::CreateListOfUniqueFragmentsOfOrder(ofstream *out, int Order, config *configuration)
4459{
4460 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
4461 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
4462 int *Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
4463 enum Shading *ColorVertexList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
4464 enum Shading *ColorEdgeList = (enum Shading *) Malloc(sizeof(enum Shading)*BondCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorBondList");
4465 StackClass<atom *> *RootStack = new StackClass<atom *>(AtomCount);
4466 StackClass<atom *> *TouchedStack = new StackClass<atom *>((int)pow(4,Order)+2); // number of atoms reached from one with maximal 4 bonds plus Root itself
4467 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!
4468 MoleculeLeafClass *Leaflet = NULL, *TempLeaf = NULL;
4469 MoleculeListClass *FragmentList = NULL;
4470 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Removal = NULL;
4471 bond *Binder = NULL;
4472 int RunningIndex = 0, FragmentCounter = 0;
4473
4474 *out << Verbose(1) << "Begin of CreateListOfUniqueFragmentsOfOrder." << endl;
4475
4476 // reset parent list
4477 *out << Verbose(3) << "Resetting labels, parent, predecessor, color and shortest path lists." << endl;
4478 for (int i=0;i<AtomCount;i++) { // reset all atom labels
4479 // initialise each vertex as white with no predecessor, empty queue, color lightgray, not labelled, no sons
4480 Labels[i] = -1;
4481 SonList[i] = NULL;
4482 PredecessorList[i] = NULL;
4483 ColorVertexList[i] = white;
4484 ShortestPathList[i] = -1;
4485 }
4486 for (int i=0;i<BondCount;i++)
4487 ColorEdgeList[i] = white;
4488 RootStack->ClearStack(); // clearstack and push first atom if exists
4489 TouchedStack->ClearStack();
4490 Walker = start->next;
4491 while ((Walker != end)
4492#ifdef ADDHYDROGEN
4493 && (Walker->type->Z == 1)
4494 }
4495 }
4496 *out << ", SP of " << ShortestPathList[Walker->nr] << " and its color is " << GetColor(ColorVertexList[Walker->nr]) << "." << endl;
4497
4498 // then check the stack for a newly stumbled upon fragment
4499 if (SnakeStack->ItemCount() == Order) { // is stack full?
4500 // store the fragment if it is one and get a removal candidate
4501 Removal = StoreFragmentFromStack(out, Root, Walker, Leaflet, SnakeStack, ShortestPathList, SonList, Labels, &FragmentCounter, configuration);
4502 // remove the candidate if one was found
4503 if (Removal != NULL) {
4504 *out << Verbose(2) << "Removing item " << Removal->Name << " with SP of " << ShortestPathList[Removal->nr] << " from snake stack." << endl;
4505 SnakeStack->RemoveItem(Removal);
4506 ColorVertexList[Removal->nr] = lightgray; // return back to not on snake stack but explored marking
4507 if (Walker == Removal) { // if the current atom is to be removed, we also have to take a step back
4508 Walker = PredecessorList[Removal->nr];
4509 *out << Verbose(2) << "Stepping back to " << Walker->Name << "." << endl;
4510 }
4511 }
4512 } else
4513 Removal = NULL;
4514
4515 // finally, look for a white neighbour as the next Walker
4516 Binder = NULL;
4517 if ((Removal == NULL) || (Walker != PredecessorList[Removal->nr])) { // don't look, if a new walker has been set above
4518 *out << Verbose(2) << "Snake has currently " << SnakeStack->ItemCount() << " item(s)." << endl;
4519 OtherAtom = NULL; // this is actually not needed, every atom has at least one neighbour
4520 if (ShortestPathList[Walker->nr] < Order) {
4521 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
4522 Binder = ListOfBondsPerAtom[Walker->nr][i];
4523 *out << Verbose(2) << "Current bond is " << *Binder << ": ";
4524 OtherAtom = Binder->GetOtherAtom(Walker);
4525 if ((Labels[OtherAtom->nr] != -1) && (Labels[OtherAtom->nr] < Labels[Root->nr])) { // we don't step up to labels bigger than us
4526 *out << "Label " << Labels[OtherAtom->nr] << " is smaller than Root's " << Labels[Root->nr] << "." << endl;
4527 //ColorVertexList[OtherAtom->nr] = lightgray; // mark as explored
4528 } else { // otherwise check its colour and element
4529 if (
4530 (OtherAtom->type->Z != 1) &&
4531#endif
4532 (ColorEdgeList[Binder->nr] == white)) { // skip hydrogen, look for unexplored vertices
4533 *out << "Moving along " << GetColor(ColorEdgeList[Binder->nr]) << " bond " << Binder << " to " << ((ColorVertexList[OtherAtom->nr] == white) ? "unexplored" : "explored") << " item: " << OtherAtom->Name << "." << endl;
4534 // i find it currently rather sensible to always set the predecessor in order to find one's way back
4535 //if (PredecessorList[OtherAtom->nr] == NULL) {
4536 PredecessorList[OtherAtom->nr] = Walker;
4537 *out << Verbose(3) << "Setting Predecessor of " << OtherAtom->Name << " to " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
4538 //} else {
4539 // *out << Verbose(3) << "Predecessor of " << OtherAtom->Name << " is " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
4540 //}
4541 Walker = OtherAtom;
4542 break;
4543 } else {
4544 if (OtherAtom->type->Z == 1)
4545 *out << "Links to a hydrogen atom." << endl;
4546 else
4547 *out << "Bond has not white but " << GetColor(ColorEdgeList[Binder->nr]) << " color." << endl;
4548 }
4549 }
4550 }
4551 } else { // means we have stepped beyond the horizon: Return!
4552 Walker = PredecessorList[Walker->nr];
4553 OtherAtom = Walker;
4554 *out << Verbose(3) << "We have gone too far, stepping back to " << Walker->Name << "." << endl;
4555 }
4556 if (Walker != OtherAtom) { // if no white neighbours anymore, color it black
4557 *out << Verbose(2) << "Coloring " << Walker->Name << " black." << endl;
4558 ColorVertexList[Walker->nr] = black;
4559 Walker = PredecessorList[Walker->nr];
4560 }
4561 }
4562 } while ((Walker != Root) || (ColorVertexList[Root->nr] != black));
4563 *out << Verbose(2) << "Inner Looping is finished." << endl;
4564
4565 // if we reset all AtomCount atoms, we have again technically O(N^2) ...
4566 *out << Verbose(2) << "Resetting lists." << endl;
4567 Walker = NULL;
4568 Binder = NULL;
4569 while (!TouchedStack->IsEmpty()) {
4570 Walker = TouchedStack->PopLast();
4571 *out << Verbose(3) << "Re-initialising entries of " << *Walker << "." << endl;
4572 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
4573 ColorEdgeList[ListOfBondsPerAtom[Walker->nr][i]->nr] = white;
4574 PredecessorList[Walker->nr] = NULL;
4575 ColorVertexList[Walker->nr] = white;
4576 ShortestPathList[Walker->nr] = -1;
4577 }
4578 }
4579 *out << Verbose(1) << "Outer Looping over all vertices is done." << endl;
4580
4581 // copy together
4582 *out << Verbose(1) << "Copying all fragments into MoleculeList structure." << endl;
4583 FragmentList = new MoleculeListClass(FragmentCounter, AtomCount);
4584 RunningIndex = 0;
4585 while ((Leaflet != NULL) && (RunningIndex < FragmentCounter)) {
4586 FragmentList->ListOfMolecules[RunningIndex++] = Leaflet->Leaf;
4587 Leaflet->Leaf = NULL; // prevent molecule from being removed
4588 TempLeaf = Leaflet;
4589 Leaflet = Leaflet->previous;
4590 delete(TempLeaf);
4591 };
4592
4593 // free memory and exit
4594 Free((void **)&PredecessorList, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
4595 Free((void **)&ShortestPathList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
4596 Free((void **)&Labels, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
4597 Free((void **)&ColorVertexList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
4598 delete(RootStack);
4599 delete(TouchedStack);
4600 delete(SnakeStack);
4601
4602 *out << Verbose(1) << "End of CreateListOfUniqueFragmentsOfOrder." << endl;
4603 return FragmentList;
4604};
4605*/
4606
4607/** Structure containing all values in power set combination generation.
4608 */
4609struct UniqueFragments {
4610 config *configuration;
4611 atom *Root;
4612 Graph *Leaflet;
4613 KeySet *FragmentSet;
4614 int ANOVAOrder;
4615 int FragmentCounter;
4616 int CurrentIndex;
4617 double TEFactor;
4618 int *ShortestPathList;
4619 bool **UsedList;
4620 bond **BondsPerSPList;
4621 int *BondsPerSPCount;
4622};
4623
4624/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
4625 * -# loops over every possible combination (2^dimension of edge set)
4626 * -# inserts current set, if there's still space left
4627 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
4628ance+1
4629 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
4630 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
4631distance) and current set
4632 * \param *out output stream for debugging
4633 * \param FragmentSearch UniqueFragments structure with all values needed
4634 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
4635 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
4636 * \param SubOrder remaining number of allowed vertices to add
4637 */
4638void molecule::SPFragmentGenerator(ofstream *out, struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
4639{
4640 atom *OtherWalker = NULL;
4641 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
4642 int NumCombinations;
4643 bool bit;
4644 int bits, TouchedIndex, SubSetDimension, SP, Added;
4645 int Removal;
4646 int SpaceLeft;
4647 int *TouchedList = (int *) Malloc(sizeof(int)*(SubOrder+1), "molecule::SPFragmentGenerator: *TouchedList");
4648 bond *Binder = NULL;
4649 bond **BondsList = NULL;
4650 KeySetTestPair TestKeySetInsert;
4651
4652 NumCombinations = 1 << SetDimension;
4653
4654 // Hier muessen von 1 bis NumberOfBondsPerAtom[Walker->nr] alle Kombinationen
4655 // von Endstuecken (aus den Bonds) hinzugefᅵᅵgt werden und fᅵᅵr verbleibende ANOVAOrder
4656 // rekursiv GraphCrawler in der nᅵᅵchsten Ebene aufgerufen werden
4657
4658 *out << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
4659 *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;
4660
4661 // initialised touched list (stores added atoms on this level)
4662 *out << Verbose(1+verbosity) << "Clearing touched list." << endl;
4663 for (TouchedIndex=SubOrder+1;TouchedIndex--;) // empty touched list
4664 TouchedList[TouchedIndex] = -1;
4665 TouchedIndex = 0;
4666
4667 // create every possible combination of the endpieces
4668 *out << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
4669 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
4670 // count the set bit of i
4671 bits = 0;
4672 for (int j=SetDimension;j--;)
4673 bits += (i & (1 << j)) >> j;
4674
4675 *out << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
4676 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
4677 // --1-- add this set of the power set of bond partners to the snake stack
4678 Added = 0;
4679 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
4680 bit = ((i & (1 << j)) != 0); // mask the bit for the j-th bond
4681 if (bit) { // if bit is set, we add this bond partner
4682 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
4683 //*out << Verbose(1+verbosity) << "Current Bond is " << ListOfBondsPerAtom[Walker->nr][i] << ", checking on " << *OtherWalker << "." << endl;
4684 *out << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
4685 TestKeySetInsert = FragmentSearch->FragmentSet->insert(OtherWalker->nr);
4686 if (TestKeySetInsert.second) {
4687 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
4688 Added++;
4689 } else {
4690 *out << Verbose(2+verbosity) << "This was item was already present in the keyset." << endl;
4691 }
4692 //FragmentSearch->UsedList[OtherWalker->nr][i] = true;
4693 //}
4694 } else {
4695 *out << Verbose(2+verbosity) << "Not adding." << endl;
4696 }
4697 }
4698
4699 SpaceLeft = SubOrder - Added ;// SubOrder - bits; // due to item's maybe being already present, this does not work anymore
4700 if (SpaceLeft > 0) {
4701 *out << Verbose(1+verbosity) << "There's still some space left on stack: " << SpaceLeft << "." << endl;
4702 if (SubOrder > 1) { // Due to Added above we have to check extra whether we're not already reaching beyond the desired Order
4703 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
4704 SP = RootDistance+1; // this is the next level
4705 // first count the members in the subset
4706 SubSetDimension = 0;
4707 Binder = FragmentSearch->BondsPerSPList[2*SP]; // start node for this level
4708 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) { // compare to end node of this level
4709 Binder = Binder->next;
4710 for (int k=TouchedIndex;k--;) {
4711 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
4712 SubSetDimension++;
4713 }
4714 }
4715 // then allocate and fill the list
4716 BondsList = (bond **) Malloc(sizeof(bond *)*SubSetDimension, "molecule::SPFragmentGenerator: **BondsList");
4717 SubSetDimension = 0;
4718 Binder = FragmentSearch->BondsPerSPList[2*SP];
4719 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) {
4720 Binder = Binder->next;
4721 for (int k=0;k<TouchedIndex;k++) {
4722 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
4723 BondsList[SubSetDimension++] = Binder;
4724 }
4725 }
4726 *out << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
4727 SPFragmentGenerator(out, FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
4728 Free((void **)&BondsList, "molecule::SPFragmentGenerator: **BondsList");
4729 }
4730 } else {
4731 // --2-- otherwise store the complete fragment
4732 *out << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
4733 // store fragment as a KeySet
4734 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
4735 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
4736 *out << (*runner) << " ";
4737 *out << endl;
4738 //if (!CheckForConnectedSubgraph(out, FragmentSearch->FragmentSet))
4739 //*out << Verbose(0) << "ERROR: The found fragment is not a connected subgraph!" << endl;
4740 InsertFragmentIntoGraph(out, FragmentSearch);
4741 //Removal = LookForRemovalCandidate(out, FragmentSearch->FragmentSet, FragmentSearch->ShortestPathList);
4742 //Removal = StoreFragmentFromStack(out, FragmentSearch->Root, FragmentSearch->Leaflet, FragmentSearch->FragmentStack, FragmentSearch->ShortestPathList, &FragmentSearch->FragmentCounter, FragmentSearch->configuration);
4743 }
4744
4745 // --3-- remove all added items in this level from snake stack
4746 *out << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
4747 for(int j=0;j<TouchedIndex;j++) {
4748 Removal = TouchedList[j];
4749 *out << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
4750 FragmentSearch->FragmentSet->erase(Removal);
4751 TouchedList[j] = -1;
4752 }
4753 *out << Verbose(2) << "Remaining local nr.s on snake stack are: ";
4754 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
4755 *out << (*runner) << " ";
4756 *out << endl;
4757 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
4758 } else {
4759 *out << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
4760 }
4761 }
4762 Free((void **)&TouchedList, "molecule::SPFragmentGenerator: *TouchedList");
4763 *out << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
4764};
4765
4766/** For a given keyset \a *Fragment, checks whether it is connected in the current molecule.
4767 * \param *out output stream for debugging
4768 * \param *Fragment Keyset of fragment's vertices
4769 * \return true - connected, false - disconnected
4770 * \note this is O(n^2) for it's just a bug checker not meant for permanent use!
4771 */
4772bool molecule::CheckForConnectedSubgraph(ofstream *out, KeySet *Fragment)
4773{
4774 atom *Walker = NULL, *Walker2 = NULL;
4775 bool BondStatus = false;
4776 int size;
4777
4778 *out << Verbose(1) << "Begin of CheckForConnectedSubgraph" << endl;
4779 *out << Verbose(2) << "Disconnected atom: ";
4780
4781 // count number of atoms in graph
4782 size = 0;
4783 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++)
4784 size++;
4785 if (size > 1)
4786 for(KeySet::iterator runner = Fragment->begin(); runner != Fragment->end(); runner++) {
4787 Walker = FindAtom(*runner);
4788 BondStatus = false;
4789 for(KeySet::iterator runners = Fragment->begin(); runners != Fragment->end(); runners++) {
4790 Walker2 = FindAtom(*runners);
4791 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
4792 if (ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker) == Walker2) {
4793 BondStatus = true;
4794 break;
4795 }
4796 if (BondStatus)
4797 break;
4798 }
4799 }
4800 if (!BondStatus) {
4801 *out << (*Walker) << endl;
4802 return false;
4803 }
4804 }
4805 else {
4806 *out << "none." << endl;
4807 return true;
4808 }
4809 *out << "none." << endl;
4810
4811 *out << Verbose(1) << "End of CheckForConnectedSubgraph" << endl;
4812
4813 return true;
4814}
4815
4816/** 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.
4817 * -# initialises UniqueFragments structure
4818 * -# fills edge list via BFS
4819 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
4820 root distance, the edge set, its dimension and the current suborder
4821 * -# Free'ing structure
4822 * 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
4823 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
4824 * \param *out output stream for debugging
4825 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
4826 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
4827 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
4828 * \return number of inserted fragments
4829 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
4830 */
4831int molecule::PowerSetGenerator(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
4832{
4833 int SP, AtomKeyNr;
4834 atom *Walker = NULL, *OtherWalker = NULL, *Predecessor = NULL;
4835 bond *Binder = NULL;
4836 bond *CurrentEdge = NULL;
4837 bond **BondsList = NULL;
4838 int RootKeyNr = FragmentSearch.Root->GetTrueFather()->nr;
4839 int Counter = FragmentSearch.FragmentCounter;
4840 int RemainingWalkers;
4841
4842 *out << endl;
4843 *out << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl;
4844
4845 // prepare Label and SP arrays of the BFS search
4846 FragmentSearch.ShortestPathList[FragmentSearch.Root->nr] = 0;
4847
4848 // prepare root level (SP = 0) and a loop bond denoting Root
4849 for (int i=1;i<Order;i++)
4850 FragmentSearch.BondsPerSPCount[i] = 0;
4851 FragmentSearch.BondsPerSPCount[0] = 1;
4852 Binder = new bond(FragmentSearch.Root, FragmentSearch.Root);
4853 add(Binder, FragmentSearch.BondsPerSPList[1]);
4854
4855 // do a BFS search to fill the SP lists and label the found vertices
4856 // Actually, we should construct a spanning tree vom the root atom and select all edges therefrom and put them into
4857 // according shortest path lists. However, we don't. Rather we fill these lists right away, as they do form a spanning
4858 // tree already sorted into various SP levels. That's why we just do loops over the depth (CurrentSP) and breadth
4859 // (EdgeinSPLevel) of this tree ...
4860 // In another picture, the bonds always contain a direction by rightatom being the one more distant from root and hence
4861 // naturally leftatom forming its predecessor, preventing the BFS"seeker" from continuing in the wrong direction.
4862 *out << endl;
4863 *out << Verbose(0) << "Starting BFS analysis ..." << endl;
4864 for (SP = 0; SP < (Order-1); SP++) {
4865 *out << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with " << FragmentSearch.BondsPerSPCount[SP] << " item(s)";
4866 if (SP > 0) {
4867 *out << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl;
4868 FragmentSearch.BondsPerSPCount[SP] = 0;
4869 } else
4870 *out << "." << endl;
4871
4872 RemainingWalkers = FragmentSearch.BondsPerSPCount[SP];
4873 CurrentEdge = FragmentSearch.BondsPerSPList[2*SP]; /// start of this SP level's list
4874 while (CurrentEdge->next != FragmentSearch.BondsPerSPList[2*SP+1]) { /// end of this SP level's list
4875 CurrentEdge = CurrentEdge->next;
4876 RemainingWalkers--;
4877 Walker = CurrentEdge->rightatom; // rightatom is always the one more distant
4878 Predecessor = CurrentEdge->leftatom; // ... and leftatom is predecessor
4879 AtomKeyNr = Walker->nr;
4880 *out << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and SP of " << SP << ", with " << RemainingWalkers << " remaining walkers on this level." << endl;
4881 // check for new sp level
4882 // go through all its bonds
4883 *out << Verbose(1) << "Going through all bonds of Walker." << endl;
4884 for (int i=0;i<NumberOfBondsPerAtom[AtomKeyNr];i++) {
4885 Binder = ListOfBondsPerAtom[AtomKeyNr][i];
4886 OtherWalker = Binder->GetOtherAtom(Walker);
4887 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end())
4888 #ifdef ADDHYDROGEN
4889 && (OtherWalker->type->Z != 1)
4890 #endif
4891 ) { // skip hydrogens and restrict to fragment
4892 *out << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *Binder << "." << endl;
4893 // set the label if not set (and push on root stack as well)
4894 if ((OtherWalker != Predecessor) && (OtherWalker->GetTrueFather()->nr > RootKeyNr)) { // only pass through those with label bigger than Root's
4895 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1;
4896 *out << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl;
4897 // add the bond in between to the SP list
4898 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
4899 add(Binder, FragmentSearch.BondsPerSPList[2*(SP+1)+1]);
4900 FragmentSearch.BondsPerSPCount[SP+1]++;
4901 *out << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP+1] << " item(s)." << endl;
4902 } else {
4903 if (OtherWalker != Predecessor)
4904 *out << Verbose(3) << "Not passing on, as index of " << *OtherWalker << " " << OtherWalker->GetTrueFather()->nr << " is smaller than that of Root " << RootKeyNr << "." << endl;
4905 else
4906 *out << Verbose(3) << "This is my predecessor " << *Predecessor << "." << endl;
4907 }
4908 } else *out << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
4909 }
4910 }
4911 }
4912
4913 // outputting all list for debugging
4914 *out << Verbose(0) << "Printing all found lists." << endl;
4915 for(int i=1;i<Order;i++) { // skip the root edge in the printing
4916 Binder = FragmentSearch.BondsPerSPList[2*i];
4917 *out << Verbose(1) << "Current SP level is " << i << "." << endl;
4918 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4919 Binder = Binder->next;
4920 *out << Verbose(2) << *Binder << endl;
4921 }
4922 }
4923
4924 // creating fragments with the found edge sets (may be done in reverse order, faster)
4925 SP = -1; // the Root <-> Root edge must be subtracted!
4926 for(int i=Order;i--;) { // sum up all found edges
4927 Binder = FragmentSearch.BondsPerSPList[2*i];
4928 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4929 Binder = Binder->next;
4930 SP ++;
4931 }
4932 }
4933 *out << Verbose(0) << "Total number of edges is " << SP << "." << endl;
4934 if (SP >= (Order-1)) {
4935 // start with root (push on fragment stack)
4936 *out << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->nr << "." << endl;
4937 FragmentSearch.FragmentSet->clear();
4938 *out << Verbose(0) << "Preparing subset for this root and calling generator." << endl;
4939 // prepare the subset and call the generator
4940 BondsList = (bond **) Malloc(sizeof(bond *)*FragmentSearch.BondsPerSPCount[0], "molecule::PowerSetGenerator: **BondsList");
4941 BondsList[0] = FragmentSearch.BondsPerSPList[0]->next; // on SP level 0 there's only the root bond
4942
4943 SPFragmentGenerator(out, &FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order);
4944
4945 Free((void **)&BondsList, "molecule::PowerSetGenerator: **BondsList");
4946 } else {
4947 *out << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl;
4948 }
4949
4950 // as FragmentSearch structure is used only once, we don't have to clean it anymore
4951 // remove root from stack
4952 *out << Verbose(0) << "Removing root again from stack." << endl;
4953 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr);
4954
4955 // free'ing the bonds lists
4956 *out << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl;
4957 for(int i=Order;i--;) {
4958 *out << Verbose(1) << "Current SP level is " << i << ": ";
4959 Binder = FragmentSearch.BondsPerSPList[2*i];
4960 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
4961 Binder = Binder->next;
4962 // *out << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local
4963 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1;
4964 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1;
4965 }
4966 // delete added bonds
4967 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]);
4968 // also start and end node
4969 *out << "cleaned." << endl;
4970 }
4971
4972 // return list
4973 *out << Verbose(0) << "End of PowerSetGenerator." << endl;
4974 return (FragmentSearch.FragmentCounter - Counter);
4975};
4976
4977/** Corrects the nuclei position if the fragment was created over the cell borders.
4978 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
4979 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
4980 * and re-add the bond. Looping on the distance check.
4981 * \param *out ofstream for debugging messages
4982 */
4983void molecule::ScanForPeriodicCorrection(ofstream *out)
4984{
4985 bond *Binder = NULL;
4986 bond *OtherBinder = NULL;
4987 atom *Walker = NULL;
4988 atom *OtherWalker = NULL;
4989 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
4990 enum Shading *ColorList = NULL;
4991 double tmp;
4992 Vector Translationvector;
4993 //class StackClass<atom *> *CompStack = NULL;
4994 class StackClass<atom *> *AtomStack = new StackClass<atom *>(AtomCount);
4995 bool flag = true;
4996
4997 *out << Verbose(2) << "Begin of ScanForPeriodicCorrection." << endl;
4998
4999 ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::ScanForPeriodicCorrection: *ColorList");
5000 while (flag) {
5001 // remove bonds that are beyond bonddistance
5002 for(int i=NDIM;i--;)
5003 Translationvector.x[i] = 0.;
5004 // scan all bonds
5005 Binder = first;
5006 flag = false;
5007 while ((!flag) && (Binder->next != last)) {
5008 Binder = Binder->next;
5009 for (int i=NDIM;i--;) {
5010 tmp = fabs(Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]);
5011 //*out << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
5012 if (tmp > BondDistance) {
5013 OtherBinder = Binder->next; // note down binding partner for later re-insertion
5014 unlink(Binder); // unlink bond
5015 *out << Verbose(2) << "Correcting at bond " << *Binder << "." << endl;
5016 flag = true;
5017 break;
5018 }
5019 }
5020 }
5021 if (flag) {
5022 // create translation vector from their periodically modified distance
5023 for (int i=NDIM;i--;) {
5024 tmp = Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i];
5025 if (fabs(tmp) > BondDistance)
5026 Translationvector.x[i] = (tmp < 0) ? +1. : -1.;
5027 }
5028 Translationvector.MatrixMultiplication(matrix);
5029 //*out << Verbose(3) << "Translation vector is ";
5030 Translationvector.Output(out);
5031 *out << endl;
5032 // apply to all atoms of first component via BFS
5033 for (int i=AtomCount;i--;)
5034 ColorList[i] = white;
5035 AtomStack->Push(Binder->leftatom);
5036 while (!AtomStack->IsEmpty()) {
5037 Walker = AtomStack->PopFirst();
5038 //*out << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
5039 ColorList[Walker->nr] = black; // mark as explored
5040 Walker->x.AddVector(&Translationvector); // translate
5041 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through all binding partners
5042 if (ListOfBondsPerAtom[Walker->nr][i] != Binder) {
5043 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
5044 if (ColorList[OtherWalker->nr] == white) {
5045 AtomStack->Push(OtherWalker); // push if yet unexplored
5046 }
5047 }
5048 }
5049 }
5050 // re-add bond
5051 link(Binder, OtherBinder);
5052 } else {
5053 *out << Verbose(3) << "No corrections for this fragment." << endl;
5054 }
5055 //delete(CompStack);
5056 }
5057
5058 // free allocated space from ReturnFullMatrixforSymmetric()
5059 delete(AtomStack);
5060 Free((void **)&ColorList, "molecule::ScanForPeriodicCorrection: *ColorList");
5061 Free((void **)&matrix, "molecule::ScanForPeriodicCorrection: *matrix");
5062 *out << Verbose(2) << "End of ScanForPeriodicCorrection." << endl;
5063};
5064
5065/** Blows the 6-dimensional \a cell_size array up to a full NDIM by NDIM matrix.
5066 * \param *symm 6-dim array of unique symmetric matrix components
5067 * \return allocated NDIM*NDIM array with the symmetric matrix
5068 */
5069double * molecule::ReturnFullMatrixforSymmetric(double *symm)
5070{
5071 double *matrix = (double *) Malloc(sizeof(double)*NDIM*NDIM, "molecule::ReturnFullMatrixforSymmetric: *matrix");
5072 matrix[0] = symm[0];
5073 matrix[1] = symm[1];
5074 matrix[2] = symm[3];
5075 matrix[3] = symm[1];
5076 matrix[4] = symm[2];
5077 matrix[5] = symm[4];
5078 matrix[6] = symm[3];
5079 matrix[7] = symm[4];
5080 matrix[8] = symm[5];
5081 return matrix;
5082};
5083
5084bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
5085{
5086 //cout << "my check is used." << endl;
5087 if (SubgraphA.size() < SubgraphB.size()) {
5088 return true;
5089 } else {
5090 if (SubgraphA.size() > SubgraphB.size()) {
5091 return false;
5092 } else {
5093 KeySet::iterator IteratorA = SubgraphA.begin();
5094 KeySet::iterator IteratorB = SubgraphB.begin();
5095 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
5096 if ((*IteratorA) < (*IteratorB))
5097 return true;
5098 else if ((*IteratorA) > (*IteratorB)) {
5099 return false;
5100 } // else, go on to next index
5101 IteratorA++;
5102 IteratorB++;
5103 } // end of while loop
5104 }// end of check in case of equal sizes
5105 }
5106 return false; // if we reach this point, they are equal
5107};
5108
5109//bool operator < (KeySet SubgraphA, KeySet SubgraphB)
5110//{
5111// return KeyCompare(SubgraphA, SubgraphB);
5112//};
5113
5114/** Checking whether KeySet is not already present in Graph, if so just adds factor.
5115 * \param *out output stream for debugging
5116 * \param &set KeySet to insert
5117 * \param &graph Graph to insert into
5118 * \param *counter pointer to unique fragment count
5119 * \param factor energy factor for the fragment
5120 */
5121inline void InsertFragmentIntoGraph(ofstream *out, struct UniqueFragments *Fragment)
5122{
5123 GraphTestPair testGraphInsert;
5124
5125 testGraphInsert = Fragment->Leaflet->insert(GraphPair (*Fragment->FragmentSet,pair<int,double>(Fragment->FragmentCounter,Fragment->TEFactor))); // store fragment number and current factor
5126 if (testGraphInsert.second) {
5127 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " successfully inserted." << endl;
5128 Fragment->FragmentCounter++;
5129 } else {
5130 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
5131 ((*(testGraphInsert.first)).second).second += Fragment->TEFactor; // increase the "created" counter
5132 *out << Verbose(2) << "New factor is " << ((*(testGraphInsert.first)).second).second << "." << endl;
5133 }
5134};
5135//void inline InsertIntoGraph(ofstream *out, KeyStack &stack, Graph &graph, int *counter, double factor)
5136//{
5137// // copy stack contents to set and call overloaded function again
5138// KeySet set;
5139// for(KeyStack::iterator runner = stack.begin(); runner != stack.begin(); runner++)
5140// set.insert((*runner));
5141// InsertIntoGraph(out, set, graph, counter, factor);
5142//};
5143
5144/** Inserts each KeySet in \a graph2 into \a graph1.
5145 * \param *out output stream for debugging
5146 * \param graph1 first (dest) graph
5147 * \param graph2 second (source) graph
5148 * \param *counter keyset counter that gets increased
5149 */
5150inline void InsertGraphIntoGraph(ofstream *out, Graph &graph1, Graph &graph2, int *counter)
5151{
5152 GraphTestPair testGraphInsert;
5153
5154 for(Graph::iterator runner = graph2.begin(); runner != graph2.end(); runner++) {
5155 testGraphInsert = graph1.insert(GraphPair ((*runner).first,pair<int,double>((*counter)++,((*runner).second).second))); // store fragment number and current factor
5156 if (testGraphInsert.second) {
5157 *out << Verbose(2) << "KeySet " << (*counter)-1 << " successfully inserted." << endl;
5158 } else {
5159 *out << Verbose(2) << "KeySet " << (*counter)-1 << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
5160 ((*(testGraphInsert.first)).second).second += (*runner).second.second;
5161 *out << Verbose(2) << "New factor is " << (*(testGraphInsert.first)).second.second << "." << endl;
5162 }
5163 }
5164};
5165
5166
5167/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
5168 * -# constructs a complete keyset of the molecule
5169 * -# In a loop over all possible roots from the given rootstack
5170 * -# increases order of root site
5171 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
5172 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
5173as the restricted one and each site in the set as the root)
5174 * -# these are merged into a fragment list of keysets
5175 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
5176 * Important only is that we create all fragments, it is not important if we create them more than once
5177 * as these copies are filtered out via use of the hash table (KeySet).
5178 * \param *out output stream for debugging
5179 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
5180 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
5181 * \param *MinimumRingSize minimum ring size for each atom (molecule::Atomcount)
5182 * \return pointer to Graph list
5183 */
5184void molecule::FragmentBOSSANOVA(ofstream *out, Graph *&FragmentList, KeyStack &RootStack, int *MinimumRingSize)
5185{
5186 Graph ***FragmentLowerOrdersList = NULL;
5187 int NumLevels, NumMolecules, TotalNumMolecules = 0, *NumMoleculesOfOrder = NULL;
5188 int counter = 0, Order;
5189 int UpgradeCount = RootStack.size();
5190 KeyStack FragmentRootStack;
5191 int RootKeyNr, RootNr;
5192 struct UniqueFragments FragmentSearch;
5193
5194 *out << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl;
5195
5196 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
5197 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
5198 NumMoleculesOfOrder = (int *) Malloc(sizeof(int)*UpgradeCount, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
5199 FragmentLowerOrdersList = (Graph ***) Malloc(sizeof(Graph **)*UpgradeCount, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
5200
5201 // initialise the fragments structure
5202 FragmentSearch.ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *ShortestPathList");
5203 FragmentSearch.FragmentCounter = 0;
5204 FragmentSearch.FragmentSet = new KeySet;
5205 FragmentSearch.Root = FindAtom(RootKeyNr);
5206 for (int i=AtomCount;i--;) {
5207 FragmentSearch.ShortestPathList[i] = -1;
5208 }
5209
5210 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
5211 atom *Walker = start;
5212 KeySet CompleteMolecule;
5213 while (Walker->next != end) {
5214 Walker = Walker->next;
5215 CompleteMolecule.insert(Walker->GetTrueFather()->nr);
5216 }
5217
5218 // 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
5219 // 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),
5220 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
5221 // 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)
5222 RootNr = 0; // counts through the roots in RootStack
5223 while ((RootNr < UpgradeCount) && (!RootStack.empty())) {
5224 RootKeyNr = RootStack.front();
5225 RootStack.pop_front();
5226 Walker = FindAtom(RootKeyNr);
5227 // check cyclic lengths
5228 //if ((MinimumRingSize[Walker->GetTrueFather()->nr] != -1) && (Walker->GetTrueFather()->AdaptiveOrder+1 > MinimumRingSize[Walker->GetTrueFather()->nr])) {
5229 // *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;
5230 //} else
5231 {
5232 // increase adaptive order by one
5233 Walker->GetTrueFather()->AdaptiveOrder++;
5234 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
5235
5236 // initialise Order-dependent entries of UniqueFragments structure
5237 FragmentSearch.BondsPerSPList = (bond **) Malloc(sizeof(bond *)*Order*2, "molecule::PowerSetGenerator: ***BondsPerSPList");
5238 FragmentSearch.BondsPerSPCount = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *BondsPerSPCount");
5239 for (int i=Order;i--;) {
5240 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node
5241 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node
5242 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two
5243 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i];
5244 FragmentSearch.BondsPerSPCount[i] = 0;
5245 }
5246
5247 // allocate memory for all lower level orders in this 1D-array of ptrs
5248 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
5249 FragmentLowerOrdersList[RootNr] = (Graph **) Malloc(sizeof(Graph *)*NumLevels, "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
5250 for (int i=0;i<NumLevels;i++)
5251 FragmentLowerOrdersList[RootNr][i] = NULL;
5252
5253 // create top order where nothing is reduced
5254 *out << Verbose(0) << "==============================================================================================================" << endl;
5255 *out << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", " << (RootStack.size()-RootNr) << " Roots remaining." << endl; // , NumLevels is " << NumLevels << "
5256
5257 // Create list of Graphs of current Bond Order (i.e. F_{ij})
5258 FragmentLowerOrdersList[RootNr][0] = new Graph;
5259 FragmentSearch.TEFactor = 1.;
5260 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
5261 FragmentSearch.Root = Walker;
5262 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(out, Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
5263 *out << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
5264 if (NumMoleculesOfOrder[RootNr] != 0) {
5265 NumMolecules = 0;
5266
5267 // we don't have to dive into suborders! These keysets are all already created on lower orders!
5268 // this was all ancient stuff, when we still depended on the TEFactors (and for those the suborders were needed)
5269
5270// if ((NumLevels >> 1) > 0) {
5271// // create lower order fragments
5272// *out << Verbose(0) << "Creating list of unique fragments of lower Bond Order terms to be subtracted." << endl;
5273// Order = Walker->AdaptiveOrder;
5274// 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)
5275// // step down to next order at (virtual) boundary of powers of 2 in array
5276// while (source >= (1 << (Walker->AdaptiveOrder-Order))) // (int)pow(2,Walker->AdaptiveOrder-Order))
5277// Order--;
5278// *out << Verbose(0) << "Current Order is: " << Order << "." << endl;
5279// for (int SubOrder=Order-1;SubOrder>0;SubOrder--) {
5280// int dest = source + (1 << (Walker->AdaptiveOrder-(SubOrder+1)));
5281// *out << Verbose(0) << "--------------------------------------------------------------------------------------------------------------" << endl;
5282// *out << Verbose(0) << "Current SubOrder is: " << SubOrder << " with source " << source << " to destination " << dest << "." << endl;
5283//
5284// // every molecule is split into a list of again (Order - 1) molecules, while counting all molecules
5285// //*out << Verbose(1) << "Splitting the " << (*FragmentLowerOrdersList[RootNr][source]).size() << " molecules of the " << source << "th cell in the array." << endl;
5286// //NumMolecules = 0;
5287// FragmentLowerOrdersList[RootNr][dest] = new Graph;
5288// for(Graph::iterator runner = (*FragmentLowerOrdersList[RootNr][source]).begin();runner != (*FragmentLowerOrdersList[RootNr][source]).end(); runner++) {
5289// for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
5290// Graph TempFragmentList;
5291// FragmentSearch.TEFactor = -(*runner).second.second;
5292// FragmentSearch.Leaflet = &TempFragmentList; // set to insertion graph
5293// FragmentSearch.Root = FindAtom(*sprinter);
5294// NumMoleculesOfOrder[RootNr] += PowerSetGenerator(out, SubOrder, FragmentSearch, (*runner).first);
5295// // insert new keysets FragmentList into FragmentLowerOrdersList[Walker->AdaptiveOrder-1][dest]
5296// *out << Verbose(1) << "Merging resulting key sets with those present in destination " << dest << "." << endl;
5297// InsertGraphIntoGraph(out, *FragmentLowerOrdersList[RootNr][dest], TempFragmentList, &NumMolecules);
5298// }
5299// }
5300// *out << Verbose(1) << "Number of resulting molecules for SubOrder " << SubOrder << " is: " << NumMolecules << "." << endl;
5301// }
5302// }
5303// }
5304 } else {
5305 Walker->GetTrueFather()->MaxOrder = true;
5306// *out << Verbose(1) << "Hence, we don't dive into SubOrders ... " << endl;
5307 }
5308 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
5309 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
5310 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
5311// *out << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
5312 RootStack.push_back(RootKeyNr); // put back on stack
5313 RootNr++;
5314
5315 // free Order-dependent entries of UniqueFragments structure for next loop cycle
5316 Free((void **)&FragmentSearch.BondsPerSPCount, "molecule::PowerSetGenerator: *BondsPerSPCount");
5317 for (int i=Order;i--;) {
5318 delete(FragmentSearch.BondsPerSPList[2*i]);
5319 delete(FragmentSearch.BondsPerSPList[2*i+1]);
5320 }
5321 Free((void **)&FragmentSearch.BondsPerSPList, "molecule::PowerSetGenerator: ***BondsPerSPList");
5322 }
5323 }
5324 *out << Verbose(0) << "==============================================================================================================" << endl;
5325 *out << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl;
5326 *out << Verbose(0) << "==============================================================================================================" << endl;
5327
5328 // cleanup FragmentSearch structure
5329 Free((void **)&FragmentSearch.ShortestPathList, "molecule::PowerSetGenerator: *ShortestPathList");
5330 delete(FragmentSearch.FragmentSet);
5331
5332 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
5333 // 5433222211111111
5334 // 43221111
5335 // 3211
5336 // 21
5337 // 1
5338
5339 // Subsequently, we combine all into a single list (FragmentList)
5340
5341 *out << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl;
5342 if (FragmentList == NULL) {
5343 FragmentList = new Graph;
5344 counter = 0;
5345 } else {
5346 counter = FragmentList->size();
5347 }
5348 RootNr = 0;
5349 while (!RootStack.empty()) {
5350 RootKeyNr = RootStack.front();
5351 RootStack.pop_front();
5352 Walker = FindAtom(RootKeyNr);
5353 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
5354 for(int i=0;i<NumLevels;i++) {
5355 if (FragmentLowerOrdersList[RootNr][i] != NULL) {
5356 InsertGraphIntoGraph(out, *FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
5357 delete(FragmentLowerOrdersList[RootNr][i]);
5358 }
5359 }
5360 Free((void **)&FragmentLowerOrdersList[RootNr], "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
5361 RootNr++;
5362 }
5363 Free((void **)&FragmentLowerOrdersList, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
5364 Free((void **)&NumMoleculesOfOrder, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
5365
5366 *out << Verbose(0) << "End of FragmentBOSSANOVA." << endl;
5367};
5368
5369/** Comparison function for GSL heapsort on distances in two molecules.
5370 * \param *a
5371 * \param *b
5372 * \return <0, \a *a less than \a *b, ==0 if equal, >0 \a *a greater than \a *b
5373 */
5374inline int CompareDoubles (const void * a, const void * b)
5375{
5376 if (*(double *)a > *(double *)b)
5377 return -1;
5378 else if (*(double *)a < *(double *)b)
5379 return 1;
5380 else
5381 return 0;
5382};
5383
5384/** Determines whether two molecules actually contain the same atoms and coordination.
5385 * \param *out output stream for debugging
5386 * \param *OtherMolecule the molecule to compare this one to
5387 * \param threshold upper limit of difference when comparing the coordination.
5388 * \return NULL - not equal, otherwise an allocated (molecule::AtomCount) permutation map of the atom numbers (which corresponds to which)
5389 */
5390int * molecule::IsEqualToWithinThreshold(ofstream *out, molecule *OtherMolecule, double threshold)
5391{
5392 int flag;
5393 double *Distances = NULL, *OtherDistances = NULL;
5394 Vector CenterOfGravity, OtherCenterOfGravity;
5395 size_t *PermMap = NULL, *OtherPermMap = NULL;
5396 int *PermutationMap = NULL;
5397 atom *Walker = NULL;
5398 bool result = true; // status of comparison
5399
5400 *out << Verbose(3) << "Begin of IsEqualToWithinThreshold." << endl;
5401 /// first count both their atoms and elements and update lists thereby ...
5402 //*out << Verbose(0) << "Counting atoms, updating list" << endl;
5403 CountAtoms(out);
5404 OtherMolecule->CountAtoms(out);
5405 CountElements();
5406 OtherMolecule->CountElements();
5407
5408 /// ... and compare:
5409 /// -# AtomCount
5410 if (result) {
5411 if (AtomCount != OtherMolecule->AtomCount) {
5412 *out << Verbose(4) << "AtomCounts don't match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
5413 result = false;
5414 } else *out << Verbose(4) << "AtomCounts match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
5415 }
5416 /// -# ElementCount
5417 if (result) {
5418 if (ElementCount != OtherMolecule->ElementCount) {
5419 *out << Verbose(4) << "ElementCount don't match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
5420 result = false;
5421 } else *out << Verbose(4) << "ElementCount match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
5422 }
5423 /// -# ElementsInMolecule
5424 if (result) {
5425 for (flag=MAX_ELEMENTS;flag--;) {
5426 //*out << Verbose(5) << "Element " << flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl;
5427 if (ElementsInMolecule[flag] != OtherMolecule->ElementsInMolecule[flag])
5428 break;
5429 }
5430 if (flag < MAX_ELEMENTS) {
5431 *out << Verbose(4) << "ElementsInMolecule don't match." << endl;
5432 result = false;
5433 } else *out << Verbose(4) << "ElementsInMolecule match." << endl;
5434 }
5435 /// then determine and compare center of gravity for each molecule ...
5436 if (result) {
5437 *out << Verbose(5) << "Calculating Centers of Gravity" << endl;
5438 DeterminePeriodicCenter(CenterOfGravity);
5439 OtherMolecule->DeterminePeriodicCenter(OtherCenterOfGravity);
5440 *out << Verbose(5) << "Center of Gravity: ";
5441 CenterOfGravity.Output(out);
5442 *out << endl << Verbose(5) << "Other Center of Gravity: ";
5443 OtherCenterOfGravity.Output(out);
5444 *out << endl;
5445 if (CenterOfGravity.DistanceSquared(&OtherCenterOfGravity) > threshold*threshold) {
5446 *out << Verbose(4) << "Centers of gravity don't match." << endl;
5447 result = false;
5448 }
5449 }
5450
5451 /// ... then make a list with the euclidian distance to this center for each atom of both molecules
5452 if (result) {
5453 *out << Verbose(5) << "Calculating distances" << endl;
5454 Distances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: Distances");
5455 OtherDistances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: OtherDistances");
5456 Walker = start;
5457 while (Walker->next != end) {
5458 Walker = Walker->next;
5459 Distances[Walker->nr] = CenterOfGravity.DistanceSquared(&Walker->x);
5460 }
5461 Walker = OtherMolecule->start;
5462 while (Walker->next != OtherMolecule->end) {
5463 Walker = Walker->next;
5464 OtherDistances[Walker->nr] = OtherCenterOfGravity.DistanceSquared(&Walker->x);
5465 }
5466
5467 /// ... sort each list (using heapsort (o(N log N)) from GSL)
5468 *out << Verbose(5) << "Sorting distances" << endl;
5469 PermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermMap");
5470 OtherPermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
5471 gsl_heapsort_index (PermMap, Distances, AtomCount, sizeof(double), CompareDoubles);
5472 gsl_heapsort_index (OtherPermMap, OtherDistances, AtomCount, sizeof(double), CompareDoubles);
5473 PermutationMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermutationMap");
5474 *out << Verbose(5) << "Combining Permutation Maps" << endl;
5475 for(int i=AtomCount;i--;)
5476 PermutationMap[PermMap[i]] = (int) OtherPermMap[i];
5477
5478 /// ... and compare them step by step, whether the difference is individiually(!) below \a threshold for all
5479 *out << Verbose(4) << "Comparing distances" << endl;
5480 flag = 0;
5481 for (int i=0;i<AtomCount;i++) {
5482 *out << Verbose(5) << "Distances squared: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " << threshold << endl;
5483 if (fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) > threshold*threshold)
5484 flag = 1;
5485 }
5486 Free((void **)&PermMap, "molecule::IsEqualToWithinThreshold: *PermMap");
5487 Free((void **)&OtherPermMap, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
5488
5489 /// free memory
5490 Free((void **)&Distances, "molecule::IsEqualToWithinThreshold: Distances");
5491 Free((void **)&OtherDistances, "molecule::IsEqualToWithinThreshold: OtherDistances");
5492 if (flag) { // if not equal
5493 Free((void **)&PermutationMap, "molecule::IsEqualToWithinThreshold: *PermutationMap");
5494 result = false;
5495 }
5496 }
5497 /// return pointer to map if all distances were below \a threshold
5498 *out << Verbose(3) << "End of IsEqualToWithinThreshold." << endl;
5499 if (result) {
5500 *out << Verbose(3) << "Result: Equal." << endl;
5501 return PermutationMap;
5502 } else {
5503 *out << Verbose(3) << "Result: Not equal." << endl;
5504 return NULL;
5505 }
5506};
5507
5508/** Returns an index map for two father-son-molecules.
5509 * The map tells which atom in this molecule corresponds to which one in the other molecul with their fathers.
5510 * \param *out output stream for debugging
5511 * \param *OtherMolecule corresponding molecule with fathers
5512 * \return allocated map of size molecule::AtomCount with map
5513 * \todo make this with a good sort O(n), not O(n^2)
5514 */
5515int * molecule::GetFatherSonAtomicMap(ofstream *out, molecule *OtherMolecule)
5516{
5517 atom *Walker = NULL, *OtherWalker = NULL;
5518 *out << Verbose(3) << "Begin of GetFatherAtomicMap." << endl;
5519 int *AtomicMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::GetAtomicMap: *AtomicMap"); //Calloc
5520 for (int i=AtomCount;i--;)
5521 AtomicMap[i] = -1;
5522 if (OtherMolecule == this) { // same molecule
5523 for (int i=AtomCount;i--;) // no need as -1 means already that there is trivial correspondence
5524 AtomicMap[i] = i;
5525 *out << Verbose(4) << "Map is trivial." << endl;
5526 } else {
5527 *out << Verbose(4) << "Map is ";
5528 Walker = start;
5529 while (Walker->next != end) {
5530 Walker = Walker->next;
5531 if (Walker->father == NULL) {
5532 AtomicMap[Walker->nr] = -2;
5533 } else {
5534 OtherWalker = OtherMolecule->start;
5535 while (OtherWalker->next != OtherMolecule->end) {
5536 OtherWalker = OtherWalker->next;
5537 //for (int i=0;i<AtomCount;i++) { // search atom
5538 //for (int j=0;j<OtherMolecule->AtomCount;j++) {
5539 //*out << Verbose(4) << "Comparing father " << Walker->father << " with the other one " << OtherWalker->father << "." << endl;
5540 if (Walker->father == OtherWalker)
5541 AtomicMap[Walker->nr] = OtherWalker->nr;
5542 }
5543 }
5544 *out << AtomicMap[Walker->nr] << "\t";
5545 }
5546 *out << endl;
5547 }
5548 *out << Verbose(3) << "End of GetFatherAtomicMap." << endl;
5549 return AtomicMap;
5550};
5551
5552/** Stores the temperature evaluated from velocities in molecule::Trajectories.
5553 * We simply use the formula equivaleting temperature and kinetic energy:
5554 * \f$k_B T = \sum_i m_i v_i^2\f$
5555 * \param *out output stream for debugging
5556 * \param startstep first MD step in molecule::Trajectories
5557 * \param endstep last plus one MD step in molecule::Trajectories
5558 * \param *output output stream of temperature file
5559 * \return file written (true), failure on writing file (false)
5560 */
5561bool molecule::OutputTemperatureFromTrajectories(ofstream *out, int startstep, int endstep, ofstream *output)
5562{
5563 double temperature;
5564 atom *Walker = NULL;
5565 // test stream
5566 if (output == NULL)
5567 return false;
5568 else
5569 *output << "# Step Temperature [K] Temperature [a.u.]" << endl;
5570 for (int step=startstep;step < endstep; step++) { // loop over all time steps
5571 temperature = 0.;
5572 Walker = start;
5573 while (Walker->next != end) {
5574 Walker = Walker->next;
5575 for (int i=NDIM;i--;)
5576 temperature += Walker->type->mass * Trajectories[Walker].U.at(step).x[i]* Trajectories[Walker].U.at(step).x[i];
5577 }
5578 *output << step << "\t" << temperature*AtomicEnergyToKelvin << "\t" << temperature << endl;
5579 }
5580 return true;
5581};
Note: See TracBrowser for help on using the repository browser.