| 1 | /*
 | 
|---|
| 2 |  * vector_ops.cpp
 | 
|---|
| 3 |  *
 | 
|---|
| 4 |  *  Created on: Apr 1, 2010
 | 
|---|
| 5 |  *      Author: crueger
 | 
|---|
| 6 |  */
 | 
|---|
| 7 | 
 | 
|---|
| 8 | #include "vector.hpp"
 | 
|---|
| 9 | #include "Plane.hpp"
 | 
|---|
| 10 | #include "log.hpp"
 | 
|---|
| 11 | #include "verbose.hpp"
 | 
|---|
| 12 | #include "gslmatrix.hpp"
 | 
|---|
| 13 | #include "leastsquaremin.hpp"
 | 
|---|
| 14 | #include "info.hpp"
 | 
|---|
| 15 | #include "Helpers/fast_functions.hpp"
 | 
|---|
| 16 | #include "Exceptions/LinearDependenceException.hpp"
 | 
|---|
| 17 | #include "Exceptions/SkewException.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 | /**
 | 
|---|
| 25 |  * !@file
 | 
|---|
| 26 |  * These files defines several common operation on vectors that should not
 | 
|---|
| 27 |  * become part of the main vector class, because they are either to complex
 | 
|---|
| 28 |  * or need methods from other subsystems that should not be moved to
 | 
|---|
| 29 |  * the LinAlg-Subsystem
 | 
|---|
| 30 |  */
 | 
|---|
| 31 | 
 | 
|---|
| 32 | /** Creates a new vector as the one with least square distance to a given set of \a vectors.
 | 
|---|
| 33 |  * \param *vectors set of vectors
 | 
|---|
| 34 |  * \param num number of vectors
 | 
|---|
| 35 |  * \return true if success, false if failed due to linear dependency
 | 
|---|
| 36 |  */
 | 
|---|
| 37 | bool LSQdistance(Vector &res,const Vector **vectors, int num)
 | 
