source: src/molecules.cpp@ 3af1f0

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 3af1f0 was 1907a7, checked in by Frederik Heber <heber@…>, 16 years ago

Basic implementation of Multiple molecules.

builder.cpp:

molecules.hpp:

moleculelist.cpp:

  • replaced listofmolecules array by STL list everywhere (only smaller changes necessary)
  • new merging function: SimpleMerge, SimpleAdd, SimpleMultiMerge, SimpleMultiAdd, (EmbedMerge, ScatterMerge ... both not finished). Add does not while merge does delete the src molecules.
  • new function: Enumerate(). Output of all molecules with number of atoms and chemical formula
  • new function: NumberOfActiveMolecules(). Counts the number of molecules in the list with ActiveFlag set.
  • new function: insert(). Inserts a molecule into the list with a unique index

molecules.cpp:

  • new function: SetNameFromFilename. Takes basename of a filename and sets name accordingly.
  • new function: UnlinkAtom. Only removes atom from list, does not delete it from memory.

atom.cpp:

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