source: src/molecules.cpp@ 19892d

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

tiny comments and docu update for FragmentMolecule()

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