source: src/molecules.cpp@ b4b7c3

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

new test function CheckForConnectedSubgraph() and bigger rewrite of PowerSetGenerator() and SPFragmentGenerator() to allow for ings

CheckForConnectedSubgraph(): Is an O(N2) function to check whether we do not create fragments we don't want to have (i.e. disconnected ones)
PowerSetGenerator(): Instead of adding the possible Walkers to an AtomStack, we use the bonds we store in the BondsPerSPList, which by the way have the necessary directional information (i.e. they come with the predecessor in Bond#leftatom). This way, we generate fragments in ring structures without any problems.
SPFragmentGenerator(): had to be adapted as the calling in PowerSetGenerator() had changed a bit. We already let the root be added by this function and don't add it in PowerSetGenerator(), which simplifies (no if-catch for first order) the code there a bit. Furthermore, we had to check whether an added vertex was not already in the keyset (this may happen, as both edge 1<->2 as 2<->1 may appear at different SPLevels in BondsPerSPLevel: Ring structures in contrast to tree structures don not allow for uniqueness! This is first realised through the hash map storing the keysets). This again caused a change in recognizing when the stack contains a fragment, as Suborder-bits (bits is the number of atoms added for this combination) is not the way anymore - we use an additional Counter "Added".

Test on Benzonitrile was successful. We counted the possible fragments by hand, checked them furthermore till order 5 and the numbers were ok up till full order 8 in the end.

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