|---|
| 38 | {
 | 
|---|
| 39 |   int j;
 | 
|---|
| 40 | 
 | 
|---|
| 41 |   for (j=0;j<num;j++) {
 | 
|---|
| 42 |     Log() << Verbose(1) << j << "th atom's vector: " << vectors[j] << endl;
 | 
|---|
| 43 |   }
 | 
|---|
| 44 | 
 | 
|---|
| 45 |   int np = 3;
 | 
|---|
| 46 |   struct LSQ_params par;
 | 
|---|
| 47 | 
 | 
|---|
| 48 |    const gsl_multimin_fminimizer_type *T =
 | 
|---|
| 49 |      gsl_multimin_fminimizer_nmsimplex;
 | 
|---|
| 50 |    gsl_multimin_fminimizer *s = NULL;
 | 
|---|
| 51 |    gsl_vector *ss, *y;
 | 
|---|
| 52 |    gsl_multimin_function minex_func;
 | 
|---|
| 53 | 
 | 
|---|
| 54 |    size_t iter = 0, i;
 | 
|---|
| 55 |    int status;
 | 
|---|
| 56 |    double size;
 | 
|---|
| 57 | 
 | 
|---|
| 58 |    /* Initial vertex size vector */
 | 
|---|
| 59 |    ss = gsl_vector_alloc (np);
 | 
|---|
| 60 |    y = gsl_vector_alloc (np);
 | 
|---|
| 61 | 
 | 
|---|
| 62 |    /* Set all step sizes to 1 */
 | 
|---|
| 63 |    gsl_vector_set_all (ss, 1.0);
 | 
|---|
| 64 | 
 | 
|---|
| 65 |    /* Starting point */
 | 
|---|
| 66 |    par.vectors = vectors;
 | 
|---|
| 67 |    par.num = num;
 | 
|---|
| 68 | 
 | 
|---|
| 69 |    for (i=NDIM;i--;)
 | 
|---|
| 70 |     gsl_vector_set(y, i, (vectors[0]->at(i) - vectors[1]->at(i))/2.);
 | 
|---|
| 71 | 
 | 
|---|
| 72 |    /* Initialize method and iterate */
 | 
|---|
| 73 |    minex_func.f = &LSQ;
 | 
|---|
| 74 |    minex_func.n = np;
 | 
|---|
| 75 |    minex_func.params = (void *)∥
 | 
|---|
| 76 | 
 | 
|---|
| 77 |    s = gsl_multimin_fminimizer_alloc (T, np);
 | 
|---|
| 78 |    gsl_multimin_fminimizer_set (s, &minex_func, y, ss);
 | 
|---|
| 79 | 
 | 
|---|
| 80 |    do
 | 
|---|
| 81 |      {
 | 
|---|
| 82 |        iter++;
 | 
|---|
| 83 |        status = gsl_multimin_fminimizer_iterate(s);
 | 
|---|
| 84 | 
 | 
|---|
| 85 |        if (status)
 | 
|---|
| 86 |          break;
 | 
|---|
| 87 | 
 | 
|---|
| 88 |        size = gsl_multimin_fminimizer_size (s);
 | 
|---|
| 89 |        status = gsl_multimin_test_size (size, 1e-2);
 | 
|---|
| 90 | 
 | 
|---|
| 91 |        if (status == GSL_SUCCESS)
 | 
|---|
| 92 |          {
 | 
|---|
| 93 |            printf ("converged to minimum at\n");
 | 
|---|
| 94 |          }
 | 
|---|
| 95 | 
 | 
|---|
| 96 |        printf ("%5d ", (int)iter);
 | 
|---|
| 97 |        for (i = 0; i < (size_t)np; i++)
 | 
|---|
| 98 |          {
 | 
|---|
| 99 |            printf ("%10.3e ", gsl_vector_get (s->x, i));
 | 
|---|
| 100 |          }
 | 
|---|
| 101 |        printf ("f() = %7.3f size = %.3f\n", s->fval, size);
 | 
|---|
| 102 |      }
 | 
|---|
| 103 |    while (status == GSL_CONTINUE && iter < 100);
 | 
|---|
| 104 | 
 | 
|---|
| 105 |   for (i=(size_t)np;i--;)
 | 
|---|
| 106 |     res[i] = gsl_vector_get(s->x, i);
 | 
|---|
| 107 |    gsl_vector_free(y);
 | 
|---|
| 108 |    gsl_vector_free(ss);
 | 
|---|
| 109 |    gsl_multimin_fminimizer_free (s);
 | 
|---|
| 110 | 
 | 
|---|
| 111 |   return true;
 | 
|---|
| 112 | };
 | 
|---|
| 113 | 
 | 
|---|
| 114 | /** Rotates the vector relative to the origin around the axis given by \a *axis by an angle of \a alpha.
 | 
|---|
| 115 |  * \param *axis rotation axis
 | 
|---|
| 116 |  * \param alpha rotation angle in radian
 | 
|---|
| 117 |  */
 | 
|---|
| 118 | Vector RotateVector(const Vector &vec,const Vector &axis, const double alpha)
 | 
|---|
| 119 | {
 | 
|---|
| 120 |   Vector a,y;
 | 
|---|
| 121 |   Vector res;
 | 
|---|
| 122 |   // normalise this vector with respect to axis
 | 
|---|
| 123 |   a = vec;
 | 
|---|
| 124 |   a.ProjectOntoPlane(axis);
 | 
|---|
| 125 |   // construct normal vector
 | 
|---|
| 126 |   try {
 | 
|---|
| 127 |     y = Plane(axis,a,0).getNormal();
 | 
|---|
| 128 |   }
 | 
|---|
| 129 |   catch (MathException &excp) {
 | 
|---|
| 130 |     // The normal vector cannot be created if there is linar dependency.
 | 
|---|
| 131 |     // Then the vector to rotate is on the axis and any rotation leads to the vector itself.
 | 
|---|
| 132 |     return vec;
 | 
|---|
| 133 |   }
 | 
|---|
| 134 |   y.Scale(vec.Norm());
 | 
|---|
| 135 |   // scale normal vector by sine and this vector by cosine
 | 
|---|
| 136 |   y.Scale(sin(alpha));
 | 
|---|
| 137 |   a.Scale(cos(alpha));
 | 
|---|
| 138 |   res = vec.Projection(axis);
 | 
|---|
| 139 |   // add scaled normal vector onto this vector
 | 
|---|
| 140 |   res += y;
 | 
|---|
| 141 |   // add part in axis direction
 | 
|---|
| 142 |   res += a;
 | 
|---|
| 143 |   return res;
 | 
|---|
| 144 | };
 | 
