source: src/molecules.cpp@ fcc9b0

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

FIX: DetermineCenterOfAll() did point in wrong direction, convex envelope working again, but algorithm is not stable

  • molecule::DetermineCenterOfAll() center was the sum of all scaled by -1/Number instead of 1/Number. This was corrected for in the code elsewhere. Now, it returns the correct center and where it's elsewhere called we subtract instead of add
  • Tesselation::TesselateOnBoundary() does now something meaningful. The NormalVector for the starting triangle could not be constructed, as we lacked the initial normal vector. It is however easy to construct from the center of all and the center of the starting triangle. However, the algorithm is faulty for 1_2_dimethylethane.
  • GetBoundaryPoints() - as we do not translate to center of gravity anymore, we have to subtract the center of all. Otherwise the radial method for determining boundary points does not work.

Is not yet working.

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