source: src/vector.cpp@ cb2146

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

FIX: operator implementation of Vector algebra was wrong and caused memory leaks.

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