source: src/vector.cpp@ 0dbddc

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 Candidate_v1.7.0 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 0dbddc was 0dbddc, checked in by Frederik Heber <heber@…>, 16 years ago

Merge branch 'ConcaveHull' of ssh://heber@192.168.194.2/home/metzler/workspace/espack into ConcaveHull

Conflicts:

molecuilder/src/atom.cpp
molecuilder/src/boundary.cpp
molecuilder/src/boundary.hpp
molecuilder/src/linkedcell.cpp
molecuilder/src/linkedcell.hpp
molecuilder/src/molecules.hpp
molecuilder/src/vector.hpp

  • added Saskia Metzler's code that finds whether a point is in- or outside.
  • The code is not yet incorporated, but I rather want to continue with merging TesselationRefactoring first.
  • Property mode set to 100755
File size: 31.8 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/** Checks whether vector has all components zero.
351 * @return true - vector is zero, false - vector is not
352 */
353bool Vector::IsNull()
354{
355 return (fabs(x[0]+x[1]+x[2]) < MYEPSILON);
356};
357
358/** Calculates the angle between this and another vector.
359 * \param *y array to second vector
360 * \return \f$\acos\bigl(frac{\langle x, y \rangle}{|x||y|}\bigr)\f$
361 */
362double Vector::Angle(const Vector *y) const
363{
364 double norm1 = Norm(), norm2 = y->Norm();
365 double angle = 1;
366 if ((fabs(norm1) > MYEPSILON) && (fabs(norm2) > MYEPSILON))
367 angle = this->ScalarProduct(y)/norm1/norm2;
368 // -1-MYEPSILON occured due to numerical imprecision, catch ...
369 //cout << Verbose(2) << "INFO: acos(-1) = " << acos(-1) << ", acos(-1+MYEPSILON) = " << acos(-1+MYEPSILON) << ", acos(-1-MYEPSILON) = " << acos(-1-MYEPSILON) << "." << endl;
370 if (angle < -1)
371 angle = -1;
372 if (angle > 1)
373 angle = 1;
374 return acos(angle);
375};
376
377/** Rotates the vector around the axis given by \a *axis by an angle of \a alpha.
378 * \param *axis rotation axis
379 * \param alpha rotation angle in radian
380 */
381void Vector::RotateVector(const Vector *axis, const double alpha)
382{
383 Vector a,y;
384 // normalise this vector with respect to axis
385 a.CopyVector(this);
386 a.Scale(Projection(axis));
387 SubtractVector(&a);
388 // construct normal vector
389 y.MakeNormalVector(axis,this);
390 y.Scale(Norm());
391 // scale normal vector by sine and this vector by cosine
392 y.Scale(sin(alpha));
393 Scale(cos(alpha));
394 // add scaled normal vector onto this vector
395 AddVector(&y);
396 // add part in axis direction
397 AddVector(&a);
398};
399
400/** Sums vector \a to this lhs component-wise.
401 * \param a base vector
402 * \param b vector components to add
403 * \return lhs + a
404 */
405Vector& operator+=(Vector& a, const Vector& b)
406{
407 a.AddVector(&b);
408 return a;
409};
410/** factor each component of \a a times a double \a m.
411 * \param a base vector
412 * \param m factor
413 * \return lhs.x[i] * m
414 */
415Vector& operator*=(Vector& a, const double m)
416{
417 a.Scale(m);
418 return a;
419};
420
421/** Sums two vectors \a and \b component-wise.
422 * \param a first vector
423 * \param b second vector
424 * \return a + b
425 */
426Vector& operator+(const Vector& a, const Vector& b)
427{
428 Vector *x = new Vector;
429 x->CopyVector(&a);
430 x->AddVector(&b);
431 return *x;
432};
433
434/** Factors given vector \a a times \a m.
435 * \param a vector
436 * \param m factor
437 * \return a + b
438 */
439Vector& operator*(const Vector& a, const double m)
440{
441 Vector *x = new Vector;
442 x->CopyVector(&a);
443 x->Scale(m);
444 return *x;
445};
446
447/** Prints a 3dim vector.
448 * prints no end of line.
449 * \param *out output stream
450 */
451bool Vector::Output(ofstream *out) const
452{
453 if (out != NULL) {
454 *out << "(";
455 for (int i=0;i<NDIM;i++) {
456 *out << x[i];
457 if (i != 2)
458 *out << ",";
459 }
460 *out << ")";
461 return true;
462 } else
463 return false;
464};
465
466ostream& operator<<(ostream& ost, const Vector& m)
467{
468 ost << "(";
469 for (int i=0;i<NDIM;i++) {
470 ost << m.x[i];
471 if (i != 2)
472 ost << ",";
473 }
474 ost << ")";
475 return ost;
476};
477
478/** Scales each atom coordinate by an individual \a factor.
479 * \param *factor pointer to scaling factor
480 */
481void Vector::Scale(double **factor)
482{
483 for (int i=NDIM;i--;)
484 x[i] *= (*factor)[i];
485};
486
487void Vector::Scale(double *factor)
488{
489 for (int i=NDIM;i--;)
490 x[i] *= *factor;
491};
492
493void Vector::Scale(double factor)
494{
495 for (int i=NDIM;i--;)
496 x[i] *= factor;
497};
498
499/** Translate atom by given vector.
500 * \param trans[] translation vector.
501 */
502void Vector::Translate(const Vector *trans)
503{
504 for (int i=NDIM;i--;)
505 x[i] += trans->x[i];
506};
507
508/** Do a matrix multiplication.
509 * \param *matrix NDIM_NDIM array
510 */
511void Vector::MatrixMultiplication(double *M)
512{
513 Vector C;
514 // do the matrix multiplication
515 C.x[0] = M[0]*x[0]+M[3]*x[1]+M[6]*x[2];
516 C.x[1] = M[1]*x[0]+M[4]*x[1]+M[7]*x[2];
517 C.x[2] = M[2]*x[0]+M[5]*x[1]+M[8]*x[2];
518 // transfer the result into this
519 for (int i=NDIM;i--;)
520 x[i] = C.x[i];
521};
522
523/** Calculate the inverse of a 3x3 matrix.
524 * \param *matrix NDIM_NDIM array
525 */
526double * Vector::InverseMatrix(double *A)
527{
528 double *B = (double *) Malloc(sizeof(double)*NDIM*NDIM, "Vector::InverseMatrix: *B");
529 double detA = RDET3(A);
530 double detAReci;
531
532 for (int i=0;i<NDIM*NDIM;++i)
533 B[i] = 0.;
534 // calculate the inverse B
535 if (fabs(detA) > MYEPSILON) {; // RDET3(A) yields precisely zero if A irregular
536 detAReci = 1./detA;
537 B[0] = detAReci*RDET2(A[4],A[5],A[7],A[8]); // A_11
538 B[1] = -detAReci*RDET2(A[1],A[2],A[7],A[8]); // A_12
539 B[2] = detAReci*RDET2(A[1],A[2],A[4],A[5]); // A_13
540 B[3] = -detAReci*RDET2(A[3],A[5],A[6],A[8]); // A_21
541 B[4] = detAReci*RDET2(A[0],A[2],A[6],A[8]); // A_22
542 B[5] = -detAReci*RDET2(A[0],A[2],A[3],A[5]); // A_23
543 B[6] = detAReci*RDET2(A[3],A[4],A[6],A[7]); // A_31
544 B[7] = -detAReci*RDET2(A[0],A[1],A[6],A[7]); // A_32
545 B[8] = detAReci*RDET2(A[0],A[1],A[3],A[4]); // A_33
546 }
547 return B;
548};
549
550/** Do a matrix multiplication with the \a *A' inverse.
551 * \param *matrix NDIM_NDIM array
552 */
553void Vector::InverseMatrixMultiplication(double *A)
554{
555 Vector C;
556 double B[NDIM*NDIM];
557 double detA = RDET3(A);
558 double detAReci;
559
560 // calculate the inverse B
561 if (fabs(detA) > MYEPSILON) {; // RDET3(A) yields precisely zero if A irregular
562 detAReci = 1./detA;
563 B[0] = detAReci*RDET2(A[4],A[5],A[7],A[8]); // A_11
564 B[1] = -detAReci*RDET2(A[1],A[2],A[7],A[8]); // A_12
565 B[2] = detAReci*RDET2(A[1],A[2],A[4],A[5]); // A_13
566 B[3] = -detAReci*RDET2(A[3],A[5],A[6],A[8]); // A_21
567 B[4] = detAReci*RDET2(A[0],A[2],A[6],A[8]); // A_22
568 B[5] = -detAReci*RDET2(A[0],A[2],A[3],A[5]); // A_23
569 B[6] = detAReci*RDET2(A[3],A[4],A[6],A[7]); // A_31
570 B[7] = -detAReci*RDET2(A[0],A[1],A[6],A[7]); // A_32
571 B[8] = detAReci*RDET2(A[0],A[1],A[3],A[4]); // A_33
572
573 // do the matrix multiplication
574 C.x[0] = B[0]*x[0]+B[3]*x[1]+B[6]*x[2];
575 C.x[1] = B[1]*x[0]+B[4]*x[1]+B[7]*x[2];
576 C.x[2] = B[2]*x[0]+B[5]*x[1]+B[8]*x[2];
577 // transfer the result into this
578 for (int i=NDIM;i--;)
579 x[i] = C.x[i];
580 } else {
581 cerr << "ERROR: inverse of matrix does not exists: det A = " << detA << "." << endl;
582 }
583};
584
585
586/** Creates this vector as the b y *factors' components scaled linear combination of the given three.
587 * this vector = x1*factors[0] + x2* factors[1] + x3*factors[2]
588 * \param *x1 first vector
589 * \param *x2 second vector
590 * \param *x3 third vector
591 * \param *factors three-component vector with the factor for each given vector
592 */
593void Vector::LinearCombinationOfVectors(const Vector *x1, const Vector *x2, const Vector *x3, double *factors)
594{
595 for(int i=NDIM;i--;)
596 x[i] = factors[0]*x1->x[i] + factors[1]*x2->x[i] + factors[2]*x3->x[i];
597};
598
599/** Mirrors atom against a given plane.
600 * \param n[] normal vector of mirror plane.
601 */
602void Vector::Mirror(const Vector *n)
603{
604 double projection;
605 projection = ScalarProduct(n)/n->ScalarProduct(n); // remove constancy from n (keep as logical one)
606 // withdraw projected vector twice from original one
607 cout << Verbose(1) << "Vector: ";
608 Output((ofstream *)&cout);
609 cout << "\t";
610 for (int i=NDIM;i--;)
611 x[i] -= 2.*projection*n->x[i];
612 cout << "Projected vector: ";
613 Output((ofstream *)&cout);
614 cout << endl;
615};
616
617/** Calculates normal vector for three given vectors (being three points in space).
618 * Makes this vector orthonormal to the three given points, making up a place in 3d space.
619 * \param *y1 first vector
620 * \param *y2 second vector
621 * \param *y3 third vector
622 * \return true - success, vectors are linear independent, false - failure due to linear dependency
623 */
624bool Vector::MakeNormalVector(const Vector *y1, const Vector *y2, const Vector *y3)
625{
626 Vector x1, x2;
627
628 x1.CopyVector(y1);
629 x1.SubtractVector(y2);
630 x2.CopyVector(y3);
631 x2.SubtractVector(y2);
632 if ((fabs(x1.Norm()) < MYEPSILON) || (fabs(x2.Norm()) < MYEPSILON) || (fabs(x1.Angle(&x2)) < MYEPSILON)) {
633 cout << Verbose(4) << "Given vectors are linear dependent." << endl;
634 return false;
635 }
636// cout << Verbose(4) << "relative, first plane coordinates:";
637// x1.Output((ofstream *)&cout);
638// cout << endl;
639// cout << Verbose(4) << "second plane coordinates:";
640// x2.Output((ofstream *)&cout);
641// cout << endl;
642
643 this->x[0] = (x1.x[1]*x2.x[2] - x1.x[2]*x2.x[1]);
644 this->x[1] = (x1.x[2]*x2.x[0] - x1.x[0]*x2.x[2]);
645 this->x[2] = (x1.x[0]*x2.x[1] - x1.x[1]*x2.x[0]);
646 Normalize();
647
648 return true;
649};
650
651
652/** Calculates orthonormal vector to two given vectors.
653 * Makes this vector orthonormal to two given vectors. This is very similar to the other
654 * vector::MakeNormalVector(), only there three points whereas here two difference
655 * vectors are given.
656 * \param *x1 first vector
657 * \param *x2 second vector
658 * \return true - success, vectors are linear independent, false - failure due to linear dependency
659 */
660bool Vector::MakeNormalVector(const Vector *y1, const Vector *y2)
661{
662 Vector x1,x2;
663 x1.CopyVector(y1);
664 x2.CopyVector(y2);
665 Zero();
666 if ((fabs(x1.Norm()) < MYEPSILON) || (fabs(x2.Norm()) < MYEPSILON) || (fabs(x1.Angle(&x2)) < MYEPSILON)) {
667 cout << Verbose(4) << "Given vectors are linear dependent." << endl;
668 return false;
669 }
670// cout << Verbose(4) << "relative, first plane coordinates:";
671// x1.Output((ofstream *)&cout);
672// cout << endl;
673// cout << Verbose(4) << "second plane coordinates:";
674// x2.Output((ofstream *)&cout);
675// cout << endl;
676
677 this->x[0] = (x1.x[1]*x2.x[2] - x1.x[2]*x2.x[1]);
678 this->x[1] = (x1.x[2]*x2.x[0] - x1.x[0]*x2.x[2]);
679 this->x[2] = (x1.x[0]*x2.x[1] - x1.x[1]*x2.x[0]);
680 Normalize();
681
682 return true;
683};
684
685/** Calculates orthonormal vector to one given vectors.
686 * Just subtracts the projection onto the given vector from this vector.
687 * \param *x1 vector
688 * \return true - success, false - vector is zero
689 */
690bool Vector::MakeNormalVector(const Vector *y1)
691{
692 bool result = false;
693 Vector x1;
694 x1.CopyVector(y1);
695 x1.Scale(x1.Projection(this));
696 SubtractVector(&x1);
697 for (int i=NDIM;i--;)
698 result = result || (fabs(x[i]) > MYEPSILON);
699
700 return result;
701};
702
703/** Creates this vector as one of the possible orthonormal ones to the given one.
704 * Just scan how many components of given *vector are unequal to zero and
705 * try to get the skp of both to be zero accordingly.
706 * \param *vector given vector
707 * \return true - success, false - failure (null vector given)
708 */
709bool Vector::GetOneNormalVector(const Vector *GivenVector)
710{
711 int Components[NDIM]; // contains indices of non-zero components
712 int Last = 0; // count the number of non-zero entries in vector
713 int j; // loop variables
714 double norm;
715
716 cout << Verbose(4);
717 GivenVector->Output((ofstream *)&cout);
718 cout << endl;
719 for (j=NDIM;j--;)
720 Components[j] = -1;
721 // find two components != 0
722 for (j=0;j<NDIM;j++)
723 if (fabs(GivenVector->x[j]) > MYEPSILON)
724 Components[Last++] = j;
725 cout << Verbose(4) << Last << " Components != 0: (" << Components[0] << "," << Components[1] << "," << Components[2] << ")" << endl;
726
727 switch(Last) {
728 case 3: // threecomponent system
729 case 2: // two component system
730 norm = sqrt(1./(GivenVector->x[Components[1]]*GivenVector->x[Components[1]]) + 1./(GivenVector->x[Components[0]]*GivenVector->x[Components[0]]));
731 x[Components[2]] = 0.;
732 // in skp both remaining parts shall become zero but with opposite sign and third is zero
733 x[Components[1]] = -1./GivenVector->x[Components[1]] / norm;
734 x[Components[0]] = 1./GivenVector->x[Components[0]] / norm;
735 return true;
736 break;
737 case 1: // one component system
738 // set sole non-zero component to 0, and one of the other zero component pendants to 1
739 x[(Components[0]+2)%NDIM] = 0.;
740 x[(Components[0]+1)%NDIM] = 1.;
741 x[Components[0]] = 0.;
742 return true;
743 break;
744 default:
745 return false;
746 }
747};
748
749/** Determines paramter needed to multiply this vector to obtain intersection point with plane defined by \a *A, \a *B and \a *C.
750 * \param *A first plane vector
751 * \param *B second plane vector
752 * \param *C third plane vector
753 * \return scaling parameter for this vector
754 */
755double Vector::CutsPlaneAt(Vector *A, Vector *B, Vector *C)
756{
757// cout << Verbose(3) << "For comparison: ";
758// cout << "A " << A->Projection(this) << "\t";
759// cout << "B " << B->Projection(this) << "\t";
760// cout << "C " << C->Projection(this) << "\t";
761// cout << endl;
762 return A->Projection(this);
763};
764
765/** Creates a new vector as the one with least square distance to a given set of \a vectors.
766 * \param *vectors set of vectors
767 * \param num number of vectors
768 * \return true if success, false if failed due to linear dependency
769 */
770bool Vector::LSQdistance(Vector **vectors, int num)
771{
772 int j;
773
774 for (j=0;j<num;j++) {
775 cout << Verbose(1) << j << "th atom's vector: ";
776 (vectors[j])->Output((ofstream *)&cout);
777 cout << endl;
778 }
779
780 int np = 3;
781 struct LSQ_params par;
782
783 const gsl_multimin_fminimizer_type *T =
784 gsl_multimin_fminimizer_nmsimplex;
785 gsl_multimin_fminimizer *s = NULL;
786 gsl_vector *ss, *y;
787 gsl_multimin_function minex_func;
788
789 size_t iter = 0, i;
790 int status;
791 double size;
792
793 /* Initial vertex size vector */
794 ss = gsl_vector_alloc (np);
795 y = gsl_vector_alloc (np);
796
797 /* Set all step sizes to 1 */
798 gsl_vector_set_all (ss, 1.0);
799
800 /* Starting point */
801 par.vectors = vectors;
802 par.num = num;
803
804 for (i=NDIM;i--;)
805 gsl_vector_set(y, i, (vectors[0]->x[i] - vectors[1]->x[i])/2.);
806
807 /* Initialize method and iterate */
808 minex_func.f = &LSQ;
809 minex_func.n = np;
810 minex_func.params = (void *)&par;
811
812 s = gsl_multimin_fminimizer_alloc (T, np);
813 gsl_multimin_fminimizer_set (s, &minex_func, y, ss);
814
815 do
816 {
817 iter++;
818 status = gsl_multimin_fminimizer_iterate(s);
819
820 if (status)
821 break;
822
823 size = gsl_multimin_fminimizer_size (s);
824 status = gsl_multimin_test_size (size, 1e-2);
825
826 if (status == GSL_SUCCESS)
827 {
828 printf ("converged to minimum at\n");
829 }
830
831 printf ("%5d ", (int)iter);
832 for (i = 0; i < (size_t)np; i++)
833 {
834 printf ("%10.3e ", gsl_vector_get (s->x, i));
835 }
836 printf ("f() = %7.3f size = %.3f\n", s->fval, size);
837 }
838 while (status == GSL_CONTINUE && iter < 100);
839
840 for (i=(size_t)np;i--;)
841 this->x[i] = gsl_vector_get(s->x, i);
842 gsl_vector_free(y);
843 gsl_vector_free(ss);
844 gsl_multimin_fminimizer_free (s);
845
846 return true;
847};
848
849/** Adds vector \a *y componentwise.
850 * \param *y vector
851 */
852void Vector::AddVector(const Vector *y)
853{
854 for (int i=NDIM;i--;)
855 this->x[i] += y->x[i];
856}
857
858/** Adds vector \a *y componentwise.
859 * \param *y vector
860 */
861void Vector::SubtractVector(const Vector *y)
862{
863 for (int i=NDIM;i--;)
864 this->x[i] -= y->x[i];
865}
866
867/** Copy vector \a *y componentwise.
868 * \param *y vector
869 */
870void Vector::CopyVector(const Vector *y)
871{
872 for (int i=NDIM;i--;)
873 this->x[i] = y->x[i];
874}
875
876
877/** Asks for position, checks for boundary.
878 * \param cell_size unitary size of cubic cell, coordinates must be within 0...cell_size
879 * \param check whether bounds shall be checked (true) or not (false)
880 */
881void Vector::AskPosition(double *cell_size, bool check)
882{
883 char coords[3] = {'x','y','z'};
884 int j = -1;
885 for (int i=0;i<3;i++) {
886 j += i+1;
887 do {
888 cout << Verbose(0) << coords[i] << "[0.." << cell_size[j] << "]: ";
889 cin >> x[i];
890 } while (((x[i] < 0) || (x[i] >= cell_size[j])) && (check));
891 }
892};
893
894/** Solves a vectorial system consisting of two orthogonal statements and a norm statement.
895 * This is linear system of equations to be solved, however of the three given (skp of this vector\
896 * with either of the three hast to be zero) only two are linear independent. The third equation
897 * is that the vector should be of magnitude 1 (orthonormal). This all leads to a case-based solution
898 * where very often it has to be checked whether a certain value is zero or not and thus forked into
899 * another case.
900 * \param *x1 first vector
901 * \param *x2 second vector
902 * \param *y third vector
903 * \param alpha first angle
904 * \param beta second angle
905 * \param c norm of final vector
906 * \return a vector with \f$\langle x1,x2 \rangle=A\f$, \f$\langle x1,y \rangle = B\f$ and with norm \a c.
907 * \bug this is not yet working properly
908 */
909bool Vector::SolveSystem(Vector *x1, Vector *x2, Vector *y, double alpha, double beta, double c)
910{
911 double D1,D2,D3,E1,E2,F1,F2,F3,p,q=0., A, B1, B2, C;
912 double ang; // angle on testing
913 double sign[3];
914 int i,j,k;
915 A = cos(alpha) * x1->Norm() * c;
916 B1 = cos(beta + M_PI/2.) * y->Norm() * c;
917 B2 = cos(beta) * x2->Norm() * c;
918 C = c * c;
919 cout << Verbose(2) << "A " << A << "\tB " << B1 << "\tC " << C << endl;
920 int flag = 0;
921 if (fabs(x1->x[0]) < MYEPSILON) { // check for zero components for the later flipping and back-flipping
922 if (fabs(x1->x[1]) > MYEPSILON) {
923 flag = 1;
924 } else if (fabs(x1->x[2]) > MYEPSILON) {
925 flag = 2;
926 } else {
927 return false;
928 }
929 }
930 switch (flag) {
931 default:
932 case 0:
933 break;
934 case 2:
935 flip(&x1->x[0],&x1->x[1]);
936 flip(&x2->x[0],&x2->x[1]);
937 flip(&y->x[0],&y->x[1]);
938 //flip(&x[0],&x[1]);
939 flip(&x1->x[1],&x1->x[2]);
940 flip(&x2->x[1],&x2->x[2]);
941 flip(&y->x[1],&y->x[2]);
942 //flip(&x[1],&x[2]);
943 case 1:
944 flip(&x1->x[0],&x1->x[1]);
945 flip(&x2->x[0],&x2->x[1]);
946 flip(&y->x[0],&y->x[1]);
947 //flip(&x[0],&x[1]);
948 flip(&x1->x[1],&x1->x[2]);
949 flip(&x2->x[1],&x2->x[2]);
950 flip(&y->x[1],&y->x[2]);
951 //flip(&x[1],&x[2]);
952 break;
953 }
954 // now comes the case system
955 D1 = -y->x[0]/x1->x[0]*x1->x[1]+y->x[1];
956 D2 = -y->x[0]/x1->x[0]*x1->x[2]+y->x[2];
957 D3 = y->x[0]/x1->x[0]*A-B1;
958 cout << Verbose(2) << "D1 " << D1 << "\tD2 " << D2 << "\tD3 " << D3 << "\n";
959 if (fabs(D1) < MYEPSILON) {
960 cout << Verbose(2) << "D1 == 0!\n";
961 if (fabs(D2) > MYEPSILON) {
962 cout << Verbose(3) << "D2 != 0!\n";
963 x[2] = -D3/D2;
964 E1 = A/x1->x[0] + x1->x[2]/x1->x[0]*D3/D2;
965 E2 = -x1->x[1]/x1->x[0];
966 cout << Verbose(3) << "E1 " << E1 << "\tE2 " << E2 << "\n";
967 F1 = E1*E1 + 1.;
968 F2 = -E1*E2;
969 F3 = E1*E1 + D3*D3/(D2*D2) - C;
970 cout << Verbose(3) << "F1 " << F1 << "\tF2 " << F2 << "\tF3 " << F3 << "\n";
971 if (fabs(F1) < MYEPSILON) {
972 cout << Verbose(4) << "F1 == 0!\n";
973 cout << Verbose(4) << "Gleichungssystem linear\n";
974 x[1] = F3/(2.*F2);
975 } else {
976 p = F2/F1;
977 q = p*p - F3/F1;
978 cout << Verbose(4) << "p " << p << "\tq " << q << endl;
979 if (q < 0) {
980 cout << Verbose(4) << "q < 0" << endl;
981 return false;
982 }
983 x[1] = p + sqrt(q);
984 }
985 x[0] = A/x1->x[0] - x1->x[1]/x1->x[0]*x[1] + x1->x[2]/x1->x[0]*x[2];
986 } else {
987 cout << Verbose(2) << "Gleichungssystem unterbestimmt\n";
988 return false;
989 }
990 } else {
991 E1 = A/x1->x[0]+x1->x[1]/x1->x[0]*D3/D1;
992 E2 = x1->x[1]/x1->x[0]*D2/D1 - x1->x[2];
993 cout << Verbose(2) << "E1 " << E1 << "\tE2 " << E2 << "\n";
994 F1 = E2*E2 + D2*D2/(D1*D1) + 1.;
995 F2 = -(E1*E2 + D2*D3/(D1*D1));
996 F3 = E1*E1 + D3*D3/(D1*D1) - C;
997 cout << Verbose(2) << "F1 " << F1 << "\tF2 " << F2 << "\tF3 " << F3 << "\n";
998 if (fabs(F1) < MYEPSILON) {
999 cout << Verbose(3) << "F1 == 0!\n";
1000 cout << Verbose(3) << "Gleichungssystem linear\n";
1001 x[2] = F3/(2.*F2);
1002 } else {
1003 p = F2/F1;
1004 q = p*p - F3/F1;
1005 cout << Verbose(3) << "p " << p << "\tq " << q << endl;
1006 if (q < 0) {
1007 cout << Verbose(3) << "q < 0" << endl;
1008 return false;
1009 }
1010 x[2] = p + sqrt(q);
1011 }
1012 x[1] = (-D2 * x[2] - D3)/D1;
1013 x[0] = A/x1->x[0] - x1->x[1]/x1->x[0]*x[1] + x1->x[2]/x1->x[0]*x[2];
1014 }
1015 switch (flag) { // back-flipping
1016 default:
1017 case 0:
1018 break;
1019 case 2:
1020 flip(&x1->x[0],&x1->x[1]);
1021 flip(&x2->x[0],&x2->x[1]);
1022 flip(&y->x[0],&y->x[1]);
1023 flip(&x[0],&x[1]);
1024 flip(&x1->x[1],&x1->x[2]);
1025 flip(&x2->x[1],&x2->x[2]);
1026 flip(&y->x[1],&y->x[2]);
1027 flip(&x[1],&x[2]);
1028 case 1:
1029 flip(&x1->x[0],&x1->x[1]);
1030 flip(&x2->x[0],&x2->x[1]);
1031 flip(&y->x[0],&y->x[1]);
1032 //flip(&x[0],&x[1]);
1033 flip(&x1->x[1],&x1->x[2]);
1034 flip(&x2->x[1],&x2->x[2]);
1035 flip(&y->x[1],&y->x[2]);
1036 flip(&x[1],&x[2]);
1037 break;
1038 }
1039 // one z component is only determined by its radius (without sign)
1040 // thus check eight possible sign flips and determine by checking angle with second vector
1041 for (i=0;i<8;i++) {
1042 // set sign vector accordingly
1043 for (j=2;j>=0;j--) {
1044 k = (i & pot(2,j)) << j;
1045 cout << Verbose(2) << "k " << k << "\tpot(2,j) " << pot(2,j) << endl;
1046 sign[j] = (k == 0) ? 1. : -1.;
1047 }
1048 cout << Verbose(2) << i << ": sign matrix is " << sign[0] << "\t" << sign[1] << "\t" << sign[2] << "\n";
1049 // apply sign matrix
1050 for (j=NDIM;j--;)
1051 x[j] *= sign[j];
1052 // calculate angle and check
1053 ang = x2->Angle (this);
1054 cout << Verbose(1) << i << "th angle " << ang << "\tbeta " << cos(beta) << " :\t";
1055 if (fabs(ang - cos(beta)) < MYEPSILON) {
1056 break;
1057 }
1058 // unapply sign matrix (is its own inverse)
1059 for (j=NDIM;j--;)
1060 x[j] *= sign[j];
1061 }
1062 return true;
1063};
Note: See TracBrowser for help on using the repository browser.