source: src/molecules.cpp@ e9b8bb

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

Rename of class vector to Vector to avoid conflict with vector from STL.

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