source: src/molecules.cpp@ fcbfc8

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

BUGFIX: molecule::CreateAdjacencyList() used CandidateBondNo in output even if no candidate had been found

+ If no Candidate has been found, output message would declare to be unable to correct bond degree for a unspecified bond (CandidateBondNo set to no sensible value)

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