source: src/molecules.cpp@ 2b4a40

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

molecule::AddHydrogenReplacementAtom() returns false on missing parameters, molecule::FragmentMolecule() less output

molecule::AddHydrogenReplacementAtom(): Gave only a warning when either typical hydrogen bond length or angle was missing, now the adding stops, error instead of warning message and false is returned instead.
molecule::BreadthFirstSearchAdd() exits, when AddHydrogenReplacementAtom() returns false
molecule::StoreFragmentFromKeySet() exits, when AddHydrogenReplacementAtom() returns false

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