source: src/molecules.cpp@ 6f6a8e

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 6f6a8e was 5de3c9, checked in by Frederik Heber <heber@…>, 17 years ago

molecule::CheckOrderAtSite() now interprets negative Orders as adaptive increase by parsing EnergyPerFragment.da
t

positive Order is global increase till all sites have at least this order, Order 0 means single global increase step, negative Order is the exponent in 10{-Order} to give the threshold value: ENERGYPERFRAGMENT is scanned in
to a map (sorted by values) and all fragments still above the threshold are taken into AtomMask for increase. Jo
iner has to write this file with (Root id of Fragment, energy contribution) pairs.

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