source: src/molecules.cpp@ 386aa2

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

new function molecule::CheckOrderAtSite and molecule::FragmentMolecule() abstractized

molecule::CheckOrderAtSite() just checks a given order against atom:AdaptiveOrder and whether there's still something to do for the fragmentation.
MoleculeLeafClass::FillBondStructureFromReference, CreateFatherLookupTable, along with the molecule::CheckOrderAtSite are used to make the structure of molecule::FragmentMolecule clearer

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