source: src/molecules.cpp@ a1fe77

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

Basic implementation of Constrained MD is done, missing testing.

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