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