source: src/molecules.cpp@ 375b458

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

fixed indentation from tabs to two spaces.

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