source: src/molecules.cpp@ fa861b

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

Fixed testsuite, removed some minor bugs.

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