source: src/molecules.cpp@ c750cc

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

char lengths of 255 and MAXDUMMYSTRING replaced with define MAXSTRINGSIZE in molecuilder and pcp

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