source: src/molecules.cpp@ 49de64

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

VolumeOfConvexEnvelope() finished and tested with SiOH4, 1_2_dimethoxyethane and CSHCluster (Ratio1-1)

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