source: src/molecules.cpp@ 2459b1

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 2459b1 was 2459b1, checked in by Frederik Heber <heber@…>, 17 years ago

ForcesFile and TEFactors are _needed_, reincorporated. UniqueFragments structure is now in BOSSANOVA

ForcesFile is again written, as we need it for the hydrogen not coming saturation (forces!)
TEFactors are back, as despite my notion they are needed in the evaluation
UniqueFragments structure is shifted from PowerSetGenerator to FragmentBOSSANOVA. Actually only for the labels - however, the if was changed to test the real indices (which are also always the same, which is better for adaptive runs) - but might be more useful there still.
analyzer and joiner again parse indices.

  • Property mode set to 100644
File size: 179.5 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/** Output of element before the actual coordination list.
1061 * \param *out stream pointer
1062 */
1063bool molecule::Checkout(ofstream *out) const
1064{
1065 return elemente->Checkout(out, ElementsInMolecule);
1066};
1067
1068/** Prints molecule to *out as xyz file.
1069 * \param *out output stream
1070 */
1071bool molecule::OutputXYZ(ofstream *out) const
1072{
1073 atom *walker = NULL;
1074 int No = 0;
1075 time_t now;
1076
1077 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
1078 walker = start;
1079 while (walker->next != end) { // go through every atom and count
1080 walker = walker->next;
1081 No++;
1082 }
1083 if (out != NULL) {
1084 *out << No << "\n\tCreated by molecuilder on " << ctime(&now);
1085 walker = start;
1086 while (walker->next != end) { // go through every atom of this element
1087 walker = walker->next;
1088 walker->OutputXYZLine(out);
1089 }
1090 return true;
1091 } else
1092 return false;
1093};
1094
1095/** Brings molecule::AtomCount and atom::*Name up-to-date.
1096 * \param *out output stream for debugging
1097 */
1098void molecule::CountAtoms(ofstream *out)
1099{
1100 int i = 0;
1101 atom *Walker = start;
1102 while (Walker->next != end) {
1103 Walker = Walker->next;
1104 i++;
1105 }
1106 if ((AtomCount == 0) || (i != AtomCount)) {
1107 *out << Verbose(3) << "Mismatch in AtomCount " << AtomCount << " and recounted number " << i << ", renaming all." << endl;
1108 AtomCount = i;
1109
1110 // count NonHydrogen atoms and give each atom a unique name
1111 if (AtomCount != 0) {
1112 i=0;
1113 NoNonHydrogen = 0;
1114 Walker = start;
1115 while (Walker->next != end) {
1116 Walker = Walker->next;
1117 Walker->nr = i; // update number in molecule (for easier referencing in FragmentMolecule lateron)
1118 if (Walker->type->Z != 1) // count non-hydrogen atoms whilst at it
1119 NoNonHydrogen++;
1120 Free((void **)&Walker->Name, "molecule::CountAtoms: *walker->Name");
1121 Walker->Name = (char *) Malloc(sizeof(char)*6, "molecule::CountAtoms: *walker->Name");
1122 sprintf(Walker->Name, "%2s%02d", Walker->type->symbol, Walker->nr+1);
1123 *out << "Naming atom nr. " << Walker->nr << " " << Walker->Name << "." << endl;
1124 i++;
1125 }
1126 } else
1127 *out << Verbose(3) << "AtomCount is still " << AtomCount << ", thus counting nothing." << endl;
1128 }
1129};
1130
1131/** Brings molecule::ElementCount and molecule::ElementsInMolecule up-to-date.
1132 */
1133void molecule::CountElements()
1134{
1135 int i = 0;
1136 for(i=0;i<MAX_ELEMENTS;i++)
1137 ElementsInMolecule[i] = 0;
1138 ElementCount = 0;
1139
1140 atom *walker = start;
1141 while (walker->next != end) {
1142 walker = walker->next;
1143 ElementsInMolecule[walker->type->Z]++;
1144 i++;
1145 }
1146 for(i=0;i<MAX_ELEMENTS;i++)
1147 ElementCount += (ElementsInMolecule[i] != 0 ? 1 : 0);
1148};
1149
1150/** Counts all cyclic bonds and returns their number.
1151 * \note Hydrogen bonds can never by cyclic, thus no check for that
1152 * \param *out output stream for debugging
1153 * \return number opf cyclic bonds
1154 */
1155int molecule::CountCyclicBonds(ofstream *out)
1156{
1157 int No = 0;
1158 int MinimumRingSize;
1159 MoleculeLeafClass *Subgraphs = NULL;
1160 bond *Binder = first;
1161 if ((Binder->next != last) && (Binder->next->Type == Undetermined)) {
1162 *out << Verbose(0) << "No Depth-First-Search analysis performed so far, calling ..." << endl;
1163 Subgraphs = DepthFirstSearchAnalysis(out, false, MinimumRingSize);
1164 while (Subgraphs->next != NULL) {
1165 Subgraphs = Subgraphs->next;
1166 delete(Subgraphs->previous);
1167 }
1168 delete(Subgraphs);
1169 }
1170 while(Binder->next != last) {
1171 Binder = Binder->next;
1172 if (Binder->Cyclic)
1173 No++;
1174 }
1175 return No;
1176};
1177
1178/** Returns Shading as a char string.
1179 * \param color the Shading
1180 * \return string of the flag
1181 */
1182char * molecule::GetColor(enum Shading color)
1183{
1184 switch(color) {
1185 case white:
1186 return "white";
1187 break;
1188 case lightgray:
1189 return "lightgray";
1190 break;
1191 case darkgray:
1192 return "darkgray";
1193 break;
1194 case black:
1195 return "black";
1196 break;
1197 default:
1198 return "uncolored";
1199 break;
1200 };
1201};
1202
1203
1204/** Counts necessary number of valence electrons and returns number and SpinType.
1205 * \param configuration containing everything
1206 */
1207void molecule::CalculateOrbitals(class config &configuration)
1208{
1209 configuration.MaxPsiDouble = configuration.PsiMaxNoDown = configuration.PsiMaxNoUp = configuration.PsiType = 0;
1210 for(int i=0;i<MAX_ELEMENTS;i++) {
1211 if (ElementsInMolecule[i] != 0) {
1212 //cout << "CalculateOrbitals: " << elemente->FindElement(i)->name << " has a valence of " << (int)elemente->FindElement(i)->Valence << " and there are " << ElementsInMolecule[i] << " of it." << endl;
1213 configuration.MaxPsiDouble += ElementsInMolecule[i]*((int)elemente->FindElement(i)->Valence);
1214 }
1215 }
1216 configuration.PsiMaxNoDown = configuration.MaxPsiDouble/2 + (configuration.MaxPsiDouble % 2);
1217 configuration.PsiMaxNoUp = configuration.MaxPsiDouble/2;
1218 configuration.MaxPsiDouble /= 2;
1219 configuration.PsiType = (configuration.PsiMaxNoDown == configuration.PsiMaxNoUp) ? 0 : 1;
1220 if ((configuration.PsiType == 1) && (configuration.ProcPEPsi < 2)) {
1221 configuration.ProcPEGamma /= 2;
1222 configuration.ProcPEPsi *= 2;
1223 } else {
1224 configuration.ProcPEGamma *= configuration.ProcPEPsi;
1225 configuration.ProcPEPsi = 1;
1226 }
1227 configuration.InitMaxMinStopStep = configuration.MaxMinStopStep = configuration.MaxPsiDouble;
1228};
1229
1230/** Creates an adjacency list of the molecule.
1231 * Generally, we use the CSD approach to bond recognition, that is the the distance
1232 * between two atoms A and B must be within [Rcov(A)+Rcov(B)-t,Rcov(A)+Rcov(B)+t] with
1233 * a threshold t = 0.4 Angstroem.
1234 * To make it O(N log N) the function uses the linked-cell technique as follows:
1235 * The procedure is step-wise:
1236 * -# Remove every bond in list
1237 * -# Count the atoms in the molecule with CountAtoms()
1238 * -# partition cell into smaller linked cells of size \a bonddistance
1239 * -# put each atom into its corresponding cell
1240 * -# go through every cell, check the atoms therein against all possible bond partners in the 27 adjacent cells, add bond if true
1241 * -# create the list of bonds via CreateListOfBondsPerAtom()
1242 * -# correct the bond degree iteratively (single->double->triple bond)
1243 * -# finally print the bond list to \a *out if desired
1244 * \param *out out stream for printing the matrix, NULL if no output
1245 * \param bonddistance length of linked cells (i.e. maximum minimal length checked)
1246 */
1247void molecule::CreateAdjacencyList(ofstream *out, double bonddistance)
1248{
1249 atom *Walker = NULL, *OtherWalker = NULL;
1250 int No, NoBonds;
1251 int NumberCells, divisor[NDIM], n[NDIM], N[NDIM], index, Index, j;
1252 molecule **CellList;
1253 double distance, MinDistance, MaxDistance;
1254 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
1255 vector x;
1256
1257 BondDistance = bonddistance;
1258 *out << Verbose(0) << "Begin of CreateAdjacencyList." << endl;
1259 // remove every bond from the list
1260 if ((first->next != last) && (last->previous != first)) { // there are bonds present
1261 cleanup(first,last);
1262 }
1263
1264 // count atoms in molecule = dimension of matrix (also give each unique name and continuous numbering)
1265 CountAtoms(out);
1266 *out << Verbose(1) << "AtomCount " << AtomCount << "." << endl;
1267
1268 if (AtomCount != 0) {
1269 // 1. find divisor for each axis, such that a sphere with radius of at least bonddistance can be placed into each cell
1270 j=-1;
1271 for (int i=0;i<NDIM;i++) {
1272 j += i+1;
1273 divisor[i] = (int)floor(cell_size[j]/bonddistance); // take smaller value such that size of linked cell is at least bonddistance
1274 *out << Verbose(1) << "divisor[" << i << "] = " << divisor[i] << "." << endl;
1275 }
1276 // 2a. allocate memory for the cell list
1277 NumberCells = divisor[0]*divisor[1]*divisor[2];
1278 *out << Verbose(1) << "Allocating " << NumberCells << " cells." << endl;
1279 CellList = (molecule **) Malloc(sizeof(molecule *)*NumberCells, "molecule::CreateAdjacencyList - ** CellList");
1280 for (int i=0;i<NumberCells;i++)
1281 CellList[i] = NULL;
1282
1283 // 2b. put all atoms into its corresponding list
1284 Walker = start;
1285 while(Walker->next != end) {
1286 Walker = Walker->next;
1287 //*out << Verbose(1) << "Current atom is " << *Walker << " with coordinates ";
1288 //Walker->x.Output(out);
1289 //*out << "." << endl;
1290 // compute the cell by the atom's coordinates
1291 j=-1;
1292 for (int i=0;i<NDIM;i++) {
1293 j += i+1;
1294 x.CopyVector(&(Walker->x));
1295 x.KeepPeriodic(out, matrix);
1296 n[i] = (int)floor(x.x[i]/cell_size[j]*(double)divisor[i]);
1297 }
1298 index = n[2] + (n[1] + n[0] * divisor[1]) * divisor[2];
1299 *out << Verbose(1) << "Atom " << *Walker << " goes into cell number [" << n[0] << "," << n[1] << "," << n[2] << "] = " << index << "." << endl;
1300 // add copy atom to this cell
1301 if (CellList[index] == NULL) // allocate molecule if not done
1302 CellList[index] = new molecule(elemente);
1303 OtherWalker = CellList[index]->AddCopyAtom(Walker); // add a copy of walker to this atom, father will be walker for later reference
1304 //*out << Verbose(1) << "Copy Atom is " << *OtherWalker << "." << endl;
1305 }
1306 //for (int i=0;i<NumberCells;i++)
1307 //*out << Verbose(1) << "Cell number " << i << ": " << CellList[i] << "." << endl;
1308
1309 // 3a. go through every cell
1310 for (N[0]=0;N[0]<divisor[0];N[0]++)
1311 for (N[1]=0;N[1]<divisor[1];N[1]++)
1312 for (N[2]=0;N[2]<divisor[2];N[2]++) {
1313 Index = N[2] + (N[1] + N[0] * divisor[1]) * divisor[2];
1314 if (CellList[Index] != NULL) { // if there atoms in this cell
1315 //*out << Verbose(1) << "Current cell is " << Index << "." << endl;
1316 // 3b. for every atom therein
1317 Walker = CellList[Index]->start;
1318 while (Walker->next != CellList[Index]->end) { // go through every atom
1319 Walker = Walker->next;
1320 //*out << Verbose(0) << "Current Atom is " << *Walker << "." << endl;
1321 // 3c. check for possible bond between each atom in this and every one in the 27 cells
1322 for (n[0]=-1;n[0]<=1;n[0]++)
1323 for (n[1]=-1;n[1]<=1;n[1]++)
1324 for (n[2]=-1;n[2]<=1;n[2]++) {
1325 // compute the index of this comparison cell and make it periodic
1326 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];
1327 //*out << Verbose(1) << "Number of comparison cell is " << index << "." << endl;
1328 if (CellList[index] != NULL) { // if there are any atoms in this cell
1329 OtherWalker = CellList[index]->start;
1330 while(OtherWalker->next != CellList[index]->end) { // go through every atom in this cell
1331 OtherWalker = OtherWalker->next;
1332 //*out << Verbose(0) << "Current comparison atom is " << *OtherWalker << "." << endl;
1333 /// \todo periodic check is missing here!
1334 //*out << Verbose(1) << "Checking distance " << OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size) << " against typical bond length of " << bonddistance*bonddistance << "." << endl;
1335 MinDistance = OtherWalker->type->CovalentRadius + Walker->type->CovalentRadius;
1336 MaxDistance = MinDistance + BONDTHRESHOLD;
1337 MinDistance -= BONDTHRESHOLD;
1338 distance = OtherWalker->x.PeriodicDistance(&(Walker->x), cell_size);
1339 if ((OtherWalker->father->nr > Walker->father->nr) && (distance <= MaxDistance*MaxDistance) && (distance >= MinDistance*MinDistance)) { // create bond if distance is smaller
1340 *out << Verbose(0) << "Adding Bond between " << *Walker << " and " << *OtherWalker << "." << endl;
1341 AddBond(Walker->father, OtherWalker->father, 1); // also increases molecule::BondCount
1342 } else {
1343 //*out << Verbose(1) << "Not Adding: Wrong label order or distance too great." << endl;
1344 }
1345 }
1346 }
1347 }
1348 }
1349 }
1350 }
1351 // 4. free the cell again
1352 for (int i=0;i<NumberCells;i++)
1353 if (CellList[i] != NULL) {
1354 delete(CellList[i]);
1355 }
1356 Free((void **)&CellList, "molecule::CreateAdjacencyList - ** CellList");
1357
1358 // create the adjacency list per atom
1359 CreateListOfBondsPerAtom(out);
1360
1361 // correct Bond degree of each bond by checking of updated(!) sum of bond degree for an atom match its valence count
1362 // bond degrres are correctled iteratively by one, so that 2-2 instead of 1-3 or 3-1 corrections are favoured: We want
1363 // a rather symmetric distribution of higher bond degrees
1364 if (BondCount != 0) {
1365 NoCyclicBonds = 0;
1366 *out << Verbose(1) << "Correcting Bond degree of each bond ... ";
1367 do {
1368 No = 0; // No acts as breakup flag (if 1 we still continue)
1369 Walker = start;
1370 while (Walker->next != end) { // go through every atom
1371 Walker = Walker->next;
1372 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through each of its bond partners
1373 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
1374 // count valence of first partner (updated!), might have changed during last bond partner
1375 NoBonds = 0;
1376 for(j=0;j<NumberOfBondsPerAtom[Walker->nr];j++)
1377 NoBonds += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
1378 //*out << Verbose(3) << "Walker: " << (int)Walker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
1379 if ((int)(Walker->type->NoValenceOrbitals) > NoBonds) { // we have a mismatch, check NoBonds of other atom
1380 // count valence of second partner
1381 NoBonds = 0;
1382 for(j=0;j<NumberOfBondsPerAtom[OtherWalker->nr];j++)
1383 NoBonds += ListOfBondsPerAtom[OtherWalker->nr][j]->BondDegree;
1384 //*out << Verbose(3) << "OtherWalker: " << (int)OtherWalker->type->NoValenceOrbitals << " > " << NoBonds << "?" << endl;
1385 if ((int)(OtherWalker->type->NoValenceOrbitals) > NoBonds) // increase bond degree by one
1386 ListOfBondsPerAtom[Walker->nr][i]->BondDegree++;
1387 }
1388 }
1389 }
1390 } while (No);
1391 *out << " done." << endl;
1392 } else
1393 *out << Verbose(1) << "BondCount is " << BondCount << ", no bonds between any of the " << AtomCount << " atoms." << endl;
1394 *out << Verbose(1) << "I detected " << BondCount << " bonds in the molecule with distance " << bonddistance << "." << endl;
1395
1396// // output bonds for debugging (if bond chain list was correctly installed)
1397// *out << Verbose(1) << endl << "From contents of bond chain list:";
1398// bond *Binder = first;
1399// while(Binder->next != last) {
1400// Binder = Binder->next;
1401// *out << *Binder << "\t" << endl;
1402// }
1403// *out << endl;
1404 } else
1405 *out << Verbose(1) << "AtomCount is " << AtomCount << ", thus no bonds, no connections!." << endl;
1406 *out << Verbose(0) << "End of CreateAdjacencyList." << endl;
1407 Free((void **)&matrix, "molecule::CreateAdjacencyList: *matrix");
1408};
1409
1410/** Performs a Depth-First search on this molecule.
1411 * Marks bonds in molecule as cyclic, bridge, ... and atoms as
1412 * articulations points, ...
1413 * We use the algorithm from [Even, Graph Algorithms, p.62].
1414 * \param *out output stream for debugging
1415 * \param ReturnStack true - return pointer to atom stack of separable components, false - return NULL
1416 * \param MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found
1417 * \return list of each disconnected subgraph as an individual molecule class structure
1418 */
1419MoleculeLeafClass * molecule::DepthFirstSearchAnalysis(ofstream *out, bool ReturnStack, int &MinimumRingSize)
1420{
1421 AtomStackClass *AtomStack = new AtomStackClass(AtomCount);
1422 MoleculeLeafClass *SubGraphs = new MoleculeLeafClass(NULL);
1423 MoleculeLeafClass *LeafWalker = SubGraphs;
1424 int CurrentGraphNr = 0, OldGraphNr;
1425 int CyclicBonds;
1426 int ComponentNumber = 0;
1427 atom *Walker = NULL, *OtherAtom = NULL, *Root = start->next;
1428 bond *Binder = NULL;
1429 bool BackStepping = false;
1430
1431 *out << Verbose(0) << "Begin of DepthFirstSearchAnalysis" << endl;
1432
1433 ResetAllBondsToUnused();
1434 ResetAllAtomNumbers();
1435 InitComponentNumbers();
1436 while (Root != end) { // if there any atoms at all
1437 // (1) mark all edges unused, empty stack, set atom->GraphNr = 0 for all
1438 AtomStack->ClearStack();
1439
1440 // put into new subgraph molecule and add this to list of subgraphs
1441 LeafWalker = new MoleculeLeafClass(LeafWalker);
1442 LeafWalker->Leaf = new molecule(elemente);
1443 LeafWalker->Leaf->AddCopyAtom(Root);
1444
1445 OldGraphNr = CurrentGraphNr;
1446 Walker = Root;
1447 do { // (10)
1448 do { // (2) set number and Lowpoint of Atom to i, increase i, push current atom
1449 if (!BackStepping) { // if we don't just return from (8)
1450 Walker->GraphNr = CurrentGraphNr;
1451 Walker->LowpointNr = CurrentGraphNr;
1452 *out << Verbose(1) << "Setting Walker[" << Walker->Name << "]'s number to " << Walker->GraphNr << " with Lowpoint " << Walker->LowpointNr << "." << endl;
1453 AtomStack->Push(Walker);
1454 CurrentGraphNr++;
1455 }
1456 do { // (3) if Walker has no unused egdes, go to (5)
1457 BackStepping = false; // reset backstepping flag for (8)
1458 if (Binder == NULL) // if we don't just return from (11), Binder is already set to next unused
1459 Binder = FindNextUnused(Walker);
1460 if (Binder == NULL)
1461 break;
1462 *out << Verbose(2) << "Current Unused Bond is " << *Binder << "." << endl;
1463 // (4) Mark Binder used, ...
1464 Binder->MarkUsed(black);
1465 OtherAtom = Binder->GetOtherAtom(Walker);
1466 *out << Verbose(2) << "(4) OtherAtom is " << OtherAtom->Name << "." << endl;
1467 if (OtherAtom->GraphNr != -1) {
1468 // (4a) ... if "other" atom has been visited (GraphNr != 0), set lowpoint to minimum of both, go to (3)
1469 Binder->Type = BackEdge;
1470 Walker->LowpointNr = ( Walker->LowpointNr < OtherAtom->GraphNr ) ? Walker->LowpointNr : OtherAtom->GraphNr;
1471 *out << Verbose(3) << "(4a) Visited: Setting Lowpoint of Walker[" << Walker->Name << "] to " << Walker->LowpointNr << "." << endl;
1472 } else {
1473 // (4b) ... otherwise set OtherAtom as Ancestor of Walker and Walker as OtherAtom, go to (2)
1474 Binder->Type = TreeEdge;
1475 OtherAtom->Ancestor = Walker;
1476 Walker = OtherAtom;
1477 *out << Verbose(3) << "(4b) Not Visited: OtherAtom[" << OtherAtom->Name << "]'s Ancestor is now " << OtherAtom->Ancestor->Name << ", Walker is OtherAtom " << OtherAtom->Name << "." << endl;
1478 break;
1479 }
1480 Binder = NULL;
1481 } while (1); // (3)
1482 if (Binder == NULL) {
1483 *out << Verbose(2) << "No more Unused Bonds." << endl;
1484 break;
1485 } else
1486 Binder = NULL;
1487 } while (1); // (2)
1488
1489 // 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!
1490 if ((Walker == Root) && (Binder == NULL))
1491 break;
1492
1493 // (5) if Ancestor of Walker is ...
1494 *out << Verbose(1) << "(5) Number of Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "] is " << Walker->Ancestor->GraphNr << "." << endl;
1495 if (Walker->Ancestor->GraphNr != Root->GraphNr) {
1496 // (6) (Ancestor of Walker is not Root)
1497 if (Walker->LowpointNr < Walker->Ancestor->GraphNr) {
1498 // (6a) set Ancestor's Lowpoint number to minimum of of its Ancestor and itself, go to Step(8)
1499 Walker->Ancestor->LowpointNr = (Walker->Ancestor->LowpointNr < Walker->LowpointNr) ? Walker->Ancestor->LowpointNr : Walker->LowpointNr;
1500 *out << Verbose(2) << "(6) Setting Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s Lowpoint to " << Walker->Ancestor->LowpointNr << "." << endl;
1501 } else {
1502 // (7) (Ancestor of Walker is a separating vertex, remove all from stack till Walker (including), these and Ancestor form a component
1503 Walker->Ancestor->SeparationVertex = true;
1504 *out << Verbose(2) << "(7) Walker[" << Walker->Name << "]'s Ancestor[" << Walker->Ancestor->Name << "]'s is a separating vertex, creating component." << endl;
1505 SetNextComponentNumber(Walker->Ancestor, ComponentNumber);
1506 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Ancestor's Compont is " << ComponentNumber << "." << endl;
1507 SetNextComponentNumber(Walker, ComponentNumber);
1508 *out << Verbose(3) << "(7) Walker[" << Walker->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1509 do {
1510 OtherAtom = AtomStack->PopLast();
1511 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
1512 SetNextComponentNumber(OtherAtom, ComponentNumber);
1513 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1514 } while (OtherAtom != Walker);
1515 ComponentNumber++;
1516 }
1517 // (8) Walker becomes its Ancestor, go to (3)
1518 *out << Verbose(2) << "(8) Walker[" << Walker->Name << "] is now its Ancestor " << Walker->Ancestor->Name << ", backstepping. " << endl;
1519 Walker = Walker->Ancestor;
1520 BackStepping = true;
1521 }
1522 if (!BackStepping) { // coming from (8) want to go to (3)
1523 // (9) remove all from stack till Walker (including), these and Root form a component
1524 AtomStack->Output(out);
1525 SetNextComponentNumber(Root, ComponentNumber);
1526 *out << Verbose(3) << "(9) Root[" << Root->Name << "]'s Component is " << ComponentNumber << "." << endl;
1527 SetNextComponentNumber(Walker, ComponentNumber);
1528 *out << Verbose(3) << "(9) Walker[" << Walker->Name << "]'s Component is " << ComponentNumber << "." << endl;
1529 do {
1530 OtherAtom = AtomStack->PopLast();
1531 LeafWalker->Leaf->AddCopyAtom(OtherAtom);
1532 SetNextComponentNumber(OtherAtom, ComponentNumber);
1533 *out << Verbose(3) << "(7) Other[" << OtherAtom->Name << "]'s Compont is " << ComponentNumber << "." << endl;
1534 } while (OtherAtom != Walker);
1535 ComponentNumber++;
1536
1537 // (11) Root is separation vertex, set Walker to Root and go to (4)
1538 Walker = Root;
1539 Binder = FindNextUnused(Walker);
1540 *out << Verbose(1) << "(10) Walker is Root[" << Root->Name << "], next Unused Bond is " << Binder << "." << endl;
1541 if (Binder != NULL) { // Root is separation vertex
1542 *out << Verbose(1) << "(11) Root is a separation vertex." << endl;
1543 Walker->SeparationVertex = true;
1544 }
1545 }
1546 } while ((BackStepping) || (Binder != NULL)); // (10) halt only if Root has no unused edges
1547
1548 // From OldGraphNr to CurrentGraphNr ranges an disconnected subgraph
1549 *out << Verbose(0) << "Disconnected subgraph ranges from " << OldGraphNr << " to " << CurrentGraphNr << "." << endl;
1550 LeafWalker->Leaf->Output(out);
1551 *out << endl;
1552
1553 // step on to next root
1554 while ((Root != end) && (Root->GraphNr != -1)) {
1555 //*out << Verbose(1) << "Current next subgraph root candidate is " << Root->Name << "." << endl;
1556 if (Root->GraphNr != -1) // if already discovered, step on
1557 Root = Root->next;
1558 }
1559 }
1560 // set cyclic bond criterium on "same LP" basis
1561 Binder = first;
1562 while(Binder->next != last) {
1563 Binder = Binder->next;
1564 if (Binder->rightatom->LowpointNr == Binder->leftatom->LowpointNr) { // cyclic ??
1565 Binder->Cyclic = true;
1566 NoCyclicBonds++;
1567 }
1568 }
1569
1570 // correct cyclic bonds that are not included in "same LP" argument
1571 Binder = first;
1572 while (Binder->next != last) {
1573 Binder = Binder->next;
1574 Walker = Binder->leftatom;
1575 OtherAtom = Binder->rightatom;
1576 // now check whether both have a cyclic bond in their list
1577 CyclicBonds = 0; // counts cyclic bonds;
1578 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
1579 if ((CyclicBonds == 0) && (ListOfBondsPerAtom[Walker->nr][i]->Cyclic))
1580 CyclicBonds = 1;
1581 for(int i=0;i<NumberOfBondsPerAtom[OtherAtom->nr];i++)
1582 if ((CyclicBonds == 1) && (ListOfBondsPerAtom[OtherAtom->nr][i]->Cyclic))
1583 CyclicBonds = 2;
1584 Binder->Cyclic = (Binder->Cyclic) || (CyclicBonds == 2); // set the Cyclic criterium either or ...
1585 }
1586
1587 // further analysis of the found cycles (print rings, get minimum cycle length)
1588 CyclicStructureAnalysis(out, MinimumRingSize);
1589 *out << Verbose(1) << "Final graph info for each atom is:" << endl;
1590 Walker = start;
1591 while (Walker->next != end) {
1592 Walker = Walker->next;
1593 *out << Verbose(2) << "Atom " << Walker->Name << " is " << ((Walker->SeparationVertex) ? "a" : "not a") << " separation vertex, components are ";
1594 OutputComponentNumber(out, Walker);
1595 *out << " with Lowpoint " << Walker->LowpointNr << " and Graph Nr. " << Walker->GraphNr << "." << endl;
1596 }
1597
1598 *out << Verbose(1) << "Final graph info for each bond is:" << endl;
1599 Binder = first;
1600 while(Binder->next != last) {
1601 Binder = Binder->next;
1602 *out << Verbose(2) << ((Binder->Type == TreeEdge) ? "TreeEdge " : "BackEdge ") << *Binder << ": <";
1603 *out << ((Binder->leftatom->SeparationVertex) ? "SP," : "") << "L" << Binder->leftatom->LowpointNr << " G" << Binder->leftatom->GraphNr << " Comp.";
1604 OutputComponentNumber(out, Binder->leftatom);
1605 *out << " === ";
1606 *out << ((Binder->rightatom->SeparationVertex) ? "SP," : "") << "L" << Binder->rightatom->LowpointNr << " G" << Binder->rightatom->GraphNr << " Comp.";
1607 OutputComponentNumber(out, Binder->rightatom);
1608 *out << ">." << endl;
1609 if (Binder->Cyclic) // cyclic ??
1610 *out << Verbose(3) << "Lowpoint at each side are equal: CYCLIC!" << endl;
1611 }
1612
1613 // free all and exit
1614 delete(AtomStack);
1615 *out << Verbose(0) << "End of DepthFirstSearchAnalysis" << endl;
1616 return SubGraphs;
1617};
1618
1619/** Analyses the cycles found and returns minimum of all cycle lengths.
1620 * \param *out output stream for debugging
1621 * \param MinimumRingSize contains smallest ring size in molecular structure on return or -1 if no rings were found
1622 * \todo BFS from the not-same-LP to find back to starting point of tributary cycle over more than one bond
1623 */
1624void molecule::CyclicStructureAnalysis(ofstream *out, int &MinimumRingSize)
1625{
1626 AtomStackClass *AtomStack = new AtomStackClass(AtomCount);
1627 int LP;
1628 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Runner = NULL;
1629 bond *Binder = NULL;
1630 int RingSize, NumCycles;
1631
1632 // go through every atom
1633 AtomStack->ClearStack();
1634 int *NoCyclicBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CyclicStructureAnalysis: *NoCyclicBondsPerAtom");
1635 Walker = start;
1636 while (Walker->next != end) {
1637 Walker = Walker->next;
1638 NoCyclicBondsPerAtom[Walker->nr] = 0;
1639 // check whether it's connected to cyclic bonds and count per atom
1640 // 0 means not part of a cycle, 2 means in a cycle, 3 or more means interconnection site of cycles
1641 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr]; i++) {
1642 Binder = ListOfBondsPerAtom[Walker->nr][i];
1643 NoCyclicBondsPerAtom[Walker->nr] += (int) Binder->Cyclic;
1644 if (NoCyclicBondsPerAtom[Walker->nr] == 3) //push all intersections
1645 AtomStack->Push(Walker);
1646 }
1647 }
1648 *out << Verbose(1) << "NoCyclicBondsPerAtom: ";
1649 for(int i=0;i<AtomCount;i++) {
1650 *out << NoCyclicBondsPerAtom[i] << " ";
1651 }
1652 *out << endl;
1653 *out << Verbose(1) << "Analysing cycles ... " << endl;
1654 MinimumRingSize = -1;
1655 NumCycles = 0;
1656 while (!AtomStack->IsEmpty()) {
1657 Walker = AtomStack->PopFirst();
1658 if (NoCyclicBondsPerAtom[Walker->nr] > 1) {
1659 NoCyclicBondsPerAtom[Walker->nr]--; // remove one for being intersection
1660 RingSize = 0;
1661 *out << Verbose(2) << "Current intersection is " << *Walker << ", expect to find " << NoCyclicBondsPerAtom[Walker->nr] << " cycles." << endl;
1662 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
1663 Binder = ListOfBondsPerAtom[Walker->nr][i];
1664 OtherAtom = Binder->GetOtherAtom(Walker);
1665 // note down the LowPoint number of this cycle
1666 if (NoCyclicBondsPerAtom[OtherAtom->nr] > 1) {
1667 LP = OtherAtom->LowpointNr;
1668 NoCyclicBondsPerAtom[Walker->nr]--; // walker is start of cycle
1669 if (LP != Walker->LowpointNr)
1670 *out << Verbose(2) << "Tributary cycle: ... <-> " << Walker->Name;
1671 else
1672 *out << Verbose(2) << "Main cycle: ... <-> " << Walker->Name;
1673 Root = Walker; // root acts as predecessor marker so that we don't step back accidentally
1674 RingSize = 1;
1675 do {
1676 for(int j=0;j<NumberOfBondsPerAtom[OtherAtom->nr];j++) { // search among its bonds for next in cycle (same lowpoint nr)
1677 Runner = ListOfBondsPerAtom[OtherAtom->nr][j]->GetOtherAtom(OtherAtom);
1678 if (((Runner->LowpointNr == LP) || (Runner->LowpointNr == Walker->LowpointNr)) && (Runner != Root)) {
1679 // first check is to stay in the cycle
1680 // middle check is allow for getting back into main cycle briefly from tributary cycle (just one step, then while further down stops)
1681 // last check is not step back
1682 *out << " <-> " << OtherAtom->Name;
1683 NoCyclicBondsPerAtom[OtherAtom->nr]--;
1684 Root = OtherAtom;
1685 OtherAtom = Runner;
1686 NoCyclicBondsPerAtom[Root->nr]--;
1687 RingSize++;
1688 break;
1689 }
1690 }
1691 } while ((OtherAtom->LowpointNr == LP) && (Walker != OtherAtom) && (Root->LowpointNr == OtherAtom->LowpointNr));
1692 // now check if the LP is different from Walker's, as then there is one more bond to follow
1693 if (LP != Walker->LowpointNr) {
1694 // find last bond to home base
1695 for(int j=0;j<NumberOfBondsPerAtom[OtherAtom->nr];j++)
1696 if (ListOfBondsPerAtom[OtherAtom->nr][j]->GetOtherAtom(OtherAtom) == Root) {
1697 *out << " <-> " << OtherAtom->Name;
1698 RingSize++;
1699 NoCyclicBondsPerAtom[OtherAtom->nr]--;
1700 }
1701 } else {
1702 // we have made the complete cycle
1703 }
1704 *out << " <-> ... with cycle length of " << RingSize << "." << endl;
1705 NumCycles++;
1706 if ((RingSize < MinimumRingSize) || (MinimumRingSize == -1))
1707 MinimumRingSize = RingSize;
1708 }
1709 }
1710 }
1711 }
1712
1713 // print NoCyclicBondsPerAtom to visually check of all are zero
1714 *out << Verbose(1) << "NoCyclicBondsPerAtom: ";
1715 for(int i=0;i<AtomCount;i++) {
1716 if (NoCyclicBondsPerAtom[i] > 0)
1717 cerr << "There was an error in molecule::CyclicStructureAnalysis!" << endl;
1718 *out << NoCyclicBondsPerAtom[i] << " ";
1719 }
1720 *out << endl;
1721
1722 if (MinimumRingSize != -1)
1723 *out << Verbose(1) << "Minimum ring size is " << MinimumRingSize << ", over " << NumCycles << " cycles total." << endl;
1724 else
1725 *out << Verbose(1) << "No rings were detected in the molecular structure." << endl;
1726
1727 Free((void **)&NoCyclicBondsPerAtom, "molecule::CyclicStructureAnalysis: *NoCyclicBondsPerAtom");
1728 delete(AtomStack);
1729};
1730
1731/** Sets the next component number.
1732 * This is O(N) as the number of bonds per atom is bound.
1733 * \param *vertex atom whose next atom::*ComponentNr is to be set
1734 * \param nr number to use
1735 */
1736void molecule::SetNextComponentNumber(atom *vertex, int nr)
1737{
1738 int i=0;
1739 if (vertex != NULL) {
1740 for(;i<NumberOfBondsPerAtom[vertex->nr];i++) {
1741 if (vertex->ComponentNr[i] == -1) { // check if not yet used
1742 vertex->ComponentNr[i] = nr;
1743 break;
1744 }
1745 else if (vertex->ComponentNr[i] == nr) // if number is already present, don't add another time
1746 break; // breaking here will not cause error!
1747 }
1748 if (i == NumberOfBondsPerAtom[vertex->nr])
1749 cerr << "Error: All Component entries are already occupied!" << endl;
1750 } else
1751 cerr << "Error: Given vertex is NULL!" << endl;
1752};
1753
1754/** Output a list of flags, stating whether the bond was visited or not.
1755 * \param *out output stream for debugging
1756 */
1757void molecule::OutputComponentNumber(ofstream *out, atom *vertex)
1758{
1759 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
1760 *out << vertex->ComponentNr[i] << " ";
1761};
1762
1763/** Allocates memory for all atom::*ComponentNr in this molecule and sets each entry to -1.
1764 */
1765void molecule::InitComponentNumbers()
1766{
1767 atom *Walker = start;
1768 while(Walker->next != end) {
1769 Walker = Walker->next;
1770 if (Walker->ComponentNr != NULL)
1771 Free((void **)&Walker->ComponentNr, "molecule::InitComponentNumbers: **Walker->ComponentNr");
1772 Walker->ComponentNr = (int *) Malloc(sizeof(int)*NumberOfBondsPerAtom[Walker->nr], "molecule::InitComponentNumbers: *Walker->ComponentNr");
1773 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
1774 Walker->ComponentNr[i] = -1;
1775 }
1776};
1777
1778/** Returns next unused bond for this atom \a *vertex or NULL of none exists.
1779 * \param *vertex atom to regard
1780 * \return bond class or NULL
1781 */
1782bond * molecule::FindNextUnused(atom *vertex)
1783{
1784 for(int i=0;i<NumberOfBondsPerAtom[vertex->nr];i++)
1785 if (ListOfBondsPerAtom[vertex->nr][i]->IsUsed() == white)
1786 return(ListOfBondsPerAtom[vertex->nr][i]);
1787 return NULL;
1788};
1789
1790/** Resets bond::Used flag of all bonds in this molecule.
1791 * \return true - success, false - -failure
1792 */
1793void molecule::ResetAllBondsToUnused()
1794{
1795 bond *Binder = first;
1796 while (Binder->next != last) {
1797 Binder = Binder->next;
1798 Binder->ResetUsed();
1799 }
1800};
1801
1802/** Resets atom::nr to -1 of all atoms in this molecule.
1803 */
1804void molecule::ResetAllAtomNumbers()
1805{
1806 atom *Walker = start;
1807 while (Walker->next != end) {
1808 Walker = Walker->next;
1809 Walker->GraphNr = -1;
1810 }
1811};
1812
1813/** Output a list of flags, stating whether the bond was visited or not.
1814 * \param *out output stream for debugging
1815 * \param *list
1816 */
1817void OutputAlreadyVisited(ofstream *out, int *list)
1818{
1819 *out << Verbose(4) << "Already Visited Bonds:\t";
1820 for(int i=1;i<=list[0];i++) *out << Verbose(0) << list[i] << " ";
1821 *out << endl;
1822};
1823
1824/** Estimates by educated guessing (using upper limit) the expected number of fragments.
1825 * The upper limit is
1826 * \f[
1827 * n = N \cdot C^k
1828 * \f]
1829 * where \f$C=2^c\f$ and c is the maximum bond degree over N number of atoms.
1830 * \param *out output stream for debugging
1831 * \param order bond order k
1832 * \return number n of fragments
1833 */
1834int molecule::GuesstimateFragmentCount(ofstream *out, int order)
1835{
1836 int c = 0;
1837 int FragmentCount;
1838 // get maximum bond degree
1839 atom *Walker = start;
1840 while (Walker->next != end) {
1841 Walker = Walker->next;
1842 c = (NumberOfBondsPerAtom[Walker->nr] > c) ? NumberOfBondsPerAtom[Walker->nr] : c;
1843 }
1844 FragmentCount = NoNonHydrogen*(1 << (c*order));
1845 *out << Verbose(1) << "Upper limit for this subgraph is " << FragmentCount << " for " << NoNonHydrogen << " non-H atoms with maximum bond degree of " << c << "." << endl;
1846 return FragmentCount;
1847};
1848
1849/** Scans a single line for number and puts them into \a KeySet.
1850 * \param *out output stream for debugging
1851 * \param *buffer buffer to scan
1852 * \param &CurrentSet filled KeySet on return
1853 * \return true - at least one valid atom id parsed, false - CurrentSet is empty
1854 */
1855bool molecule::ScanBufferIntoKeySet(ofstream *out, char *buffer, KeySet &CurrentSet)
1856{
1857 stringstream line;
1858 int AtomNr;
1859 int status = 0;
1860
1861 line.str(buffer);
1862 while (!line.eof()) {
1863 line >> AtomNr;
1864 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
1865 CurrentSet.insert(AtomNr); // insert at end, hence in same order as in file!
1866 status++;
1867 } // else it's "-1" or else and thus must not be added
1868 }
1869 *out << Verbose(1) << "The scanned KeySet is ";
1870 for(KeySet::iterator runner = CurrentSet.begin(); runner != CurrentSet.end(); runner++) {
1871 *out << (*runner) << "\t";
1872 }
1873 *out << endl;
1874 return (status != 0);
1875};
1876
1877/** Parses the KeySet file and fills \a *FragmentList from the known molecule structure.
1878 * Does two-pass scanning:
1879 * -# Scans the keyset file and initialises a temporary graph
1880 * -# Scans TEFactors file and sets the TEFactor of each key set in the temporary graph accordingly
1881 * Finally, the temporary graph is inserted into the given \a FragmentList for return.
1882 * \param *out output stream for debugging
1883 * \param *path path to file
1884 * \param *FragmentList empty, filled on return
1885 * \param IsAngstroem whether we have Ansgtroem or bohrradius
1886 * \return true - parsing successfully, false - failure on parsing (FragmentList will be NULL)
1887 */
1888bool molecule::ParseKeySetFile(ofstream *out, char *path, Graph *&FragmentList, bool IsAngstroem)
1889{
1890 bool status = true;
1891 ifstream InputFile;
1892 stringstream line;
1893 GraphTestPair testGraphInsert;
1894 int NumberOfFragments = 0;
1895 double TEFactor;
1896 char *filename = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - filename");
1897
1898 if (FragmentList == NULL) { // check list pointer
1899 FragmentList = new Graph;
1900 }
1901
1902 // 1st pass: open file and read
1903 *out << Verbose(1) << "Parsing the KeySet file ... " << endl;
1904 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, KEYSETFILE);
1905 InputFile.open(filename);
1906 if (InputFile != NULL) {
1907 // each line represents a new fragment
1908 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::ParseKeySetFile - *buffer");
1909 // 1. parse keysets and insert into temp. graph
1910 while (!InputFile.eof()) {
1911 InputFile.getline(buffer, MAXSTRINGSIZE);
1912 KeySet CurrentSet;
1913 if ((strlen(buffer) > 0) && (ScanBufferIntoKeySet(out, buffer, CurrentSet))) { // if at least one valid atom was added, write config
1914 testGraphInsert = FragmentList->insert(GraphPair (CurrentSet,pair<int,double>(NumberOfFragments++,1))); // store fragment number and current factor
1915 if (!testGraphInsert.second) {
1916 cerr << "KeySet file must be corrupt as there are two equal key sets therein!" << endl;
1917 }
1918 //FragmentList->ListOfMolecules[NumberOfFragments++] = StoreFragmentFromKeySet(out, CurrentSet, IsAngstroem);
1919 }
1920 }
1921 // 2. Free and done
1922 InputFile.close();
1923 InputFile.clear();
1924 Free((void **)&buffer, "molecule::ParseKeySetFile - *buffer");
1925 *out << Verbose(1) << "done." << endl;
1926 } else {
1927 *out << Verbose(1) << "File " << filename << " not found." << endl;
1928 status = false;
1929 }
1930
1931 // 2nd pass: open TEFactors file and read
1932 *out << Verbose(1) << "Parsing the TEFactors file ... " << endl;
1933 sprintf(filename, "%s/%s%s", path, FRAGMENTPREFIX, TEFACTORSFILE);
1934 InputFile.open(filename);
1935 if (InputFile != NULL) {
1936 // 3. add found TEFactors to each keyset
1937 NumberOfFragments = 0;
1938 for(Graph::iterator runner = FragmentList->begin();runner != FragmentList->end(); runner++) {
1939 if (!InputFile.eof()) {
1940 InputFile >> TEFactor;
1941 (*runner).second.second = TEFactor;
1942 *out << Verbose(2) << "Setting " << ++NumberOfFragments << " fragment's TEFactor to " << (*runner).second.second << "." << endl;
1943 } else {
1944 status = false;
1945 break;
1946 }
1947 }
1948 // 4. Free and done
1949 InputFile.close();
1950 *out << Verbose(1) << "done." << endl;
1951 } else {
1952 *out << Verbose(1) << "File " << filename << " not found." << endl;
1953 status = false;
1954 }
1955
1956 Free((void **)&filename, "molecule::ParseKeySetFile - filename");
1957
1958 return status;
1959};
1960
1961/** Stores keysets and TEFactors to file.
1962 * \param *out output stream for debugging
1963 * \param KeySetList Graph with Keysets and factors
1964 * \param *path path to file
1965 * \return true - file written successfully, false - writing failed
1966 */
1967bool molecule::StoreKeySetFile(ofstream *out, Graph &KeySetList, char *path)
1968{
1969 ofstream output;
1970 bool status = true;
1971 string line;
1972 string::iterator ende;
1973
1974 // open KeySet file
1975 line = path;
1976 line.append("/");
1977 line += FRAGMENTPREFIX;
1978 ende = line.end();
1979 line += KEYSETFILE;
1980 output.open(line.c_str(), ios::out);
1981 *out << Verbose(1) << "Saving key sets of the total graph ... ";
1982 if(output != NULL) {
1983 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++) {
1984 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++)
1985 output << *sprinter << "\t";
1986 output << endl;
1987 }
1988 *out << "done." << endl;
1989 } else {
1990 cerr << "Unable to open " << line << " for writing keysets!" << endl;
1991 status = false;
1992 }
1993 output.close();
1994 output.clear();
1995
1996 // open TEFactors file
1997 line.erase(ende, line.end());
1998 line += TEFACTORSFILE;
1999 output.open(line.c_str(), ios::out);
2000 *out << Verbose(1) << "Saving TEFactors of the total graph ... ";
2001 if(output != NULL) {
2002 for(Graph::iterator runner = KeySetList.begin(); runner != KeySetList.end(); runner++)
2003 output << (*runner).second.second << endl;
2004 *out << Verbose(1) << "done." << endl;
2005 } else {
2006 *out << Verbose(1) << "failed to open file" << line << "." << endl;
2007 status = false;
2008 }
2009 output.close();
2010
2011 return status;
2012};
2013
2014/** Storing the bond structure of a molecule to file.
2015 * Simply stores Atom::nr and then the Atom::nr of all bond partners per line.
2016 * \param *out output stream for debugging
2017 * \param *path path to file
2018 * \return true - file written successfully, false - writing failed
2019 */
2020bool molecule::StoreAdjacencyToFile(ofstream *out, char *path)
2021{
2022 ofstream AdjacencyFile;
2023 atom *Walker = NULL;
2024 stringstream line;
2025 bool status = true;
2026
2027 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
2028 AdjacencyFile.open(line.str().c_str(), ios::out);
2029 *out << Verbose(1) << "Saving adjacency list ... ";
2030 if (AdjacencyFile != NULL) {
2031 Walker = start;
2032 while(Walker->next != end) {
2033 Walker = Walker->next;
2034 AdjacencyFile << Walker->nr << "\t";
2035 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
2036 AdjacencyFile << ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker)->nr << "\t";
2037 AdjacencyFile << endl;
2038 }
2039 AdjacencyFile.close();
2040 *out << Verbose(1) << "done." << endl;
2041 } else {
2042 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
2043 status = false;
2044 }
2045
2046 return status;
2047};
2048
2049/** Checks contents of adjacency file against bond structure in structure molecule.
2050 * \param *out output stream for debugging
2051 * \param *path path to file
2052 * \param **ListOfAtoms allocated (molecule::AtomCount) and filled lookup table for ids (Atom::nr) to *Atom
2053 * \return true - structure is equal, false - not equivalence
2054 */
2055bool molecule::CheckAdjacencyFileAgainstMolecule(ofstream *out, char *path, atom **ListOfAtoms)
2056{
2057 ifstream File;
2058 stringstream line;
2059 bool status = true;
2060 char *buffer = (char *) Malloc(sizeof(char)*MAXSTRINGSIZE, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
2061
2062 line << path << "/" << FRAGMENTPREFIX << ADJACENCYFILE;
2063 File.open(line.str().c_str(), ios::out);
2064 *out << Verbose(1) << "Looking at bond structure stored in adjacency file and comparing to present one ... " << endl;
2065 if (File != NULL) {
2066 // allocate storage structure
2067 int NonMatchNumber = 0; // will number of atoms with differing bond structure
2068 int *CurrentBonds = (int *) Malloc(sizeof(int)*8, "molecule::CheckAdjacencyFileAgainstMolecule - CurrentBonds"); // contains parsed bonds of current atom
2069 int CurrentBondsOfAtom;
2070
2071 // Parse the file line by line and count the bonds
2072 while (!File.eof()) {
2073 File.getline(buffer, MAXSTRINGSIZE);
2074 stringstream line;
2075 line.str(buffer);
2076 int AtomNr = -1;
2077 line >> AtomNr;
2078 CurrentBondsOfAtom = -1; // we count one too far due to line end
2079 // parse into structure
2080 if ((AtomNr >= 0) && (AtomNr < AtomCount)) {
2081 while (!line.eof())
2082 line >> CurrentBonds[ ++CurrentBondsOfAtom ];
2083 // compare against present bonds
2084 //cout << Verbose(2) << "Walker is " << *Walker << ", bond partners: ";
2085 if (CurrentBondsOfAtom == NumberOfBondsPerAtom[AtomNr]) {
2086 for(int i=0;i<NumberOfBondsPerAtom[AtomNr];i++) {
2087 int id = ListOfBondsPerAtom[AtomNr][i]->GetOtherAtom(ListOfAtoms[AtomNr])->nr;
2088 int j = 0;
2089 for (;(j<CurrentBondsOfAtom) && (CurrentBonds[j++] != id);); // check against all parsed bonds
2090 if (CurrentBonds[j-1] != id) { // no match ? Then mark in ListOfAtoms
2091 ListOfAtoms[AtomNr] = NULL;
2092 NonMatchNumber++;
2093 status = false;
2094 //out << "[" << id << "]\t";
2095 } else {
2096 //out << id << "\t";
2097 }
2098 }
2099 //out << endl;
2100 } else {
2101 *out << "Number of bonds for Atom " << *ListOfAtoms[AtomNr] << " does not match, parsed " << CurrentBondsOfAtom << " against " << NumberOfBondsPerAtom[AtomNr] << "." << endl;
2102 status = false;
2103 }
2104 }
2105 }
2106 File.close();
2107 File.clear();
2108 if (status) { // if equal we parse the KeySetFile
2109 *out << Verbose(1) << "done: Equal." << endl;
2110 status = true;
2111 } else
2112 *out << Verbose(1) << "done: Not equal by " << NonMatchNumber << " atoms." << endl;
2113 Free((void **)&CurrentBonds, "molecule::CheckAdjacencyFileAgainstMolecule - **CurrentBonds");
2114 } else {
2115 *out << Verbose(1) << "Adjacency file not found." << endl;
2116 status = false;
2117 }
2118 Free((void **)&buffer, "molecule::CheckAdjacencyFileAgainstMolecule: *buffer");
2119
2120 return status;
2121};
2122
2123/** Performs a many-body bond order analysis for a given bond order.
2124 * -# parses adjacency, keysets and orderatsite files
2125 * -# performs DFS to find connected subgraphs (to leave this in was a design decision: might be useful later)
2126 * -# RootStack is created for every subgraph (here, later we implement the "update 10 sites with highest energ
2127y contribution", and that's why this consciously not done in the following loop)
2128 * -# in a loop over all subgraphs
2129 * -# calls FragmentBOSSANOVA with this RootStack and within the subgraph molecule structure
2130 * -# creates molecule (fragment)s from the returned keysets (StoreFragmentFromKeySet)
2131 * -# combines the generated molecule lists from all subgraphs
2132 * -# saves to disk: fragment configs, adjacency, orderatsite, keyset files
2133 * Note that as we split "this" molecule up into a list of subgraphs, i.e. a MoleculeListClass, we have two sets
2134 * of vertex indices: Global always means the index in "this" molecule, whereas local refers to the molecule or
2135 * subgraph in the MoleculeListClass.
2136 * \param *out output stream for debugging
2137 * \param Order up to how many neighbouring bonds a fragment contains in BondOrderScheme::BottumUp scheme
2138 * \param *configuration configuration for writing config files for each fragment
2139 */
2140void molecule::FragmentMolecule(ofstream *out, int Order, config *configuration)
2141{
2142 MoleculeListClass *BondFragments = NULL;
2143 atom *Walker = NULL;
2144 atom *OtherWalker = NULL;
2145 bond *Binder = NULL;
2146 int *SortIndex = NULL;
2147 element *runner = NULL;
2148 int AtomNo;
2149 int MinimumRingSize;
2150 int FragmentCounter;
2151 MoleculeLeafClass *MolecularWalker = NULL;
2152 MoleculeLeafClass *Subgraphs = NULL; // list of subgraphs from DFS analysis
2153 fstream File;
2154 bool FragmentationToDo = true;
2155 Graph **FragmentList = NULL;
2156 Graph *TempFragmentList = NULL;
2157 Graph TotalGraph; // graph with all keysets however local numbers
2158 KeySet *TempSet = NULL;
2159 int TotalNumberOfKeySets = 0;
2160 int KeySetCounter = 0;
2161 atom ***ListOfLocalAtoms = NULL;
2162
2163 *out << endl;
2164#ifdef ADDHYDROGEN
2165 *out << Verbose(0) << "I will treat hydrogen special and saturate dangling bonds with it." << endl;
2166#else
2167 *out << Verbose(0) << "Hydrogen is treated just like the rest of the lot." << endl;
2168#endif
2169
2170 // ===== 1. Check whether bond structure is same as stored in files ====
2171
2172 // fill the adjacency list
2173 CreateListOfBondsPerAtom(out);
2174
2175 // create lookup table for Atom::nr
2176 atom **ListOfAtoms = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::FragmentMolecule - **ListOfAtoms");
2177 Walker = start;
2178 while (Walker->next != end) { // create a lookup table (Atom::nr -> atom) used as a marker table lateron
2179 Walker = Walker->next;
2180 if ((Walker->nr >= 0) && (Walker->nr < AtomCount)) {
2181 ListOfAtoms[Walker->nr] = Walker;
2182 } else
2183 break;
2184 }
2185 if (Walker->next != end) { // everything went alright
2186 *out << " range of nuclear ids exceeded [0, AtomCount)." << endl;
2187 FragmentationToDo = false;
2188 }
2189 // === compare it with adjacency file ===
2190 FragmentationToDo = FragmentationToDo && CheckAdjacencyFileAgainstMolecule(out, configuration->configpath, ListOfAtoms);
2191 Free((void **)&ListOfAtoms, "molecule::FragmentMolecule - **ListOfAtoms");
2192
2193 // ===== 2. perform a DFS analysis to gather info on cyclic structure and a list of disconnected subgraphs =====
2194 Subgraphs = DepthFirstSearchAnalysis((ofstream *)&*out, false, MinimumRingSize);
2195
2196 // fill index lookup list for each subgraph from global nr to local pointer
2197 ListOfLocalAtoms = (atom ***) Malloc(sizeof(atom **)*FragmentCounter, "molecule::FragmentMolecule - **ListOfLocalAtoms");
2198 for (int i=0;i<FragmentCounter;i++) {
2199 ListOfLocalAtoms[i] = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::FragmentMolecule - *ListOfLocalAtoms[]");
2200 for(int j=0;j<AtomCount;j++)
2201 ListOfLocalAtoms[i][j] = NULL;
2202 }
2203 FragmentCounter = 0;
2204 MolecularWalker = Subgraphs;
2205 while (MolecularWalker->next != NULL) {
2206 MolecularWalker = MolecularWalker->next;
2207 Walker = MolecularWalker->Leaf->start;
2208 while (Walker->next != MolecularWalker->Leaf->end) {
2209 Walker = Walker->next;
2210#ifdef ADDHYDROGEN
2211 if (Walker->type->Z != 1) // skip hydrogen
2212#endif
2213 ListOfLocalAtoms[FragmentCounter][Walker->GetTrueFather()->nr] = Walker; // set present global id index to the local pointer
2214 }
2215 FragmentCounter++;
2216 }
2217
2218 // fill the bond structure of the individually stored subgraphs
2219 FragmentCounter = 0;
2220 MolecularWalker = Subgraphs;
2221 while (MolecularWalker->next != NULL) {
2222 MolecularWalker = MolecularWalker->next;
2223 *out << Verbose(1) << "Creating adjacency list for subgraph " << MolecularWalker << "." << endl;
2224 Walker = MolecularWalker->Leaf->start;
2225 while (Walker->next != MolecularWalker->Leaf->end) {
2226 Walker = Walker->next;
2227 AtomNo = Walker->father->nr; // global id of the current walker
2228 for(int i=0;i<NumberOfBondsPerAtom[AtomNo];i++) { // go through father's bonds and copy them all
2229 Binder = ListOfBondsPerAtom[AtomNo][i];
2230 OtherWalker = ListOfLocalAtoms[FragmentCounter][Binder->GetOtherAtom(Walker->father)->nr]; // local copy of current bond partner of walker
2231 if ((OtherWalker != NULL) && (OtherWalker->nr > Walker->nr))
2232 MolecularWalker->Leaf->AddBond(Walker, OtherWalker, Binder->BondDegree);
2233 }
2234 }
2235 //MolecularWalker->Leaf->CreateAdjacencyList(out, BondDistance);
2236 MolecularWalker->Leaf->CreateListOfBondsPerAtom(out);
2237 FragmentCounter++;
2238 }
2239
2240 // ===== 3. if structure still valid, parse key set file and others =====
2241 if (FragmentationToDo) {
2242 // parse key sets into new graph
2243 TempFragmentList = new Graph;
2244 FragmentationToDo = FragmentationToDo && ParseKeySetFile(out, configuration->configpath, TempFragmentList, configuration->GetIsAngstroem());
2245 } else
2246 *out << Verbose(1) << "Creation of lookup table Atom::nr <-> Atom failed!" << endl;
2247 if (FragmentationToDo) // parse the adaptive order per atom/site/vertex
2248 FragmentationToDo = FragmentationToDo && ParseOrderAtSiteFromFile(out, configuration->configpath);
2249 else
2250 *out << Verbose(1) << "Parsing keyset file failed" << endl;
2251
2252 // ===== 4. check globally whether there's something to do actually (first adaptivity check)
2253 if (FragmentationToDo) { // check whether OrderAtSite is above Order everywhere
2254 FragmentationToDo = false;
2255 Walker = start;
2256 while (Walker->next != end) {
2257 Walker = Walker->next;
2258#ifdef ADDHYDROGEN
2259 if (Walker->type->Z != 1) // skip hydrogen
2260#endif
2261 if (Walker->AdaptiveOrder < Order)
2262 FragmentationToDo = true;
2263 }
2264 } else
2265 *out << Verbose(1) << "Parsing order at site file failed" << endl;
2266
2267 if (!FragmentationToDo)
2268 *out << Verbose(0) << "Order at every site is already equal or above desired order " << Order << "." << endl;
2269
2270 // =================================== Begin of FRAGMENTATION ===============================
2271 // check cyclic lengths
2272 if ((MinimumRingSize != -1) && (Order >= MinimumRingSize)) {
2273 *out << Verbose(0) << "Bond order " << Order << " greater than or equal to Minimum Ring size of " << MinimumRingSize << " found is not allowed." << endl;
2274 } else {
2275 FragmentCounter = 0;
2276 MolecularWalker = Subgraphs;
2277 // count subgraphs and allocate fragments
2278 while (MolecularWalker->next != NULL) {
2279 MolecularWalker = MolecularWalker->next;
2280 FragmentCounter++;
2281 }
2282 FragmentList = (Graph **) Malloc(sizeof(Graph *)*FragmentCounter, "molecule::FragmentMolecule - **BondFragments");
2283
2284 // ===== 6a. fill RootStack for each subgraph (second adaptivity check) =====
2285 // NOTE: (keep this extern of following while loop, as lateron we may here look for which site to add to which subgraph)
2286 // fill the root stack
2287 KeyStack RootStack[FragmentCounter];
2288
2289 if (Order == -1) { // means we want to increase order adaptively
2290 cerr << "Adaptive chosing of sites not yet implemented!" << endl;
2291 } else { // means we just want to increase it at every site by one
2292 FragmentCounter = 0;
2293 MolecularWalker = Subgraphs;
2294 // count subgraphs and allocate fragments
2295 while (MolecularWalker->next != NULL) {
2296 MolecularWalker = MolecularWalker->next;
2297 // find first root candidates
2298 RootStack[FragmentCounter].clear();
2299 Walker = MolecularWalker->Leaf->start;
2300 while (Walker->next != MolecularWalker->Leaf->end) { // go through all (non-hydrogen) atoms
2301 Walker = Walker->next;
2302 #ifdef ADDHYDROGEN
2303 if (Walker->type->Z != 1) // skip hydrogen
2304 #endif
2305 if (Walker->GetTrueFather()->AdaptiveOrder < Order) // only if Order is still greater
2306 RootStack[FragmentCounter].push_front(Walker->nr);
2307 }
2308 FragmentCounter++;
2309 }
2310 }
2311
2312 // ===== 6b. assign each keyset to its respective subgraph =====
2313 if ((TempFragmentList != NULL) && (TempFragmentList->size() != 0)) { // if there are some scanned keysets at all
2314 // spread the keysets
2315 FragmentCounter = 0;
2316 MolecularWalker = Subgraphs;
2317 while (MolecularWalker->next != NULL) {
2318 MolecularWalker = MolecularWalker->next;
2319 // assign scanned keysets
2320 FragmentList[FragmentCounter] = new Graph;
2321 TempSet = new KeySet;
2322 KeySetCounter = 0;
2323 for(Graph::iterator runner = TempFragmentList->begin();runner != TempFragmentList->end(); runner++) { // key sets contain global numbers!
2324 if ( ListOfLocalAtoms[FragmentCounter][FindAtom(*((*runner).first.begin()))->nr]->nr != -1) {// as we may assume that that bond structure is unchanged, we only test the first key in each set
2325 // translate keyset to local numbers
2326 for(KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
2327 TempSet->insert(ListOfLocalAtoms[FragmentCounter][FindAtom(*sprinter)->nr]->nr);
2328 // insert into FragmentList
2329 FragmentList[FragmentCounter]->insert(GraphPair (*TempSet, pair<int,double>(KeySetCounter++, (*runner).second.second)));
2330 }
2331 TempSet->clear();
2332 }
2333 delete(TempSet);
2334 if (KeySetCounter == 0)
2335 delete(FragmentList[FragmentCounter]);
2336 else
2337 *out << Verbose(1) << KeySetCounter << " atoms were put into subgraph " << FragmentCounter << "." << endl;
2338 FragmentCounter++;
2339 }
2340 } else // otherwise make sure all lists are initialised to NULL
2341 for(int i=0;i<FragmentCounter;i++)
2342 FragmentList[i] = NULL;
2343
2344
2345 // ===== 7. fill the bond fragment list =====
2346 FragmentCounter = 0;
2347 TotalNumberOfKeySets = 0;
2348 MolecularWalker = Subgraphs;
2349 while (MolecularWalker->next != NULL) {
2350 MolecularWalker = MolecularWalker->next;
2351 *out << Verbose(1) << "Fragmenting subgraph " << MolecularWalker << "." << endl;
2352 if (MolecularWalker->Leaf->first->next != MolecularWalker->Leaf->last) {
2353 // output ListOfBondsPerAtom for debugging
2354 *out << Verbose(0) << endl << "From Contents of ListOfBondsPerAtom, all non-hydrogen atoms:" << endl;
2355 Walker = MolecularWalker->Leaf->start;
2356 while (Walker->next != MolecularWalker->Leaf->end) {
2357 Walker = Walker->next;
2358#ifdef ADDHYDROGEN
2359 if (Walker->type->Z != 1) { // regard only non-hydrogen
2360#endif
2361 *out << Verbose(0) << "Atom " << Walker->Name << " has Bonds: "<<endl;
2362 for(int j=0;j<MolecularWalker->Leaf->NumberOfBondsPerAtom[Walker->nr];j++) {
2363 *out << Verbose(1) << *(MolecularWalker->Leaf->ListOfBondsPerAtom)[Walker->nr][j] << endl;
2364 }
2365#ifdef ADDHYDROGEN
2366 }
2367#endif
2368 }
2369 *out << endl;
2370
2371 *out << Verbose(0) << endl << " ========== BOND ENERGY of subgraph " << FragmentCounter << " ========================= " << endl;
2372 *out << Verbose(0) << "Begin of bond fragmentation." << endl;
2373
2374 // call BOSSANOVA method
2375 MolecularWalker->Leaf->FragmentBOSSANOVA(out, FragmentList[FragmentCounter], RootStack[FragmentCounter]);
2376
2377 // translate list into global numbers (i.e. valid in "this" molecule, not in MolecularWalker->Leaf)
2378 KeySet *TempSet = new KeySet;
2379 for(Graph::iterator runner = FragmentList[FragmentCounter]->begin(); runner != FragmentList[FragmentCounter]->end(); runner++) {
2380 for(KeySet::iterator sprinter = (*runner).first.begin(); sprinter != (*runner).first.end(); sprinter++)
2381 TempSet->insert((MolecularWalker->Leaf->FindAtom(*sprinter))->GetTrueFather()->nr);
2382 TotalGraph.insert(GraphPair(*TempSet, pair<int,double>(TotalNumberOfKeySets++, (*runner).second.second)));
2383 TempSet->clear();
2384 }
2385 delete(TempSet);
2386 delete(FragmentList[FragmentCounter]);
2387 } else {
2388 cerr << "Subgraph " << MolecularWalker << " has no atoms!" << endl;
2389 }
2390 FragmentCounter++; // next fragment list
2391 }
2392 }
2393 Free((void **)&FragmentList, "molecule::FragmentMolecule - **FragmentList");
2394
2395 // ===== 8. gather keyset lists (graphs) from all subgraphs and transform into MoleculeListClass =====
2396 // allocate memory for the pointer array and transmorph graphs into full molecular fragments
2397 BondFragments = new MoleculeListClass(TotalGraph.size(), AtomCount);
2398 int k=0;
2399 for(Graph::iterator runner = TotalGraph.begin(); runner != TotalGraph.end(); runner++) {
2400 KeySet test = (*runner).first;
2401 *out << "Fragment No." << (*runner).second.first << " with TEFactor " << (*runner).second.second << "." << endl;
2402 BondFragments->ListOfMolecules[k] = StoreFragmentFromKeySet(out, test, configuration);
2403 k++;
2404 }
2405 *out << k << "/" << BondFragments->NumberOfMolecules << " fragments generated from the keysets." << endl;
2406
2407 // ==================================== End of FRAGMENTATION ================================
2408
2409 // ===== 10. Save fragments' configuration and keyset files et al to disk ===
2410 if (BondFragments->NumberOfMolecules != 0) {
2411 // create a SortIndex to map from BFS labels to the sequence in which the atoms are given in the config file
2412 SortIndex = (int *) Malloc(sizeof(int)*AtomCount, "molecule::FragmentMolecule: *SortIndex");
2413 for(int i=0;i<AtomCount;i++)
2414 SortIndex[i] = -1;
2415 runner = elemente->start;
2416 AtomNo = 0;
2417 while (runner->next != elemente->end) { // go through every element
2418 runner = runner->next;
2419 if (ElementsInMolecule[runner->Z]) { // if this element got atoms
2420 Walker = start;
2421 while (Walker->next != end) { // go through every atom of this element
2422 Walker = Walker->next;
2423 if (Walker->type->Z == runner->Z) // if this atom fits to element
2424 SortIndex[Walker->nr] = AtomNo++;
2425 }
2426 }
2427 }
2428 *out << Verbose(1) << "Writing " << BondFragments->NumberOfMolecules << " possible bond fragmentation configs" << endl;
2429 if (BondFragments->OutputConfigForListOfFragments(out, configuration, SortIndex))
2430 *out << Verbose(1) << "All configs written." << endl;
2431 else
2432 *out << Verbose(1) << "Some config writing failed." << endl;
2433
2434 // store force index reference file
2435 BondFragments->StoreForcesFile(out, configuration->configpath, SortIndex);
2436
2437 // store keysets file
2438 StoreKeySetFile(out, TotalGraph, configuration->configpath);
2439
2440 // store Adjacency file
2441 StoreAdjacencyToFile(out, configuration->configpath);
2442
2443 // store adaptive orders into file
2444 StoreOrderAtSiteFile(out, configuration->configpath);
2445
2446 // restore orbital and Stop values
2447 CalculateOrbitals(*configuration);
2448
2449 // free memory for bond part
2450 *out << Verbose(1) << "Freeing bond memory" << endl;
2451 delete(FragmentList); // remove bond molecule from memory
2452 FragmentList = NULL;
2453 Free((void **)&SortIndex, "molecule::FragmentMolecule: *SortIndex");
2454 } else
2455 *out << Verbose(1) << "FragmentList is zero on return, splitting failed." << endl;
2456
2457 // free the index lookup list
2458 for (int i=0;i<FragmentCounter;i++)
2459 Free((void **)&ListOfLocalAtoms[i], "molecule::FragmentMolecule - *ListOfLocalAtoms[]");
2460 Free((void **)&ListOfLocalAtoms, "molecule::FragmentMolecule - **ListOfLocalAtoms");
2461 // free subgraph memory again
2462 delete(TempFragmentList);
2463 if (Subgraphs != NULL) {
2464 while (Subgraphs->next != NULL) {
2465 Subgraphs = Subgraphs->next;
2466 delete(Subgraphs->previous);
2467 }
2468 delete(Subgraphs);
2469 }
2470
2471 *out << Verbose(0) << "End of bond fragmentation." << endl;
2472};
2473
2474/** Stores pairs (Atom::nr, Atom::AdaptiveOrder) into file.
2475 * Atoms not present in the file get "-1".
2476 * \param *out output stream for debugging
2477 * \param *path path to file ORDERATSITEFILE
2478 * \return true - file writable, false - not writable
2479 */
2480bool molecule::StoreOrderAtSiteFile(ofstream *out, char *path)
2481{
2482 stringstream line;
2483 ofstream file;
2484
2485 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
2486 file.open(line.str().c_str());
2487 *out << Verbose(1) << "Writing OrderAtSite " << ORDERATSITEFILE << " ... " << endl;
2488 if (file != NULL) {
2489 atom *Walker = start;
2490 while (Walker->next != end) {
2491 Walker = Walker->next;
2492 file << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << endl;
2493 *out << Verbose(2) << "Storing: " << Walker->nr << "\t" << (int)Walker->AdaptiveOrder << "." << endl;
2494 }
2495 file.close();
2496 *out << Verbose(1) << "done." << endl;
2497 return true;
2498 } else {
2499 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
2500 return false;
2501 }
2502};
2503
2504/** Parses pairs(Atom::nr, Atom::AdaptiveOrder) from file and stores in molecule's Atom's.
2505 * Atoms not present in the file get "0".
2506 * \param *out output stream for debugging
2507 * \param *path path to file ORDERATSITEFILEe
2508 * \return true - file found and scanned, false - file not found
2509 * \sa ParseKeySetFile() and CheckAdjacencyFileAgainstMolecule() as this is meant to be used in conjunction with the two
2510 */
2511bool molecule::ParseOrderAtSiteFromFile(ofstream *out, char *path)
2512{
2513 unsigned char *OrderArray = (unsigned char *) Malloc(sizeof(unsigned char)*AtomCount, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
2514 bool status;
2515 int AtomNr;
2516 stringstream line;
2517 ifstream file;
2518 int Order;
2519
2520 *out << Verbose(1) << "Begin of ParseOrderAtSiteFromFile" << endl;
2521 for(int i=0;i<AtomCount;i++)
2522 OrderArray[i] = 0;
2523 line << path << "/" << FRAGMENTPREFIX << ORDERATSITEFILE;
2524 file.open(line.str().c_str());
2525 if (file != NULL) {
2526 for (int i=0;i<AtomCount;i++) // initialise with 0
2527 OrderArray[i] = 0;
2528 while (!file.eof()) { // parse from file
2529 file >> AtomNr;
2530 file >> Order;
2531 OrderArray[AtomNr] = (unsigned char) Order;
2532 //*out << Verbose(2) << "AtomNr " << AtomNr << " with order " << (int)OrderArray[AtomNr] << "." << endl;
2533 }
2534 atom *Walker = start;
2535 while (Walker->next != end) { // fill into atom classes
2536 Walker = Walker->next;
2537 Walker->AdaptiveOrder = OrderArray[Walker->nr];
2538 *out << Verbose(2) << *Walker << " gets order " << (int)Walker->AdaptiveOrder << "." << endl;
2539 }
2540 file.close();
2541 *out << Verbose(1) << "done." << endl;
2542 status = true;
2543 } else {
2544 *out << Verbose(1) << "failed to open file " << line.str() << "." << endl;
2545 status = false;
2546 }
2547 Free((void **)&OrderArray, "molecule::ParseOrderAtSiteFromFile - *OrderArray");
2548
2549 *out << Verbose(1) << "End of ParseOrderAtSiteFromFile" << endl;
2550 return status;
2551};
2552
2553/** Creates an 2d array of pointer with an entry for each atom and each bond it has.
2554 * Updates molecule::ListOfBondsPerAtom, molecule::NumberOfBondsPerAtom by parsing through
2555 * bond chain list, using molecule::AtomCount and molecule::BondCount.
2556 * Allocates memory, fills the array and exits
2557 * \param *out output stream for debugging
2558 */
2559void molecule::CreateListOfBondsPerAtom(ofstream *out)
2560{
2561 bond *Binder = NULL;
2562 atom *Walker = NULL;
2563 int TotalDegree;
2564 *out << Verbose(1) << "Begin of Creating ListOfBondsPerAtom: AtomCount = " << AtomCount << "\tBondCount = " << BondCount << "\tNoNonBonds = " << NoNonBonds << "." << endl;
2565
2566 // re-allocate memory
2567 *out << Verbose(2) << "(Re-)Allocating memory." << endl;
2568 if (ListOfBondsPerAtom != NULL) {
2569 for(int i=0;i<AtomCount;i++)
2570 Free((void **)&ListOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom[i]");
2571 Free((void **)&ListOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: ListOfBondsPerAtom");
2572 }
2573 if (NumberOfBondsPerAtom != NULL)
2574 Free((void **)&NumberOfBondsPerAtom, "molecule::CreateListOfBondsPerAtom: NumberOfBondsPerAtom");
2575 ListOfBondsPerAtom = (bond ***) Malloc(sizeof(bond **)*AtomCount, "molecule::CreateListOfBondsPerAtom: ***ListOfBondsPerAtom");
2576 NumberOfBondsPerAtom = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfBondsPerAtom: *NumberOfBondsPerAtom");
2577
2578 // reset bond counts per atom
2579 for(int i=0;i<AtomCount;i++)
2580 NumberOfBondsPerAtom[i] = 0;
2581 // count bonds per atom
2582 Binder = first;
2583 while (Binder->next != last) {
2584 Binder = Binder->next;
2585 NumberOfBondsPerAtom[Binder->leftatom->nr]++;
2586 NumberOfBondsPerAtom[Binder->rightatom->nr]++;
2587 }
2588 // allocate list of bonds per atom
2589 for(int i=0;i<AtomCount;i++)
2590 ListOfBondsPerAtom[i] = (bond **) Malloc(sizeof(bond *)*NumberOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: **ListOfBondsPerAtom[]");
2591 // clear the list again, now each NumberOfBondsPerAtom marks current free field
2592 for(int i=0;i<AtomCount;i++)
2593 NumberOfBondsPerAtom[i] = 0;
2594 // fill the list
2595 Binder = first;
2596 while (Binder->next != last) {
2597 Binder = Binder->next;
2598 ListOfBondsPerAtom[Binder->leftatom->nr][NumberOfBondsPerAtom[Binder->leftatom->nr]++] = Binder;
2599 ListOfBondsPerAtom[Binder->rightatom->nr][NumberOfBondsPerAtom[Binder->rightatom->nr]++] = Binder;
2600 }
2601
2602 // output list for debugging
2603 *out << Verbose(3) << "ListOfBondsPerAtom for each atom:" << endl;
2604 Walker = start;
2605 while (Walker->next != end) {
2606 Walker = Walker->next;
2607 *out << Verbose(4) << "Atom " << Walker->Name << " with " << NumberOfBondsPerAtom[Walker->nr] << " bonds: ";
2608 TotalDegree = 0;
2609 for (int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
2610 *out << *ListOfBondsPerAtom[Walker->nr][j] << "\t";
2611 TotalDegree += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
2612 }
2613 *out << " -- TotalDegree: " << TotalDegree << endl;
2614 }
2615 *out << Verbose(1) << "End of Creating ListOfBondsPerAtom." << endl << endl;
2616};
2617
2618/** Adds atoms up to \a BondCount distance from \a *Root and notes them down in \a **AddedAtomList.
2619 * Gray vertices are always enqueued in an AtomStackClass FIFO queue, the rest is usual BFS with adding vertices found was
2620 * white and putting into queue.
2621 * \param *out output stream for debugging
2622 * \param *Mol Molecule class to add atoms to
2623 * \param **AddedAtomList list with added atom pointers, index is atom father's number
2624 * \param **AddedBondList list with added bond pointers, index is bond father's number
2625 * \param *Root root vertex for BFS
2626 * \param *Bond bond not to look beyond
2627 * \param BondOrder maximum distance for vertices to add
2628 * \param IsAngstroem lengths are in angstroem or bohrradii
2629 */
2630void molecule::BreadthFirstSearchAdd(ofstream *out, molecule *Mol, atom **&AddedAtomList, bond **&AddedBondList, atom *Root, bond *Bond, int BondOrder, bool IsAngstroem)
2631{
2632 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::BreadthFirstSearchAdd: **PredecessorList");
2633 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::BreadthFirstSearchAdd: *ShortestPathList");
2634 enum Shading *ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::BreadthFirstSearchAdd: *ColorList");
2635 AtomStackClass *AtomStack = new AtomStackClass(AtomCount);
2636 atom *Walker = NULL, *OtherAtom = NULL;
2637 bond *Binder = NULL;
2638
2639 // add Root if not done yet
2640 AtomStack->ClearStack();
2641 if (AddedAtomList[Root->nr] == NULL) // add Root if not yet present
2642 AddedAtomList[Root->nr] = Mol->AddCopyAtom(Root);
2643 AtomStack->Push(Root);
2644
2645 // initialise each vertex as white with no predecessor, empty queue, color Root lightgray
2646 for (int i=0;i<AtomCount;i++) {
2647 PredecessorList[i] = NULL;
2648 ShortestPathList[i] = -1;
2649 if (AddedAtomList[i] != NULL) // mark already present atoms (i.e. Root and maybe others) as visited
2650 ColorList[i] = lightgray;
2651 else
2652 ColorList[i] = white;
2653 }
2654 ShortestPathList[Root->nr] = 0;
2655
2656 // and go on ... Queue always contains all lightgray vertices
2657 while (!AtomStack->IsEmpty()) {
2658 // we have to pop the oldest atom from stack. This keeps the atoms on the stack always of the same ShortestPath distance.
2659 // 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
2660 // append length of 3 (their neighbours). Thus on stack we have always atoms of a certain length n at bottom of stack and
2661 // followed by n+1 till top of stack.
2662 Walker = AtomStack->PopFirst(); // pop oldest added
2663 *out << Verbose(1) << "Current Walker is: " << Walker->Name << ", and has " << NumberOfBondsPerAtom[Walker->nr] << " bonds." << endl;
2664 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
2665 Binder = ListOfBondsPerAtom[Walker->nr][i];
2666 if (Binder != NULL) { // don't look at bond equal NULL
2667 OtherAtom = Binder->GetOtherAtom(Walker);
2668 *out << Verbose(2) << "Current OtherAtom is: " << OtherAtom->Name << " for bond " << *Binder << "." << endl;
2669 if (ColorList[OtherAtom->nr] == white) {
2670 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)
2671 ColorList[OtherAtom->nr] = lightgray;
2672 PredecessorList[OtherAtom->nr] = Walker; // Walker is the predecessor
2673 ShortestPathList[OtherAtom->nr] = ShortestPathList[Walker->nr]+1;
2674 *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;
2675 if ((((ShortestPathList[OtherAtom->nr] < BondOrder) && (Binder != Bond))) ) { // Check for maximum distance
2676 *out << Verbose(3);
2677 if (AddedAtomList[OtherAtom->nr] == NULL) { // add if it's not been so far
2678 AddedAtomList[OtherAtom->nr] = Mol->AddCopyAtom(OtherAtom);
2679 *out << "Added OtherAtom " << OtherAtom->Name;
2680 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
2681 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
2682 AddedBondList[Binder->nr]->Type = Binder->Type;
2683 *out << " and bond " << *(AddedBondList[Binder->nr]) << ", ";
2684 } 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)
2685 *out << "Not adding OtherAtom " << OtherAtom->Name;
2686 if (AddedBondList[Binder->nr] == NULL) {
2687 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
2688 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
2689 AddedBondList[Binder->nr]->Type = Binder->Type;
2690 *out << ", added Bond " << *(AddedBondList[Binder->nr]);
2691 } else
2692 *out << ", not added Bond ";
2693 }
2694 *out << ", putting OtherAtom into queue." << endl;
2695 AtomStack->Push(OtherAtom);
2696 } else { // out of bond order, then replace
2697 if ((AddedAtomList[OtherAtom->nr] == NULL) && (Binder->Cyclic))
2698 ColorList[OtherAtom->nr] = white; // unmark if it has not been queued/added, to make it available via its other bonds (cyclic)
2699 if (Binder == Bond)
2700 *out << Verbose(3) << "Not Queueing, is the Root bond";
2701 else if (ShortestPathList[OtherAtom->nr] >= BondOrder)
2702 *out << Verbose(3) << "Not Queueing, is out of Bond Count of " << BondOrder;
2703 if (!Binder->Cyclic)
2704 *out << ", is not part of a cyclic bond, saturating bond with Hydrogen." << endl;
2705 if (AddedBondList[Binder->nr] == NULL) {
2706 if ((AddedAtomList[OtherAtom->nr] != NULL)) { // .. whether we add or saturate
2707 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
2708 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
2709 AddedBondList[Binder->nr]->Type = Binder->Type;
2710 } else {
2711#ifdef ADDHYDROGEN
2712 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
2713#endif
2714 }
2715 }
2716 }
2717 } else {
2718 *out << Verbose(3) << "Not Adding, has already been visited." << endl;
2719 // This has to be a cyclic bond, check whether it's present ...
2720 if (AddedBondList[Binder->nr] == NULL) {
2721 if ((Binder != Bond) && (Binder->Cyclic) && (((ShortestPathList[Walker->nr]+1) < BondOrder))) {
2722 AddedBondList[Binder->nr] = Mol->AddBond(AddedAtomList[Walker->nr], AddedAtomList[OtherAtom->nr], Binder->BondDegree);
2723 AddedBondList[Binder->nr]->Cyclic = Binder->Cyclic;
2724 AddedBondList[Binder->nr]->Type = Binder->Type;
2725 } else { // if it's root bond it has to broken (otherwise we would not create the fragments)
2726#ifdef ADDHYDROGEN
2727 Mol->AddHydrogenReplacementAtom(out, Binder, AddedAtomList[Walker->nr], Walker, OtherAtom, ListOfBondsPerAtom[Walker->nr], NumberOfBondsPerAtom[Walker->nr], IsAngstroem);
2728#endif
2729 }
2730 }
2731 }
2732 }
2733 }
2734 ColorList[Walker->nr] = black;
2735 *out << Verbose(1) << "Coloring Walker " << Walker->Name << " black." << endl;
2736 }
2737 Free((void **)&PredecessorList, "molecule::BreadthFirstSearchAdd: **PredecessorList");
2738 Free((void **)&ShortestPathList, "molecule::BreadthFirstSearchAdd: **ShortestPathList");
2739 Free((void **)&ColorList, "molecule::BreadthFirstSearchAdd: **ColorList");
2740 delete(AtomStack);
2741};
2742
2743/** Adds bond structure to this molecule from \a Father molecule.
2744 * This basically causes this molecule to become an induced subgraph of the \a Father, i.e. for every bond in Father
2745 * with end points present in this molecule, bond is created in this molecule.
2746 * Special care was taken to ensure that this is of complexity O(N), where N is the \a Father's molecule::AtomCount.
2747 * \param *out output stream for debugging
2748 * \param *Father father molecule
2749 * \return true - is induced subgraph, false - there are atoms with fathers not in \a Father
2750 * \todo not checked, not fully working probably
2751 */
2752bool molecule::BuildInducedSubgraph(ofstream *out, const molecule *Father)
2753{
2754 atom *Walker = NULL, *OtherAtom = NULL;
2755 bool status = true;
2756 atom **ParentList = (atom **) Malloc(sizeof(atom *)*Father->AtomCount, "molecule::BuildInducedSubgraph: **ParentList");
2757
2758 *out << Verbose(2) << "Begin of BuildInducedSubgraph." << endl;
2759
2760 // reset parent list
2761 *out << Verbose(3) << "Resetting ParentList." << endl;
2762 for (int i=0;i<Father->AtomCount;i++)
2763 ParentList[i] = NULL;
2764
2765 // fill parent list with sons
2766 *out << Verbose(3) << "Filling Parent List." << endl;
2767 Walker = start;
2768 while (Walker->next != end) {
2769 Walker = Walker->next;
2770 ParentList[Walker->father->nr] = Walker;
2771 // Outputting List for debugging
2772 *out << Verbose(4) << "Son["<< Walker->father->nr <<"] of " << Walker->father << " is " << ParentList[Walker->father->nr] << "." << endl;
2773 }
2774
2775 // check each entry of parent list and if ok (one-to-and-onto matching) create bonds
2776 *out << Verbose(3) << "Creating bonds." << endl;
2777 Walker = Father->start;
2778 while (Walker->next != Father->end) {
2779 Walker = Walker->next;
2780 if (ParentList[Walker->nr] != NULL) {
2781 if (ParentList[Walker->nr]->father != Walker) {
2782 status = false;
2783 } else {
2784 for (int i=0;i<Father->NumberOfBondsPerAtom[Walker->nr];i++) {
2785 OtherAtom = Father->ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
2786 if (ParentList[OtherAtom->nr] != NULL) { // if otheratom is also a father of an atom on this molecule, create the bond
2787 *out << Verbose(4) << "Endpoints of Bond " << Father->ListOfBondsPerAtom[Walker->nr][i] << " are both present: " << ParentList[Walker->nr]->Name << " and " << ParentList[OtherAtom->nr]->Name << "." << endl;
2788 AddBond(ParentList[Walker->nr], ParentList[OtherAtom->nr], Father->ListOfBondsPerAtom[Walker->nr][i]->BondDegree);
2789 }
2790 }
2791 }
2792 }
2793 }
2794
2795 Free((void **)&ParentList, "molecule::BuildInducedSubgraph: **ParentList");
2796 *out << Verbose(2) << "End of BuildInducedSubgraph." << endl;
2797 return status;
2798};
2799
2800
2801/** Looks through a AtomStackClass and returns the likeliest removal candiate.
2802 * \param *out output stream for debugging messages
2803 * \param *&Leaf KeySet to look through
2804 * \param *&ShortestPathList list of the shortest path to decide which atom to suggest as removal candidate in the end
2805 * \param index of the atom suggested for removal
2806 */
2807int molecule::LookForRemovalCandidate(ofstream *&out, KeySet *&Leaf, int *&ShortestPathList)
2808{
2809 atom *Runner = NULL;
2810 int SP, Removal;
2811
2812 *out << Verbose(2) << "Looking for removal candidate." << endl;
2813 SP = -1; //0; // not -1, so that Root is never removed
2814 Removal = -1;
2815 for (KeySet::iterator runner = Leaf->begin(); runner != Leaf->end(); runner++) {
2816 Runner = FindAtom((*runner));
2817 if (Runner->type->Z != 1) { // skip all those added hydrogens when re-filling snake stack
2818 if (ShortestPathList[(*runner)] > SP) { // remove the oldest one with longest shortest path
2819 SP = ShortestPathList[(*runner)];
2820 Removal = (*runner);
2821 }
2822 }
2823 }
2824 return Removal;
2825};
2826
2827/** Stores a fragment from \a KeySet into \a molecule.
2828 * First creates the minimal set of atoms from the KeySet, then creates the bond structure from the complete
2829 * molecule and adds missing hydrogen where bonds were cut.
2830 * \param *out output stream for debugging messages
2831 * \param &Leaflet pointer to KeySet structure
2832 * \param IsAngstroem whether we have Ansgtroem or bohrradius
2833 * \return pointer to constructed molecule
2834 */
2835molecule * molecule::StoreFragmentFromKeySet(ofstream *out, KeySet &Leaflet, bool IsAngstroem)
2836{
2837 atom *Runner = NULL, *FatherOfRunner = NULL, *OtherFather = NULL;
2838 atom **SonList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::StoreFragmentFromStack: **SonList");
2839 molecule *Leaf = new molecule(elemente);
2840
2841// *out << Verbose(1) << "Begin of StoreFragmentFromKeyset." << endl;
2842
2843 Leaf->BondDistance = BondDistance;
2844 for(int i=0;i<NDIM*2;i++)
2845 Leaf->cell_size[i] = cell_size[i];
2846
2847 // initialise SonList (indicates when we need to replace a bond with hydrogen instead)
2848 for(int i=0;i<AtomCount;i++)
2849 SonList[i] = NULL;
2850
2851 // first create the minimal set of atoms from the KeySet
2852 for(KeySet::iterator runner = Leaflet.begin(); runner != Leaflet.end(); runner++) {
2853 FatherOfRunner = FindAtom((*runner)); // find the id
2854 SonList[FatherOfRunner->nr] = Leaf->AddCopyAtom(FatherOfRunner);
2855 }
2856
2857 // create the bonds between all: Make it an induced subgraph and add hydrogen
2858// *out << Verbose(2) << "Creating bonds from father graph (i.e. induced subgraph creation)." << endl;
2859 Runner = Leaf->start;
2860 while (Runner->next != Leaf->end) {
2861 Runner = Runner->next;
2862 FatherOfRunner = Runner->father;
2863 if (SonList[FatherOfRunner->nr] != NULL) { // check if this, our father, is present in list
2864 // create all bonds
2865 for (int i=0;i<NumberOfBondsPerAtom[FatherOfRunner->nr];i++) { // go through every bond of father
2866 OtherFather = ListOfBondsPerAtom[FatherOfRunner->nr][i]->GetOtherAtom(FatherOfRunner);
2867// *out << Verbose(2) << "Father " << *FatherOfRunner << " of son " << *SonList[FatherOfRunner->nr] << " is bound to " << *OtherFather;
2868 if (SonList[OtherFather->nr] != NULL) {
2869// *out << ", whose son is " << *SonList[OtherFather->nr] << "." << endl;
2870 if (OtherFather->nr > FatherOfRunner->nr) { // add bond (nr check is for adding only one of both variants: ab, ba)
2871// *out << Verbose(3) << "Adding Bond: " << Leaf->AddBond(Runner, SonList[OtherFather->nr], ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree) << "." << endl;
2872 //NumBonds[Runner->nr]++;
2873 } else {
2874// *out << Verbose(3) << "Not adding bond, labels in wrong order." << endl;
2875 }
2876 } else {
2877// *out << ", who has no son in this fragment molecule." << endl;
2878#ifdef ADDHYDROGEN
2879// *out << Verbose(3) << "Adding Hydrogen to " << Runner->Name << " and a bond in between." << endl;
2880 Leaf->AddHydrogenReplacementAtom(out, ListOfBondsPerAtom[FatherOfRunner->nr][i], Runner, FatherOfRunner, OtherFather, ListOfBondsPerAtom[FatherOfRunner->nr],NumberOfBondsPerAtom[FatherOfRunner->nr], IsAngstroem);
2881#endif
2882 //NumBonds[Runner->nr] += ListOfBondsPerAtom[FatherOfRunner->nr][i]->BondDegree;
2883 }
2884 }
2885 } else {
2886 *out << Verbose(0) << "ERROR: Son " << Runner->Name << " has father " << FatherOfRunner->Name << " but its entry in SonList is " << SonList[FatherOfRunner->nr] << "!" << endl;
2887 }
2888#ifdef ADDHYDROGEN
2889 while ((Runner->next != Leaf->end) && (Runner->next->type->Z == 1)) // skip added hydrogen
2890 Runner = Runner->next;
2891#endif
2892 }
2893 Leaf->CreateListOfBondsPerAtom(out);
2894 //Leaflet->Leaf->ScanForPeriodicCorrection(out);
2895 Free((void **)&SonList, "molecule::StoreFragmentFromStack: **SonList");
2896// *out << Verbose(1) << "End of StoreFragmentFromKeyset." << endl;
2897 return Leaf;
2898};
2899
2900/** Creates \a MoleculeListClass of all unique fragments of the \a molecule containing \a Order atoms or vertices.
2901 * The picture to have in mind is that of a DFS "snake" of a certain length \a Order, i.e. as in the infamous
2902 * computer game, that winds through the connected graph representing the molecule. Color (white,
2903 * lightgray, darkgray, black) indicates whether a vertex has been discovered so far or not. Labels will help in
2904 * creating only unique fragments and not additional ones with vertices simply in different sequence.
2905 * The Predecessor is always the one that came before in discovering, needed on backstepping. And
2906 * finally, the ShortestPath is needed for removing vertices from the snake stack during the back-
2907 * stepping.
2908 * \param *out output stream for debugging
2909 * \param Order number of atoms in each fragment
2910 * \param *configuration configuration for writing config files for each fragment
2911 * \return List of all unique fragments with \a Order atoms
2912 */
2913/*
2914MoleculeListClass * molecule::CreateListOfUniqueFragmentsOfOrder(ofstream *out, int Order, config *configuration)
2915{
2916 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
2917 int *ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
2918 int *Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
2919 enum Shading *ColorVertexList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
2920 enum Shading *ColorEdgeList = (enum Shading *) Malloc(sizeof(enum Shading)*BondCount, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorBondList");
2921 AtomStackClass *RootStack = new AtomStackClass(AtomCount);
2922 AtomStackClass *TouchedStack = new AtomStackClass((int)pow(4,Order)+2); // number of atoms reached from one with maximal 4 bonds plus Root itself
2923 AtomStackClass *SnakeStack = new AtomStackClass(Order+1); // equal to Order is not possible, as then the AtomStackClass cannot discern between full and empty stack!
2924 MoleculeLeafClass *Leaflet = NULL, *TempLeaf = NULL;
2925 MoleculeListClass *FragmentList = NULL;
2926 atom *Walker = NULL, *OtherAtom = NULL, *Root = NULL, *Removal = NULL;
2927 bond *Binder = NULL;
2928 int RunningIndex = 0, FragmentCounter = 0;
2929
2930 *out << Verbose(1) << "Begin of CreateListOfUniqueFragmentsOfOrder." << endl;
2931
2932 // reset parent list
2933 *out << Verbose(3) << "Resetting labels, parent, predecessor, color and shortest path lists." << endl;
2934 for (int i=0;i<AtomCount;i++) { // reset all atom labels
2935 // initialise each vertex as white with no predecessor, empty queue, color lightgray, not labelled, no sons
2936 Labels[i] = -1;
2937 SonList[i] = NULL;
2938 PredecessorList[i] = NULL;
2939 ColorVertexList[i] = white;
2940 ShortestPathList[i] = -1;
2941 }
2942 for (int i=0;i<BondCount;i++)
2943 ColorEdgeList[i] = white;
2944 RootStack->ClearStack(); // clearstack and push first atom if exists
2945 TouchedStack->ClearStack();
2946 Walker = start->next;
2947 while ((Walker != end)
2948#ifdef ADDHYDROGEN
2949 && (Walker->type->Z == 1)
2950#endif
2951 ) { // search for first non-hydrogen atom
2952 *out << Verbose(4) << "Current Root candidate is " << Walker->Name << "." << endl;
2953 Walker = Walker->next;
2954 }
2955 if (Walker != end)
2956 RootStack->Push(Walker);
2957 else
2958 *out << Verbose(0) << "ERROR: Could not find an appropriate Root atom!" << endl;
2959 *out << Verbose(3) << "Root " << Walker->Name << " is on AtomStack, beginning loop through all vertices ..." << endl;
2960
2961 ///// OUTER LOOP ////////////
2962 while (!RootStack->IsEmpty()) {
2963 // get new root vertex from atom stack
2964 Root = RootStack->PopFirst();
2965 ShortestPathList[Root->nr] = 0;
2966 if (Labels[Root->nr] == -1)
2967 Labels[Root->nr] = RunningIndex++; // prevent it from getting again on AtomStack
2968 PredecessorList[Root->nr] = Root;
2969 TouchedStack->Push(Root);
2970 *out << Verbose(0) << "Root for this loop is: " << Root->Name << ".\n";
2971
2972 // clear snake stack
2973 SnakeStack->ClearStack();
2974 //SnakeStack->TestImplementation(out, start->next);
2975
2976 ///// INNER LOOP ////////////
2977 // Problems:
2978 // - what about cyclic bonds?
2979 Walker = Root;
2980 do {
2981 *out << Verbose(1) << "Current Walker is: " << Walker->Name;
2982 // initial setting of the new Walker: label, color, shortest path and put on stacks
2983 if (Labels[Walker->nr] == -1) { // give atom a unique, monotonely increasing number
2984 Labels[Walker->nr] = RunningIndex++;
2985 RootStack->Push(Walker);
2986 }
2987 *out << ", has label " << Labels[Walker->nr];
2988 if ((ColorVertexList[Walker->nr] == white) || ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white))) { // color it if newly discovered and push on stacks (and if within reach!)
2989 if ((Binder != NULL) && (ColorEdgeList[Binder->nr] == white)) {
2990 // Binder ought to be set still from last neighbour search
2991 *out << ", coloring bond " << *Binder << " black";
2992 ColorEdgeList[Binder->nr] = black; // mark this bond as used
2993 }
2994 if (ShortestPathList[Walker->nr] == -1) {
2995 ShortestPathList[Walker->nr] = ShortestPathList[PredecessorList[Walker->nr]->nr]+1;
2996 TouchedStack->Push(Walker); // mark every atom for lists cleanup later, whose shortest path has been changed
2997 }
2998 if ((ShortestPathList[Walker->nr] < Order) && (ColorVertexList[Walker->nr] != darkgray)) { // if not already on snake stack
2999 SnakeStack->Push(Walker);
3000 ColorVertexList[Walker->nr] = darkgray; // mark as dark gray of on snake stack
3001 }
3002 }
3003 *out << ", SP of " << ShortestPathList[Walker->nr] << " and its color is " << GetColor(ColorVertexList[Walker->nr]) << "." << endl;
3004
3005 // then check the stack for a newly stumbled upon fragment
3006 if (SnakeStack->ItemCount() == Order) { // is stack full?
3007 // store the fragment if it is one and get a removal candidate
3008 Removal = StoreFragmentFromStack(out, Root, Walker, Leaflet, SnakeStack, ShortestPathList, SonList, Labels, &FragmentCounter, configuration);
3009 // remove the candidate if one was found
3010 if (Removal != NULL) {
3011 *out << Verbose(2) << "Removing item " << Removal->Name << " with SP of " << ShortestPathList[Removal->nr] << " from snake stack." << endl;
3012 SnakeStack->RemoveItem(Removal);
3013 ColorVertexList[Removal->nr] = lightgray; // return back to not on snake stack but explored marking
3014 if (Walker == Removal) { // if the current atom is to be removed, we also have to take a step back
3015 Walker = PredecessorList[Removal->nr];
3016 *out << Verbose(2) << "Stepping back to " << Walker->Name << "." << endl;
3017 }
3018 }
3019 } else
3020 Removal = NULL;
3021
3022 // finally, look for a white neighbour as the next Walker
3023 Binder = NULL;
3024 if ((Removal == NULL) || (Walker != PredecessorList[Removal->nr])) { // don't look, if a new walker has been set above
3025 *out << Verbose(2) << "Snake has currently " << SnakeStack->ItemCount() << " item(s)." << endl;
3026 OtherAtom = NULL; // this is actually not needed, every atom has at least one neighbour
3027 if (ShortestPathList[Walker->nr] < Order) {
3028 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) {
3029 Binder = ListOfBondsPerAtom[Walker->nr][i];
3030 *out << Verbose(2) << "Current bond is " << *Binder << ": ";
3031 OtherAtom = Binder->GetOtherAtom(Walker);
3032 if ((Labels[OtherAtom->nr] != -1) && (Labels[OtherAtom->nr] < Labels[Root->nr])) { // we don't step up to labels bigger than us
3033 *out << "Label " << Labels[OtherAtom->nr] << " is smaller than Root's " << Labels[Root->nr] << "." << endl;
3034 //ColorVertexList[OtherAtom->nr] = lightgray; // mark as explored
3035 } else { // otherwise check its colour and element
3036 if (
3037#ifdef ADDHYDROGEN
3038 (OtherAtom->type->Z != 1) &&
3039#endif
3040 (ColorEdgeList[Binder->nr] == white)) { // skip hydrogen, look for unexplored vertices
3041 *out << "Moving along " << GetColor(ColorEdgeList[Binder->nr]) << " bond " << Binder << " to " << ((ColorVertexList[OtherAtom->nr] == white) ? "unexplored" : "explored") << " item: " << OtherAtom->Name << "." << endl;
3042 // i find it currently rather sensible to always set the predecessor in order to find one's way back
3043 //if (PredecessorList[OtherAtom->nr] == NULL) {
3044 PredecessorList[OtherAtom->nr] = Walker;
3045 *out << Verbose(3) << "Setting Predecessor of " << OtherAtom->Name << " to " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
3046 //} else {
3047 // *out << Verbose(3) << "Predecessor of " << OtherAtom->Name << " is " << PredecessorList[OtherAtom->nr]->Name << "." << endl;
3048 //}
3049 Walker = OtherAtom;
3050 break;
3051 } else {
3052 if (OtherAtom->type->Z == 1)
3053 *out << "Links to a hydrogen atom." << endl;
3054 else
3055 *out << "Bond has not white but " << GetColor(ColorEdgeList[Binder->nr]) << " color." << endl;
3056 }
3057 }
3058 }
3059 } else { // means we have stepped beyond the horizon: Return!
3060 Walker = PredecessorList[Walker->nr];
3061 OtherAtom = Walker;
3062 *out << Verbose(3) << "We have gone too far, stepping back to " << Walker->Name << "." << endl;
3063 }
3064 if (Walker != OtherAtom) { // if no white neighbours anymore, color it black
3065 *out << Verbose(2) << "Coloring " << Walker->Name << " black." << endl;
3066 ColorVertexList[Walker->nr] = black;
3067 Walker = PredecessorList[Walker->nr];
3068 }
3069 }
3070 } while ((Walker != Root) || (ColorVertexList[Root->nr] != black));
3071 *out << Verbose(2) << "Inner Looping is finished." << endl;
3072
3073 // if we reset all AtomCount atoms, we have again technically O(N^2) ...
3074 *out << Verbose(2) << "Resetting lists." << endl;
3075 Walker = NULL;
3076 Binder = NULL;
3077 while (!TouchedStack->IsEmpty()) {
3078 Walker = TouchedStack->PopLast();
3079 *out << Verbose(3) << "Re-initialising entries of " << *Walker << "." << endl;
3080 for(int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++)
3081 ColorEdgeList[ListOfBondsPerAtom[Walker->nr][i]->nr] = white;
3082 PredecessorList[Walker->nr] = NULL;
3083 ColorVertexList[Walker->nr] = white;
3084 ShortestPathList[Walker->nr] = -1;
3085 }
3086 }
3087 *out << Verbose(1) << "Outer Looping over all vertices is done." << endl;
3088
3089 // copy together
3090 *out << Verbose(1) << "Copying all fragments into MoleculeList structure." << endl;
3091 FragmentList = new MoleculeListClass(FragmentCounter, AtomCount);
3092 RunningIndex = 0;
3093 while ((Leaflet != NULL) && (RunningIndex < FragmentCounter)) {
3094 FragmentList->ListOfMolecules[RunningIndex++] = Leaflet->Leaf;
3095 Leaflet->Leaf = NULL; // prevent molecule from being removed
3096 TempLeaf = Leaflet;
3097 Leaflet = Leaflet->previous;
3098 delete(TempLeaf);
3099 };
3100
3101 // free memory and exit
3102 Free((void **)&PredecessorList, "molecule::CreateListOfUniqueFragmentsOfOrder: **PredecessorList");
3103 Free((void **)&ShortestPathList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ShortestPathList");
3104 Free((void **)&Labels, "molecule::CreateListOfUniqueFragmentsOfOrder: *Labels");
3105 Free((void **)&ColorVertexList, "molecule::CreateListOfUniqueFragmentsOfOrder: *ColorList");
3106 delete(RootStack);
3107 delete(TouchedStack);
3108 delete(SnakeStack);
3109
3110 *out << Verbose(1) << "End of CreateListOfUniqueFragmentsOfOrder." << endl;
3111 return FragmentList;
3112};
3113*/
3114
3115/** Structure containing all values in power set combination generation.
3116 */
3117struct UniqueFragments {
3118 config *configuration;
3119 atom *Root;
3120 Graph *Leaflet;
3121 KeySet *FragmentSet;
3122 int ANOVAOrder;
3123 int FragmentCounter;
3124 int CurrentIndex;
3125 int *Labels;
3126 double TEFactor;
3127 int *ShortestPathList;
3128 bool **UsedList;
3129 bond **BondsPerSPList;
3130 int *BondsPerSPCount;
3131};
3132
3133/** From a given set of Bond sorted by Shortest Path distance, create all possible fragments of size \a SetDimension.
3134 * -# loops over every possible combination (2^dimension of edge set)
3135 * -# inserts current set, if there's still space left
3136 * -# yes: calls SPFragmentGenerator with structure, created new edge list and size respective to root dist
3137ance+1
3138 * -# no: stores fragment into keyset list by calling InsertFragmentIntoGraph
3139 * -# removes all items added into the snake stack (in UniqueFragments structure) added during level (root
3140distance) and current set
3141 * \param *out output stream for debugging
3142 * \param FragmentSearch UniqueFragments structure with all values needed
3143 * \param RootDistance current shortest path level, whose set of edges is represented by **BondsSet
3144 * \param SetDimension Number of possible bonds on this level (i.e. size of the array BondsSet[])
3145 * \param SubOrder remaining number of allowed vertices to add
3146 */
3147void molecule::SPFragmentGenerator(ofstream *out, struct UniqueFragments *FragmentSearch, int RootDistance, bond **BondsSet, int SetDimension, int SubOrder)
3148{
3149 atom *OtherWalker = NULL;
3150 int verbosity = 0; //FragmentSearch->ANOVAOrder-SubOrder;
3151 int NumCombinations;
3152 bool bit;
3153 int bits, TouchedIndex, SubSetDimension, SP;
3154 int Removal;
3155 int *TouchedList = (int *) Malloc(sizeof(int)*(SubOrder+1), "molecule::SPFragmentGenerator: *TouchedList");
3156 bond *Binder = NULL;
3157 bond **BondsList = NULL;
3158
3159 NumCombinations = 1 << SetDimension;
3160
3161 // Hier muessen von 1 bis NumberOfBondsPerAtom[Walker->nr] alle Kombinationen
3162 // von Endstuecken (aus den Bonds) hinzugefÃŒgt werden und fÃŒr verbleibende ANOVAOrder
3163 // rekursiv GraphCrawler in der nÀchsten Ebene aufgerufen werden
3164
3165 *out << Verbose(1+verbosity) << "Begin of SPFragmentGenerator." << endl;
3166 *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;
3167
3168 // initialised touched list (stores added atoms on this level)
3169 *out << Verbose(1+verbosity) << "Clearing touched list." << endl;
3170 for (TouchedIndex=0;TouchedIndex<=SubOrder;TouchedIndex++) // empty touched list
3171 TouchedList[TouchedIndex] = -1;
3172 TouchedIndex = 0;
3173
3174 // create every possible combination of the endpieces
3175 *out << Verbose(1+verbosity) << "Going through all combinations of the power set." << endl;
3176 for (int i=1;i<NumCombinations;i++) { // sweep through all power set combinations (skip empty set!)
3177 // count the set bit of i
3178 bits = 0;
3179 for (int j=0;j<SetDimension;j++)
3180 bits += (i & (1 << j)) >> j;
3181
3182 *out << Verbose(1+verbosity) << "Current set is " << Binary(i | (1 << SetDimension)) << ", number of bits is " << bits << "." << endl;
3183 if (bits <= SubOrder) { // if not greater than additional atoms allowed on stack, continue
3184 // --1-- add this set of the power set of bond partners to the snake stack
3185 for (int j=0;j<SetDimension;j++) { // pull out every bit by shifting
3186 bit = ((i & (1 << j)) != 0); // mask the bit for the j-th bond
3187 if (bit) { // if bit is set, we add this bond partner
3188 OtherWalker = BondsSet[j]->rightatom; // rightatom is always the one more distant, i.e. the one to add
3189 //*out << Verbose(1+verbosity) << "Current Bond is " << ListOfBondsPerAtom[Walker->nr][i] << ", checking on " << *OtherWalker << "." << endl;
3190 //if ((!FragmentSearch->UsedList[OtherWalker->nr][i]) && (FragmentSearch->Labels[OtherWalker->nr] > FragmentSearch->Labels[FragmentSearch->Root->nr])) {
3191 //*out << Verbose(2+verbosity) << "Not used so far, label " << FragmentSearch->Labels[OtherWalker->nr] << " is bigger than Root's " << FragmentSearch->Labels[FragmentSearch->Root->nr] << "." << endl;
3192 *out << Verbose(2+verbosity) << "Adding " << *OtherWalker << " with nr " << OtherWalker->nr << "." << endl;
3193 TouchedList[TouchedIndex++] = OtherWalker->nr; // note as added
3194 FragmentSearch->FragmentSet->insert(OtherWalker->nr);
3195 //FragmentSearch->UsedList[OtherWalker->nr][i] = true;
3196 //}
3197 } else {
3198 *out << Verbose(2+verbosity) << "Not adding." << endl;
3199 }
3200 }
3201
3202 if (bits < SubOrder) {
3203 *out << Verbose(1+verbosity) << "There's still some space left on stack: " << (SubOrder - bits) << "." << endl;
3204 // --2-- look at all added end pieces of this combination, construct bond subsets and sweep through a power set of these by recursion
3205 SP = RootDistance+1; // this is the next level
3206 // first count the members in the subset
3207 SubSetDimension = 0;
3208 Binder = FragmentSearch->BondsPerSPList[2*SP]; // start node for this level
3209 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) { // compare to end node of this level
3210 Binder = Binder->next;
3211 for (int k=0;k<TouchedIndex;k++) {
3212 if (Binder->Contains(TouchedList[k])) // if we added this very endpiece
3213 SubSetDimension++;
3214 }
3215 }
3216 // then allocate and fill the list
3217 BondsList = (bond **) Malloc(sizeof(bond *)*SubSetDimension, "molecule::SPFragmentGenerator: **BondsList");
3218 SubSetDimension = 0;
3219 Binder = FragmentSearch->BondsPerSPList[2*SP];
3220 while (Binder->next != FragmentSearch->BondsPerSPList[2*SP+1]) {
3221 Binder = Binder->next;
3222 for (int k=0;k<TouchedIndex;k++) {
3223 if (Binder->leftatom->nr == TouchedList[k]) // leftatom is always the close one
3224 BondsList[SubSetDimension++] = Binder;
3225 }
3226 }
3227 *out << Verbose(2+verbosity) << "Calling subset generator " << SP << " away from root " << *FragmentSearch->Root << " with sub set dimension " << SubSetDimension << "." << endl;
3228 SPFragmentGenerator(out, FragmentSearch, SP, BondsList, SubSetDimension, SubOrder-bits);
3229 Free((void **)&BondsList, "molecule::SPFragmentGenerator: **BondsList");
3230 } else {
3231 // --2-- otherwise store the complete fragment
3232 *out << Verbose(1+verbosity) << "Enough items on stack for a fragment!" << endl;
3233 // store fragment as a KeySet
3234 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch->FragmentCounter << "], local nr.s are: ";
3235 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
3236 *out << (*runner) << " ";
3237 InsertFragmentIntoGraph(out, FragmentSearch);
3238 //Removal = LookForRemovalCandidate(out, FragmentSearch->FragmentSet, FragmentSearch->ShortestPathList);
3239 //Removal = StoreFragmentFromStack(out, FragmentSearch->Root, FragmentSearch->Leaflet, FragmentSearch->FragmentStack, FragmentSearch->ShortestPathList,FragmentSearch->Labels, &FragmentSearch->FragmentCounter, FragmentSearch->configuration);
3240 }
3241
3242 // --3-- remove all added items in this level from snake stack
3243 *out << Verbose(1+verbosity) << "Removing all items that were added on this SP level " << RootDistance << "." << endl;
3244 for(int j=0;j<TouchedIndex;j++) {
3245 Removal = TouchedList[j];
3246 *out << Verbose(2+verbosity) << "Removing item nr. " << Removal << " from snake stack." << endl;
3247 FragmentSearch->FragmentSet->erase(Removal);
3248 TouchedList[j] = -1;
3249 }
3250 *out << Verbose(2) << "Remaining local nr.s on snake stack are: ";
3251 for(KeySet::iterator runner = FragmentSearch->FragmentSet->begin(); runner != FragmentSearch->FragmentSet->end(); runner++)
3252 *out << (*runner) << " ";
3253 *out << endl;
3254 TouchedIndex = 0; // set Index to 0 for list of atoms added on this level
3255 } else {
3256 *out << Verbose(2+verbosity) << "More atoms to add for this set (" << bits << ") than space left on stack " << SubOrder << ", skipping this set." << endl;
3257 }
3258 }
3259 Free((void **)&TouchedList, "molecule::SPFragmentGenerator: *TouchedList");
3260 *out << Verbose(1+verbosity) << "End of SPFragmentGenerator, " << RootDistance << " away from Root " << *FragmentSearch->Root << " and SubOrder is " << SubOrder << "." << endl;
3261};
3262
3263/** 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.
3264 * -# initialises UniqueFragments structure
3265 * -# fills edge list via BFS
3266 * -# creates the fragment by calling recursive function SPFragmentGenerator with UniqueFragments structure, 0 as
3267 root distance, the edge set, its dimension and the current suborder
3268 * -# Free'ing structure
3269 * 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
3270 * with SP of 2, then those with SP of 3, then those with SP of 4 and so on.
3271 * \param *out output stream for debugging
3272 * \param Order bond order (limits BFS exploration and "number of digits" in power set generation
3273 * \param FragmentSearch UniqueFragments structure containing TEFactor, root atom and so on
3274 * \param RestrictedKeySet Restricted vertex set to use in context of molecule
3275 * \return number of inserted fragments
3276 * \note ShortestPathList in FragmentSearch structure is probably due to NumberOfAtomsSPLevel and SP not needed anymore
3277 */
3278int molecule::PowerSetGenerator(ofstream *out, int Order, struct UniqueFragments &FragmentSearch, KeySet RestrictedKeySet)
3279{
3280 int SP, UniqueIndex, AtomKeyNr;
3281 int *NumberOfAtomsSPLevel = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *SPLevelCount");
3282 atom *Walker = NULL, *OtherWalker = NULL;
3283 bond *Binder = NULL;
3284 bond **BondsList = NULL;
3285 KeyStack AtomStack;
3286 atom **PredecessorList = (atom **) Malloc(sizeof(atom *)*AtomCount, "molecule::PowerSetGenerator: **PredecessorList");
3287 KeySet::iterator runner;
3288 int RootKeyNr = FragmentSearch.Root->nr;
3289 int Counter = FragmentSearch.FragmentCounter;
3290
3291 for (int i=0;i<AtomCount;i++) {
3292 PredecessorList[i] = NULL;
3293 }
3294
3295 *out << endl;
3296 *out << Verbose(0) << "Begin of PowerSetGenerator with order " << Order << " at Root " << *FragmentSearch.Root << "." << endl;
3297
3298 UniqueIndex = 0;
3299 if (FragmentSearch.Labels[RootKeyNr] == -1)
3300 FragmentSearch.Labels[RootKeyNr] = UniqueIndex++;
3301 FragmentSearch.ShortestPathList[RootKeyNr] = 0;
3302 // prepare the atom stack counters (number of atoms with certain SP on stack)
3303 for (int i=0;i<Order;i++)
3304 NumberOfAtomsSPLevel[i] = 0;
3305 NumberOfAtomsSPLevel[0] = 1; // for root
3306 SP = -1;
3307 *out << endl;
3308 *out << Verbose(0) << "Starting BFS analysis ..." << endl;
3309 // push as first on atom stack and goooo ...
3310 AtomStack.clear();
3311 AtomStack.push_back(RootKeyNr);
3312 *out << Verbose(0) << "Cleared AtomStack and pushed root as first item onto it." << endl;
3313 // do a BFS search to fill the SP lists and label the found vertices
3314 while (!AtomStack.empty()) {
3315 // pop next atom
3316 AtomKeyNr = AtomStack.front();
3317 AtomStack.pop_front();
3318 if (SP != -1)
3319 NumberOfAtomsSPLevel[SP]--;
3320 if ((SP == -1) || (NumberOfAtomsSPLevel[SP] == -1)) {
3321 SP++;
3322 NumberOfAtomsSPLevel[SP]--; // carry over "-1" to next level
3323 *out << Verbose(1) << "New SP level reached: " << SP << ", creating new SP list with 0 item(s)";
3324 if (SP > 0)
3325 *out << ", old level closed with " << FragmentSearch.BondsPerSPCount[SP-1] << " item(s)." << endl;
3326 else
3327 *out << "." << endl;
3328 FragmentSearch.BondsPerSPCount[SP] = 0;
3329 } else {
3330 *out << Verbose(1) << "Still " << NumberOfAtomsSPLevel[SP]+1 << " on this SP (" << SP << ") level, currently having " << FragmentSearch.BondsPerSPCount[SP] << " item(s)." << endl;
3331 }
3332 Walker = FindAtom(AtomKeyNr);
3333 *out << Verbose(0) << "Current Walker is: " << *Walker << " with nr " << Walker->nr << " and label " << FragmentSearch.Labels[AtomKeyNr] << " and SP of " << SP << "." << endl;
3334 // check for new sp level
3335 // go through all its bonds
3336 *out << Verbose(1) << "Going through all bonds of Walker." << endl;
3337 for (int i=0;i<NumberOfBondsPerAtom[AtomKeyNr];i++) {
3338 Binder = ListOfBondsPerAtom[AtomKeyNr][i];
3339 OtherWalker = Binder->GetOtherAtom(Walker);
3340 if ((RestrictedKeySet.find(OtherWalker->nr) != RestrictedKeySet.end())
3341#ifdef ADDHYDROGEN
3342 && (OtherWalker->type->Z != 1)
3343#endif
3344 ) { // skip hydrogens and restrict to fragment
3345 *out << Verbose(2) << "Current partner is " << *OtherWalker << " with nr " << OtherWalker->nr << " in bond " << *Binder << "." << endl;
3346 // set the label if not set (and push on root stack as well)
3347 if (FragmentSearch.Labels[OtherWalker->nr] == -1) {
3348 FragmentSearch.Labels[OtherWalker->nr] = UniqueIndex++;
3349 *out << Verbose(3) << "Set label to " << FragmentSearch.Labels[OtherWalker->nr] << "." << endl;
3350 } else {
3351 *out << Verbose(3) << "Label is already " << FragmentSearch.Labels[OtherWalker->nr] << "." << endl;
3352 }
3353 if ((OtherWalker != PredecessorList[AtomKeyNr]) && (OtherWalker->nr > RootKeyNr)) { // only pass through those with label bigger than Root's
3354 FragmentSearch.ShortestPathList[OtherWalker->nr] = SP+1;
3355 *out << Verbose(3) << "Set Shortest Path to " << FragmentSearch.ShortestPathList[OtherWalker->nr] << "." << endl;
3356 if (FragmentSearch.ShortestPathList[OtherWalker->nr] < Order) { // only pass through those within reach of Order
3357 // push for exploration on stack (only if the SP of OtherWalker is longer than of Walker! (otherwise it has been added already!)
3358 if (FragmentSearch.ShortestPathList[OtherWalker->nr] > SP) {
3359 if (FragmentSearch.ShortestPathList[OtherWalker->nr] < (Order-1)) {
3360 *out << Verbose(3) << "Putting on atom stack for further exploration." << endl;
3361 PredecessorList[OtherWalker->nr] = Walker; // note down the one further up the exploration tree
3362 AtomStack.push_back(OtherWalker->nr);
3363 NumberOfAtomsSPLevel[FragmentSearch.ShortestPathList[OtherWalker->nr]]++;
3364 } else {
3365 *out << Verbose(3) << "Not putting on atom stack, is at end of reach." << endl;
3366 }
3367 // add the bond in between to the SP list
3368 Binder = new bond(Walker, OtherWalker); // create a new bond in such a manner, that bond::rightatom is always the one more distant
3369 add(Binder, FragmentSearch.BondsPerSPList[2*SP+1]);
3370 FragmentSearch.BondsPerSPCount[SP]++;
3371 *out << Verbose(3) << "Added its bond to SP list, having now " << FragmentSearch.BondsPerSPCount[SP] << " item(s)." << endl;
3372 } else *out << Verbose(3) << "Not putting on atom stack, nor adding bond, as " << *OtherWalker << "'s SP is shorter than Walker's." << endl;
3373 } else *out << Verbose(3) << "Not continuing, as " << *OtherWalker << " is out of reach of order " << Order << "." << endl;
3374 } 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;
3375 } else *out << Verbose(2) << "Is not in the restricted keyset or skipping hydrogen " << *OtherWalker << "." << endl;
3376 }
3377 }
3378 // reset predecessor list
3379 for(int i=0;i<Order;i++) {
3380 Binder = FragmentSearch.BondsPerSPList[2*i];
3381 *out << Verbose(1) << "Current SP level is " << i << "." << endl;
3382 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
3383 Binder = Binder->next;
3384 PredecessorList[Binder->rightatom->nr] = NULL; // By construction "OtherAtom" is always Bond::rightatom!
3385 }
3386 }
3387 *out << endl;
3388
3389 // outputting all list for debugging
3390 *out << Verbose(0) << "Printing all found lists." << endl;
3391 for(int i=0;i<Order;i++) {
3392 Binder = FragmentSearch.BondsPerSPList[2*i];
3393 *out << Verbose(1) << "Current SP level is " << i << "." << endl;
3394 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
3395 Binder = Binder->next;
3396 *out << Verbose(2) << *Binder << endl;
3397 }
3398 }
3399
3400 // creating fragments with the found edge sets
3401 SP = 0;
3402 for(int i=0;i<Order;i++) { // sum up all found edges
3403 Binder = FragmentSearch.BondsPerSPList[2*i];
3404 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
3405 Binder = Binder->next;
3406 SP ++;
3407 }
3408 }
3409 *out << Verbose(0) << "Total number of edges is " << SP << "." << endl;
3410 if (SP >= (Order-1)) {
3411 // start with root (push on fragment stack)
3412 *out << Verbose(0) << "Starting fragment generation with " << *FragmentSearch.Root << ", local nr is " << FragmentSearch.Root->nr << "." << endl;
3413 FragmentSearch.FragmentSet->clear();
3414 FragmentSearch.FragmentSet->insert(FragmentSearch.Root->nr);
3415
3416 if (FragmentSearch.FragmentSet->size() == (unsigned int) Order) {
3417 *out << Verbose(0) << "Enough items on stack already for a fragment!" << endl;
3418 // store fragment as a KeySet
3419 *out << Verbose(2) << "Found a new fragment[" << FragmentSearch.FragmentCounter << "], local nr.s are: ";
3420 for(KeySet::iterator runner = FragmentSearch.FragmentSet->begin(); runner != FragmentSearch.FragmentSet->end(); runner++) {
3421 *out << (*runner) << " ";
3422 }
3423 *out << endl;
3424 InsertFragmentIntoGraph(out, &FragmentSearch);
3425 } else {
3426 *out << Verbose(0) << "Preparing subset for this root and calling generator." << endl;
3427 // prepare the subset and call the generator
3428 BondsList = (bond **) Malloc(sizeof(bond *)*FragmentSearch.BondsPerSPCount[0], "molecule::PowerSetGenerator: **BondsList");
3429 Binder = FragmentSearch.BondsPerSPList[0];
3430 for(int i=0;i<FragmentSearch.BondsPerSPCount[0];i++) {
3431 Binder = Binder->next;
3432 BondsList[i] = Binder;
3433 }
3434 SPFragmentGenerator(out, &FragmentSearch, 0, BondsList, FragmentSearch.BondsPerSPCount[0], Order-1);
3435 Free((void **)&BondsList, "molecule::PowerSetGenerator: **BondsList");
3436 }
3437 } else {
3438 *out << Verbose(0) << "Not enough total number of edges to build " << Order << "-body fragments." << endl;
3439 }
3440
3441 // as FragmentSearch structure is used only once, we don't have to clean it anymore
3442 // remove root from stack
3443 *out << Verbose(0) << "Removing root again from stack." << endl;
3444 FragmentSearch.FragmentSet->erase(FragmentSearch.Root->nr);
3445
3446 // free'ing the bonds lists
3447 *out << Verbose(0) << "Free'ing all found lists. and resetting index lists" << endl;
3448 for(int i=0;i<Order;i++) {
3449 *out << Verbose(1) << "Current SP level is " << i << ": ";
3450 Binder = FragmentSearch.BondsPerSPList[2*i];
3451 while (Binder->next != FragmentSearch.BondsPerSPList[2*i+1]) {
3452 Binder = Binder->next;
3453 // *out << "Removing atom " << Binder->leftatom->nr << " and " << Binder->rightatom->nr << "." << endl; // make sure numbers are local
3454 FragmentSearch.ShortestPathList[Binder->leftatom->nr] = -1;
3455 FragmentSearch.ShortestPathList[Binder->rightatom->nr] = -1;
3456 }
3457 // delete added bonds
3458 cleanup(FragmentSearch.BondsPerSPList[2*i], FragmentSearch.BondsPerSPList[2*i+1]);
3459 // also start and end node
3460 *out << "cleaned." << endl;
3461 }
3462
3463 // free allocated memory
3464 Free((void **)&NumberOfAtomsSPLevel, "molecule::PowerSetGenerator: *SPLevelCount");
3465 Free((void **)&PredecessorList, "molecule::PowerSetGenerator: **PredecessorList");
3466
3467 // return list
3468 *out << Verbose(0) << "End of PowerSetGenerator." << endl;
3469 return (FragmentSearch.FragmentCounter - Counter);
3470};
3471
3472/** Corrects the nuclei position if the fragment was created over the cell borders.
3473 * Scans all bonds, checks the distance, if greater than typical, we have a candidate for the correction.
3474 * We remove the bond whereafter the graph probably separates. Then, we translate the one component periodically
3475 * and re-add the bond. Looping on the distance check.
3476 * \param *out ofstream for debugging messages
3477 */
3478void molecule::ScanForPeriodicCorrection(ofstream *out)
3479{
3480 bond *Binder = NULL;
3481 bond *OtherBinder = NULL;
3482 atom *Walker = NULL;
3483 atom *OtherWalker = NULL;
3484 double *matrix = ReturnFullMatrixforSymmetric(cell_size);
3485 enum Shading *ColorList = NULL;
3486 double tmp;
3487 vector TranslationVector;
3488 //AtomStackClass *CompStack = NULL;
3489 AtomStackClass *AtomStack = new AtomStackClass(AtomCount);
3490 bool flag = true;
3491
3492// *out << Verbose(1) << "Begin of ScanForPeriodicCorrection." << endl;
3493
3494 ColorList = (enum Shading *) Malloc(sizeof(enum Shading)*AtomCount, "molecule::ScanForPeriodicCorrection: *ColorList");
3495 while (flag) {
3496 // remove bonds that are beyond bonddistance
3497 for(int i=0;i<NDIM;i++)
3498 TranslationVector.x[i] = 0.;
3499 // scan all bonds
3500 Binder = first;
3501 flag = false;
3502 while ((!flag) && (Binder->next != last)) {
3503 Binder = Binder->next;
3504 for (int i=0;i<NDIM;i++) {
3505 tmp = fabs(Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i]);
3506 //*out << Verbose(3) << "Checking " << i << "th distance of " << *Binder->leftatom << " to " << *Binder->rightatom << ": " << tmp << "." << endl;
3507 if (tmp > BondDistance) {
3508 OtherBinder = Binder->next; // note down binding partner for later re-insertion
3509 unlink(Binder); // unlink bond
3510// *out << Verbose(2) << "Correcting at bond " << *Binder << "." << endl;
3511 flag = true;
3512 break;
3513 }
3514 }
3515 }
3516 if (flag) {
3517 // create translation vector from their periodically modified distance
3518 for (int i=0;i<NDIM;i++) {
3519 tmp = Binder->leftatom->x.x[i] - Binder->rightatom->x.x[i];
3520 if (fabs(tmp) > BondDistance)
3521 TranslationVector.x[i] = (tmp < 0) ? +1. : -1.;
3522 }
3523 TranslationVector.MatrixMultiplication(matrix);
3524 //*out << "Translation vector is ";
3525 //TranslationVector.Output(out);
3526 //*out << endl;
3527 // apply to all atoms of first component via BFS
3528 for (int i=0;i<AtomCount;i++)
3529 ColorList[i] = white;
3530 AtomStack->Push(Binder->leftatom);
3531 while (!AtomStack->IsEmpty()) {
3532 Walker = AtomStack->PopFirst();
3533 //*out << Verbose (3) << "Current Walker is: " << *Walker << "." << endl;
3534 ColorList[Walker->nr] = black; // mark as explored
3535 Walker->x.AddVector(&TranslationVector); // translate
3536 for (int i=0;i<NumberOfBondsPerAtom[Walker->nr];i++) { // go through all binding partners
3537 if (ListOfBondsPerAtom[Walker->nr][i] != Binder) {
3538 OtherWalker = ListOfBondsPerAtom[Walker->nr][i]->GetOtherAtom(Walker);
3539 if (ColorList[OtherWalker->nr] == white) {
3540 AtomStack->Push(OtherWalker); // push if yet unexplored
3541 }
3542 }
3543 }
3544 }
3545 // re-add bond
3546 link(Binder, OtherBinder);
3547 } else {
3548// *out << Verbose(2) << "No corrections for this fragment." << endl;
3549 }
3550 //delete(CompStack);
3551 }
3552
3553 // free allocated space from ReturnFullMatrixforSymmetric()
3554 delete(AtomStack);
3555 Free((void **)&ColorList, "molecule::ScanForPeriodicCorrection: *ColorList");
3556 Free((void **)&matrix, "molecule::ScanForPeriodicCorrection: *matrix");
3557// *out << Verbose(1) << "End of ScanForPeriodicCorrection." << endl;
3558};
3559
3560/** Blows the 6-dimensional \a cell_size array up to a full NDIM by NDIM matrix.
3561 * \param *symm 6-dim array of unique symmetric matrix components
3562 * \return allocated NDIM*NDIM array with the symmetric matrix
3563 */
3564double * molecule::ReturnFullMatrixforSymmetric(double *symm)
3565{
3566 double *matrix = (double *) Malloc(sizeof(double)*NDIM*NDIM, "molecule::ReturnFullMatrixforSymmetric: *matrix");
3567 matrix[0] = symm[0];
3568 matrix[1] = symm[1];
3569 matrix[2] = symm[3];
3570 matrix[3] = symm[1];
3571 matrix[4] = symm[2];
3572 matrix[5] = symm[4];
3573 matrix[6] = symm[3];
3574 matrix[7] = symm[4];
3575 matrix[8] = symm[5];
3576 return matrix;
3577};
3578
3579bool KeyCompare::operator() (const KeySet SubgraphA, const KeySet SubgraphB) const
3580{
3581 //cout << "my check is used." << endl;
3582 if (SubgraphA.size() < SubgraphB.size()) {
3583 return true;
3584 } else {
3585 if (SubgraphA.size() > SubgraphB.size()) {
3586 return false;
3587 } else {
3588 KeySet::iterator IteratorA = SubgraphA.begin();
3589 KeySet::iterator IteratorB = SubgraphB.begin();
3590 while ((IteratorA != SubgraphA.end()) && (IteratorB != SubgraphB.end())) {
3591 if ((*IteratorA) < (*IteratorB))
3592 return true;
3593 else if ((*IteratorA) > (*IteratorB)) {
3594 return false;
3595 } // else, go on to next index
3596 IteratorA++;
3597 IteratorB++;
3598 } // end of while loop
3599 }// end of check in case of equal sizes
3600 }
3601 return false; // if we reach this point, they are equal
3602};
3603
3604//bool operator < (KeySet SubgraphA, KeySet SubgraphB)
3605//{
3606// return KeyCompare(SubgraphA, SubgraphB);
3607//};
3608
3609/** Checking whether KeySet is not already present in Graph, if so just adds factor.
3610 * \param *out output stream for debugging
3611 * \param &set KeySet to insert
3612 * \param &graph Graph to insert into
3613 * \param *counter pointer to unique fragment count
3614 * \param factor energy factor for the fragment
3615 */
3616inline void InsertFragmentIntoGraph(ofstream *out, struct UniqueFragments *Fragment)
3617{
3618 GraphTestPair testGraphInsert;
3619
3620 testGraphInsert = Fragment->Leaflet->insert(GraphPair (*Fragment->FragmentSet,pair<int,double>(Fragment->FragmentCounter,Fragment->TEFactor))); // store fragment number and current factor
3621 if (testGraphInsert.second) {
3622 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " successfully inserted." << endl;
3623 Fragment->FragmentCounter++;
3624 } else {
3625 *out << Verbose(2) << "KeySet " << Fragment->FragmentCounter << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
3626 ((*(testGraphInsert.first)).second).second += Fragment->TEFactor; // increase the "created" counter
3627 *out << Verbose(2) << "New factor is " << ((*(testGraphInsert.first)).second).second << "." << endl;
3628 }
3629};
3630//void inline InsertIntoGraph(ofstream *out, KeyStack &stack, Graph &graph, int *counter, double factor)
3631//{
3632// // copy stack contents to set and call overloaded function again
3633// KeySet set;
3634// for(KeyStack::iterator runner = stack.begin(); runner != stack.begin(); runner++)
3635// set.insert((*runner));
3636// InsertIntoGraph(out, set, graph, counter, factor);
3637//};
3638
3639/** Inserts each KeySet in \a graph2 into \a graph1.
3640 * \param *out output stream for debugging
3641 * \param graph1 first (dest) graph
3642 * \param graph2 second (source) graph
3643 * \param *counter keyset counter that gets increased
3644 */
3645inline void InsertGraphIntoGraph(ofstream *out, Graph &graph1, Graph &graph2, int *counter)
3646{
3647 GraphTestPair testGraphInsert;
3648
3649 for(Graph::iterator runner = graph2.begin(); runner != graph2.end(); runner++) {
3650 testGraphInsert = graph1.insert(GraphPair ((*runner).first,pair<int,double>((*counter)++,((*runner).second).second))); // store fragment number and current factor
3651 if (testGraphInsert.second) {
3652 *out << Verbose(2) << "KeySet " << (*counter)-1 << " successfully inserted." << endl;
3653 } else {
3654 *out << Verbose(2) << "KeySet " << (*counter)-1 << " failed to insert, present fragment is " << ((*(testGraphInsert.first)).second).first << endl;
3655 ((*(testGraphInsert.first)).second).second += (*runner).second.second;
3656 *out << Verbose(2) << "New factor is " << (*(testGraphInsert.first)).second.second << "." << endl;
3657 }
3658 }
3659};
3660
3661
3662/** Performs BOSSANOVA decomposition at selected sites, increasing the cutoff by one at these sites.
3663 * -# constructs a complete keyset of the molecule
3664 * -# In a loop over all possible roots from the given rootstack
3665 * -# increases order of root site
3666 * -# calls PowerSetGenerator with this order, the complete keyset and the rootkeynr
3667 * -# for all consecutive lower levels PowerSetGenerator is called with the suborder, the higher order keyset
3668as the restricted one and each site in the set as the root)
3669 * -# these are merged into a fragment list of keysets
3670 * -# All fragment lists (for all orders, i.e. from all destination fields) are merged into one list for return
3671 * Important only is that we create all fragments, it is not important if we create them more than once
3672 * as these copies are filtered out via use of the hash table (KeySet).
3673 * \param *out output stream for debugging
3674 * \param Fragment&*List list of already present keystacks (adaptive scheme) or empty list
3675 * \param &RootStack stack with all root candidates (unequal to each atom in complete molecule if adaptive scheme is applied)
3676 * \return pointer to Graph list
3677 */
3678void molecule::FragmentBOSSANOVA(ofstream *out, Graph *&FragmentList, KeyStack &RootStack)
3679{
3680 Graph ***FragmentLowerOrdersList = NULL;
3681 int Order, NumLevels, NumMolecules, TotalNumMolecules = 0, *NumMoleculesOfOrder = NULL;
3682 int counter = 0;
3683 int UpgradeCount = RootStack.size();
3684 KeyStack FragmentRootStack;
3685 int RootKeyNr, RootNr;
3686 struct UniqueFragments FragmentSearch;
3687
3688 *out << Verbose(0) << "Begin of FragmentBOSSANOVA." << endl;
3689
3690 // FragmentLowerOrdersList is a 2D-array of pointer to MoleculeListClass objects, one dimension represents the ANOVA expansion of a single order (i.e. 5)
3691 // with all needed lower orders that are subtracted, the other dimension is the BondOrder (i.e. from 1 to 5)
3692 NumMoleculesOfOrder = (int *) Malloc(sizeof(int)*UpgradeCount, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
3693 FragmentLowerOrdersList = (Graph ***) Malloc(sizeof(Graph **)*UpgradeCount, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
3694
3695 // initialise the fragments structure
3696 FragmentSearch.BondsPerSPList = (bond **) Malloc(sizeof(bond *)*Order*2, "molecule::PowerSetGenerator: ***BondsPerSPList");
3697 FragmentSearch.BondsPerSPCount = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *BondsPerSPCount");
3698 FragmentSearch.ShortestPathList = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *ShortestPathList");
3699 FragmentSearch.Labels = (int *) Malloc(sizeof(int)*AtomCount, "molecule::PowerSetGenerator: *Labels");
3700 FragmentSearch.FragmentCounter = 0;
3701 FragmentSearch.FragmentSet = new KeySet;
3702 FragmentSearch.Root = FindAtom(RootKeyNr);
3703 for (int i=0;i<AtomCount;i++) {
3704 FragmentSearch.Labels[i] = -1;
3705 FragmentSearch.ShortestPathList[i] = -1;
3706 }
3707
3708 // Construct the complete KeySet which we need for topmost level only (but for all Roots)
3709 atom *Walker = start;
3710 KeySet CompleteMolecule;
3711 while (Walker->next != end) {
3712 Walker = Walker->next;
3713 CompleteMolecule.insert(Walker->GetTrueFather()->nr);
3714 }
3715
3716 // 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
3717 // 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),
3718 // hence we have overall four 2th order levels for splitting. This also allows for putting all into a single array (FragmentLowerOrdersList[])
3719 // 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)
3720 RootNr = 0; // counts through the roots in RootStack
3721 while (RootNr < UpgradeCount) {
3722 RootKeyNr = RootStack.front();
3723 RootStack.pop_front();
3724 // increase adaptive order by one
3725 Walker = FindAtom(RootKeyNr);
3726 Walker->GetTrueFather()->AdaptiveOrder++;
3727 Order = Walker->AdaptiveOrder = Walker->GetTrueFather()->AdaptiveOrder;
3728
3729 // initialise Order-dependent entries of UniqueFragments structure
3730 FragmentSearch.BondsPerSPList = (bond **) Malloc(sizeof(bond *)*Order*2, "molecule::PowerSetGenerator: ***BondsPerSPList");
3731 FragmentSearch.BondsPerSPCount = (int *) Malloc(sizeof(int)*Order, "molecule::PowerSetGenerator: *BondsPerSPCount");
3732 for (int i=0;i<Order;i++) {
3733 FragmentSearch.BondsPerSPList[2*i] = new bond(); // start node
3734 FragmentSearch.BondsPerSPList[2*i+1] = new bond(); // end node
3735 FragmentSearch.BondsPerSPList[2*i]->next = FragmentSearch.BondsPerSPList[2*i+1]; // intertwine these two
3736 FragmentSearch.BondsPerSPList[2*i+1]->previous = FragmentSearch.BondsPerSPList[2*i];
3737 FragmentSearch.BondsPerSPCount[i] = 0;
3738 }
3739
3740 // allocate memory for all lower level orders in this 1D-array of ptrs
3741 NumLevels = 1 << (Order-1); // (int)pow(2,Order);
3742 FragmentLowerOrdersList[RootNr] = (Graph **) Malloc(sizeof(Graph *)*NumLevels, "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
3743
3744 // create top order where nothing is reduced
3745 *out << Verbose(0) << "==============================================================================================================" << endl;
3746 *out << Verbose(0) << "Creating KeySets of Bond Order " << Order << " for " << *Walker << ", NumLevels is " << NumLevels << ", " << (RootStack.size()-RootNr-1) << " Roots remaining." << endl;
3747
3748 // Create list of Graphs of current Bond Order (i.e. F_{ij})
3749 FragmentLowerOrdersList[RootNr][0] = new Graph;
3750 FragmentSearch.TEFactor = 1.;
3751 FragmentSearch.Leaflet = FragmentLowerOrdersList[RootNr][0]; // set to insertion graph
3752 FragmentSearch.Root = Walker;
3753 NumMoleculesOfOrder[RootNr] = PowerSetGenerator(out, Walker->AdaptiveOrder, FragmentSearch, CompleteMolecule);
3754 *out << Verbose(1) << "Number of resulting KeySets is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
3755 NumMolecules = 0;
3756
3757 if ((NumLevels >> 1) > 0) {
3758 // create lower order fragments
3759 *out << Verbose(0) << "Creating list of unique fragments of lower Bond Order terms to be subtracted." << endl;
3760 Order = Walker->AdaptiveOrder;
3761 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)
3762 // step down to next order at (virtual) boundary of powers of 2 in array
3763 while (source >= (1 << (Walker->AdaptiveOrder-Order))) // (int)pow(2,Walker->AdaptiveOrder-Order))
3764 Order--;
3765 *out << Verbose(0) << "Current Order is: " << Order << "." << endl;
3766 for (int SubOrder=Order-1;SubOrder>0;SubOrder--) {
3767 int dest = source + (1 << (Walker->AdaptiveOrder-(SubOrder+1)));
3768 *out << Verbose(0) << "--------------------------------------------------------------------------------------------------------------" << endl;
3769 *out << Verbose(0) << "Current SubOrder is: " << SubOrder << " with source " << source << " to destination " << dest << "." << endl;
3770
3771 // every molecule is split into a list of again (Order - 1) molecules, while counting all molecules
3772 //*out << Verbose(1) << "Splitting the " << (*FragmentLowerOrdersList[RootNr][source]).size() << " molecules of the " << source << "th cell in the array." << endl;
3773 //NumMolecules = 0;
3774 FragmentLowerOrdersList[RootNr][dest] = new Graph;
3775 for(Graph::iterator runner = (*FragmentLowerOrdersList[RootNr][source]).begin();runner != (*FragmentLowerOrdersList[RootNr][source]).end(); runner++) {
3776 for (KeySet::iterator sprinter = (*runner).first.begin();sprinter != (*runner).first.end(); sprinter++) {
3777 Graph TempFragmentList;
3778 FragmentSearch.TEFactor = -(*runner).second.second;
3779 FragmentSearch.Leaflet = &TempFragmentList; // set to insertion graph
3780 FragmentSearch.Root = FindAtom(*sprinter);
3781 NumMoleculesOfOrder[RootNr] += PowerSetGenerator(out, SubOrder, FragmentSearch, (*runner).first);
3782 // insert new keysets FragmentList into FragmentLowerOrdersList[Walker->AdaptiveOrder-1][dest]
3783 *out << Verbose(1) << "Merging resulting key sets with those present in destination " << dest << "." << endl;
3784 InsertGraphIntoGraph(out, *FragmentLowerOrdersList[RootNr][dest], TempFragmentList, &NumMolecules);
3785 }
3786 }
3787 *out << Verbose(1) << "Number of resulting molecules for SubOrder " << SubOrder << " is: " << NumMolecules << "." << endl;
3788 }
3789 }
3790 }
3791 // now, we have completely filled each cell of FragmentLowerOrdersList[] for the current Walker->AdaptiveOrder
3792 //NumMoleculesOfOrder[Walker->AdaptiveOrder-1] = NumMolecules;
3793 TotalNumMolecules += NumMoleculesOfOrder[RootNr];
3794 *out << Verbose(1) << "Number of resulting molecules for Order " << (int)Walker->GetTrueFather()->AdaptiveOrder << " is: " << NumMoleculesOfOrder[RootNr] << "." << endl;
3795 RootStack.push_back(RootKeyNr); // put back on stack
3796 RootNr++;
3797
3798 // free Order-dependent entries of UniqueFragments structure for next loop cycle
3799 Free((void **)&FragmentSearch.BondsPerSPCount, "molecule::PowerSetGenerator: *BondsPerSPCount");
3800 for (int i=0;i<Order;i++) {
3801 delete(FragmentSearch.BondsPerSPList[2*i]);
3802 delete(FragmentSearch.BondsPerSPList[2*i+1]);
3803 }
3804 Free((void **)&FragmentSearch.BondsPerSPList, "molecule::PowerSetGenerator: ***BondsPerSPList");
3805 }
3806 *out << Verbose(0) << "==============================================================================================================" << endl;
3807 *out << Verbose(1) << "Total number of resulting molecules is: " << TotalNumMolecules << "." << endl;
3808 *out << Verbose(0) << "==============================================================================================================" << endl;
3809
3810 // cleanup FragmentSearch structure
3811 Free((void **)&FragmentSearch.ShortestPathList, "molecule::PowerSetGenerator: *ShortestPathList");
3812 Free((void **)&FragmentSearch.Labels, "molecule::PowerSetGenerator: *Labels");
3813 delete(FragmentSearch.FragmentSet);
3814
3815 // now, FragmentLowerOrdersList is complete, it looks - for BondOrder 5 - as this (number is the ANOVA Order of the terms therein)
3816 // 5433222211111111
3817 // 43221111
3818 // 3211
3819 // 21
3820 // 1
3821
3822 // Subsequently, we combine all into a single list (FragmentList)
3823
3824 *out << Verbose(0) << "Combining the lists of all orders per order and finally into a single one." << endl;
3825 if (FragmentList == NULL) {
3826 FragmentList = new Graph;
3827 counter = 0;
3828 } else {
3829 counter = FragmentList->size();
3830 }
3831 RootNr = 0;
3832 while (!RootStack.empty()) {
3833 RootKeyNr = RootStack.front();
3834 RootStack.pop_front();
3835 Walker = FindAtom(RootKeyNr);
3836 NumLevels = 1 << (Walker->AdaptiveOrder - 1);
3837 for(int i=0;i<NumLevels;i++) {
3838 InsertGraphIntoGraph(out, *FragmentList, (*FragmentLowerOrdersList[RootNr][i]), &counter);
3839 delete(FragmentLowerOrdersList[RootNr][i]);
3840 }
3841 Free((void **)&FragmentLowerOrdersList[RootNr], "molecule::FragmentBOSSANOVA: **FragmentLowerOrdersList[]");
3842 RootNr++;
3843 }
3844 Free((void **)&FragmentLowerOrdersList, "molecule::FragmentBOSSANOVA: ***FragmentLowerOrdersList");
3845 Free((void **)&NumMoleculesOfOrder, "molecule::FragmentBOSSANOVA: *NumMoleculesOfOrder");
3846
3847 *out << Verbose(0) << "End of FragmentBOSSANOVA." << endl;
3848};
3849
3850/** Comparison function for GSL heapsort on distances in two molecules.
3851 * \param *a
3852 * \param *b
3853 * \return <0, \a *a less than \a *b, ==0 if equal, >0 \a *a greater than \a *b
3854 */
3855int CompareDoubles (const void * a, const void * b)
3856{
3857 if (*(double *)a > *(double *)b)
3858 return -1;
3859 else if (*(double *)a < *(double *)b)
3860 return 1;
3861 else
3862 return 0;
3863};
3864
3865/** Determines whether two molecules actually contain the same atoms and coordination.
3866 * \param *out output stream for debugging
3867 * \param *OtherMolecule the molecule to compare this one to
3868 * \param threshold upper limit of difference when comparing the coordination.
3869 * \return NULL - not equal, otherwise an allocated (molecule::AtomCount) permutation map of the atom numbers (which corresponds to which)
3870 */
3871int * molecule::IsEqualToWithinThreshold(ofstream *out, molecule *OtherMolecule, double threshold)
3872{
3873 int flag;
3874 double *Distances = NULL, *OtherDistances = NULL;
3875 vector CenterOfGravity, OtherCenterOfGravity;
3876 size_t *PermMap = NULL, *OtherPermMap = NULL;
3877 int *PermutationMap = NULL;
3878 atom *Walker = NULL;
3879 bool result = true; // status of comparison
3880
3881 *out << Verbose(3) << "Begin of IsEqualToWithinThreshold." << endl;
3882 /// first count both their atoms and elements and update lists thereby ...
3883 //*out << Verbose(0) << "Counting atoms, updating list" << endl;
3884 CountAtoms(out);
3885 OtherMolecule->CountAtoms(out);
3886 CountElements();
3887 OtherMolecule->CountElements();
3888
3889 /// ... and compare:
3890 /// -# AtomCount
3891 if (result) {
3892 if (AtomCount != OtherMolecule->AtomCount) {
3893 *out << Verbose(4) << "AtomCounts don't match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
3894 result = false;
3895 } else *out << Verbose(4) << "AtomCounts match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
3896 }
3897 /// -# ElementCount
3898 if (result) {
3899 if (ElementCount != OtherMolecule->ElementCount) {
3900 *out << Verbose(4) << "ElementCount don't match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
3901 result = false;
3902 } else *out << Verbose(4) << "ElementCount match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
3903 }
3904 /// -# ElementsInMolecule
3905 if (result) {
3906 for (flag=0;flag<MAX_ELEMENTS;flag++) {
3907 //*out << Verbose(5) << "Element " << flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl;
3908 if (ElementsInMolecule[flag] != OtherMolecule->ElementsInMolecule[flag])
3909 break;
3910 }
3911 if (flag < MAX_ELEMENTS) {
3912 *out << Verbose(4) << "ElementsInMolecule don't match." << endl;
3913 result = false;
3914 } else *out << Verbose(4) << "ElementsInMolecule match." << endl;
3915 }
3916 /// then determine and compare center of gravity for each molecule ...
3917 if (result) {
3918 *out << Verbose(5) << "Calculating Centers of Gravity" << endl;
3919 DetermineCenterOfGravity(CenterOfGravity);
3920 OtherMolecule->DetermineCenterOfGravity(OtherCenterOfGravity);
3921 *out << Verbose(5) << "Center of Gravity: ";
3922 CenterOfGravity.Output(out);
3923 *out << endl << Verbose(5) << "Other Center of Gravity: ";
3924 OtherCenterOfGravity.Output(out);
3925 *out << endl;
3926 if (CenterOfGravity.Distance(&OtherCenterOfGravity) > threshold) {
3927 *out << Verbose(4) << "Centers of gravity don't match." << endl;
3928 result = false;
3929 }
3930 }
3931
3932 /// ... then make a list with the euclidian distance to this center for each atom of both molecules
3933 if (result) {
3934 *out << Verbose(5) << "Calculating distances" << endl;
3935 Distances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: Distances");
3936 OtherDistances = (double *) Malloc(sizeof(double)*AtomCount, "molecule::IsEqualToWithinThreshold: OtherDistances");
3937 Walker = start;
3938 while (Walker->next != end) {
3939 Walker = Walker->next;
3940 //for (i=0;i<AtomCount;i++) {
3941 Distances[Walker->nr] = CenterOfGravity.Distance(&Walker->x);
3942 }
3943 Walker = OtherMolecule->start;
3944 while (Walker->next != OtherMolecule->end) {
3945 Walker = Walker->next;
3946 OtherDistances[Walker->nr] = OtherCenterOfGravity.Distance(&Walker->x);
3947 }
3948
3949 /// ... sort each list (using heapsort (o(N log N)) from GSL)
3950 *out << Verbose(5) << "Sorting distances" << endl;
3951 PermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermMap");
3952 OtherPermMap = (size_t *) Malloc(sizeof(size_t)*AtomCount, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
3953 gsl_heapsort_index (PermMap, Distances, AtomCount, sizeof(double), CompareDoubles);
3954 gsl_heapsort_index (OtherPermMap, OtherDistances, AtomCount, sizeof(double), CompareDoubles);
3955 PermutationMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::IsEqualToWithinThreshold: *PermutationMap");
3956 *out << Verbose(5) << "Combining Permutation Maps" << endl;
3957 for(int i=0;i<AtomCount;i++)
3958 PermutationMap[PermMap[i]] = (int) OtherPermMap[i];
3959
3960 /// ... and compare them step by step, whether the difference is individiually(!) below \a threshold for all
3961 *out << Verbose(4) << "Comparing distances" << endl;
3962 flag = 0;
3963 for (int i=0;i<AtomCount;i++) {
3964 *out << Verbose(5) << "Distances: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " << threshold << endl;
3965 if (fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) > threshold)
3966 flag = 1;
3967 }
3968 Free((void **)&PermMap, "molecule::IsEqualToWithinThreshold: *PermMap");
3969 Free((void **)&OtherPermMap, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
3970
3971 /// free memory
3972 Free((void **)&Distances, "molecule::IsEqualToWithinThreshold: Distances");
3973 Free((void **)&OtherDistances, "molecule::IsEqualToWithinThreshold: OtherDistances");
3974 if (flag) { // if not equal
3975 Free((void **)&PermutationMap, "molecule::IsEqualToWithinThreshold: *PermutationMap");
3976 result = false;
3977 }
3978 }
3979 /// return pointer to map if all distances were below \a threshold
3980 *out << Verbose(3) << "End of IsEqualToWithinThreshold." << endl;
3981 if (result) {
3982 *out << Verbose(3) << "Result: Equal." << endl;
3983 return PermutationMap;
3984 } else {
3985 *out << Verbose(3) << "Result: Not equal." << endl;
3986 return NULL;
3987 }
3988};
3989
3990/** Returns an index map for two father-son-molecules.
3991 * The map tells which atom in this molecule corresponds to which one in the other molecul with their fathers.
3992 * \param *out output stream for debugging
3993 * \param *OtherMolecule corresponding molecule with fathers
3994 * \return allocated map of size molecule::AtomCount with map
3995 * \todo make this with a good sort O(n), not O(n^2)
3996 */
3997int * molecule::GetFatherSonAtomicMap(ofstream *out, molecule *OtherMolecule)
3998{
3999 atom *Walker = NULL, *OtherWalker = NULL;
4000 *out << Verbose(3) << "Begin of GetFatherAtomicMap." << endl;
4001 int *AtomicMap = (int *) Malloc(sizeof(int)*AtomCount, "molecule::GetAtomicMap: *AtomicMap"); //Calloc
4002 for (int i=0;i<AtomCount;i++)
4003 AtomicMap[i] = -1;
4004 if (OtherMolecule == this) { // same molecule
4005 for (int i=0;i<AtomCount;i++) // no need as -1 means already that there is trivial correspondence
4006 AtomicMap[i] = i;
4007 *out << Verbose(4) << "Map is trivial." << endl;
4008 } else {
4009 *out << Verbose(4) << "Map is ";
4010 Walker = start;
4011 while (Walker->next != end) {
4012 Walker = Walker->next;
4013 if (Walker->father == NULL) {
4014 AtomicMap[Walker->nr] = -2;
4015 } else {
4016 OtherWalker = OtherMolecule->start;
4017 while (OtherWalker->next != OtherMolecule->end) {
4018 OtherWalker = OtherWalker->next;
4019 //for (int i=0;i<AtomCount;i++) { // search atom
4020 //for (int j=0;j<OtherMolecule->AtomCount;j++) {
4021 //*out << Verbose(4) << "Comparing father " << Walker->father << " with the other one " << OtherWalker->father << "." << endl;
4022 if (Walker->father == OtherWalker)
4023 AtomicMap[Walker->nr] = OtherWalker->nr;
4024 }
4025 }
4026 *out << AtomicMap[Walker->nr] << "\t";
4027 }
4028 *out << endl;
4029 }
4030 *out << Verbose(3) << "End of GetFatherAtomicMap." << endl;
4031 return AtomicMap;
4032};
4033
Note: See TracBrowser for help on using the repository browser.