source: src/molecules.cpp@ a6b7fb

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

BUGFIX: config::SaveMPQC() used molecule::DetermineCenter() which relies on the created bond structure, causing segfault.

When storing a newly created configuration file, the bond structure needs not be present yet. Hence, we created the function molecule:DetermineCenterOfAll(), similar to molecule::DetermineCenterOfGravity() just without scaling by masses. This new function is now used instead.

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