source: src/molecules.cpp@ 570125

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

BUGFIX: PointCloud implementation in molecule stopped one before last, IsLast() -> IsEnd()

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