source: src/molecules.cpp@ 21c017

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

molecule::CenterInBox puts atoms now periodically into the given box, new function molecule::TranslatePeriodically, BUGFIX: molecule::ReturnFullMatrixforSymmetrical()

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