source: src/molecules.cpp@ 5466f3

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

XYZ and config files now store the atoms in the same order as they are loaded.

changed functions: molecule::OutputXYZ, molecule::OutputTrajectoriesXYZ, molecule::OutputTrajectories, molecule::Output

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