|---|
| 145 | 
 | 
|---|
| 146 | /** Calculates the intersection of the two lines that are both on the same plane.
 | 
|---|
| 147 |  * This is taken from Weisstein, Eric W. "Line-Line Intersection." From MathWorld--A Wolfram Web Resource. http://mathworld.wolfram.com/Line-LineIntersection.html
 | 
|---|
| 148 |  * \param *out output stream for debugging
 | 
|---|
| 149 |  * \param *Line1a first vector of first line
 | 
|---|
| 150 |  * \param *Line1b second vector of first line
 | 
|---|
| 151 |  * \param *Line2a first vector of second line
 | 
|---|
| 152 |  * \param *Line2b second vector of second line
 | 
|---|
| 153 |  * \return true - \a this will contain the intersection on return, false - lines are parallel
 | 
|---|
| 154 |  */
 | 
|---|
| 155 | Vector GetIntersectionOfTwoLinesOnPlane(const Vector &Line1a, const Vector &Line1b, const Vector &Line2a, const Vector &Line2b)
 | 
|---|
| 156 | {
 | 
|---|
| 157 |   Info FunctionInfo(__func__);
 | 
|---|
| 158 | 
 | 
|---|
| 159 |   Vector res;
 | 
|---|
| 160 | 
 | 
|---|
| 161 |   auto_ptr<GSLMatrix> M = auto_ptr<GSLMatrix>(new GSLMatrix(4,4));
 | 
|---|
| 162 | 
 | 
|---|
| 163 |   M->SetAll(1.);
 | 
|---|
| 164 |   for (int i=0;i<3;i++) {
 | 
|---|
| 165 |     M->Set(0, i, Line1a[i]);
 | 
|---|
| 166 |     M->Set(1, i, Line1b[i]);
 | 
|---|
| 167 |     M->Set(2, i, Line2a[i]);
 | 
|---|
| 168 |     M->Set(3, i, Line2b[i]);
 | 
|---|
| 169 |   }
 | 
|---|
| 170 | 
 | 
|---|
| 171 |   //Log() << Verbose(1) << "Coefficent matrix is:" << endl;
 | 
|---|
| 172 |   //for (int i=0;i<4;i++) {
 | 
|---|
| 173 |   //  for (int j=0;j<4;j++)
 | 
|---|
| 174 |   //    cout << "\t" << M->Get(i,j);
 | 
|---|
| 175 |   //  cout << endl;
 | 
|---|
| 176 |   //}
 | 
|---|
| 177 |   if (fabs(M->Determinant()) > MYEPSILON) {
 | 
|---|
| 178 |     Log() << Verbose(1) << "Determinant of coefficient matrix is NOT zero." << endl;
 | 
|---|
| 179 |     throw SkewException(__FILE__,__LINE__);
 | 
|---|
| 180 |   }
 | 
|---|
| 181 | 
 | 
|---|
| 182 |   Log() << Verbose(1) << "INFO: Line1a = " << Line1a << ", Line1b = " << Line1b << ", Line2a = " << Line2a << ", Line2b = " << Line2b << "." << endl;
 | 
|---|
| 183 | 
 | 
|---|
| 184 | 
 | 
|---|
| 185 |   // constuct a,b,c
 | 
|---|
| 186 |   Vector a = Line1b - Line1a;
 | 
|---|
| 187 |   Vector b = Line2b - Line2a;
 | 
|---|
| 188 |   Vector c = Line2a - Line1a;
 | 
|---|
| 189 |   Vector d = Line2b - Line1b;
 | 
|---|
| 190 |   Log() << Verbose(1) << "INFO: a = " << a << ", b = " << b << ", c = " << c << "." << endl;
 | 
|---|
| 191 |   if ((a.NormSquared() < MYEPSILON) || (b.NormSquared() < MYEPSILON)) {
 | 
|---|
| 192 |    res.Zero();
 | 
|---|
| 193 |    Log() << Verbose(1) << "At least one of the lines is ill-defined, i.e. offset equals second vector." << endl;
 | 
|---|
| 194 |    throw LinearDependenceException(__FILE__,__LINE__);
 | 
|---|
| 195 |   }
 | 
|---|
| 196 | 
 | 
|---|
| 197 |   // check for parallelity
 | 
|---|
| 198 |   Vector parallel;
 | 
|---|
| 199 |   double factor = 0.;
 | 
|---|
| 200 |   if (fabs(a.ScalarProduct(b)*a.ScalarProduct(b)/a.NormSquared()/b.NormSquared() - 1.) < MYEPSILON) {
 | 
|---|
| 201 |     parallel = Line1a - Line2a;
 | 
|---|
| 202 |     factor = parallel.ScalarProduct(a)/a.Norm();
 | 
|---|
| 203 |     if ((factor >= -MYEPSILON) && (factor - 1. < MYEPSILON)) {
 | 
|---|
| 204 |       res = Line2a;
 | 
|---|
| 205 |       Log() << Verbose(1) << "Lines conincide." << endl;
 | 
|---|
| 206 |       return res;
 | 
|---|
| 207 |     } else {
 | 
|---|
| 208 |       parallel = Line1a - Line2b;
 | 
|---|
| 209 |       factor = parallel.ScalarProduct(a)/a.Norm();
 | 
|---|
| 210 |       if ((factor >= -MYEPSILON) && (factor - 1. < MYEPSILON)) {
 | 
|---|
| 211 |         res = Line2b;
 | 
|---|
| 212 |         Log() << Verbose(1) << "Lines conincide." << endl;
 | 
|---|
| 213 |         return res;
 | 
|---|
| 214 |       }
 | 
|---|
| 215 |     }
 | 
|---|
| 216 |     Log() << Verbose(1) << "Lines are parallel." << endl;
 | 
|---|
| 217 |     res.Zero();
 | 
|---|
| 218 |     throw LinearDependenceException(__FILE__,__LINE__);
 | 
|---|
| 219 |   }
 | 
|---|
| 220 | 
 | 
|---|
| 221 |   // obtain s
 | 
|---|
| 222 |   double s;
 | 
|---|
| 223 |   Vector temp1, temp2;
 | 
|---|
| 224 |   temp1 = c;
 | 
|---|
| 225 |   temp1.VectorProduct(b);
 | 
|---|
| 226 |   temp2 = a;
 | 
|---|
| 227 |   temp2.VectorProduct(b);
 | 
|---|
| 228 |   Log() << Verbose(1) << "INFO: temp1 = " << temp1 << ", temp2 = " << temp2 << "." << endl;
 | 
|---|
| 229 |   if (fabs(temp2.NormSquared()) > MYEPSILON)
 | 
|---|
| 230 |     s = temp1.ScalarProduct(temp2)/temp2.NormSquared();
 | 
|---|
| 231 |   else
 | 
|---|
| 232 |     s = 0.;
 | 
|---|
| 233 |   Log() << Verbose(1) << "Factor s is " << temp1.ScalarProduct(temp2) << "/" << temp2.NormSquared() << " = " << s << "." << endl;
 | 
|---|
| 234 | 
 | 
|---|
| 235 |   // construct intersection
 | 
|---|
| 236 |   res = a;
 | 
|---|
| 237 |   res.Scale(s);
 | 
|---|
| 238 |   res += Line1a;
 | 
|---|
| 239 |   Log() << Verbose(1) << "Intersection is at " << res << "." << endl;
 | 
|---|
| 240 | 
 | 
|---|
| 241 |   return res;
 | 
|---|
| 242 | };
 | 
|---|