source: src/molecules.cpp@ d067d45

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

Merge branch 'MultipleMolecules'

Conflicts:

molecuilder/src/analyzer.cpp
molecuilder/src/atom.cpp
molecuilder/src/boundary.cpp
molecuilder/src/boundary.hpp
molecuilder/src/builder.cpp
molecuilder/src/config.cpp
molecuilder/src/datacreator.hpp
molecuilder/src/helpers.cpp
molecuilder/src/joiner.cpp
molecuilder/src/moleculelist.cpp
molecuilder/src/molecules.cpp
molecuilder/src/molecules.hpp
molecuilder/src/parser.cpp
molecuilder/src/parser.hpp
molecuilder/src/vector.cpp
molecuilder/src/verbose.cpp

merges:

compilation fixes:

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