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