source: src/molecules.cpp@ 042f82

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

fixed indentation from tabs to two spaces.

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