source: src/molecules.cpp@ fc850d

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

MinimumRingSize is now an array over all atoms

Each entry in MinimumRingSize defines the maximum bond order possible due to membership in or vicinity to a ring. In order to do create this array, CyclicStructureAnalysis() was expanded with another BFS going over all atoms that are only close to a ring (nearest ring member is search and entri in array set). All other functions such as DepthFirstSearchAnalysis() and FragmentBOSSANOVA(), where the MinimumRingSize is now checked (and not in FragmentMolecule) anymore, are adapted to have an array parameter.

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