source: src/molecules.cpp@ 41194a

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 41194a was 29812d, checked in by Saskia Metzler <metzler@…>, 16 years ago

Ticket 11: use templates and/or traits to fix Malloc/ReAlloc-Free warnings in a clean manner

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