source: src/vector.cpp@ caf4ba

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

We are one step further in fixing the convex hull: There are two functions of Saskia Metzler missing, but then we may proceed with testing whether the simple correction scheme of the convex envelope works, but one thing: Right now we cannot associate a Tesselation to its molecule as the snake bites it's one tail. Hence, the next commit will consist of fixing this bad-OOP issue.

  • Makefile.am: Just some alphabetical resorting.
  • atom::atom() new copy constructor
  • builder.cpp: some output for cluster volume, molecule::AddCopyAtom() uses new copy constructor
  • FillBoxWithMolecule() - new function to fill the remainder of the simulation box with some given filler molecules. Makes explicit use of the tesselated surfaces
  • find_convex_border() - InsertStraddlingPoints() and CorrectConcaveBaselines() is called to correct for atoms outside the envelope and caused-by concave points
  • Tesselation::InsertStraddlingPoints() enlarges the envelope for all atoms found outside, Tesselation::CorrectConcaveBaselines() corrects all found baselines if the adjacent triangles are concave by flipping.
  • boundary.cpp: Lots of helper routines for stuff further below:
  • The following routines are needed to check whether point is in- or outside:
  • FIX: Tesselation::AddPoint() - newly created BoundaryPoint is removed if already present.

Problem: We want to associate a Tesselation class with each molecule class. However, so far we have to know about atoms and bond and molecules inside the Tesselation. We have to remove this dependency and create some intermediate class which enables/encapsulates the access to Vectors, e.g. hidden inside the atom class. This is also good OOP! The Tesselation also only needs a set of Vectors, not more!

  • Property mode set to 100755
