source: src/molecules.cpp@ 357fba

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

Huge refactoring of Tesselation routines, but not finished yet.

  • new file tesselation.cpp with all of classes tesselation, Boundary..Set and CandidatesForTesselationOB
  • new file tesselationhelper.cpp with all auxiliary functions.
  • boundary.cpp just contains super functions, combininb molecule and Tesselation pointers
  • new pointer molecule::TesselStruct
  • PointMap, LineMap, TriangleMap DistanceMap have been moved from molecules.hpp to tesselation.hpp
  • new abstract class PointCloud and TesselPoint
  • atom inherits TesselPoint
  • molecule inherits PointCloud (i.e. a set of TesselPoints) and implements all virtual functions for the chained list
  • TriangleFilesWritten is thrown out, intermediate steps are written in find_nonconvex_border and not in find_next_triangle()
  • LinkedCell class uses TesselPoint as its nodes, i.e. as long as any class inherits TesselPoint, it may make use of LinkedCell as well and a PointCloud is used to initialize
  • class atom and bond definitions have been moved to own header files

NOTE: This is not bugfree yet. Tesselation of heptan produces way too many triangles, but runs without faults or leaks.

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