source: src/molecules.cpp@ 69eb71

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 69eb71 was 69eb71, checked in by Christian Neuen <neuen@…>, 16 years ago

Multiple changes to boundary, currently not fully operational.
Molecules has a new routine to create adjacency lists, reading bonds from a dbond file instead of looking for the distances by itself.
Vector function Project onto plane has been updated.

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