source: src/vector.cpp@ b1a6d8

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

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

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

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

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