source: src/molecules.cpp@ c30cda

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since c30cda was c30cda, checked in by Frederik Heber <heber@…>, 17 years ago

molecule::MinimiseConstrainedPotential() : Minimisation is fixed

Now, minimisation works. The re-occurence of doubles despite pair-wise exchanging during argument minimisation was due to a wrong DistanceIterator list setting in the injective minimisation before.
Also, we enhanced the minimisation finding (though it is not optimal yet!) by going through each possible target in the distance list from the very beginning (i.e. we also take again smaller distances into account).
For control purpose PrintPermutationMap also checks on the number of doubles (i.e. target's that are owned by two sources).

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