source: src/molecules.cpp@ 631dcb

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

Merge branch 'Thermostat'

Conflicts:

.gitignore
Makefile.am
molecuilder/src/analyzer.cpp
molecuilder/src/builder.cpp
molecuilder/src/config.cpp
molecuilder/src/moleculelist.cpp
molecuilder/src/molecules.cpp
molecuilder/src/molecules.hpp

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