source: src/molecules.cpp@ 85bac0

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 Candidate_v1.7.0 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 85bac0 was 85bac0, checked in by Frederik Heber <heber@…>, 17 years ago

Implemented molecule::LinearInterpolationBetweenConfiguration().

command line option "-L" with start and end step performs a linear interpolation between two atomic configurations. So far the mapping from initial atom labels to final labels is not yet finished, it is injective, but not yet minimal.

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