Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/clhep/src/RotationE.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /externals/clhep/src/RotationE.cc (Version 11.3.0) and /externals/clhep/src/RotationE.cc (Version 9.6.p4)


  1 // -*- C++ -*-                                      1 // -*- C++ -*-
  2 // -------------------------------------------      2 // ---------------------------------------------------------------------------
  3 //                                                  3 //
  4 // This file is a part of the CLHEP - a Class       4 // This file is a part of the CLHEP - a Class Library for High Energy Physics.
  5 //                                                  5 //
  6 // This is the implementation of methods of th      6 // This is the implementation of methods of the HepRotation class which
  7 // were introduced when ZOOM PhysicsVectors wa      7 // were introduced when ZOOM PhysicsVectors was merged in, and which involve
  8 // Euler Angles representation.                     8 // Euler Angles representation.
  9 //                                                  9 //
 10 // Apr 28, 2003  mf  Modified way of computing     10 // Apr 28, 2003  mf  Modified way of computing Euler angles to avoid flawed
 11 //                   answers in the case where     11 //                   answers in the case where theta is near 0 of pi, and
 12 //                   the matrix is not a perfe     12 //                   the matrix is not a perfect rotation (due to roundoff).
 13                                                    13 
                                                   >>  14 #ifdef GNUPRAGMA
                                                   >>  15 #pragma implementation
                                                   >>  16 #endif
                                                   >>  17 
 14 #include "CLHEP/Vector/Rotation.h"                 18 #include "CLHEP/Vector/Rotation.h"
 15 #include "CLHEP/Vector/EulerAngles.h"              19 #include "CLHEP/Vector/EulerAngles.h"
 16 #include "CLHEP/Units/PhysicalConstants.h"         20 #include "CLHEP/Units/PhysicalConstants.h"
 17                                                    21 
 18 #include <cmath>                                   22 #include <cmath>
 19 #include <iostream>                            << 
 20                                                    23 
 21 namespace CLHEP  {                                 24 namespace CLHEP  {
 22                                                    25 
 23 static inline double safe_acos (double x) {        26 static inline double safe_acos (double x) {
 24   if (std::abs(x) <= 1.0) return std::acos(x);     27   if (std::abs(x) <= 1.0) return std::acos(x);
 25   return ( (x>0) ? 0 : CLHEP::pi );                28   return ( (x>0) ? 0 : CLHEP::pi );
 26 }                                                  29 }
 27                                                    30 
 28 // ----------  Constructors and Assignment:        31 // ----------  Constructors and Assignment:
 29                                                    32 
 30 // Euler angles                                    33 // Euler angles
 31                                                    34 
 32 HepRotation & HepRotation::set(double phi1, do     35 HepRotation & HepRotation::set(double phi1, double theta1, double psi1) {
 33                                                    36 
 34   double sinPhi   = std::sin( phi1   ), cosPhi <<  37   register double sinPhi   = std::sin( phi1   ), cosPhi   = std::cos( phi1   );
 35   double sinTheta = std::sin( theta1 ), cosThe <<  38   register double sinTheta = std::sin( theta1 ), cosTheta = std::cos( theta1 );
 36   double sinPsi   = std::sin( psi1   ), cosPsi <<  39   register double sinPsi   = std::sin( psi1   ), cosPsi   = std::cos( psi1   );
 37                                                    40 
 38   rxx =   cosPsi * cosPhi - cosTheta * sinPhi      41   rxx =   cosPsi * cosPhi - cosTheta * sinPhi * sinPsi;
 39   rxy =   cosPsi * sinPhi + cosTheta * cosPhi      42   rxy =   cosPsi * sinPhi + cosTheta * cosPhi * sinPsi;
 40   rxz =   sinPsi * sinTheta;                       43   rxz =   sinPsi * sinTheta;
 41                                                    44 
 42   ryx = - sinPsi * cosPhi - cosTheta * sinPhi      45   ryx = - sinPsi * cosPhi - cosTheta * sinPhi * cosPsi;
 43   ryy = - sinPsi * sinPhi + cosTheta * cosPhi      46   ryy = - sinPsi * sinPhi + cosTheta * cosPhi * cosPsi;
 44   ryz =   cosPsi * sinTheta;                       47   ryz =   cosPsi * sinTheta;
 45                                                    48 
 46   rzx =   sinTheta * sinPhi;                       49   rzx =   sinTheta * sinPhi;
 47   rzy = - sinTheta * cosPhi;                       50   rzy = - sinTheta * cosPhi;
 48   rzz =   cosTheta;                                51   rzz =   cosTheta;
 49                                                    52 
 50   return  *this;                                   53   return  *this;
 51                                                    54 
 52 }  // Rotation::set(phi, theta, psi)               55 }  // Rotation::set(phi, theta, psi)
 53                                                    56 
 54 HepRotation::HepRotation( double phi1, double      57 HepRotation::HepRotation( double phi1, double theta1, double psi1 ) 
 55 {                                                  58 {
 56   set (phi1, theta1, psi1);                        59   set (phi1, theta1, psi1);
 57 }                                                  60 }
 58 HepRotation & HepRotation::set( const HepEuler     61 HepRotation & HepRotation::set( const HepEulerAngles & e ) {
 59   return set(e.phi(), e.theta(), e.psi());         62   return set(e.phi(), e.theta(), e.psi());
 60 }                                                  63 }
 61 HepRotation::HepRotation ( const HepEulerAngle     64 HepRotation::HepRotation ( const HepEulerAngles & e ) 
 62 {                                                  65 {
 63   set(e.phi(), e.theta(), e.psi());                66   set(e.phi(), e.theta(), e.psi());
 64 }                                                  67 }
 65                                                    68 
 66                                                    69  
 67 double HepRotation::phi  () const {                70 double HepRotation::phi  () const {
 68                                                    71 
 69   double s2 =  1.0 - rzz*rzz;                      72   double s2 =  1.0 - rzz*rzz;
 70   if (s2 < 0) {                                    73   if (s2 < 0) {
 71     std::cerr << "HepRotation::phi() - "           74     std::cerr << "HepRotation::phi() - "
 72         << "HepRotation::phi() finds | rzz | >     75         << "HepRotation::phi() finds | rzz | > 1 " << std::endl;
 73     s2 = 0;                                        76     s2 = 0;
 74   }                                                77   }
 75   const double sinTheta = std::sqrt( s2 );         78   const double sinTheta = std::sqrt( s2 );
 76                                                    79 
 77   if (sinTheta < .01) { // For theta close to      80   if (sinTheta < .01) { // For theta close to 0 or PI, use the more stable
 78         // algorithm to get all three Euler an     81         // algorithm to get all three Euler angles
 79     HepEulerAngles ea = eulerAngles();             82     HepEulerAngles ea = eulerAngles();
 80     return ea.phi();                               83     return ea.phi();
 81   }                                                84   }
 82                                                    85   
 83   const double cscTheta = 1/sinTheta;              86   const double cscTheta = 1/sinTheta;
 84   double cosabsphi =  - rzy * cscTheta;            87   double cosabsphi =  - rzy * cscTheta;
 85   if ( std::fabs(cosabsphi) > 1 ) { // NaN-pro     88   if ( std::fabs(cosabsphi) > 1 ) { // NaN-proofing
 86     std::cerr << "HepRotation::phi() - "           89     std::cerr << "HepRotation::phi() - "
 87       << "HepRotation::phi() finds | cos phi |     90       << "HepRotation::phi() finds | cos phi | > 1 " << std::endl;
 88     cosabsphi = 1;                                 91     cosabsphi = 1;
 89   }                                                92   }
 90   const double absPhi = std::acos ( cosabsphi      93   const double absPhi = std::acos ( cosabsphi );
 91   if (rzx > 0) {                                   94   if (rzx > 0) {
 92     return   absPhi;                               95     return   absPhi;
 93   } else if (rzx < 0) {                            96   } else if (rzx < 0) {
 94     return  -absPhi;                               97     return  -absPhi;
 95   } else {                                         98   } else {
 96     return  (rzy < 0) ? 0 : CLHEP::pi;             99     return  (rzy < 0) ? 0 : CLHEP::pi;
 97   }                                               100   }
 98                                                   101 
 99 } // phi()                                        102 } // phi()
100                                                   103 
101 double HepRotation::theta() const {               104 double HepRotation::theta() const {
102                                                   105 
103   return  safe_acos( rzz );                       106   return  safe_acos( rzz );
104                                                   107 
105 } // theta()                                      108 } // theta()
106                                                   109 
107 double HepRotation::psi  () const {               110 double HepRotation::psi  () const {
108                                                   111 
109   double sinTheta;                                112   double sinTheta;
110   if ( std::fabs(rzz) > 1 ) { // NaN-proofing     113   if ( std::fabs(rzz) > 1 ) { // NaN-proofing
111     std::cerr << "HepRotation::psi() - "          114     std::cerr << "HepRotation::psi() - "
112       << "HepRotation::psi() finds | rzz | > 1    115       << "HepRotation::psi() finds | rzz | > 1" << std::endl;
113     sinTheta = 0;                                 116     sinTheta = 0;
114   } else {                                        117   } else { 
115     sinTheta = std::sqrt( 1.0 - rzz*rzz );        118     sinTheta = std::sqrt( 1.0 - rzz*rzz );
116   }                                               119   }
117                                                   120   
118   if (sinTheta < .01) { // For theta close to     121   if (sinTheta < .01) { // For theta close to 0 or PI, use the more stable
119         // algorithm to get all three Euler an    122         // algorithm to get all three Euler angles
120     HepEulerAngles ea = eulerAngles();            123     HepEulerAngles ea = eulerAngles();
121     return ea.psi();                              124     return ea.psi();
122   }                                               125   }
123                                                   126 
124   const double cscTheta = 1/sinTheta;             127   const double cscTheta = 1/sinTheta;
125   double cosabspsi =  ryz * cscTheta;             128   double cosabspsi =  ryz * cscTheta;
126   if ( std::fabs(cosabspsi) > 1 ) { // NaN-pro    129   if ( std::fabs(cosabspsi) > 1 ) { // NaN-proofing
127     std::cerr << "HepRotation::psi() - "          130     std::cerr << "HepRotation::psi() - "
128       << "HepRotation::psi() finds | cos psi |    131       << "HepRotation::psi() finds | cos psi | > 1" << std::endl;
129     cosabspsi = 1;                                132     cosabspsi = 1;
130   }                                               133   }
131   const double absPsi = std::acos ( cosabspsi     134   const double absPsi = std::acos ( cosabspsi );
132   if (rxz > 0) {                                  135   if (rxz > 0) {
133     return   absPsi;                              136     return   absPsi;
134   } else if (rxz < 0) {                           137   } else if (rxz < 0) {
135     return  -absPsi;                              138     return  -absPsi;
136   } else {                                        139   } else {
137     return  (ryz > 0) ? 0 : CLHEP::pi;            140     return  (ryz > 0) ? 0 : CLHEP::pi;
138   }                                               141   }
139                                                   142 
140 } // psi()                                        143 } // psi()
141                                                   144 
142 // Helpers for eulerAngles():                     145 // Helpers for eulerAngles():
143                                                   146 
144 static                                            147 static         
145 void correctByPi ( double& psi1, double& phi1     148 void correctByPi ( double& psi1, double& phi1 ) {
146   if (psi1 > 0) {                                 149   if (psi1 > 0) {
147     psi1 -= CLHEP::pi;                            150     psi1 -= CLHEP::pi;
148   } else {                                        151   } else {
149     psi1 += CLHEP::pi;                            152     psi1 += CLHEP::pi;
150   }                                               153   }
151   if (phi1 > 0) {                                 154   if (phi1 > 0) {
152     phi1 -= CLHEP::pi;                            155     phi1 -= CLHEP::pi;
153   } else {                                        156   } else {
154     phi1 += CLHEP::pi;                            157     phi1 += CLHEP::pi;
155   }                                               158   }  
156 }                                                 159 }
157                                                   160 
158 static                                            161 static
159 void correctPsiPhi ( double rxz, double rzx, d    162 void correctPsiPhi ( double rxz, double rzx, double ryz, double rzy, 
160          double& psi1, double& phi1 ) {           163          double& psi1, double& phi1 ) {
161                                                   164 
162   // set up quatities which would be positive     165   // set up quatities which would be positive if sin and cosine of
163   // psi1 and phi1 were positive:                 166   // psi1 and phi1 were positive:
164   double w[4];                                    167   double w[4];
165   w[0] = rxz; w[1] = rzx; w[2] = ryz; w[3] = -    168   w[0] = rxz; w[1] = rzx; w[2] = ryz; w[3] = -rzy;
166                                                   169 
167   // find biggest relevant term, which is the     170   // find biggest relevant term, which is the best one to use in correcting.
168   double maxw = std::abs(w[0]);                   171   double maxw = std::abs(w[0]); 
169   int imax = 0;                                   172   int imax = 0;
170   for (int i = 1; i < 4; ++i) {                   173   for (int i = 1; i < 4; ++i) {
171     if (std::abs(w[i]) > maxw) {                  174     if (std::abs(w[i]) > maxw) {
172       maxw = std::abs(w[i]);                      175       maxw = std::abs(w[i]);
173       imax = i;                                   176       imax = i;
174     }                                             177     }
175   }                                               178   }
176   // Determine if the correction needs to be a    179   // Determine if the correction needs to be applied:  The criteria are 
177   // different depending on whether a sine or     180   // different depending on whether a sine or cosine was the determinor: 
178   switch (imax) {                                 181   switch (imax) {
179     case 0:                                       182     case 0:
180       if (w[0] > 0 && psi1 < 0)           corr    183       if (w[0] > 0 && psi1 < 0)           correctByPi ( psi1, phi1 );
181       if (w[0] < 0 && psi1 > 0)           corr    184       if (w[0] < 0 && psi1 > 0)           correctByPi ( psi1, phi1 );
182       break;                                      185       break;
183     case 1:                                       186     case 1:
184       if (w[1] > 0 && phi1 < 0)           corr    187       if (w[1] > 0 && phi1 < 0)           correctByPi ( psi1, phi1 );
185       if (w[1] < 0 && phi1 > 0)           corr    188       if (w[1] < 0 && phi1 > 0)           correctByPi ( psi1, phi1 );
186       break;                                      189       break;
187     case 2:                                       190     case 2:
188       if (w[2] > 0 && std::abs(psi1) > CLHEP::    191       if (w[2] > 0 && std::abs(psi1) > CLHEP::halfpi) correctByPi ( psi1, phi1 );    
189       if (w[2] < 0 && std::abs(psi1) < CLHEP::    192       if (w[2] < 0 && std::abs(psi1) < CLHEP::halfpi) correctByPi ( psi1, phi1 );    
190       break;                                      193       break;
191     case 3:                                       194     case 3:
192       if (w[3] > 0 && std::abs(phi1) > CLHEP::    195       if (w[3] > 0 && std::abs(phi1) > CLHEP::halfpi) correctByPi ( psi1, phi1 );    
193       if (w[3] < 0 && std::abs(phi1) < CLHEP::    196       if (w[3] < 0 && std::abs(phi1) < CLHEP::halfpi) correctByPi ( psi1, phi1 );    
194       break;                                      197       break;
195   }                                               198   }          
196 }                                                 199 }
197                                                   200 
198 HepEulerAngles HepRotation::eulerAngles() cons    201 HepEulerAngles HepRotation::eulerAngles() const {
199                                                   202 
200   // Please see the mathematical justification    203   // Please see the mathematical justification in eulerAngleComputations.ps
201                                                   204 
202   double phi1, theta1, psi1;                      205   double phi1, theta1, psi1;
203   double psiPlusPhi, psiMinusPhi;                 206   double psiPlusPhi, psiMinusPhi;
204                                                   207   
205   theta1 = safe_acos( rzz );                      208   theta1 = safe_acos( rzz );
206                                                   209   
207 //  if (rzz > 1 || rzz < -1) {                    210 //  if (rzz > 1 || rzz < -1) {
208 //    std::cerr << "HepRotation::eulerAngles()    211 //    std::cerr << "HepRotation::eulerAngles() - "
209 //        << "HepRotation::eulerAngles() finds    212 //        << "HepRotation::eulerAngles() finds | rzz | > 1 " << std::endl;
210 //  }                                             213 //  }
211                                                   214   
212   double cosTheta = rzz;                          215   double cosTheta = rzz;
213   if (cosTheta > 1)  cosTheta = 1;                216   if (cosTheta > 1)  cosTheta = 1;
214   if (cosTheta < -1) cosTheta = -1;               217   if (cosTheta < -1) cosTheta = -1;
215                                                   218 
216   if (cosTheta == 1) {                            219   if (cosTheta == 1) {
217     psiPlusPhi = std::atan2 ( rxy - ryx, rxx +    220     psiPlusPhi = std::atan2 ( rxy - ryx, rxx + ryy );
218     psiMinusPhi = 0;                              221     psiMinusPhi = 0;     
219                                                   222 
220   } else if (cosTheta >= 0) {                     223   } else if (cosTheta >= 0) {
221                                                   224 
222     // In this realm, the atan2 expression for    225     // In this realm, the atan2 expression for psi + phi is numerically stable
223     psiPlusPhi = std::atan2 ( rxy - ryx, rxx +    226     psiPlusPhi = std::atan2 ( rxy - ryx, rxx + ryy );
224                                                   227 
225     // psi - phi is potentially more subtle, b    228     // psi - phi is potentially more subtle, but when unstable it is moot
226     double s1 = -rxy - ryx; // sin (psi-phi) *    229     double s1 = -rxy - ryx; // sin (psi-phi) * (1 - cos theta)
227     double c1 =  rxx - ryy; // cos (psi-phi) *    230     double c1 =  rxx - ryy; // cos (psi-phi) * (1 - cos theta)
228     psiMinusPhi = std::atan2 ( s1, c1 );          231     psiMinusPhi = std::atan2 ( s1, c1 );
229                                                   232         
230   } else if (cosTheta > -1) {                     233   } else if (cosTheta > -1) {
231                                                   234 
232     // In this realm, the atan2 expression for    235     // In this realm, the atan2 expression for psi - phi is numerically stable
233     psiMinusPhi = std::atan2 ( -rxy - ryx, rxx    236     psiMinusPhi = std::atan2 ( -rxy - ryx, rxx - ryy );
234                                                   237 
235    // psi + phi is potentially more subtle, bu    238    // psi + phi is potentially more subtle, but when unstable it is moot
236     double s1 = rxy - ryx; // sin (psi+phi) *     239     double s1 = rxy - ryx; // sin (psi+phi) * (1 + cos theta)
237     double c1 = rxx + ryy; // cos (psi+phi) *     240     double c1 = rxx + ryy; // cos (psi+phi) * (1 + cos theta)
238     psiPlusPhi = std::atan2 ( s1, c1 );           241     psiPlusPhi = std::atan2 ( s1, c1 );
239                                                   242 
240   } else { // cosTheta == -1                      243   } else { // cosTheta == -1
241                                                   244 
242     psiMinusPhi = std::atan2 ( -rxy - ryx, rxx    245     psiMinusPhi = std::atan2 ( -rxy - ryx, rxx - ryy );
243     psiPlusPhi = 0;                               246     psiPlusPhi = 0;
244                                                   247 
245   }                                               248   }
246                                                   249   
247   psi1 = .5 * (psiPlusPhi + psiMinusPhi);         250   psi1 = .5 * (psiPlusPhi + psiMinusPhi); 
248   phi1 = .5 * (psiPlusPhi - psiMinusPhi);         251   phi1 = .5 * (psiPlusPhi - psiMinusPhi); 
249                                                   252 
250   // Now correct by pi if we have managed to g    253   // Now correct by pi if we have managed to get a value of psiPlusPhi
251   // or psiMinusPhi that was off by 2 pi:         254   // or psiMinusPhi that was off by 2 pi:
252   correctPsiPhi ( rxz, rzx, ryz, rzy, psi1, ph    255   correctPsiPhi ( rxz, rzx, ryz, rzy, psi1, phi1 );
253                                                   256   
254   return  HepEulerAngles( phi1, theta1, psi1 )    257   return  HepEulerAngles( phi1, theta1, psi1 );
255                                                   258 
256 } // eulerAngles()                                259 } // eulerAngles()
257                                                   260 
258                                                   261 
259 void HepRotation::setPhi (double phi1) {          262 void HepRotation::setPhi (double phi1) {
260   set ( phi1, theta(), psi() );                   263   set ( phi1, theta(), psi() );
261 }                                                 264 }
262                                                   265 
263 void HepRotation::setTheta (double theta1) {      266 void HepRotation::setTheta (double theta1) {
264   set ( phi(), theta1, psi() );                   267   set ( phi(), theta1, psi() );
265 }                                                 268 }
266                                                   269 
267 void HepRotation::setPsi (double psi1) {          270 void HepRotation::setPsi (double psi1) {
268   set ( phi(), theta(), psi1 );                   271   set ( phi(), theta(), psi1 );
269 }                                                 272 }
270                                                   273 
271 }  // namespace CLHEP                             274 }  // namespace CLHEP
272                                                   275 
273                                                   276