source: src/SingleVector.cpp@ 1bd79e

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 1bd79e was 1bd79e, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Changed implementation of Vector to forward operations to contained objects

  • Property mode set to 100644
File size: 15.0 KB
Line 
1/** \file vector.cpp
2 *
3 * Function implementations for the class vector.
4 *
5 */
6
7
8#include "defs.hpp"
9#include "gslmatrix.hpp"
10#include "leastsquaremin.hpp"
11#include "memoryallocator.hpp"
12#include "SingleVector.hpp"
13#include "Helpers/fast_functions.hpp"
14#include "Helpers/Assert.hpp"
15#include "Plane.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#include <iostream>
24
25using namespace std;
26
27/************************************ Functions for class vector ************************************/
28
29/** Constructor of class vector.
30 */
31SingleVector::SingleVector() :
32 Vector(Baseconstructor())
33{
34 x[0] = x[1] = x[2] = 0.;
35};
36
37/** Constructor of class vector.
38 */
39SingleVector::SingleVector(const double x1, const double x2, const double x3) :
40 Vector(Baseconstructor())
41{
42 x[0] = x1;
43 x[1] = x2;
44 x[2] = x3;
45};
46
47/**
48 * Copy constructor
49 */
50SingleVector::SingleVector(const Vector& src) :
51 Vector(Baseconstructor())
52{
53 x[0] = src[0];
54 x[1] = src[1];
55 x[2] = src[2];
56}
57
58SingleVector* SingleVector::clone() const{
59 return new SingleVector(x[0],x[1],x[2]);
60}
61
62/** Desctructor of class vector.
63 */
64SingleVector::~SingleVector() {};
65
66/** Calculates square of distance between this and another vector.
67 * \param *y array to second vector
68 * \return \f$| x - y |^2\f$
69 */
70double SingleVector::DistanceSquared(const Vector &y) const
71{
72 double res = 0.;
73 for (int i=NDIM;i--;)
74 res += (x[i]-y[i])*(x[i]-y[i]);
75 return (res);
76};
77
78/** Calculates distance between this and another vector in a periodic cell.
79 * \param *y array to second vector
80 * \param *cell_size 6-dimensional array with (xx, xy, yy, xz, yz, zz) entries specifying the periodic cell
81 * \return \f$| x - y |\f$
82 */
83double SingleVector::PeriodicDistance(const Vector &y, const double * const cell_size) const
84{
85 double res = Distance(y), tmp, matrix[NDIM*NDIM];
86 Vector Shiftedy, TranslationVector;
87 int N[NDIM];
88 matrix[0] = cell_size[0];
89 matrix[1] = cell_size[1];
90 matrix[2] = cell_size[3];
91 matrix[3] = cell_size[1];
92 matrix[4] = cell_size[2];
93 matrix[5] = cell_size[4];
94 matrix[6] = cell_size[3];
95 matrix[7] = cell_size[4];
96 matrix[8] = cell_size[5];
97 // in order to check the periodic distance, translate one of the vectors into each of the 27 neighbouring cells
98 for (N[0]=-1;N[0]<=1;N[0]++)
99 for (N[1]=-1;N[1]<=1;N[1]++)
100 for (N[2]=-1;N[2]<=1;N[2]++) {
101 // create the translation vector
102 TranslationVector.Zero();
103 for (int i=NDIM;i--;)
104 TranslationVector[i] = (double)N[i];
105 TranslationVector.MatrixMultiplication(matrix);
106 // add onto the original vector to compare with
107 Shiftedy = y + TranslationVector;
108 // get distance and compare with minimum so far
109 tmp = Distance(Shiftedy);
110 if (tmp < res) res = tmp;
111 }
112 return (res);
113};
114
115/** Calculates distance between this and another vector in a periodic cell.
116 * \param *y array to second vector
117 * \param *cell_size 6-dimensional array with (xx, xy, yy, xz, yz, zz) entries specifying the periodic cell
118 * \return \f$| x - y |^2\f$
119 */
120double SingleVector::PeriodicDistanceSquared(const Vector &y, const double * const cell_size) const
121{
122 double res = DistanceSquared(y), tmp, matrix[NDIM*NDIM];
123 Vector Shiftedy, TranslationVector;
124 int N[NDIM];
125 matrix[0] = cell_size[0];
126 matrix[1] = cell_size[1];
127 matrix[2] = cell_size[3];
128 matrix[3] = cell_size[1];
129 matrix[4] = cell_size[2];
130 matrix[5] = cell_size[4];
131 matrix[6] = cell_size[3];
132 matrix[7] = cell_size[4];
133 matrix[8] = cell_size[5];
134 // in order to check the periodic distance, translate one of the vectors into each of the 27 neighbouring cells
135 for (N[0]=-1;N[0]<=1;N[0]++)
136 for (N[1]=-1;N[1]<=1;N[1]++)
137 for (N[2]=-1;N[2]<=1;N[2]++) {
138 // create the translation vector
139 TranslationVector.Zero();
140 for (int i=NDIM;i--;)
141 TranslationVector[i] = (double)N[i];
142 TranslationVector.MatrixMultiplication(matrix);
143 // add onto the original vector to compare with
144 Shiftedy = y + TranslationVector;
145 // get distance and compare with minimum so far
146 tmp = DistanceSquared(Shiftedy);
147 if (tmp < res) res = tmp;
148 }
149 return (res);
150};
151
152/** Keeps the vector in a periodic cell, defined by the symmetric \a *matrix.
153 * \param *out ofstream for debugging messages
154 * Tries to translate a vector into each adjacent neighbouring cell.
155 */
156void SingleVector::KeepPeriodic(const double * const matrix)
157{
158// int N[NDIM];
159// bool flag = false;
160 //vector Shifted, TranslationVector;
161// Log() << Verbose(1) << "Begin of KeepPeriodic." << endl;
162// Log() << Verbose(2) << "Vector is: ";
163// Output(out);
164// Log() << Verbose(0) << endl;
165 SingleVector TestVector(*this);
166 TestVector.InverseMatrixMultiplication(matrix);
167 for(int i=NDIM;i--;) { // correct periodically
168 if (TestVector[i] < 0) { // get every coefficient into the interval [0,1)
169 TestVector[i] += ceil(TestVector[i]);
170 } else {
171 TestVector[i] -= floor(TestVector[i]);
172 }
173 }
174 TestVector.MatrixMultiplication(matrix);
175 CopyVector(TestVector);
176// Log() << Verbose(2) << "New corrected vector is: ";
177// Output(out);
178// Log() << Verbose(0) << endl;
179// Log() << Verbose(1) << "End of KeepPeriodic." << endl;
180};
181
182/** Calculates scalar product between this and another vector.
183 * \param *y array to second vector
184 * \return \f$\langle x, y \rangle\f$
185 */
186double SingleVector::ScalarProduct(const Vector &y) const
187{
188 double res = 0.;
189 for (int i=NDIM;i--;)
190 res += x[i]*y[i];
191 return (res);
192};
193
194
195void SingleVector::AddVector(const Vector &y) {
196 for(int i=NDIM;i--;)
197 x[i] += y[i];
198}
199
200void SingleVector::SubtractVector(const Vector &y){
201 for(int i=NDIM;i--;)
202 x[i] -= y[i];
203}
204
205/** Calculates VectorProduct between this and another vector.
206 * -# returns the Product in place of vector from which it was initiated
207 * -# ATTENTION: Only three dim.
208 * \param *y array to vector with which to calculate crossproduct
209 * \return \f$ x \times y \f&
210 */
211void SingleVector::VectorProduct(const Vector &y)
212{
213 SingleVector tmp;
214 tmp[0] = x[1]* (y[2]) - x[2]* (y[1]);
215 tmp[1] = x[2]* (y[0]) - x[0]* (y[2]);
216 tmp[2] = x[0]* (y[1]) - x[1]* (y[0]);
217 CopyVector(tmp);
218};
219
220
221/** projects this vector onto plane defined by \a *y.
222 * \param *y normal vector of plane
223 * \return \f$\langle x, y \rangle\f$
224 */
225void SingleVector::ProjectOntoPlane(const Vector &y)
226{
227 Vector tmp;
228 tmp = y;
229 tmp.Normalize();
230 tmp.Scale(ScalarProduct(tmp));
231 *this -= tmp;
232};
233
234/** Calculates the minimum distance of this vector to the plane.
235 * \param *out output stream for debugging
236 * \param *PlaneNormal normal of plane
237 * \param *PlaneOffset offset of plane
238 * \return distance to plane
239 */
240double SingleVector::DistanceToPlane(const Vector &PlaneNormal, const Vector &PlaneOffset) const
241{
242 // first create part that is orthonormal to PlaneNormal with withdraw
243 Vector temp = VecFromRep(this)- PlaneOffset;
244 temp.MakeNormalTo(PlaneNormal);
245 temp.Scale(-1.);
246 // then add connecting vector from plane to point
247 temp += VecFromRep(this)-PlaneOffset;
248 double sign = temp.ScalarProduct(PlaneNormal);
249 if (fabs(sign) > MYEPSILON)
250 sign /= fabs(sign);
251 else
252 sign = 0.;
253
254 return (temp.Norm()*sign);
255};
256
257/** Calculates the projection of a vector onto another \a *y.
258 * \param *y array to second vector
259 */
260void SingleVector::ProjectIt(const Vector &y)
261{
262 Vector helper = y;
263 helper.Scale(-(ScalarProduct(y)));
264 AddVector(helper);
265};
266
267/** Calculates the projection of a vector onto another \a *y.
268 * \param *y array to second vector
269 * \return Vector
270 */
271Vector SingleVector::Projection(const Vector &y) const
272{
273 Vector helper = y;
274 helper.Scale((ScalarProduct(y)/y.NormSquared()));
275
276 return helper;
277};
278
279/** Checks whether vector has all components zero.
280 * @return true - vector is zero, false - vector is not
281 */
282bool SingleVector::IsZero() const
283{
284 return (fabs(x[0])+fabs(x[1])+fabs(x[2]) < MYEPSILON);
285};
286
287/** Checks whether vector has length of 1.
288 * @return true - vector is normalized, false - vector is not
289 */
290bool SingleVector::IsOne() const
291{
292 return (fabs(Norm() - 1.) < MYEPSILON);
293};
294
295/** Checks whether vector is normal to \a *normal.
296 * @return true - vector is normalized, false - vector is not
297 */
298bool SingleVector::IsNormalTo(const Vector &normal) const
299{
300 if (ScalarProduct(normal) < MYEPSILON)
301 return true;
302 else
303 return false;
304};
305
306/** Checks whether vector is normal to \a *normal.
307 * @return true - vector is normalized, false - vector is not
308 */
309bool SingleVector::IsEqualTo(const Vector &a) const
310{
311 bool status = true;
312 for (int i=0;i<NDIM;i++) {
313 if (fabs(x[i] - a[i]) > MYEPSILON)
314 status = false;
315 }
316 return status;
317};
318
319/** Calculates the angle between this and another vector.
320 * \param *y array to second vector
321 * \return \f$\acos\bigl(frac{\langle x, y \rangle}{|x||y|}\bigr)\f$
322 */
323double SingleVector::Angle(const Vector &y) const
324{
325 double norm1 = Norm(), norm2 = y.Norm();
326 double angle = -1;
327 if ((fabs(norm1) > MYEPSILON) && (fabs(norm2) > MYEPSILON))
328 angle = this->ScalarProduct(y)/norm1/norm2;
329 // -1-MYEPSILON occured due to numerical imprecision, catch ...
330 //Log() << Verbose(2) << "INFO: acos(-1) = " << acos(-1) << ", acos(-1+MYEPSILON) = " << acos(-1+MYEPSILON) << ", acos(-1-MYEPSILON) = " << acos(-1-MYEPSILON) << "." << endl;
331 if (angle < -1)
332 angle = -1;
333 if (angle > 1)
334 angle = 1;
335 return acos(angle);
336};
337
338
339double& SingleVector::operator[](size_t i){
340 ASSERT(i<=NDIM && i>=0,"Vector Index out of Range");
341 return x[i];
342}
343
344const double& SingleVector::operator[](size_t i) const{
345 ASSERT(i<=NDIM && i>=0,"Vector Index out of Range");
346 return x[i];
347}
348
349double* SingleVector::get(){
350 return x;
351}
352/** Scales each atom coordinate by an individual \a factor.
353 * \param *factor pointer to scaling factor
354 */
355void SingleVector::ScaleAll(const double *factor)
356{
357 for (int i=NDIM;i--;)
358 x[i] *= factor[i];
359};
360
361void SingleVector::Scale(const double factor)
362{
363 for (int i=NDIM;i--;)
364 x[i] *= factor;
365};
366
367/** Given a box by its matrix \a *M and its inverse *Minv the vector is made to point within that box.
368 * \param *M matrix of box
369 * \param *Minv inverse matrix
370 */
371void SingleVector::WrapPeriodically(const double * const M, const double * const Minv)
372{
373 MatrixMultiplication(Minv);
374 // truncate to [0,1] for each axis
375 for (int i=0;i<NDIM;i++) {
376 x[i] += 0.5; // set to center of box
377 while (x[i] >= 1.)
378 x[i] -= 1.;
379 while (x[i] < 0.)
380 x[i] += 1.;
381 }
382 MatrixMultiplication(M);
383};
384
385/** Do a matrix multiplication.
386 * \param *matrix NDIM_NDIM array
387 */
388void SingleVector::MatrixMultiplication(const double * const M)
389{
390 SingleVector C;
391 // do the matrix multiplication
392 C[0] = M[0]*x[0]+M[3]*x[1]+M[6]*x[2];
393 C[1] = M[1]*x[0]+M[4]*x[1]+M[7]*x[2];
394 C[2] = M[2]*x[0]+M[5]*x[1]+M[8]*x[2];
395
396 CopyVector(C);
397};
398
399/** Do a matrix multiplication with the \a *A' inverse.
400 * \param *matrix NDIM_NDIM array
401 */
402bool SingleVector::InverseMatrixMultiplication(const double * const A)
403{
404 SingleVector C;
405 double B[NDIM*NDIM];
406 double detA = RDET3(A);
407 double detAReci;
408
409 // calculate the inverse B
410 if (fabs(detA) > MYEPSILON) {; // RDET3(A) yields precisely zero if A irregular
411 detAReci = 1./detA;
412 B[0] = detAReci*RDET2(A[4],A[5],A[7],A[8]); // A_11
413 B[1] = -detAReci*RDET2(A[1],A[2],A[7],A[8]); // A_12
414 B[2] = detAReci*RDET2(A[1],A[2],A[4],A[5]); // A_13
415 B[3] = -detAReci*RDET2(A[3],A[5],A[6],A[8]); // A_21
416 B[4] = detAReci*RDET2(A[0],A[2],A[6],A[8]); // A_22
417 B[5] = -detAReci*RDET2(A[0],A[2],A[3],A[5]); // A_23
418 B[6] = detAReci*RDET2(A[3],A[4],A[6],A[7]); // A_31
419 B[7] = -detAReci*RDET2(A[0],A[1],A[6],A[7]); // A_32
420 B[8] = detAReci*RDET2(A[0],A[1],A[3],A[4]); // A_33
421
422 // do the matrix multiplication
423 C[0] = B[0]*x[0]+B[3]*x[1]+B[6]*x[2];
424 C[1] = B[1]*x[0]+B[4]*x[1]+B[7]*x[2];
425 C[2] = B[2]*x[0]+B[5]*x[1]+B[8]*x[2];
426
427 CopyVector(C);
428 return true;
429 } else {
430 return false;
431 }
432};
433
434
435/** Mirrors atom against a given plane.
436 * \param n[] normal vector of mirror plane.
437 */
438void SingleVector::Mirror(const Vector &n)
439{
440 double projection;
441 projection = ScalarProduct(n)/n.NormSquared(); // remove constancy from n (keep as logical one)
442 // withdraw projected vector twice from original one
443 for (int i=NDIM;i--;)
444 x[i] -= 2.*projection*n[i];
445};
446
447
448/** Calculates orthonormal vector to one given vector.
449 * Just subtracts the projection onto the given vector from this vector.
450 * The removed part of the vector is Vector::Projection()
451 * \param *x1 vector
452 * \return true - success, false - vector is zero
453 */
454bool SingleVector::MakeNormalTo(const Vector &y1)
455{
456 bool result = false;
457 double factor = y1.ScalarProduct(*this)/y1.NormSquared();
458 Vector x1;
459 x1 = factor * y1;
460 SubtractVector(x1);
461 for (int i=NDIM;i--;)
462 result = result || (fabs(x[i]) > MYEPSILON);
463
464 return result;
465};
466
467/** Creates this vector as one of the possible orthonormal ones to the given one.
468 * Just scan how many components of given *vector are unequal to zero and
469 * try to get the skp of both to be zero accordingly.
470 * \param *vector given vector
471 * \return true - success, false - failure (null vector given)
472 */
473bool SingleVector::GetOneNormalVector(const Vector &GivenVector)
474{
475 int Components[NDIM]; // contains indices of non-zero components
476 int Last = 0; // count the number of non-zero entries in vector
477 int j; // loop variables
478 double norm;
479
480 for (j=NDIM;j--;)
481 Components[j] = -1;
482 // find two components != 0
483 for (j=0;j<NDIM;j++)
484 if (fabs(GivenVector[j]) > MYEPSILON)
485 Components[Last++] = j;
486
487 switch(Last) {
488 case 3: // threecomponent system
489 case 2: // two component system
490 norm = sqrt(1./(GivenVector[Components[1]]*GivenVector[Components[1]]) + 1./(GivenVector[Components[0]]*GivenVector[Components[0]]));
491 x[Components[2]] = 0.;
492 // in skp both remaining parts shall become zero but with opposite sign and third is zero
493 x[Components[1]] = -1./GivenVector[Components[1]] / norm;
494 x[Components[0]] = 1./GivenVector[Components[0]] / norm;
495 return true;
496 break;
497 case 1: // one component system
498 // set sole non-zero component to 0, and one of the other zero component pendants to 1
499 x[(Components[0]+2)%NDIM] = 0.;
500 x[(Components[0]+1)%NDIM] = 1.;
501 x[Components[0]] = 0.;
502 return true;
503 break;
504 default:
505 return false;
506 }
507};
508
509/**
510 * Checks whether this vector is within the parallelepiped defined by the given three vectors and
511 * their offset.
512 *
513 * @param offest for the origin of the parallelepiped
514 * @param three vectors forming the matrix that defines the shape of the parallelpiped
515 */
516bool SingleVector::IsInParallelepiped(const Vector &offset, const double * const parallelepiped) const
517{
518 Vector a = VecFromRep(this);
519 a -= offset;
520 a.InverseMatrixMultiplication(parallelepiped);
521 bool isInside = true;
522
523 for (int i=NDIM;i--;)
524 isInside = isInside && ((a[i] <= 1) && (a[i] >= 0));
525
526 return isInside;
527}
528
529
530void SingleVector::CopyVector(SingleVector& vec) {
531 for(int i =NDIM; i--;)
532 x[i]=vec.x[i];
533}
534
535bool SingleVector::isBaseClass() const{
536 return false;
537}
Note: See TracBrowser for help on using the repository browser.