source: src/molecules.cpp@ d52e70c

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

Implemenation of embedding merge, untested. LinearInterpolation now has switch for using identity map.

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