source: src/molecule.cpp@ b8c9d8

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

Huge change: Log() << Verbose(.) --> DoLog(.) && (Log() << Verbose(.) << ...);

Most of the files are affected, but this is necessary as if DoLog() says verbosity is not enough, all the stream operators won"t get executed which saves substantial amount of computation time.

Signed-off-by: Frederik Heber <heber@…>

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