File size: 31.6 KB
Line 
1/** \file vector.cpp
2 *
3 * Function implementations for the class vector.
4 *
5 */
6
7#include "molecules.hpp"
8
9
10/************************************ Functions for class vector ************************************/
11
12/** Constructor of class vector.
13 */
14Vector::Vector() { x[0] = x[1] = x[2] = 0.; };
15
16/** Constructor of class vector.
17 */
18Vector::Vector(double x1, double x2, double x3) { x[0] = x1; x[1] = x2; x[2] = x3; };
19
20/** Desctructor of class vector.
21 */
22Vector::~Vector() {};
23
24/** Calculates square of distance between this and another vector.
25 * \param *y array to second vector
26 * \return \f$| x - y |^2\f$
27 */
28double Vector::DistanceSquared(const Vector *y) const
29{
30 double res = 0.;
31 for (int i=NDIM;i--;)
32 res += (x[i]-y->x[i])*(x[i]-y->x[i]);
33 return (res);
34};
35
36/** Calculates distance between this and another vector.
37 * \param *y array to second vector
38 * \return \f$| x - y |\f$
39 */
40double Vector::Distance(const Vector *y) const
41{
42 double res = 0.;
43 for (int i=NDIM;i--;)
44 res += (x[i]-y->x[i])*(x[i]-y->x[i]);
45 return (sqrt(res));
46};
47
48/** Calculates distance between this and another vector in a periodic cell.
49 * \param *y array to second vector
50 * \param *cell_size 6-dimensional array with (xx, xy, yy, xz, yz, zz) entries specifying the periodic cell
51 * \return \f$| x - y |\f$
52 */
53double Vector::PeriodicDistance(const Vector *y, const double *cell_size) const
54{
55 double res = Distance(y), tmp, matrix[NDIM*NDIM];
56 Vector Shiftedy, TranslationVector;
57 int N[NDIM];
58 matrix[0] = cell_size[0];
59 matrix[1] = cell_size[1];
60 matrix[2] = cell_size[3];
61 matrix[3] = cell_size[1];
62 matrix[4] = cell_size[2];
63 matrix[5] = cell_size[4];
64 matrix[6] = cell_size[3];
65 matrix[7] = cell_size[4];
66 matrix[8] = cell_size[5];
67 // in order to check the periodic distance, translate one of the vectors into each of the 27 neighbouring cells
68 for (N[0]=-1;N[0]<=1;N[0]++)
69 for (N[1]=-1;N[1]<=1;N[1]++)
70 for (N[2]=-1;N[2]<=1;N[2]++) {
71 // create the translation vector
72 TranslationVector.Zero();
73 for (int i=NDIM;i--;)
74 TranslationVector.x[i] = (double)N[i];
75 TranslationVector.MatrixMultiplication(matrix);
76 // add onto the original vector to compare with
77 Shiftedy.CopyVector(y);
78 Shiftedy.AddVector(&TranslationVector);
79 // get distance and compare with minimum so far
80 tmp = Distance(&Shiftedy);
81 if (tmp < res) res = tmp;
82 }
83 return (res);
84};
85
86/** Calculates distance between this and another vector in a periodic cell.
87 * \param *y array to second vector
88 * \param *cell_size 6-dimensional array with (xx, xy, yy, xz, yz, zz) entries specifying the periodic cell
89 * \return \f$| x - y |^2\f$
90 */
91double Vector::PeriodicDistanceSquared(const Vector *y, const double *cell_size) const
92{
93 double res = DistanceSquared(y), tmp, matrix[NDIM*NDIM];
94 Vector Shiftedy, TranslationVector;
95 int N[NDIM];
96 matrix[0] = cell_size[0];
97 matrix[1] = cell_size[1];
98 matrix[2] = cell_size[3];
99 matrix[3] = cell_size[1];
100 matrix[4] = cell_size[2];
101 matrix[5] = cell_size[4];
102 matrix[6] = cell_size[3];
103 matrix[7] = cell_size[4];
104 matrix[8] = cell_size[5];
105 // in order to check the periodic distance, translate one of the vectors into each of the 27 neighbouring cells
106 for (N[0]=-1;N[0]<=1;N[0]++)
107 for (N[1]=-1;N[1]<=1;N[1]++)
108 for (N[2]=-1;N[2]<=1;N[2]++) {
109 // create the translation vector
110 TranslationVector.Zero();
111 for (int i=NDIM;i--;)
112 TranslationVector.x[i] = (double)N[i];
113 TranslationVector.MatrixMultiplication(matrix);
114 // add onto the original vector to compare with
115 Shiftedy.CopyVector(y);
116 Shiftedy.AddVector(&TranslationVector);
117 // get distance and compare with minimum so far
118 tmp = DistanceSquared(&Shiftedy);
119 if (tmp < res) res = tmp;
120 }
121 return (res);
122};
123
124/** Keeps the vector in a periodic cell, defined by the symmetric \a *matrix.
125 * \param *out ofstream for debugging messages
126 * Tries to translate a vector into each adjacent neighbouring cell.
127 */
128void Vector::KeepPeriodic(ofstream *out, double *matrix)
129{
130// int N[NDIM];
131// bool flag = false;
132 //vector Shifted, TranslationVector;
133 Vector TestVector;
134// *out << Verbose(1) << "Begin of KeepPeriodic." << endl;
135// *out << Verbose(2) << "Vector is: ";
136// Output(out);
137// *out << endl;
138 TestVector.CopyVector(this);
139 TestVector.InverseMatrixMultiplication(matrix);
140 for(int i=NDIM;i--;) { // correct periodically
141 if (TestVector.x[i] < 0) { // get every coefficient into the interval [0,1)
142 TestVector.x[i] += ceil(TestVector.x[i]);
143 } else {
144 TestVector.x[i] -= floor(TestVector.x[i]);
145 }
146 }
147 TestVector.MatrixMultiplication(matrix);
148 CopyVector(&TestVector);
149// *out << Verbose(2) << "New corrected vector is: ";
150// Output(out);
151// *out << endl;
152// *out << Verbose(1) << "End of KeepPeriodic." << endl;
153};
154
155/** Calculates scalar product between this and another vector.
156 * \param *y array to second vector
157 * \return \f$\langle x, y \rangle\f$
158 */
159double Vector::ScalarProduct(const Vector *y) const
160{
161 double res = 0.;
162 for (int i=NDIM;i--;)
163 res += x[i]*y->x[i];
164 return (res);
165};
166
167
168/** Calculates VectorProduct between this and another vector.
169 * -# returns the Product in place of vector from which it was initiated
170 * -# ATTENTION: Only three dim.
171 * \param *y array to vector with which to calculate crossproduct
172 * \return \f$ x \times y \f&
173 */
174void Vector::VectorProduct(const Vector *y)
175{
176 Vector tmp;
177 tmp.x[0] = x[1]* (y->x[2]) - x[2]* (y->x[1]);
178 tmp.x[1] = x[2]* (y->x[0]) - x[0]* (y->x[2]);
179 tmp.x[2] = x[0]* (y->x[1]) - x[1]* (y->x[0]);
180 this->CopyVector(&tmp);
181
182};
183
184
185/** projects this vector onto plane defined by \a *y.
186 * \param *y normal vector of plane
187 * \return \f$\langle x, y \rangle\f$
188 */
189void Vector::ProjectOntoPlane(const Vector *y)
190{
191 Vector tmp;
192 tmp.CopyVector(y);
193 tmp.Normalize();
194 tmp.Scale(ScalarProduct(&tmp));
195 this->SubtractVector(&tmp);
196};
197
198/** Calculates the intersection point between a line defined by \a *LineVector and \a *LineVector2 and a plane defined by \a *Normal and \a *PlaneOffset.
199 * According to [Bronstein] the vectorial plane equation is:
200 * -# \f$\stackrel{r}{\rightarrow} \cdot \stackrel{N}{\rightarrow} + D = 0\f$,
201 * where \f$\stackrel{r}{\rightarrow}\f$ is the vector to be testet, \f$\stackrel{N}{\rightarrow}\f$ is the plane's normal vector and
202 * \f$D = - \stackrel{a}{\rightarrow} \stackrel{N}{\rightarrow}\f$, the offset with respect to origin, if \f$\stackrel{a}{\rightarrow}\f$,
203 * is an offset vector onto the plane. The line is parametrized by \f$\stackrel{x}{\rightarrow} + k \stackrel{t}{\rightarrow}\f$, where
204 * \f$\stackrel{x}{\rightarrow}\f$ is the offset and \f$\stackrel{t}{\rightarrow}\f$ the directional vector (NOTE: No need to normalize
205 * the latter). Inserting the parametrized form into the plane equation and solving for \f$k\f$, which we insert then into the parametrization
206 * of the line yields the intersection point on the plane.
207 * \param *out output stream for debugging
208 * \param *PlaneNormal Plane's normal vector
209 * \param *PlaneOffset Plane's offset vector
210 * \param *LineVector first vector of line
211 * \param *LineVector2 second vector of line
212 * \return true - \a this contains intersection point on return, false - line is parallel to plane
213 */
214bool Vector::GetIntersectionWithPlane(ofstream *out, Vector *PlaneNormal, Vector *PlaneOffset, Vector *LineVector, Vector *LineVector2)
215{
216 double factor;
217 Vector Direction;
218
219 // find intersection of a line defined by Offset and Direction with a plane defined by triangle
220 Direction.CopyVector(LineVector2);
221 Direction.SubtractVector(LineVector);
222 if (Direction.ScalarProduct(PlaneNormal) < MYEPSILON)
223 return false;
224 factor = LineVector->ScalarProduct(PlaneNormal)*(-PlaneOffset->ScalarProduct(PlaneNormal))/(Direction.ScalarProduct(PlaneNormal));
225 Direction.Scale(factor);
226 CopyVector(LineVector);
227 SubtractVector(&Direction);
228
229 // test whether resulting vector really is on plane
230 Direction.CopyVector(this);
231 Direction.SubtractVector(PlaneOffset);
232 if (Direction.ScalarProduct(PlaneNormal) > MYEPSILON)
233 return true;
234 else
235 return false;
236};
237
238/** Calculates the intersection of the two lines that are both on the same plane.
239 * Note that we do not check whether they are on the same plane.
240 * \param *out output stream for debugging
241 * \param *Line1a first vector of first line
242 * \param *Line1b second vector of first line
243 * \param *Line2a first vector of second line
244 * \param *Line2b second vector of second line
245 * \return true - \a this will contain the intersection on return, false - lines are parallel
246 */
247bool Vector::GetIntersectionOfTwoLinesOnPlane(ofstream *out, Vector *Line1a, Vector *Line1b, Vector *Line2a, Vector *Line2b)
248{
249 double k1,a1,h1,b1,k2,a2,h2,b2;
250 // equation for line 1
251 if (fabs(Line1a->x[0] - Line2a->x[0]) < MYEPSILON) {
252 k1 = 0;
253 h1 = 0;
254 } else {
255 k1 = (Line1a->x[1] - Line2a->x[1])/(Line1a->x[0] - Line2a->x[0]);
256 h1 = (Line1a->x[2] - Line2a->x[2])/(Line1a->x[0] - Line2a->x[0]);
257 }
258 a1 = 0.5*((Line1a->x[1] + Line2a->x[1]) - k1*(Line1a->x[0] + Line2a->x[0]));
259 b1 = 0.5*((Line1a->x[2] + Line2a->x[2]) - h1*(Line1a->x[0] + Line2a->x[0]));
260
261 // equation for line 2
262 if (fabs(Line2a->x[0] - Line2a->x[0]) < MYEPSILON) {
263 k1 = 0;
264 h1 = 0;
265 } else {
266 k1 = (Line2a->x[1] - Line2a->x[1])/(Line2a->x[0] - Line2a->x[0]);
267 h1 = (Line2a->x[2] - Line2a->x[2])/(Line2a->x[0] - Line2a->x[0]);
268 }
269 a1 = 0.5*((Line2a->x[1] + Line2a->x[1]) - k1*(Line2a->x[0] + Line2a->x[0]));
270 b1 = 0.5*((Line2a->x[2] + Line2a->x[2]) - h1*(Line2a->x[0] + Line2a->x[0]));
271
272 // calculate cross point
273 if (fabs((a1-a2)*(h1-h2) - (b1-b2)*(k1-k2)) < MYEPSILON) {
274 x[0] = (a2-a1)/(k1-k2);
275 x[1] = (k1*a2-k2*a1)/(k1-k2);
276 x[2] = (h1*b2-h2*b1)/(h1-h2);
277 *out << Verbose(4) << "Lines do intersect at " << this << "." << endl;
278 return true;
279 } else {
280 *out << Verbose(4) << "Lines do not intersect." << endl;
281 return false;
282 }
283};
284
285/** Calculates the projection of a vector onto another \a *y.
286 * \param *y array to second vector
287 * \return \f$\langle x, y \rangle\f$
288 */
289double Vector::Projection(const Vector *y) const
290{
291 return (ScalarProduct(y));
292};
293
294/** Calculates norm of this vector.
295 * \return \f$|x|\f$
296 */
297double Vector::Norm() const
298{
299 double res = 0.;
300 for (int i=NDIM;i--;)
301 res += this->x[i]*this->x[i];
302 return (sqrt(res));
303};
304
305/** Calculates squared norm of this vector.
306 * \return \f$|x|^2\f$
307 */
308double Vector::NormSquared() const
309{
310 return (ScalarProduct(this));
311};
312
313/** Normalizes this vector.
314 */
315void Vector::Normalize()
316{
317 double res = 0.;
318 for (int i=NDIM;i--;)
319 res += this->x[i]*this->x[i];
320 if (fabs(res) > MYEPSILON)
321 res = 1./sqrt(res);
322 Scale(&res);
323};
324
325/** Zeros all components of this vector.
326 */
327void Vector::Zero()
328{
329 for (int i=NDIM;i--;)
330 this->x[i] = 0.;
331};
332
333/** Zeros all components of this vector.
334 */
335void Vector::One(double one)
336{
337 for (int i=NDIM;i--;)
338 this->x[i] = one;
339};
340
341/** Initialises all components of this vector.
342 */
343void Vector::Init(double x1, double x2, double x3)
344{
345 x[0] = x1;
346 x[1] = x2;
347 x[2] = x3;
348};
349
350/** Calculates the angle between this and another vector.
351 * \param *y array to second vector
352 * \return \f$\acos\bigl(frac{\langle x, y \rangle}{|x||y|}\bigr)\f$
353 */
354double Vector::Angle(const Vector *y) const
355{
356 double norm1 = Norm(), norm2 = y->Norm();
357 double angle = 1;
358 if ((fabs(norm1) > MYEPSILON) && (fabs(norm2) > MYEPSILON))
359 angle = this->ScalarProduct(y)/norm1/norm2;
360 // -1-MYEPSILON occured due to numerical imprecision, catch ...
361 //cout << Verbose(2) << "INFO: acos(-1) = " << acos(-1) << ", acos(-1+MYEPSILON) = " << acos(-1+MYEPSILON) << ", acos(-1-MYEPSILON) = " << acos(-1-MYEPSILON) << "." << endl;
362 if (angle < -1)
363 angle = -1;
364 if (angle > 1)
365 angle = 1;
366 return acos(angle);
367};
368
369/** Rotates the vector around the axis given by \a *axis by an angle of \a alpha.
370 * \param *axis rotation axis
371 * \param alpha rotation angle in radian
372 */
373void Vector::RotateVector(const Vector *axis, const double alpha)
374{
375 Vector a,y;
376 // normalise this vector with respect to axis
377 a.CopyVector(this);
378 a.Scale(Projection(axis));
379 SubtractVector(&a);
380 // construct normal vector
381 y.MakeNormalVector(axis,this);
382 y.Scale(Norm());
383 // scale normal vector by sine and this vector by cosine
384 y.Scale(sin(alpha));
385 Scale(cos(alpha));
386 // add scaled normal vector onto this vector
387 AddVector(&y);
388 // add part in axis direction
389 AddVector(&a);
390};
391
392/** Sums vector \a to this lhs component-wise.
393 * \param a base vector
394 * \param b vector components to add
395 * \return lhs + a
396 */
397Vector& operator+=(Vector& a, const Vector& b)
398{
399 a.AddVector(&b);
400 return a;
401};
402/** factor each component of \a a times a double \a m.
403 * \param a base vector
404 * \param m factor
405 * \return lhs.x[i] * m
406 */
407Vector& operator*=(Vector& a, const double m)
408{
409 a.Scale(m);
410 return a;
411};
412
413/** Sums two vectors \a and \b component-wise.
414 * \param a first vector
415 * \param b second vector
416 * \return a + b
417 */
418Vector& operator+(const Vector& a, const Vector& b)
419{
420 Vector *x = new Vector;
421 x->CopyVector(&a);
422 x->AddVector(&b);
423 return *x;
424};
425
426/** Factors given vector \a a times \a m.
427 * \param a vector
428 * \param m factor
429 * \return a + b
430 */
431Vector& operator*(const Vector& a, const double m)
432{
433 Vector *x = new Vector;
434 x->CopyVector(&a);
435 x->Scale(m);
436 return *x;
437};
438
439/** Prints a 3dim vector.
440 * prints no end of line.
441 * \param *out output stream
442 */
443bool Vector::Output(ofstream *out) const
444{
445 if (out != NULL) {
446 *out << "(";
447 for (int i=0;i<NDIM;i++) {
448 *out << x[i];
449 if (i != 2)
450 *out << ",";
451 }
452 *out << ")";
453 return true;
454 } else
455 return false;
456};
457
458ostream& operator<<(ostream& ost,Vector& m)
459{
460 ost << "(";
461 for (int i=0;i<NDIM;i++) {
462 ost << m.x[i];
463 if (i != 2)
464 ost << ",";
465 }
466 ost << ")";
467 return ost;
468};
469
470/** Scales each atom coordinate by an individual \a factor.
471 * \param *factor pointer to scaling factor
472 */
473void Vector::Scale(double **factor)
474{
475 for (int i=NDIM;i--;)
476 x[i] *= (*factor)[i];
477};
478
479void Vector::Scale(double *factor)
480{
481 for (int i=NDIM;i--;)
482 x[i] *= *factor;
483};
484
485void Vector::Scale(double factor)
486{
487 for (int i=NDIM;i--;)
488 x[i] *= factor;
489};
490
491/** Translate atom by given vector.
492 * \param trans[] translation vector.
493 */
494void Vector::Translate(const Vector *trans)
495{
496 for (int i=NDIM;i--;)
497 x[i] += trans->x[i];
498};
499
500/** Do a matrix multiplication.
501 * \param *matrix NDIM_NDIM array
502 */
503void Vector::MatrixMultiplication(double *M)
504{
505 Vector C;
506 // do the matrix multiplication
507 C.x[0] = M[0]*x[0]+M[3]*x[1]+M[6]*x[2];
508 C.x[1] = M[1]*x[0]+M[4]*x[1]+M[7]*x[2];
509 C.x[2] = M[2]*x[0]+M[5]*x[1]+M[8]*x[2];
510 // transfer the result into this
511 for (int i=NDIM;i--;)
512 x[i] = C.x[i];
513};
514
515/** Calculate the inverse of a 3x3 matrix.
516 * \param *matrix NDIM_NDIM array
517 */
518double * Vector::InverseMatrix(double *A)
519{
520 double *B = (double *) Malloc(sizeof(double)*NDIM*NDIM, "Vector::InverseMatrix: *B");
521 double detA = RDET3(A);
522 double detAReci;
523
524 for (int i=0;i<NDIM*NDIM;++i)
525 B[i] = 0.;
526 // calculate the inverse B
527 if (fabs(detA) > MYEPSILON) {; // RDET3(A) yields precisely zero if A irregular
528 detAReci = 1./detA;
529 B[0] = detAReci*RDET2(A[4],A[5],A[7],A[8]); // A_11
530 B[1] = -detAReci*RDET2(A[1],A[2],A[7],A[8]); // A_12
531 B[2] = detAReci*RDET2(A[1],A[2],A[4],A[5]); // A_13
532 B[3] = -detAReci*RDET2(A[3],A[5],A[6],A[8]); // A_21
533 B[4] = detAReci*RDET2(A[0],A[2],A[6],A[8]); // A_22
534 B[5] = -detAReci*RDET2(A[0],A[2],A[3],A[5]); // A_23
535 B[6] = detAReci*RDET2(A[3],A[4],A[6],A[7]); // A_31
536 B[7] = -detAReci*RDET2(A[0],A[1],A[6],A[7]); // A_32
537 B[8] = detAReci*RDET2(A[0],A[1],A[3],A[4]); // A_33
538 }
539 return B;
540};
541
542/** Do a matrix multiplication with the \a *A' inverse.
543 * \param *matrix NDIM_NDIM array
544 */
545void Vector::InverseMatrixMultiplication(double *A)
546{
547 Vector C;
548 double B[NDIM*NDIM];
549 double detA = RDET3(A);
550 double detAReci;
551
552 // calculate the inverse B
553 if (fabs(detA) > MYEPSILON) {; // RDET3(A) yields precisely zero if A irregular
554 detAReci = 1./detA;
555 B[0] = detAReci*RDET2(A[4],A[5],A[7],A[8]); // A_11
556 B[1] = -detAReci*RDET2(A[1],A[2],A[7],A[8]); // A_12
557 B[2] = detAReci*RDET2(A[1],A[2],A[4],A[5]); // A_13
558 B[3] = -detAReci*RDET2(A[3],A[5],A[6],A[8]); // A_21
559 B[4] = detAReci*RDET2(A[0],A[2],A[6],A[8]); // A_22
560 B[5] = -detAReci*RDET2(A[0],A[2],A[3],A[5]); // A_23
561 B[6] = detAReci*RDET2(A[3],A[4],A[6],A[7]); // A_31
562 B[7] = -detAReci*RDET2(A[0],A[1],A[6],A[7]); // A_32
563 B[8] = detAReci*RDET2(A[0],A[1],A[3],A[4]); // A_33
564
565 // do the matrix multiplication
566 C.x[0] = B[0]*x[0]+B[3]*x[1]+B[6]*x[2];
567 C.x[1] = B[1]*x[0]+B[4]*x[1]+B[7]*x[2];
568 C.x[2] = B[2]*x[0]+B[5]*x[1]+B[8]*x[2];
569 // transfer the result into this
570 for (int i=NDIM;i--;)
571 x[i] = C.x[i];
572 } else {
573 cerr << "ERROR: inverse of matrix does not exists: det A = " << detA << "." << endl;
574 }
575};
576
577
578/** Creates this vector as the b y *factors' components scaled linear combination of the given three.
579 * this vector = x1*factors[0] + x2* factors[1] + x3*factors[2]
580 * \param *x1 first vector
581 * \param *x2 second vector
582 * \param *x3 third vector
583 * \param *factors three-component vector with the factor for each given vector
584 */
585void Vector::LinearCombinationOfVectors(const Vector *x1, const Vector *x2, const Vector *x3, double *factors)
586{
587 for(int i=NDIM;i--;)
588 x[i] = factors[0]*x1->x[i] + factors[1]*x2->x[i] + factors[2]*x3->x[i];
589};
590
591/** Mirrors atom against a given plane.
592 * \param n[] normal vector of mirror plane.
593 */
594void Vector::Mirror(const Vector *n)
595{
596 double projection;
597 projection = ScalarProduct(n)/n->ScalarProduct(n); // remove constancy from n (keep as logical one)
598 // withdraw projected vector twice from original one
599 cout << Verbose(1) << "Vector: ";
600 Output((ofstream *)&cout);
601 cout << "\t";
602 for (int i=NDIM;i--;)
603 x[i] -= 2.*projection*n->x[i];
604 cout << "Projected vector: ";
605 Output((ofstream *)&cout);
606 cout << endl;
607};
608
609/** Calculates normal vector for three given vectors (being three points in space).
610 * Makes this vector orthonormal to the three given points, making up a place in 3d space.
611 * \param *y1 first vector
612 * \param *y2 second vector
613 * \param *y3 third vector
614 * \return true - success, vectors are linear independent, false - failure due to linear dependency
615 */
616bool Vector::MakeNormalVector(const Vector *y1, const Vector *y2, const Vector *y3)
617{
618 Vector x1, x2;
619
620 x1.CopyVector(y1);
621 x1.SubtractVector(y2);
622 x2.CopyVector(y3);
623 x2.SubtractVector(y2);
624 if ((fabs(x1.Norm()) < MYEPSILON) || (fabs(x2.Norm()) < MYEPSILON) || (fabs(x1.Angle(&x2)) < MYEPSILON)) {
625 cout << Verbose(4) << "Given vectors are linear dependent." << endl;
626 return false;
627 }
628// cout << Verbose(4) << "relative, first plane coordinates:";
629// x1.Output((ofstream *)&cout);
630// cout << endl;
631// cout << Verbose(4) << "second plane coordinates:";
632// x2.Output((ofstream *)&cout);
633// cout << endl;
634
635 this->x[0] = (x1.x[1]*x2.x[2] - x1.x[2]*x2.x[1]);
636 this->x[1] = (x1.x[2]*x2.x[0] - x1.x[0]*x2.x[2]);
637 this->x[2] = (x1.x[0]*x2.x[1] - x1.x[1]*x2.x[0]);
638 Normalize();
639
640 return true;
641};
642
643
644/** Calculates orthonormal vector to two given vectors.
645 * Makes this vector orthonormal to two given vectors. This is very similar to the other
646 * vector::MakeNormalVector(), only there three points whereas here two difference
647 * vectors are given.
648 * \param *x1 first vector
649 * \param *x2 second vector
650 * \return true - success, vectors are linear independent, false - failure due to linear dependency
651 */
652bool Vector::MakeNormalVector(const Vector *y1, const Vector *y2)
653{
654 Vector x1,x2;
655 x1.CopyVector(y1);
656 x2.CopyVector(y2);
657 Zero();
658 if ((fabs(x1.Norm()) < MYEPSILON) || (fabs(x2.Norm()) < MYEPSILON) || (fabs(x1.Angle(&x2)) < MYEPSILON)) {
659 cout << Verbose(4) << "Given vectors are linear dependent." << endl;
660 return false;
661 }
662// cout << Verbose(4) << "relative, first plane coordinates:";
663// x1.Output((ofstream *)&cout);
664// cout << endl;
665// cout << Verbose(4) << "second plane coordinates:";
666// x2.Output((ofstream *)&cout);
667// cout << endl;
668
669 this->x[0] = (x1.x[1]*x2.x[2] - x1.x[2]*x2.x[1]);
670 this->x[1] = (x1.x[2]*x2.x[0] - x1.x[0]*x2.x[2]);
671 this->x[2] = (x1.x[0]*x2.x[1] - x1.x[1]*x2.x[0]);
672 Normalize();
673
674 return true;
675};
676
677/** Calculates orthonormal vector to one given vectors.
678 * Just subtracts the projection onto the given vector from this vector.
679 * \param *x1 vector
680 * \return true - success, false - vector is zero
681 */
682bool Vector::MakeNormalVector(const Vector *y1)
683{
684 bool result = false;
685 Vector x1;
686 x1.CopyVector(y1);
687 x1.Scale(x1.Projection(this));
688 SubtractVector(&x1);
689 for (int i=NDIM;i--;)
690 result = result || (fabs(x[i]) > MYEPSILON);
691
692 return result;
693};
694
695/** Creates this vector as one of the possible orthonormal ones to the given one.
696 * Just scan how many components of given *vector are unequal to zero and
697 * try to get the skp of both to be zero accordingly.
698 * \param *vector given vector
699 * \return true - success, false - failure (null vector given)
700 */
701bool Vector::GetOneNormalVector(const Vector *GivenVector)
702{
703 int Components[NDIM]; // contains indices of non-zero components
704 int Last = 0; // count the number of non-zero entries in vector
705 int j; // loop variables
706 double norm;
707
708 cout << Verbose(4);
709 GivenVector->Output((ofstream *)&cout);
710 cout << endl;
711 for (j=NDIM;j--;)
712 Components[j] = -1;
713 // find two components != 0
714 for (j=0;j<NDIM;j++)
715 if (fabs(GivenVector->x[j]) > MYEPSILON)
716 Components[Last++] = j;
717 cout << Verbose(4) << Last << " Components != 0: (" << Components[0] << "," << Components[1] << "," << Components[2] << ")" << endl;
718
719 switch(Last) {
720 case 3: // threecomponent system
721 case 2: // two component system
722 norm = sqrt(1./(GivenVector->x[Components[1]]*GivenVector->x[Components[1]]) + 1./(GivenVector->x[Components[0]]*GivenVector->x[Components[0]]));
723 x[Components[2]] = 0.;
724 // in skp both remaining parts shall become zero but with opposite sign and third is zero
725 x[Components[1]] = -1./GivenVector->x[Components[1]] / norm;
726 x[Components[0]] = 1./GivenVector->x[Components[0]] / norm;
727 return true;
728 break;
729 case 1: // one component system
730 // set sole non-zero component to 0, and one of the other zero component pendants to 1
731 x[(Components[0]+2)%NDIM] = 0.;
732 x[(Components[0]+1)%NDIM] = 1.;
733 x[Components[0]] = 0.;
734 return true;
735 break;
736 default:
737 return false;
738 }
739};
740
741/** Determines paramter needed to multiply this vector to obtain intersection point with plane defined by \a *A, \a *B and \a *C.
742 * \param *A first plane vector
743 * \param *B second plane vector
744 * \param *C third plane vector
745 * \return scaling parameter for this vector
746 */
747double Vector::CutsPlaneAt(Vector *A, Vector *B, Vector *C)
748{
749// cout << Verbose(3) << "For comparison: ";
750// cout << "A " << A->Projection(this) << "\t";
751// cout << "B " << B->Projection(this) << "\t";
752// cout << "C " << C->Projection(this) << "\t";
753// cout << endl;
754 return A->Projection(this);
755};
756
757/** Creates a new vector as the one with least square distance to a given set of \a vectors.
758 * \param *vectors set of vectors
759 * \param num number of vectors
760 * \return true if success, false if failed due to linear dependency
761 */
762bool Vector::LSQdistance(Vector **vectors, int num)
763{
764 int j;
765
766 for (j=0;j<num;j++) {
767 cout << Verbose(1) << j << "th atom's vector: ";
768 (vectors[j])->Output((ofstream *)&cout);
769 cout << endl;
770 }
771
772 int np = 3;
773 struct LSQ_params par;
774
775 const gsl_multimin_fminimizer_type *T =
776 gsl_multimin_fminimizer_nmsimplex;
777 gsl_multimin_fminimizer *s = NULL;
778 gsl_vector *ss, *y;
779 gsl_multimin_function minex_func;
780
781 size_t iter = 0, i;
782 int status;
783 double size;
784
785 /* Initial vertex size vector */
786 ss = gsl_vector_alloc (np);
787 y = gsl_vector_alloc (np);
788
789 /* Set all step sizes to 1 */
790 gsl_vector_set_all (ss, 1.0);
791
792 /* Starting point */
793 par.vectors = vectors;
794 par.num = num;
795
796 for (i=NDIM;i--;)
797 gsl_vector_set(y, i, (vectors[0]->x[i] - vectors[1]->x[i])/2.);
798
799 /* Initialize method and iterate */
800 minex_func.f = &LSQ;
801 minex_func.n = np;
802 minex_func.params = (void *)&par;
803
804 s = gsl_multimin_fminimizer_alloc (T, np);
805 gsl_multimin_fminimizer_set (s, &minex_func, y, ss);
806
807 do
808 {
809 iter++;
810 status = gsl_multimin_fminimizer_iterate(s);
811
812 if (status)
813 break;
814
815 size = gsl_multimin_fminimizer_size (s);
816 status = gsl_multimin_test_size (size, 1e-2);
817
818 if (status == GSL_SUCCESS)
819 {
820 printf ("converged to minimum at\n");
821 }
822
823 printf ("%5d ", (int)iter);
824 for (i = 0; i < (size_t)np; i++)
825 {
826 printf ("%10.3e ", gsl_vector_get (s->x, i));
827 }
828 printf ("f() = %7.3f size = %.3f\n", s->fval, size);
829 }
830 while (status == GSL_CONTINUE && iter < 100);
831
832 for (i=(size_t)np;i--;)
833 this->x[i] = gsl_vector_get(s->x, i);
834 gsl_vector_free(y);
835 gsl_vector_free(ss);
836 gsl_multimin_fminimizer_free (s);
837
838 return true;
839};
840
841/** Adds vector \a *y componentwise.
842 * \param *y vector
843 */
844void Vector::AddVector(const Vector *y)
845{
846 for (int i=NDIM;i--;)
847 this->x[i] += y->x[i];
848}
849
850/** Adds vector \a *y componentwise.
851 * \param *y vector
852 */
853void Vector::SubtractVector(const Vector *y)
854{
855 for (int i=NDIM;i--;)
856 this->x[i] -= y->x[i];
857}
858
859/** Copy vector \a *y componentwise.
860 * \param *y vector
861 */
862void Vector::CopyVector(const Vector *y)
863{
864 for (int i=NDIM;i--;)
865 this->x[i] = y->x[i];
866}
867
868
869/** Asks for position, checks for boundary.
870 * \param cell_size unitary size of cubic cell, coordinates must be within 0...cell_size
871 * \param check whether bounds shall be checked (true) or not (false)
872 */
873void Vector::AskPosition(double *cell_size, bool check)
874{
875 char coords[3] = {'x','y','z'};
876 int j = -1;
877 for (int i=0;i<3;i++) {
878 j += i+1;
879 do {
880 cout << Verbose(0) << coords[i] << "[0.." << cell_size[j] << "]: ";
881 cin >> x[i];
882 } while (((x[i] < 0) || (x[i] >= cell_size[j])) && (check));
883 }
884};
885
886/** Solves a vectorial system consisting of two orthogonal statements and a norm statement.
887 * This is linear system of equations to be solved, however of the three given (skp of this vector\
888 * with either of the three hast to be zero) only two are linear independent. The third equation
889 * is that the vector should be of magnitude 1 (orthonormal). This all leads to a case-based solution
890 * where very often it has to be checked whether a certain value is zero or not and thus forked into
891 * another case.
892 * \param *x1 first vector
893 * \param *x2 second vector
894 * \param *y third vector
895 * \param alpha first angle
896 * \param beta second angle
897 * \param c norm of final vector
898 * \return a vector with \f$\langle x1,x2 \rangle=A\f$, \f$\langle x1,y \rangle = B\f$ and with norm \a c.
899 * \bug this is not yet working properly
900 */
901bool Vector::SolveSystem(Vector *x1, Vector *x2, Vector *y, double alpha, double beta, double c)
902{
903 double D1,D2,D3,E1,E2,F1,F2,F3,p,q=0., A, B1, B2, C;
904 double ang; // angle on testing
905 double sign[3];
906 int i,j,k;
907 A = cos(alpha) * x1->Norm() * c;
908 B1 = cos(beta + M_PI/2.) * y->Norm() * c;
909 B2 = cos(beta) * x2->Norm() * c;
910 C = c * c;
911 cout << Verbose(2) << "A " << A << "\tB " << B1 << "\tC " << C << endl;
912 int flag = 0;
913 if (fabs(x1->x[0]) < MYEPSILON) { // check for zero components for the later flipping and back-flipping
914 if (fabs(x1->x[1]) > MYEPSILON) {
915 flag = 1;
916 } else if (fabs(x1->x[2]) > MYEPSILON) {
917 flag = 2;
918 } else {
919 return false;
920 }
921 }
922 switch (flag) {
923 default:
924 case 0:
925 break;
926 case 2:
927 flip(&x1->x[0],&x1->x[1]);
928 flip(&x2->x[0],&x2->x[1]);
929 flip(&y->x[0],&y->x[1]);
930 //flip(&x[0],&x[1]);
931 flip(&x1->x[1],&x1->x[2]);
932 flip(&x2->x[1],&x2->x[2]);
933 flip(&y->x[1],&y->x[2]);
934 //flip(&x[1],&x[2]);
935 case 1:
936 flip(&x1->x[0],&x1->x[1]);
937 flip(&x2->x[0],&x2->x[1]);
938 flip(&y->x[0],&y->x[1]);
939 //flip(&x[0],&x[1]);
940 flip(&x1->x[1],&x1->x[2]);
941 flip(&x2->x[1],&x2->x[2]);
942 flip(&y->x[1],&y->x[2]);
943 //flip(&x[1],&x[2]);
944 break;
945 }
946 // now comes the case system
947 D1 = -y->x[0]/x1->x[0]*x1->x[1]+y->x[1];
948 D2 = -y->x[0]/x1->x[0]*x1->x[2]+y->x[2];
949 D3 = y->x[0]/x1->x[0]*A-B1;
950 cout << Verbose(2) << "D1 " << D1 << "\tD2 " << D2 << "\tD3 " << D3 << "\n";
951 if (fabs(D1) < MYEPSILON) {
952 cout << Verbose(2) << "D1 == 0!\n";
953 if (fabs(D2) > MYEPSILON) {
954 cout << Verbose(3) << "D2 != 0!\n";
955 x[2] = -D3/D2;
956 E1 = A/x1->x[0] + x1->x[2]/x1->x[0]*D3/D2;
957 E2 = -x1->x[1]/x1->x[0];
958 cout << Verbose(3) << "E1 " << E1 << "\tE2 " << E2 << "\n";
959 F1 = E1*E1 + 1.;
960 F2 = -E1*E2;
961 F3 = E1*E1 + D3*D3/(D2*D2) - C;
962 cout << Verbose(3) << "F1 " << F1 << "\tF2 " << F2 << "\tF3 " << F3 << "\n";
963 if (fabs(F1) < MYEPSILON) {
964 cout << Verbose(4) << "F1 == 0!\n";
965 cout << Verbose(4) << "Gleichungssystem linear\n";
966 x[1] = F3/(2.*F2);
967 } else {
968 p = F2/F1;
969 q = p*p - F3/F1;
970 cout << Verbose(4) << "p " << p << "\tq " << q << endl;
971 if (q < 0) {
972 cout << Verbose(4) << "q < 0" << endl;
973 return false;
974 }
975 x[1] = p + sqrt(q);
976 }
977 x[0] = A/x1->x[0] - x1->x[1]/x1->x[0]*x[1] + x1->x[2]/x1->x[0]*x[2];
978 } else {
979 cout << Verbose(2) << "Gleichungssystem unterbestimmt\n";
980 return false;
981 }
982 } else {
983 E1 = A/x1->x[0]+x1->x[1]/x1->x[0]*D3/D1;
984 E2 = x1->x[1]/x1->x[0]*D2/D1 - x1->x[2];
985 cout << Verbose(2) << "E1 " << E1 << "\tE2 " << E2 << "\n";
986 F1 = E2*E2 + D2*D2/(D1*D1) + 1.;
987 F2 = -(E1*E2 + D2*D3/(D1*D1));
988 F3 = E1*E1 + D3*D3/(D1*D1) - C;
989 cout << Verbose(2) << "F1 " << F1 << "\tF2 " << F2 << "\tF3 " << F3 << "\n";
990 if (fabs(F1) < MYEPSILON) {
991 cout << Verbose(3) << "F1 == 0!\n";
992 cout << Verbose(3) << "Gleichungssystem linear\n";
993 x[2] = F3/(2.*F2);
994 } else {
995 p = F2/F1;
996 q = p*p - F3/F1;
997 cout << Verbose(3) << "p " << p << "\tq " << q << endl;
998 if (q < 0) {
999 cout << Verbose(3) << "q < 0" << endl;
1000 return false;
1001 }
1002 x[2] = p + sqrt(q);
1003 }
1004 x[1] = (-D2 * x[2] - D3)/D1;
1005 x[0] = A/x1->x[0] - x1->x[1]/x1->x[0]*x[1] + x1->x[2]/x1->x[0]*x[2];
1006 }
1007 switch (flag) { // back-flipping
1008 default:
1009 case 0:
1010 break;
1011 case 2:
1012 flip(&x1->x[0],&x1->x[1]);
1013 flip(&x2->x[0],&x2->x[1]);
1014 flip(&y->x[0],&y->x[1]);
1015 flip(&x[0],&x[1]);
1016 flip(&x1->x[1],&x1->x[2]);
1017 flip(&x2->x[1],&x2->x[2]);
1018 flip(&y->x[1],&y->x[2]);
1019 flip(&x[1],&x[2]);
1020 case 1:
1021 flip(&x1->x[0],&x1->x[1]);
1022 flip(&x2->x[0],&x2->x[1]);
1023 flip(&y->x[0],&y->x[1]);
1024 //flip(&x[0],&x[1]);
1025 flip(&x1->x[1],&x1->x[2]);
1026 flip(&x2->x[1],&x2->x[2]);
1027 flip(&y->x[1],&y->x[2]);
1028 flip(&x[1],&x[2]);
1029 break;
1030 }
1031 // one z component is only determined by its radius (without sign)
1032 // thus check eight possible sign flips and determine by checking angle with second vector
1033 for (i=0;i<8;i++) {
1034 // set sign vector accordingly
1035 for (j=2;j>=0;j--) {
1036 k = (i & pot(2,j)) << j;
1037 cout << Verbose(2) << "k " << k << "\tpot(2,j) " << pot(2,j) << endl;
1038 sign[j] = (k == 0) ? 1. : -1.;
1039 }
1040 cout << Verbose(2) << i << ": sign matrix is " << sign[0] << "\t" << sign[1] << "\t" << sign[2] << "\n";
1041 // apply sign matrix
1042 for (j=NDIM;j--;)
1043 x[j] *= sign[j];
1044 // calculate angle and check
1045 ang = x2->Angle (this);
1046 cout << Verbose(1) << i << "th angle " << ang << "\tbeta " << cos(beta) << " :\t";
1047 if (fabs(ang - cos(beta)) < MYEPSILON) {
1048 break;
1049 }
1050 // unapply sign matrix (is its own inverse)
1051 for (j=NDIM;j--;)
1052 x[j] *= sign[j];
1053 }
1054 return true;
1055};
Note: See TracBrowser for help on using the repository browser.