source: src/molecules.cpp@ 89c8b2

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 89c8b2 was 89c8b2, checked in by Saskia Metzler <metzler@…>, 15 years ago

Ticket 17: Write new function molecule::CopyMoleculeFromSubRegion()

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