source: src/molecule.cpp@ fcd7b6

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since fcd7b6 was fcd7b6, checked in by Frederik Heber <heber@…>, 15 years ago

In molecule::OutputTrajectories() ActOnAllAtoms() with new function atom::OutputTrajectory() is used.

For this to work, I had to change the Trajectory struct that was so far included in molecule.hpp to be incorporated directly into the class atom.
NOTE: This incorporation is incomplete and a ticket (#34) has been filed to remind of this issue.
However, the trajectory is better suited to reside in atom anyway and was probably just put in molecule due to memory prejudices against STL vector<>.
Functions in molecule.cpp, config.cpp, molecule_geometry.cpp and molecule_dynamics.cpp were adapted (changed from Trajectories[atom *] to atom *->Trajectory).
And the atom pointer in the Trajectory structure was removed.

  • Property mode set to 100755
File size: 48.1 KB
Line 
1/** \file molecules.cpp
2 *
3 * Functions for the class molecule.
4 *
5 */
6
7#include "config.hpp"
8#include "helpers.hpp"
9#include "memoryallocator.hpp"
10#include "molecule.hpp"
11
12/************************************* Functions for class molecule *********************************/
13
14/** Constructor of class molecule.
15 * Initialises molecule list with correctly referenced start and end, and sets molecule::last_atom to zero.
16 */
17molecule::molecule(periodentafel *teil)
18{
19 // init atom chain list
20 start = new atom;
21 end = new atom;
22 start->father = NULL;
23 end->father = NULL;
24 link(start,end);
25 InternalPointer = start;
26 // init bond chain list
27 first = new bond(start, end, 1, -1);
28 last = new bond(start, end, 1, -1);
29 link(first,last);
30 // other stuff
31 MDSteps = 0;
32 last_atom = 0;
33 elemente = teil;
34 AtomCount = 0;
35 BondCount = 0;
36 NoNonBonds = 0;
37 NoNonHydrogen = 0;
38 NoCyclicBonds = 0;
39 ListOfBondsPerAtom = NULL;
40 NumberOfBondsPerAtom = NULL;
41 ElementCount = 0;
42 for(int i=MAX_ELEMENTS;i--;)
43 ElementsInMolecule[i] = 0;
44 cell_size[0] = cell_size[2] = cell_size[5]= 20.;
45 cell_size[1] = cell_size[3] = cell_size[4]= 0.;
46 strcpy(name,"none");
47 IndexNr = -1;
48 ActiveFlag = false;
49 TesselStruct = NULL;
50};
51
52/** Destructor of class molecule.
53 * Initialises molecule list with correctly referenced start and end, and sets molecule::last_atom to zero.
54 */
55molecule::~molecule()
56{
57 if (ListOfBondsPerAtom != NULL)
58 for(int i=AtomCount;i--;)
59 Free(&ListOfBondsPerAtom[i]);
60 Free(&ListOfBondsPerAtom);
61 Free(&NumberOfBondsPerAtom);
62 if (TesselStruct != NULL)
63 delete(TesselStruct);
64 CleanupMolecule();
65 delete(first);
66 delete(last);
67 delete(end);
68 delete(start);
69};
70
71
72/** Adds given atom \a *pointer from molecule list.
73 * Increases molecule::last_atom and gives last number to added atom and names it according to its element::abbrev and molecule::AtomCount
74 * \param *pointer allocated and set atom
75 * \return true - succeeded, false - atom not found in list
76 */
77bool molecule::AddAtom(atom *pointer)
78{
79 if (pointer != NULL) {
80 pointer->sort = &pointer->nr;
81 pointer->nr = last_atom++; // increase number within molecule
82 AtomCount++;
83 if (pointer->type != NULL) {
84 if (ElementsInMolecule[pointer->type->Z] == 0)
85 ElementCount++;
86 ElementsInMolecule[pointer->type->Z]++; // increase number of elements
87 if (pointer->type->Z != 1)
88 NoNonHydrogen++;
89 if (pointer->Name == NULL) {
90 Free(&pointer->Name);
91 pointer->Name = Malloc<char>(6, "molecule::AddAtom: *pointer->Name");
92 sprintf(pointer->Name, "%2s%02d", pointer->type->symbol, pointer->nr+1);
93 }
94 }
95 return add(pointer, end);
96 } else
97 return false;
98};
99
100/** Adds a copy of the given atom \a *pointer from molecule list.
101 * Increases molecule::last_atom and gives last number to added atom.
102 * \param *pointer allocated and set atom
103 * \return pointer to the newly added atom
104 */
105atom * molecule::AddCopyAtom(atom *pointer)
106{
107 if (pointer != NULL) {
108 atom *walker = new atom(pointer);
109 walker->Name = Malloc<char>(strlen(pointer->Name) + 1, "atom::atom: *Name");
110 strcpy (walker->Name, pointer->Name);
111 walker->nr = last_atom++; // increase number within molecule
112 add(walker, end);
113 if ((pointer->type != NULL) && (pointer->type->Z != 1))
114 NoNonHydrogen++;
115 AtomCount++;
116 return walker;
117 } else
118 return NULL;
119};
120
121/** Adds a Hydrogen atom in replacement for the given atom \a *partner in bond with a *origin.
122 * Here, we have to distinguish between single, double or triple bonds as stated by \a BondDegree, that each demand
123 * a different scheme when adding \a *replacement atom for the given one.
124 * -# Single Bond: Simply add new atom with bond distance rescaled to typical hydrogen one
125 * -# Double Bond: Here, we need the **BondList of the \a *origin atom, by scanning for the other bonds instead of
126 * *Bond, we use the through these connected atoms to determine the plane they lie in, vector::MakeNormalvector().
127 * The orthonormal vector to this plane along with the vector in *Bond direction determines the plane the two
128 * replacing hydrogens shall lie in. Now, all remains to do is take the usual hydrogen double bond angle for the
129 * element of *origin and form the sin/cos admixture of both plane vectors for the new coordinates of the two
130 * hydrogens forming this angle with *origin.
131 * -# 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
132 * triangle formed by the to be added hydrogens are not equal to the typical bond distance \f$l\f$ but have to be
133 * determined from the typical angle \f$\alpha\f$ for a hydrogen triple connected to the element of *origin):
134 * We have the height \f$d\f$ as the vector in *Bond direction (from triangle C1-H1-H2).
135 * \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 )}}
136 * \f]
137 * vector::GetNormalvector() creates one orthonormal vector from this *Bond vector and vector::MakeNormalvector creates
138 * the third one from the former two vectors. The latter ones form the plane of the base triangle mentioned above.
139 * The lengths for these are \f$f\f$ and \f$g\f$ (from triangle H1-H2-(center of H1-H2-H3)) with knowledge that
140 * the median lines in an isosceles triangle meet in the center point with a ratio 2:1.
141 * \f[ f = \frac{b}{\sqrt{3}} \qquad g = \frac{b}{2}
142 * \f]
143 * as the coordination of all three atoms in the coordinate system of these three vectors:
144 * \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$.
145 *
146 * \param *out output stream for debugging
147 * \param *Bond pointer to bond between \a *origin and \a *replacement
148 * \param *TopOrigin son of \a *origin of upper level molecule (the atom added to this molecule as a copy of \a *origin)
149 * \param *origin pointer to atom which acts as the origin for scaling the added hydrogen to correct bond length
150 * \param *replacement pointer to the atom which shall be copied as a hydrogen atom in this molecule
151 * \param **BondList list of bonds \a *replacement has (necessary to determine plane for double and triple bonds)
152 * \param NumBond number of bonds in \a **BondList
153 * \param isAngstroem whether the coordination of the given atoms is in AtomicLength (false) or Angstrom(true)
154 * \return number of atoms added, if < bond::BondDegree then something went wrong
155 * \todo double and triple bonds splitting (always use the tetraeder angle!)
156 */
157bool molecule::AddHydrogenReplacementAtom(ofstream *out, bond *TopBond, atom *BottomOrigin, atom *TopOrigin, atom *TopReplacement, bond **BondList, int NumBond, bool IsAngstroem)
158{
159 double bondlength; // bond length of the bond to be replaced/cut
160 double bondangle; // bond angle of the bond to be replaced/cut
161 double BondRescale; // rescale value for the hydrogen bond length
162 bool AllWentWell = true; // flag gathering the boolean return value of molecule::AddAtom and other functions, as return value on exit
163 bond *FirstBond = NULL, *SecondBond = NULL; // Other bonds in double bond case to determine "other" plane
164 atom *FirstOtherAtom = NULL, *SecondOtherAtom = NULL, *ThirdOtherAtom = NULL; // pointer to hydrogen atoms to be added
165 double b,l,d,f,g, alpha, factors[NDIM]; // hold temporary values in triple bond case for coordination determination
166 Vector Orthovector1, Orthovector2; // temporary vectors in coordination construction
167 Vector InBondvector; // vector in direction of *Bond
168 bond *Binder = NULL;
169 double *matrix;
170
171// *out << Verbose(3) << "Begin of AddHydrogenReplacementAtom." << endl;
172 // create vector in direction of bond
173 InBondvector.CopyVector(&TopReplacement->x);
174 InBondvector.SubtractVector(&TopOrigin->x);
175 bondlength = InBondvector.Norm();
176
177 // is greater than typical bond distance? Then we have to correct periodically
178 // the problem is not the H being out of the box, but InBondvector have the wrong direction
179 // due to TopReplacement or Origin being on the wrong side!
180 if (bondlength > BondDistance) {
181// *out << Verbose(4) << "InBondvector is: ";
182// InBondvector.Output(out);
183// *out << endl;
184 Orthovector1.Zero();
185 for (int i=NDIM;i--;) {
186 l = TopReplacement->x.x[i] - TopOrigin->x.x[i];
187 if (fabs(l) > BondDistance) { // is component greater than bond distance
188 Orthovector1.x[i] = (l < 0) ? -1. : +1.;
189 } // (signs are correct, was tested!)
190 }
191 matrix = ReturnFullMatrixforSymmetric(cell_size);
192 Orthovector1.MatrixMultiplication(matrix);
193 InBondvector.SubtractVector(&Orthovector1); // subtract just the additional translation
194 Free(&matrix);
195 bondlength = InBondvector.Norm();
196// *out << Verbose(4) << "Corrected InBondvector is now: ";
197// InBondvector.Output(out);
198// *out << endl;
199 } // periodic correction finished
200
201 InBondvector.Normalize();
202 // get typical bond length and store as scale factor for later
203 BondRescale = TopOrigin->type->HBondDistance[TopBond->BondDegree-1];
204 if (BondRescale == -1) {
205 cerr << Verbose(3) << "ERROR: There is no typical hydrogen bond distance in replacing bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") of degree " << TopBond->BondDegree << "!" << endl;
206 return false;
207 BondRescale = bondlength;
208 } else {
209 if (!IsAngstroem)
210 BondRescale /= (1.*AtomicLengthToAngstroem);
211 }
212
213 // discern single, double and triple bonds
214 switch(TopBond->BondDegree) {
215 case 1:
216 FirstOtherAtom = new atom(); // new atom
217 FirstOtherAtom->type = elemente->FindElement(1); // element is Hydrogen
218 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
219 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
220 if (TopReplacement->type->Z == 1) { // neither rescale nor replace if it's already hydrogen
221 FirstOtherAtom->father = TopReplacement;
222 BondRescale = bondlength;
223 } else {
224 FirstOtherAtom->father = NULL; // if we replace hydrogen, we mark it as our father, otherwise we are just an added hydrogen with no father
225 }
226 InBondvector.Scale(&BondRescale); // rescale the distance vector to Hydrogen bond length
227 FirstOtherAtom->x.CopyVector(&TopOrigin->x); // set coordination to origin ...
228 FirstOtherAtom->x.AddVector(&InBondvector); // ... and add distance vector to replacement atom
229 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
230// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
231// FirstOtherAtom->x.Output(out);
232// *out << endl;
233 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
234 Binder->Cyclic = false;
235 Binder->Type = TreeEdge;
236 break;
237 case 2:
238 // determine two other bonds (warning if there are more than two other) plus valence sanity check
239 for (int i=0;i<NumBond;i++) {
240 if (BondList[i] != TopBond) {
241 if (FirstBond == NULL) {
242 FirstBond = BondList[i];
243 FirstOtherAtom = BondList[i]->GetOtherAtom(TopOrigin);
244 } else if (SecondBond == NULL) {
245 SecondBond = BondList[i];
246 SecondOtherAtom = BondList[i]->GetOtherAtom(TopOrigin);
247 } else {
248 *out << Verbose(3) << "WARNING: Detected more than four bonds for atom " << TopOrigin->Name;
249 }
250 }
251 }
252 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)
253 SecondBond = TopBond;
254 SecondOtherAtom = TopReplacement;
255 }
256 if (FirstOtherAtom != NULL) { // then we just have this double bond and the plane does not matter at all
257// *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;
258
259 // determine the plane of these two with the *origin
260 AllWentWell = AllWentWell && Orthovector1.MakeNormalVector(&TopOrigin->x, &FirstOtherAtom->x, &SecondOtherAtom->x);
261 } else {
262 Orthovector1.GetOneNormalVector(&InBondvector);
263 }
264 //*out << Verbose(3)<< "Orthovector1: ";
265 //Orthovector1.Output(out);
266 //*out << endl;
267 // orthogonal vector and bond vector between origin and replacement form the new plane
268 Orthovector1.MakeNormalVector(&InBondvector);
269 Orthovector1.Normalize();
270 //*out << Verbose(3) << "ReScaleCheck: " << Orthovector1.Norm() << " and " << InBondvector.Norm() << "." << endl;
271
272 // create the two Hydrogens ...
273 FirstOtherAtom = new atom();
274 SecondOtherAtom = new atom();
275 FirstOtherAtom->type = elemente->FindElement(1);
276 SecondOtherAtom->type = elemente->FindElement(1);
277 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
278 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
279 SecondOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
280 SecondOtherAtom->FixedIon = TopReplacement->FixedIon;
281 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father
282 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father
283 bondangle = TopOrigin->type->HBondAngle[1];
284 if (bondangle == -1) {
285 *out << Verbose(3) << "ERROR: There is no typical hydrogen bond angle in replacing bond (" << TopOrigin->Name << "<->" << TopReplacement->Name << ") of degree " << TopBond->BondDegree << "!" << endl;
286 return false;
287 bondangle = 0;
288 }
289 bondangle *= M_PI/180./2.;
290// *out << Verbose(3) << "ReScaleCheck: InBondvector ";
291// InBondvector.Output(out);
292// *out << endl;
293// *out << Verbose(3) << "ReScaleCheck: Orthovector ";
294// Orthovector1.Output(out);
295// *out << endl;
296// *out << Verbose(3) << "Half the bond angle is " << bondangle << ", sin and cos of it: " << sin(bondangle) << ", " << cos(bondangle) << endl;
297 FirstOtherAtom->x.Zero();
298 SecondOtherAtom->x.Zero();
299 for(int i=NDIM;i--;) { // rotate by half the bond angle in both directions (InBondvector is bondangle = 0 direction)
300 FirstOtherAtom->x.x[i] = InBondvector.x[i] * cos(bondangle) + Orthovector1.x[i] * (sin(bondangle));
301 SecondOtherAtom->x.x[i] = InBondvector.x[i] * cos(bondangle) + Orthovector1.x[i] * (-sin(bondangle));
302 }
303 FirstOtherAtom->x.Scale(&BondRescale); // rescale by correct BondDistance
304 SecondOtherAtom->x.Scale(&BondRescale);
305 //*out << Verbose(3) << "ReScaleCheck: " << FirstOtherAtom->x.Norm() << " and " << SecondOtherAtom->x.Norm() << "." << endl;
306 for(int i=NDIM;i--;) { // and make relative to origin atom
307 FirstOtherAtom->x.x[i] += TopOrigin->x.x[i];
308 SecondOtherAtom->x.x[i] += TopOrigin->x.x[i];
309 }
310 // ... and add to molecule
311 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
312 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom);
313// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
314// FirstOtherAtom->x.Output(out);
315// *out << endl;
316// *out << Verbose(4) << "Added " << *SecondOtherAtom << " at: ";
317// SecondOtherAtom->x.Output(out);
318// *out << endl;
319 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
320 Binder->Cyclic = false;
321 Binder->Type = TreeEdge;
322 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1);
323 Binder->Cyclic = false;
324 Binder->Type = TreeEdge;
325 break;
326 case 3:
327 // take the "usual" tetraoidal angle and add the three Hydrogen in direction of the bond (height of the tetraoid)
328 FirstOtherAtom = new atom();
329 SecondOtherAtom = new atom();
330 ThirdOtherAtom = new atom();
331 FirstOtherAtom->type = elemente->FindElement(1);
332 SecondOtherAtom->type = elemente->FindElement(1);
333 ThirdOtherAtom->type = elemente->FindElement(1);
334 FirstOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
335 FirstOtherAtom->FixedIon = TopReplacement->FixedIon;
336 SecondOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
337 SecondOtherAtom->FixedIon = TopReplacement->FixedIon;
338 ThirdOtherAtom->v.CopyVector(&TopReplacement->v); // copy velocity
339 ThirdOtherAtom->FixedIon = TopReplacement->FixedIon;
340 FirstOtherAtom->father = NULL; // we are just an added hydrogen with no father
341 SecondOtherAtom->father = NULL; // we are just an added hydrogen with no father
342 ThirdOtherAtom->father = NULL; // we are just an added hydrogen with no father
343
344 // we need to vectors orthonormal the InBondvector
345 AllWentWell = AllWentWell && Orthovector1.GetOneNormalVector(&InBondvector);
346// *out << Verbose(3) << "Orthovector1: ";
347// Orthovector1.Output(out);
348// *out << endl;
349 AllWentWell = AllWentWell && Orthovector2.MakeNormalVector(&InBondvector, &Orthovector1);
350// *out << Verbose(3) << "Orthovector2: ";
351// Orthovector2.Output(out);
352// *out << endl;
353
354 // create correct coordination for the three atoms
355 alpha = (TopOrigin->type->HBondAngle[2])/180.*M_PI/2.; // retrieve triple bond angle from database
356 l = BondRescale; // desired bond length
357 b = 2.*l*sin(alpha); // base length of isosceles triangle
358 d = l*sqrt(cos(alpha)*cos(alpha) - sin(alpha)*sin(alpha)/3.); // length for InBondvector
359 f = b/sqrt(3.); // length for Orthvector1
360 g = b/2.; // length for Orthvector2
361// *out << Verbose(3) << "Bond length and half-angle: " << l << ", " << alpha << "\t (b,d,f,g) = " << b << ", " << d << ", " << f << ", " << g << ", " << endl;
362// *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;
363 factors[0] = d;
364 factors[1] = f;
365 factors[2] = 0.;
366 FirstOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
367 factors[1] = -0.5*f;
368 factors[2] = g;
369 SecondOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
370 factors[2] = -g;
371 ThirdOtherAtom->x.LinearCombinationOfVectors(&InBondvector, &Orthovector1, &Orthovector2, factors);
372
373 // rescale each to correct BondDistance
374// FirstOtherAtom->x.Scale(&BondRescale);
375// SecondOtherAtom->x.Scale(&BondRescale);
376// ThirdOtherAtom->x.Scale(&BondRescale);
377
378 // and relative to *origin atom
379 FirstOtherAtom->x.AddVector(&TopOrigin->x);
380 SecondOtherAtom->x.AddVector(&TopOrigin->x);
381 ThirdOtherAtom->x.AddVector(&TopOrigin->x);
382
383 // ... and add to molecule
384 AllWentWell = AllWentWell && AddAtom(FirstOtherAtom);
385 AllWentWell = AllWentWell && AddAtom(SecondOtherAtom);
386 AllWentWell = AllWentWell && AddAtom(ThirdOtherAtom);
387// *out << Verbose(4) << "Added " << *FirstOtherAtom << " at: ";
388// FirstOtherAtom->x.Output(out);
389// *out << endl;
390// *out << Verbose(4) << "Added " << *SecondOtherAtom << " at: ";
391// SecondOtherAtom->x.Output(out);
392// *out << endl;
393// *out << Verbose(4) << "Added " << *ThirdOtherAtom << " at: ";
394// ThirdOtherAtom->x.Output(out);
395// *out << endl;
396 Binder = AddBond(BottomOrigin, FirstOtherAtom, 1);
397 Binder->Cyclic = false;
398 Binder->Type = TreeEdge;
399 Binder = AddBond(BottomOrigin, SecondOtherAtom, 1);
400 Binder->Cyclic = false;
401 Binder->Type = TreeEdge;
402 Binder = AddBond(BottomOrigin, ThirdOtherAtom, 1);
403 Binder->Cyclic = false;
404 Binder->Type = TreeEdge;
405 break;
406 default:
407 cerr << "ERROR: BondDegree does not state single, double or triple bond!" << endl;
408 AllWentWell = false;
409 break;
410 }
411
412// *out << Verbose(3) << "End of AddHydrogenReplacementAtom." << endl;
413 return AllWentWell;
414};
415
416/** Adds given atom \a *pointer from molecule list.
417 * Increases molecule::last_atom and gives last number to added atom.
418 * \param filename name and path of xyz file
419 * \return true - succeeded, false - file not found
420 */
421bool molecule::AddXYZFile(string filename)
422{
423 istringstream *input = NULL;
424 int NumberOfAtoms = 0; // atom number in xyz read
425 int i, j; // loop variables
426 atom *Walker = NULL; // pointer to added atom
427 char shorthand[3]; // shorthand for atom name
428 ifstream xyzfile; // xyz file
429 string line; // currently parsed line
430 double x[3]; // atom coordinates
431
432 xyzfile.open(filename.c_str());
433 if (!xyzfile)
434 return false;
435
436 getline(xyzfile,line,'\n'); // Read numer of atoms in file
437 input = new istringstream(line);
438 *input >> NumberOfAtoms;
439 cout << Verbose(0) << "Parsing " << NumberOfAtoms << " atoms in file." << endl;
440 getline(xyzfile,line,'\n'); // Read comment
441 cout << Verbose(1) << "Comment: " << line << endl;
442
443 if (MDSteps == 0) // no atoms yet present
444 MDSteps++;
445 for(i=0;i<NumberOfAtoms;i++){
446 Walker = new atom;
447 getline(xyzfile,line,'\n');
448 istringstream *item = new istringstream(line);
449 //istringstream input(line);
450 //cout << Verbose(1) << "Reading: " << line << endl;
451 *item >> shorthand;
452 *item >> x[0];
453 *item >> x[1];
454 *item >> x[2];
455 Walker->type = elemente->FindElement(shorthand);
456 if (Walker->type == NULL) {
457 cerr << "Could not parse the element at line: '" << line << "', setting to H.";
458 Walker->type = elemente->FindElement(1);
459 }
460 if (Walker->Trajectory.R.size() <= (unsigned int)MDSteps) {
461 Walker->Trajectory.R.resize(MDSteps+10);
462 Walker->Trajectory.U.resize(MDSteps+10);
463 Walker->Trajectory.F.resize(MDSteps+10);
464 }
465 for(j=NDIM;j--;) {
466 Walker->x.x[j] = x[j];
467 Walker->Trajectory.R.at(MDSteps-1).x[j] = x[j];
468 Walker->Trajectory.U.at(MDSteps-1).x[j] = 0;
469 Walker->Trajectory.F.at(MDSteps-1).x[j] = 0;
470 }
471 AddAtom(Walker); // add to molecule
472 delete(item);
473 }
474 xyzfile.close();
475 delete(input);
476 return true;
477};
478
479/** Creates a copy of this molecule.
480 * \return copy of molecule
481 */
482molecule *molecule::CopyMolecule()
483{
484 molecule *copy = new molecule(elemente);
485 atom *LeftAtom = NULL, *RightAtom = NULL;
486
487 // copy all atoms
488 ActOnCopyWithEachAtom ( &molecule::AddCopyAtom, copy );
489
490 // copy all bonds
491 bond *Binder = first;
492 bond *NewBond = NULL;
493 while(Binder->next != last) {
494 Binder = Binder->next;
495
496 // get the pendant atoms of current bond in the copy molecule
497 copy->ActOnAllAtoms( &atom::EqualsFather, Binder->leftatom, &LeftAtom );
498 copy->ActOnAllAtoms( &atom::EqualsFather, Binder->rightatom, &RightAtom );
499
500 NewBond = copy->AddBond(LeftAtom, RightAtom, Binder->BondDegree);
501 NewBond->Cyclic = Binder->Cyclic;
502 if (Binder->Cyclic)
503 copy->NoCyclicBonds++;
504 NewBond->Type = Binder->Type;
505 }
506 // correct fathers
507 ActOnAllAtoms( &atom::CorrectFather );
508
509 // copy values
510 copy->CountAtoms((ofstream *)&cout);
511 copy->CountElements();
512 if (first->next != last) { // if adjaceny list is present
513 copy->BondDistance = BondDistance;
514 copy->CreateListOfBondsPerAtom((ofstream *)&cout);
515 }
516
517 return copy;
518};
519
520
521/**
522 * Copies all atoms of a molecule which are within the defined parallelepiped.
523 *
524 * @param offest for the origin of the parallelepiped
525 * @param three vectors forming the matrix that defines the shape of the parallelpiped
526 */
527molecule* molecule::CopyMoleculeFromSubRegion(Vector offset, double *parallelepiped) {
528 molecule *copy = new molecule(elemente);
529
530 ActOnCopyWithEachAtomIfTrue ( &molecule::AddCopyAtom, copy, &atom::IsInParallelepiped, offset, parallelepiped );
531
532 //TODO: copy->BuildInducedSubgraph((ofstream *)&cout, this);
533
534 return copy;
535}
536
537/** Adds a bond to a the molecule specified by two atoms, \a *first and \a *second.
538 * Also updates molecule::BondCount and molecule::NoNonBonds.
539 * \param *first first atom in bond
540 * \param *second atom in bond
541 * \return pointer to bond or NULL on failure
542 */
543bond * molecule::AddBond(atom *atom1, atom *atom2, int degree)
544{
545 bond *Binder = NULL;
546 if ((atom1 != NULL) && (FindAtom(atom1->nr) != NULL) && (atom2 != NULL) && (FindAtom(atom2->nr) != NULL)) {
547 Binder = new bond(atom1, atom2, degree, BondCount++);
548 if ((atom1->type != NULL) && (atom1->type->Z != 1) && (atom2->type != NULL) && (atom2->type->Z != 1))
549 NoNonBonds++;
550 add(Binder, last);
551 } else {
552 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;
553 }
554 return Binder;
555};
556
557/** Remove bond from bond chain list.
558 * \todo Function not implemented yet
559 * \param *pointer bond pointer
560 * \return true - bound found and removed, false - bond not found/removed
561 */
562bool molecule::RemoveBond(bond *pointer)
563{
564 //cerr << Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl;
565 removewithoutcheck(pointer);
566 return true;
567};
568
569/** Remove every bond from bond chain list that atom \a *BondPartner is a constituent of.
570 * \todo Function not implemented yet
571 * \param *BondPartner atom to be removed
572 * \return true - bounds found and removed, false - bonds not found/removed
573 */
574bool molecule::RemoveBonds(atom *BondPartner)
575{
576 cerr << Verbose(1) << "molecule::RemoveBond: Function not implemented yet." << endl;
577 return false;
578};
579
580/** Set molecule::name from the basename without suffix in the given \a *filename.
581 * \param *filename filename
582 */
583void molecule::SetNameFromFilename(const char *filename)
584{
585 int length = 0;
586 const char *molname = strrchr(filename, '/');
587 if (molname != NULL)
588 molname += sizeof(char); // search for filename without dirs
589 else
590 molname = filename; // contains no slashes
591 char *endname = strchr(molname, '.');
592 if ((endname == NULL) || (endname < molname))
593 length = strlen(molname);
594 else
595 length = strlen(molname) - strlen(endname);
596 strncpy(name, molname, length);
597 name[length]='\0';
598};
599
600/** Sets the molecule::cell_size to the components of \a *dim (rectangular box)
601 * \param *dim vector class
602 */
603void molecule::SetBoxDimension(Vector *dim)
604{
605 cell_size[0] = dim->x[0];
606 cell_size[1] = 0.;
607 cell_size[2] = dim->x[1];
608 cell_size[3] = 0.;
609 cell_size[4] = 0.;
610 cell_size[5] = dim->x[2];
611};
612
613/** Removes atom from molecule list and deletes it.
614 * \param *pointer atom to be removed
615 * \return true - succeeded, false - atom not found in list
616 */
617bool molecule::RemoveAtom(atom *pointer)
618{
619 if (ElementsInMolecule[pointer->type->Z] != 0) { // this would indicate an error
620 ElementsInMolecule[pointer->type->Z]--; // decrease number of atom of this element
621 AtomCount--;
622 } else
623 cerr << "ERROR: Atom " << pointer->Name << " is of element " << pointer->type->Z << " but the entry in the table of the molecule is 0!" << endl;
624 if (ElementsInMolecule[pointer->type->Z] == 0) // was last atom of this element?
625 ElementCount--;
626 return remove(pointer, start, end);
627};
628
629/** Removes atom from molecule list, but does not delete it.
630 * \param *pointer atom to be removed
631 * \return true - succeeded, false - atom not found in list
632 */
633bool molecule::UnlinkAtom(atom *pointer)
634{
635 if (pointer == NULL)
636 return false;
637 if (ElementsInMolecule[pointer->type->Z] != 0) // this would indicate an error
638 ElementsInMolecule[pointer->type->Z]--; // decrease number of atom of this element
639 else
640 cerr << "ERROR: Atom " << pointer->Name << " is of element " << pointer->type->Z << " but the entry in the table of the molecule is 0!" << endl;
641 if (ElementsInMolecule[pointer->type->Z] == 0) // was last atom of this element?
642 ElementCount--;
643 unlink(pointer);
644 return true;
645};
646
647/** Removes every atom from molecule list.
648 * \return true - succeeded, false - atom not found in list
649 */
650bool molecule::CleanupMolecule()
651{
652 return (cleanup(start,end) && cleanup(first,last));
653};
654
655/** Finds an atom specified by its continuous number.
656 * \param Nr number of atom withim molecule
657 * \return pointer to atom or NULL
658 */
659atom * molecule::FindAtom(int Nr) const{
660 atom * walker = find(&Nr, start,end);
661 if (walker != NULL) {
662 //cout << Verbose(0) << "Found Atom Nr. " << walker->nr << endl;
663 return walker;
664 } else {
665 cout << Verbose(0) << "Atom not found in list." << endl;
666 return NULL;
667 }
668};
669
670/** Asks for atom number, and checks whether in list.
671 * \param *text question before entering
672 */
673atom * molecule::AskAtom(string text)
674{
675 int No;
676 atom *ion = NULL;
677 do {
678 //cout << Verbose(0) << "============Atom list==========================" << endl;
679 //mol->Output((ofstream *)&cout);
680 //cout << Verbose(0) << "===============================================" << endl;
681 cout << Verbose(0) << text;
682 cin >> No;
683 ion = this->FindAtom(No);
684 } while (ion == NULL);
685 return ion;
686};
687
688/** Checks if given coordinates are within cell volume.
689 * \param *x array of coordinates
690 * \return true - is within, false - out of cell
691 */
692bool molecule::CheckBounds(const Vector *x) const
693{
694 bool result = true;
695 int j =-1;
696 for (int i=0;i<NDIM;i++) {
697 j += i+1;
698 result = result && ((x->x[i] >= 0) && (x->x[i] < cell_size[j]));
699 }
700 //return result;
701 return true; /// probably not gonna use the check no more
702};
703
704/** Prints molecule to *out.
705 * \param *out output stream
706 */
707bool molecule::Output(ofstream *out)
708{
709 int ElementNo[MAX_ELEMENTS], AtomNo[MAX_ELEMENTS];
710 CountElements();
711
712 for (int i=0;i<MAX_ELEMENTS;++i) {
713 AtomNo[i] = 0;
714 ElementNo[i] = 0;
715 }
716 if (out == NULL) {
717 return false;
718 } else {
719 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
720 SetIndexedArrayForEachAtomTo ( ElementNo, &element::Z, &AbsoluteValue, 1);
721 int current=1;
722 for (int i=0;i<MAX_ELEMENTS;++i) {
723 if (ElementNo[i] == 1)
724 ElementNo[i] = current++;
725 }
726 ActOnAllAtoms( &atom::Output, out, ElementNo, AtomNo, (const char *) NULL ); // (bool (atom::*)(int *, int *, ofstream *, const char *))
727 return true;
728 }
729};
730
731/** Prints molecule with all atomic trajectory positions to *out.
732 * \param *out output stream
733 */
734bool molecule::OutputTrajectories(ofstream *out)
735{
736 atom *walker = NULL;
737 int ElementNo[MAX_ELEMENTS], AtomNo[MAX_ELEMENTS];
738 CountElements();
739
740 if (out == NULL) {
741 return false;
742 } else {
743 for (int step = 0; step < MDSteps; step++) {
744 if (step == 0) {
745 *out << "#Ion_TypeNr._Nr.R[0] R[1] R[2] MoveType (0 MoveIon, 1 FixedIon)" << endl;
746 } else {
747 *out << "# ====== MD step " << step << " =========" << endl;
748 }
749 for (int i=0;i<MAX_ELEMENTS;++i) {
750 AtomNo[i] = 0;
751 ElementNo[i] = 0;
752 }
753 SetIndexedArrayForEachAtomTo ( ElementNo, &element::Z, &AbsoluteValue, 1);
754 int current=1;
755 for (int i=0;i<MAX_ELEMENTS;++i) {
756 if (ElementNo[i] == 1)
757 ElementNo[i] = current++;
758 }
759 ActOnAllAtoms( &atom::OutputTrajectory, out, ElementNo, AtomNo, step ); // (bool (atom::*)(int *, int *, ofstream *, const char *))
760 }
761 return true;
762 }
763};
764
765/** Outputs contents of molecule::ListOfBondsPerAtom.
766 * \param *out output stream
767 */
768void molecule::OutputListOfBonds(ofstream *out) const
769{
770 *out << Verbose(2) << endl << "From Contents of ListOfBondsPerAtom, all non-hydrogen atoms:" << endl;
771 atom *Walker = start;
772 while (Walker->next != end) {
773 Walker = Walker->next;
774#ifdef ADDHYDROGEN
775 if (Walker->type->Z != 1) { // regard only non-hydrogen
776#endif
777 *out << Verbose(2) << "Atom " << Walker->Name << " has Bonds: "<<endl;
778 for(int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
779 *out << Verbose(3) << *(ListOfBondsPerAtom)[Walker->nr][j] << endl;
780 }
781#ifdef ADDHYDROGEN
782 }
783#endif
784 }
785 *out << endl;
786};
787
788/** Output of element before the actual coordination list.
789 * \param *out stream pointer
790 */
791bool molecule::Checkout(ofstream *out) const
792{
793 return elemente->Checkout(out, ElementsInMolecule);
794};
795
796/** Prints molecule with all its trajectories to *out as xyz file.
797 * \param *out output stream
798 */
799bool molecule::OutputTrajectoriesXYZ(ofstream *out)
800{
801 atom *walker = NULL;
802 int No = 0;
803 time_t now;
804
805 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
806 walker = start;
807 while (walker->next != end) { // go through every atom and count
808 walker = walker->next;
809 No++;
810 }
811 if (out != NULL) {
812 for (int step=0;step<MDSteps;step++) {
813 *out << No << "\n\tCreated by molecuilder, step " << step << ", on " << ctime(&now);
814 walker = start;
815 while (walker->next != end) { // go through every atom of this element
816 walker = walker->next;
817 *out << walker->type->symbol << "\t" << walker->Trajectory.R.at(step).x[0] << "\t" << walker->Trajectory.R.at(step).x[1] << "\t" << walker->Trajectory.R.at(step).x[2] << endl;
818 }
819 }
820 return true;
821 } else
822 return false;
823};
824
825/** Prints molecule to *out as xyz file.
826* \param *out output stream
827 */
828bool molecule::OutputXYZ(ofstream *out) const
829{
830 atom *walker = NULL;
831 int AtomNo = 0;
832 time_t now;
833
834 now = time((time_t *)NULL); // Get the system time and put it into 'now' as 'calender time'
835 walker = start;
836 while (walker->next != end) { // go through every atom and count
837 walker = walker->next;
838 AtomNo++;
839 }
840 if (out != NULL) {
841 *out << AtomNo << "\n\tCreated by molecuilder on " << ctime(&now);
842 ActOnAllAtoms( &atom::OutputXYZLine, out );
843 return true;
844 } else
845 return false;
846};
847
848/** Brings molecule::AtomCount and atom::*Name up-to-date.
849 * \param *out output stream for debugging
850 */
851void molecule::CountAtoms(ofstream *out)
852{
853 int i = 0;
854 atom *Walker = start;
855 while (Walker->next != end) {
856 Walker = Walker->next;
857 i++;
858 }
859 if ((AtomCount == 0) || (i != AtomCount)) {
860 *out << Verbose(3) << "Mismatch in AtomCount " << AtomCount << " and recounted number " << i << ", renaming all." << endl;
861 AtomCount = i;
862
863 // count NonHydrogen atoms and give each atom a unique name
864 if (AtomCount != 0) {
865 i=0;
866 NoNonHydrogen = 0;
867 Walker = start;
868 while (Walker->next != end) {
869 Walker = Walker->next;
870 Walker->nr = i; // update number in molecule (for easier referencing in FragmentMolecule lateron)
871 if (Walker->type->Z != 1) // count non-hydrogen atoms whilst at it
872 NoNonHydrogen++;
873 Free(&Walker->Name);
874 Walker->Name = Malloc<char>(6, "molecule::CountAtoms: *walker->Name");
875 sprintf(Walker->Name, "%2s%02d", Walker->type->symbol, Walker->nr+1);
876 *out << "Naming atom nr. " << Walker->nr << " " << Walker->Name << "." << endl;
877 i++;
878 }
879 } else
880 *out << Verbose(3) << "AtomCount is still " << AtomCount << ", thus counting nothing." << endl;
881 }
882};
883
884/** Brings molecule::ElementCount and molecule::ElementsInMolecule up-to-date.
885 */
886void molecule::CountElements()
887{
888 int i = 0;
889 for(i=MAX_ELEMENTS;i--;)
890 ElementsInMolecule[i] = 0;
891 ElementCount = 0;
892
893 atom *walker = start;
894 while (walker->next != end) {
895 walker = walker->next;
896 ElementsInMolecule[walker->type->Z]++;
897 i++;
898 }
899 for(i=MAX_ELEMENTS;i--;)
900 ElementCount += (ElementsInMolecule[i] != 0 ? 1 : 0);
901};
902
903
904
905/** Counts necessary number of valence electrons and returns number and SpinType.
906 * \param configuration containing everything
907 */
908void molecule::CalculateOrbitals(class config &configuration)
909{
910 configuration.MaxPsiDouble = configuration.PsiMaxNoDown = configuration.PsiMaxNoUp = configuration.PsiType = 0;
911 for(int i=MAX_ELEMENTS;i--;) {
912 if (ElementsInMolecule[i] != 0) {
913 //cout << "CalculateOrbitals: " << elemente->FindElement(i)->name << " has a valence of " << (int)elemente->FindElement(i)->Valence << " and there are " << ElementsInMolecule[i] << " of it." << endl;
914 configuration.MaxPsiDouble += ElementsInMolecule[i]*((int)elemente->FindElement(i)->Valence);
915 }
916 }
917 configuration.PsiMaxNoDown = configuration.MaxPsiDouble/2 + (configuration.MaxPsiDouble % 2);
918 configuration.PsiMaxNoUp = configuration.MaxPsiDouble/2;
919 configuration.MaxPsiDouble /= 2;
920 configuration.PsiType = (configuration.PsiMaxNoDown == configuration.PsiMaxNoUp) ? 0 : 1;
921 if ((configuration.PsiType == 1) && (configuration.ProcPEPsi < 2)) {
922 configuration.ProcPEGamma /= 2;
923 configuration.ProcPEPsi *= 2;
924 } else {
925 configuration.ProcPEGamma *= configuration.ProcPEPsi;
926 configuration.ProcPEPsi = 1;
927 }
928 configuration.InitMaxMinStopStep = configuration.MaxMinStopStep = configuration.MaxPsiDouble;
929};
930
931
932/** Creates an 2d array of pointer with an entry for each atom and each bond it has.
933 * Updates molecule::ListOfBondsPerAtom, molecule::NumberOfBondsPerAtom by parsing through
934 * bond chain list, using molecule::AtomCount and molecule::BondCount.
935 * Allocates memory, fills the array and exits
936 * \param *out output stream for debugging
937 */
938void molecule::CreateListOfBondsPerAtom(ofstream *out)
939{
940 bond *Binder = NULL;
941 atom *Walker = NULL;
942 int TotalDegree;
943 *out << Verbose(1) << "Begin of Creating ListOfBondsPerAtom: AtomCount = " << AtomCount << "\tBondCount = " << BondCount << "\tNoNonBonds = " << NoNonBonds << "." << endl;
944
945 // re-allocate memory
946 *out << Verbose(2) << "(Re-)Allocating memory." << endl;
947 if (ListOfBondsPerAtom != NULL) {
948 for(int i=AtomCount;i--;)
949 Free(&ListOfBondsPerAtom[i]);
950 Free(&ListOfBondsPerAtom);
951 }
952 if (NumberOfBondsPerAtom != NULL)
953 Free(&NumberOfBondsPerAtom);
954 ListOfBondsPerAtom = Malloc<bond**>(AtomCount, "molecule::CreateListOfBondsPerAtom: ***ListOfBondsPerAtom");
955 NumberOfBondsPerAtom = Malloc<int>(AtomCount, "molecule::CreateListOfBondsPerAtom: *NumberOfBondsPerAtom");
956
957 // reset bond counts per atom
958 for(int i=AtomCount;i--;)
959 NumberOfBondsPerAtom[i] = 0;
960 // count bonds per atom
961 Binder = first;
962 while (Binder->next != last) {
963 Binder = Binder->next;
964 NumberOfBondsPerAtom[Binder->leftatom->nr]++;
965 NumberOfBondsPerAtom[Binder->rightatom->nr]++;
966 }
967 for(int i=AtomCount;i--;) {
968 // allocate list of bonds per atom
969 ListOfBondsPerAtom[i] = Malloc<bond*>(NumberOfBondsPerAtom[i], "molecule::CreateListOfBondsPerAtom: **ListOfBondsPerAtom[]");
970 // clear the list again, now each NumberOfBondsPerAtom marks current free field
971 NumberOfBondsPerAtom[i] = 0;
972 }
973 // fill the list
974 Binder = first;
975 while (Binder->next != last) {
976 Binder = Binder->next;
977 ListOfBondsPerAtom[Binder->leftatom->nr][NumberOfBondsPerAtom[Binder->leftatom->nr]++] = Binder;
978 ListOfBondsPerAtom[Binder->rightatom->nr][NumberOfBondsPerAtom[Binder->rightatom->nr]++] = Binder;
979 }
980
981 // output list for debugging
982 *out << Verbose(3) << "ListOfBondsPerAtom for each atom:" << endl;
983 Walker = start;
984 while (Walker->next != end) {
985 Walker = Walker->next;
986 *out << Verbose(4) << "Atom " << Walker->Name << "/" << Walker->nr << " with " << NumberOfBondsPerAtom[Walker->nr] << " bonds: ";
987 TotalDegree = 0;
988 for (int j=0;j<NumberOfBondsPerAtom[Walker->nr];j++) {
989 *out << *ListOfBondsPerAtom[Walker->nr][j] << "\t";
990 TotalDegree += ListOfBondsPerAtom[Walker->nr][j]->BondDegree;
991 }
992 *out << " -- TotalDegree: " << TotalDegree << endl;
993 }
994 *out << Verbose(1) << "End of Creating ListOfBondsPerAtom." << endl << endl;
995};
996
997
998/** Blows the 6-dimensional \a cell_size array up to a full NDIM by NDIM matrix.
999 * \param *symm 6-dim array of unique symmetric matrix components
1000 * \return allocated NDIM*NDIM array with the symmetric matrix
1001 */
1002double * molecule::ReturnFullMatrixforSymmetric(double *symm)
1003{
1004 double *matrix = Malloc<double>(NDIM * NDIM, "molecule::ReturnFullMatrixforSymmetric: *matrix");
1005 matrix[0] = symm[0];
1006 matrix[1] = symm[1];
1007 matrix[2] = symm[3];
1008 matrix[3] = symm[1];
1009 matrix[4] = symm[2];
1010 matrix[5] = symm[4];
1011 matrix[6] = symm[3];
1012 matrix[7] = symm[4];
1013 matrix[8] = symm[5];
1014 return matrix;
1015};
1016
1017
1018/** Comparison function for GSL heapsort on distances in two molecules.
1019 * \param *a
1020 * \param *b
1021 * \return <0, \a *a less than \a *b, ==0 if equal, >0 \a *a greater than \a *b
1022 */
1023inline int CompareDoubles (const void * a, const void * b)
1024{
1025 if (*(double *)a > *(double *)b)
1026 return -1;
1027 else if (*(double *)a < *(double *)b)
1028 return 1;
1029 else
1030 return 0;
1031};
1032
1033/** Determines whether two molecules actually contain the same atoms and coordination.
1034 * \param *out output stream for debugging
1035 * \param *OtherMolecule the molecule to compare this one to
1036 * \param threshold upper limit of difference when comparing the coordination.
1037 * \return NULL - not equal, otherwise an allocated (molecule::AtomCount) permutation map of the atom numbers (which corresponds to which)
1038 */
1039int * molecule::IsEqualToWithinThreshold(ofstream *out, molecule *OtherMolecule, double threshold)
1040{
1041 int flag;
1042 double *Distances = NULL, *OtherDistances = NULL;
1043 Vector CenterOfGravity, OtherCenterOfGravity;
1044 size_t *PermMap = NULL, *OtherPermMap = NULL;
1045 int *PermutationMap = NULL;
1046 atom *Walker = NULL;
1047 bool result = true; // status of comparison
1048
1049 *out << Verbose(3) << "Begin of IsEqualToWithinThreshold." << endl;
1050 /// first count both their atoms and elements and update lists thereby ...
1051 //*out << Verbose(0) << "Counting atoms, updating list" << endl;
1052 CountAtoms(out);
1053 OtherMolecule->CountAtoms(out);
1054 CountElements();
1055 OtherMolecule->CountElements();
1056
1057 /// ... and compare:
1058 /// -# AtomCount
1059 if (result) {
1060 if (AtomCount != OtherMolecule->AtomCount) {
1061 *out << Verbose(4) << "AtomCounts don't match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
1062 result = false;
1063 } else *out << Verbose(4) << "AtomCounts match: " << AtomCount << " == " << OtherMolecule->AtomCount << endl;
1064 }
1065 /// -# ElementCount
1066 if (result) {
1067 if (ElementCount != OtherMolecule->ElementCount) {
1068 *out << Verbose(4) << "ElementCount don't match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
1069 result = false;
1070 } else *out << Verbose(4) << "ElementCount match: " << ElementCount << " == " << OtherMolecule->ElementCount << endl;
1071 }
1072 /// -# ElementsInMolecule
1073 if (result) {
1074 for (flag=MAX_ELEMENTS;flag--;) {
1075 //*out << Verbose(5) << "Element " << flag << ": " << ElementsInMolecule[flag] << " <-> " << OtherMolecule->ElementsInMolecule[flag] << "." << endl;
1076 if (ElementsInMolecule[flag] != OtherMolecule->ElementsInMolecule[flag])
1077 break;
1078 }
1079 if (flag < MAX_ELEMENTS) {
1080 *out << Verbose(4) << "ElementsInMolecule don't match." << endl;
1081 result = false;
1082 } else *out << Verbose(4) << "ElementsInMolecule match." << endl;
1083 }
1084 /// then determine and compare center of gravity for each molecule ...
1085 if (result) {
1086 *out << Verbose(5) << "Calculating Centers of Gravity" << endl;
1087 DeterminePeriodicCenter(CenterOfGravity);
1088 OtherMolecule->DeterminePeriodicCenter(OtherCenterOfGravity);
1089 *out << Verbose(5) << "Center of Gravity: ";
1090 CenterOfGravity.Output(out);
1091 *out << endl << Verbose(5) << "Other Center of Gravity: ";
1092 OtherCenterOfGravity.Output(out);
1093 *out << endl;
1094 if (CenterOfGravity.DistanceSquared(&OtherCenterOfGravity) > threshold*threshold) {
1095 *out << Verbose(4) << "Centers of gravity don't match." << endl;
1096 result = false;
1097 }
1098 }
1099
1100 /// ... then make a list with the euclidian distance to this center for each atom of both molecules
1101 if (result) {
1102 *out << Verbose(5) << "Calculating distances" << endl;
1103 Distances = Malloc<double>(AtomCount, "molecule::IsEqualToWithinThreshold: Distances");
1104 OtherDistances = Malloc<double>(AtomCount, "molecule::IsEqualToWithinThreshold: OtherDistances");
1105 Walker = start;
1106 while (Walker->next != end) {
1107 Walker = Walker->next;
1108 Distances[Walker->nr] = CenterOfGravity.DistanceSquared(&Walker->x);
1109 }
1110 Walker = OtherMolecule->start;
1111 while (Walker->next != OtherMolecule->end) {
1112 Walker = Walker->next;
1113 OtherDistances[Walker->nr] = OtherCenterOfGravity.DistanceSquared(&Walker->x);
1114 }
1115
1116 /// ... sort each list (using heapsort (o(N log N)) from GSL)
1117 *out << Verbose(5) << "Sorting distances" << endl;
1118 PermMap = Malloc<size_t>(AtomCount, "molecule::IsEqualToWithinThreshold: *PermMap");
1119 OtherPermMap = Malloc<size_t>(AtomCount, "molecule::IsEqualToWithinThreshold: *OtherPermMap");
1120 gsl_heapsort_index (PermMap, Distances, AtomCount, sizeof(double), CompareDoubles);
1121 gsl_heapsort_index (OtherPermMap, OtherDistances, AtomCount, sizeof(double), CompareDoubles);
1122 PermutationMap = Malloc<int>(AtomCount, "molecule::IsEqualToWithinThreshold: *PermutationMap");
1123 *out << Verbose(5) << "Combining Permutation Maps" << endl;
1124 for(int i=AtomCount;i--;)
1125 PermutationMap[PermMap[i]] = (int) OtherPermMap[i];
1126
1127 /// ... and compare them step by step, whether the difference is individually(!) below \a threshold for all
1128 *out << Verbose(4) << "Comparing distances" << endl;
1129 flag = 0;
1130 for (int i=0;i<AtomCount;i++) {
1131 *out << Verbose(5) << "Distances squared: |" << Distances[PermMap[i]] << " - " << OtherDistances[OtherPermMap[i]] << "| = " << fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) << " ?<? " << threshold << endl;
1132 if (fabs(Distances[PermMap[i]] - OtherDistances[OtherPermMap[i]]) > threshold*threshold)
1133 flag = 1;
1134 }
1135
1136 // free memory
1137 Free(&PermMap);
1138 Free(&OtherPermMap);
1139 Free(&Distances);
1140 Free(&OtherDistances);
1141 if (flag) { // if not equal
1142 Free(&PermutationMap);
1143 result = false;
1144 }
1145 }
1146 /// return pointer to map if all distances were below \a threshold
1147 *out << Verbose(3) << "End of IsEqualToWithinThreshold." << endl;
1148 if (result) {
1149 *out << Verbose(3) << "Result: Equal." << endl;
1150 return PermutationMap;
1151 } else {
1152 *out << Verbose(3) << "Result: Not equal." << endl;
1153 return NULL;
1154 }
1155};
1156
1157/** Returns an index map for two father-son-molecules.
1158 * The map tells which atom in this molecule corresponds to which one in the other molecul with their fathers.
1159 * \param *out output stream for debugging
1160 * \param *OtherMolecule corresponding molecule with fathers
1161 * \return allocated map of size molecule::AtomCount with map
1162 * \todo make this with a good sort O(n), not O(n^2)
1163 */
1164int * molecule::GetFatherSonAtomicMap(ofstream *out, molecule *OtherMolecule)
1165{
1166 atom *Walker = NULL, *OtherWalker = NULL;
1167 *out << Verbose(3) << "Begin of GetFatherAtomicMap." << endl;
1168 int *AtomicMap = Malloc<int>(AtomCount, "molecule::GetAtomicMap: *AtomicMap");
1169 for (int i=AtomCount;i--;)
1170 AtomicMap[i] = -1;
1171 if (OtherMolecule == this) { // same molecule
1172 for (int i=AtomCount;i--;) // no need as -1 means already that there is trivial correspondence
1173 AtomicMap[i] = i;
1174 *out << Verbose(4) << "Map is trivial." << endl;
1175 } else {
1176 *out << Verbose(4) << "Map is ";
1177 Walker = start;
1178 while (Walker->next != end) {
1179 Walker = Walker->next;
1180 if (Walker->father == NULL) {
1181 AtomicMap[Walker->nr] = -2;
1182 } else {
1183 OtherWalker = OtherMolecule->start;
1184 while (OtherWalker->next != OtherMolecule->end) {
1185 OtherWalker = OtherWalker->next;
1186 //for (int i=0;i<AtomCount;i++) { // search atom
1187 //for (int j=0;j<OtherMolecule->AtomCount;j++) {
1188 //*out << Verbose(4) << "Comparing father " << Walker->father << " with the other one " << OtherWalker->father << "." << endl;
1189 if (Walker->father == OtherWalker)
1190 AtomicMap[Walker->nr] = OtherWalker->nr;
1191 }
1192 }
1193 *out << AtomicMap[Walker->nr] << "\t";
1194 }
1195 *out << endl;
1196 }
1197 *out << Verbose(3) << "End of GetFatherAtomicMap." << endl;
1198 return AtomicMap;
1199};
1200
1201/** Stores the temperature evaluated from velocities in molecule::Trajectories.
1202 * We simply use the formula equivaleting temperature and kinetic energy:
1203 * \f$k_B T = \sum_i m_i v_i^2\f$
1204 * \param *out output stream for debugging
1205 * \param startstep first MD step in molecule::Trajectories
1206 * \param endstep last plus one MD step in molecule::Trajectories
1207 * \param *output output stream of temperature file
1208 * \return file written (true), failure on writing file (false)
1209 */
1210bool molecule::OutputTemperatureFromTrajectories(ofstream *out, int startstep, int endstep, ofstream *output)
1211{
1212 double temperature;
1213 atom *Walker = NULL;
1214 // test stream
1215 if (output == NULL)
1216 return false;
1217 else
1218 *output << "# Step Temperature [K] Temperature [a.u.]" << endl;
1219 for (int step=startstep;step < endstep; step++) { // loop over all time steps
1220 temperature = 0.;
1221 Walker = start;
1222 while (Walker->next != end) {
1223 Walker = Walker->next;
1224 for (int i=NDIM;i--;)
1225 temperature += Walker->type->mass * Walker->Trajectory.U.at(step).x[i]* Walker->Trajectory.U.at(step).x[i];
1226 }
1227 *output << step << "\t" << temperature*AtomicEnergyToKelvin << "\t" << temperature << endl;
1228 }
1229 return true;
1230};
Note: See TracBrowser for help on using the repository browser.