source: src/molecules.cpp@ 0dbddc

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 0dbddc was 2319ed, checked in by Frederik Heber <heber@…>, 16 years ago

We are one step further in fixing the convex hull: There are two functions of Saskia Metzler missing, but then we may proceed with testing whether the simple correction scheme of the convex envelope works, but one thing: Right now we cannot associate a Tesselation to its molecule as the snake bites it's one tail. Hence, the next commit will consist of fixing this bad-OOP issue.

  • Makefile.am: Just some alphabetical resorting.
  • atom::atom() new copy constructor
  • builder.cpp: some output for cluster volume, molecule::AddCopyAtom() uses new copy constructor
  • FillBoxWithMolecule() - new function to fill the remainder of the simulation box with some given filler molecules. Makes explicit use of the tesselated surfaces
  • find_convex_border() - InsertStraddlingPoints() and CorrectConcaveBaselines() is called to correct for atoms outside the envelope and caused-by concave points
  • Tesselation::InsertStraddlingPoints() enlarges the envelope for all atoms found outside, Tesselation::CorrectConcaveBaselines() corrects all found baselines if the adjacent triangles are concave by flipping.
  • boundary.cpp: Lots of helper routines for stuff further below:
  • The following routines are needed to check whether point is in- or outside:
  • FIX: Tesselation::AddPoint() - newly created BoundaryPoint is removed if already present.

Problem: We want to associate a Tesselation class with each molecule class. However, so far we have to know about atoms and bond and molecules inside the Tesselation. We have to remove this dependency and create some intermediate class which enables/encapsulates the access to Vectors, e.g. hidden inside the atom class. This is also good OOP! The Tesselation also only needs a set of Vectors, not more!

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