source: src/molecules.cpp@ 267e95

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

FragmentMolecule(): debug messages removed for ADDHYDROGEN

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