Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/error_propagation/src/G4ErrorFreeTrajState.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 ]

  1 //
  2 // ********************************************************************
  3 // * License and Disclaimer                                           *
  4 // *                                                                  *
  5 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
  6 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
  7 // * conditions of the Geant4 Software License,  included in the file *
  8 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
  9 // * include a list of copyright holders.                             *
 10 // *                                                                  *
 11 // * Neither the authors of this software system, nor their employing *
 12 // * institutes,nor the agencies providing financial support for this *
 13 // * work  make  any representation or  warranty, express or implied, *
 14 // * regarding  this  software system or assume any liability for its *
 15 // * use.  Please see the license in the file  LICENSE  and URL above *
 16 // * for the full disclaimer and the limitation of liability.         *
 17 // *                                                                  *
 18 // * This  code  implementation is the result of  the  scientific and *
 19 // * technical work of the GEANT4 collaboration.                      *
 20 // * By using,  copying,  modifying or  distributing the software (or *
 21 // * any work based  on the software)  you  agree  to acknowledge its *
 22 // * use  in  resulting  scientific  publications,  and indicate your *
 23 // * acceptance of all terms of the Geant4 Software license.          *
 24 // ********************************************************************
 25 //
 26 //
 27 // ------------------------------------------------------------
 28 //      GEANT 4 class implementation file
 29 // ------------------------------------------------------------
 30 //
 31 
 32 #include <iomanip>
 33 
 34 #include "G4PhysicalConstants.hh"
 35 #include "G4SystemOfUnits.hh"
 36 #include "G4Field.hh"
 37 #include "G4FieldManager.hh"
 38 #include "G4TransportationManager.hh"
 39 #include "G4GeometryTolerance.hh"
 40 #include "G4Material.hh"
 41 #include "G4ErrorPropagatorData.hh"
 42 #include "G4ErrorFreeTrajState.hh"
 43 #include "G4ErrorFreeTrajParam.hh"
 44 #include "G4ErrorSurfaceTrajState.hh"
 45 #include "G4ErrorMatrix.hh"
 46 
 47 //------------------------------------------------------------------------
 48 G4ErrorFreeTrajState::G4ErrorFreeTrajState(const G4String& partName,
 49                                            const G4Point3D& pos,
 50                                            const G4Vector3D& mom,
 51                                            const G4ErrorTrajErr& errmat)
 52   : G4ErrorTrajState(partName, pos, mom, errmat)
 53 {
 54   fTrajParam = G4ErrorFreeTrajParam(pos, mom);
 55   Init();
 56 }
 57 
 58 //------------------------------------------------------------------------
 59 G4ErrorFreeTrajState::G4ErrorFreeTrajState(const G4ErrorSurfaceTrajState& tpSD)
 60   : G4ErrorTrajState(tpSD.GetParticleType(), tpSD.GetPosition(),
 61                      tpSD.GetMomentum())
 62 {
 63   // G4ThreeVector planeNormal = tpSD.GetPlaneNormal();
 64   // G4double fPt = tpSD.GetMomentum()*planeNormal;//mom projected on normal to
 65   // plane G4ErrorSurfaceTrajParam tpSDparam = tpSD.GetParameters();
 66   // G4ThreeVector Psc = fPt * planeNormal +
 67   // tpSDparam.GetPU()*tpSDparam.GetVectorU() + tpSD.GetPV()*tpSD.GetVectorW();
 68 
 69   fTrajParam = G4ErrorFreeTrajParam(fPosition, fMomentum);
 70   Init();
 71 
 72   //----- Get the error matrix in SC coordinates
 73   G4ErrorSurfaceTrajParam tpSDparam = tpSD.GetParameters();
 74   G4double mom                      = fMomentum.mag();
 75   G4double mom2                     = fMomentum.mag2();
 76   G4double TVW1 =
 77     std::sqrt(mom2 / (mom2 + tpSDparam.GetPV() * tpSDparam.GetPV() +
 78                       tpSDparam.GetPW() * tpSDparam.GetPW()));
 79   G4ThreeVector vTVW(TVW1, tpSDparam.GetPV() / mom * TVW1,
 80                      tpSDparam.GetPW() / mom * TVW1);
 81   G4Vector3D vectorU = tpSDparam.GetVectorV().cross(tpSDparam.GetVectorW());
 82   G4Vector3D vTN     = vTVW.x() * vectorU + vTVW.y() * tpSDparam.GetVectorV() +
 83                    vTVW.z() * tpSDparam.GetVectorW();
 84 
 85 #ifdef G4EVERBOSE
 86   if(iverbose >= 5)
 87   {
 88     G4double pc2 = std::asin(vTN.z());
 89     G4double pc3 = std::atan(vTN.y() / vTN.x());
 90 
 91     G4cout << " CHECK: pc2 " << pc2 << " = " << GetParameters().GetLambda()
 92            << " diff " << pc2 - GetParameters().GetLambda() << G4endl;
 93     G4cout << " CHECK: pc3 " << pc3 << " = " << GetParameters().GetPhi()
 94            << " diff " << pc3 - GetParameters().GetPhi() << G4endl;
 95   }
 96 #endif
 97 
 98   //--- Get the unit vectors perp to P
 99   G4double cosl = std::cos(GetParameters().GetLambda());
100   if(cosl < 1.E-30)
101     cosl = 1.E-30;
102   G4double cosl1 = 1. / cosl;
103   G4Vector3D vUN(-vTN.y() * cosl1, vTN.x() * cosl1, 0.);
104   G4Vector3D vVN(-vTN.z() * vUN.y(), vTN.z() * vUN.x(), cosl);
105 
106   G4Vector3D vUperp = G4Vector3D(-fMomentum.y(), fMomentum.x(), 0.);
107   G4Vector3D vVperp = vUperp.cross(fMomentum);
108   vUperp *= 1. / vUperp.mag();
109   vVperp *= 1. / vVperp.mag();
110 
111 #ifdef G4EVERBOSE
112   if(iverbose >= 5)
113   {
114     G4cout << " CHECK: vUN " << vUN << " = " << vUperp << " diff "
115            << (vUN - vUperp).mag() << G4endl;
116     G4cout << " CHECK: vVN " << vVN << " = " << vVperp << " diff "
117            << (vVN - vVperp).mag() << G4endl;
118   }
119 #endif
120 
121   // get the dot products of vectors perpendicular to direction and vector
122   // defining SD plane
123   G4double dUU = vUperp * tpSD.GetVectorV();
124   G4double dUV = vUperp * tpSD.GetVectorW();
125   G4double dVU = vVperp * tpSD.GetVectorV();
126   G4double dVV = vVperp * tpSD.GetVectorW();
127 
128   //--- Get transformation first
129   G4ErrorMatrix transfM(5, 5, 1);
130   //--- Get magnetic field
131   const G4Field* field = G4TransportationManager::GetTransportationManager()
132                            ->GetFieldManager()
133                            ->GetDetectorField();
134   G4ThreeVector dir    = fTrajParam.GetDirection();
135   G4double invCosTheta = 1. / std::cos(dir.theta());
136   G4cout << " dir=" << dir << " invCosTheta " << invCosTheta << G4endl;
137 
138   if(fCharge != 0 && field)
139   {
140     G4double pos1[3];
141     pos1[0] = fPosition.x() * cm;
142     pos1[1] = fPosition.y() * cm;
143     pos1[2] = fPosition.z() * cm;
144     G4double h1[3];
145     field->GetFieldValue(pos1, h1);
146     G4ThreeVector HPre = G4ThreeVector(h1[0], h1[1], h1[2]) / tesla * 10.;
147     G4double magHPre   = HPre.mag();
148     G4double invP      = 1. / fMomentum.mag();
149     G4double magHPreM  = magHPre * invP;
150     if(magHPre != 0.)
151     {
152       G4double magHPreM2 = fCharge / magHPre;
153 
154       G4double Q    = -magHPreM * c_light;
155       G4double sinz = -HPre * vUperp * magHPreM2;
156       G4double cosz = HPre * vVperp * magHPreM2;
157 
158       transfM[1][3] = -Q * dir.y() * sinz;
159       transfM[1][4] = -Q * dir.z() * sinz;
160       transfM[2][3] = -Q * dir.y() * cosz * invCosTheta;
161       transfM[2][4] = -Q * dir.z() * cosz * invCosTheta;
162     }
163   }
164 
165   transfM[0][0] = 1.;
166   transfM[1][1] = dir.x() * dVU;
167   transfM[1][2] = dir.x() * dVV;
168   transfM[2][1] = dir.x() * dUU * invCosTheta;
169   transfM[2][2] = dir.x() * dUV * invCosTheta;
170   transfM[3][3] = dUU;
171   transfM[3][4] = dUV;
172   transfM[4][3] = dVU;
173   transfM[4][4] = dVV;
174 
175   fError = G4ErrorTrajErr(tpSD.GetError().similarity(transfM));
176 
177 #ifdef G4EVERBOSE
178   if(iverbose >= 1)
179     G4cout << "error matrix SD2SC " << fError << G4endl;
180   if(iverbose >= 4)
181     G4cout << "G4ErrorFreeTrajState from SD " << *this << G4endl;
182 #endif
183 }
184 
185 //------------------------------------------------------------------------
186 void G4ErrorFreeTrajState::Init()
187 {
188   theTSType = G4eTS_FREE;
189   BuildCharge();
190   theTransfMat = G4ErrorMatrix(5, 5, 0);
191   theFirstStep = true;
192 }
193 
194 //------------------------------------------------------------------------
195 void G4ErrorFreeTrajState::Dump(std::ostream& out) const { out << *this; }
196 
197 //------------------------------------------------------------------------
198 G4int G4ErrorFreeTrajState::Update(const G4Track* aTrack)
199 {
200   G4int ierr = 0;
201   fTrajParam.Update(aTrack);
202   UpdatePosMom(aTrack->GetPosition(), aTrack->GetMomentum());
203   return ierr;
204 }
205 
206 //------------------------------------------------------------------------
207 std::ostream& operator<<(std::ostream& out, const G4ErrorFreeTrajState& ts)
208 {
209   std::ios::fmtflags orig_flags = out.flags();
210 
211   out.setf(std::ios::fixed, std::ios::floatfield);
212 
213   ts.DumpPosMomError(out);
214 
215   out << " G4ErrorFreeTrajState: Params: " << ts.fTrajParam << G4endl;
216 
217   out.flags(orig_flags);
218 
219   return out;
220 }
221 
222 //------------------------------------------------------------------------
223 G4int G4ErrorFreeTrajState::PropagateError(const G4Track* aTrack)
224 {
225   G4double stepLengthCm = aTrack->GetStep()->GetStepLength() / cm;
226   if(G4ErrorPropagatorData::GetErrorPropagatorData()->GetStage() ==
227      G4ErrorStage_Deflation)
228     stepLengthCm *= -1.;
229 
230   G4double kCarTolerance =
231     G4GeometryTolerance::GetInstance()->GetSurfaceTolerance();
232 
233   if(std::fabs(stepLengthCm) <= kCarTolerance / cm)
234     return 0;
235 
236 #ifdef G4EVERBOSE
237   if(iverbose >= 2)
238     G4cout << "  G4ErrorFreeTrajState::PropagateError " << G4endl;
239   G4cout << "G4EP: iverbose=" << iverbose << G4endl;
240 #endif
241 
242   // * *** ERROR PROPAGATION ON A HELIX ASSUMING SC VARIABLES
243   G4Point3D vposPost = aTrack->GetPosition() / cm;
244   G4Vector3D vpPost  = aTrack->GetMomentum() / GeV;
245   //  G4Point3D vposPre = fPosition/cm;
246   //  G4Vector3D vpPre = fMomentum/GeV;
247   G4Point3D vposPre = aTrack->GetStep()->GetPreStepPoint()->GetPosition() / cm;
248   G4Vector3D vpPre  = aTrack->GetStep()->GetPreStepPoint()->GetMomentum() / GeV;
249   // correct to avoid propagation along Z
250   if(vpPre.mag() == vpPre.z())
251     vpPre.setX(1.E-6 * MeV);
252   if(vpPost.mag() == vpPost.z())
253     vpPost.setX(1.E-6 * MeV);
254 
255   G4double pPre  = vpPre.mag();
256   G4double pPost = vpPost.mag();
257 #ifdef G4EVERBOSE
258   if(iverbose >= 2)
259   {
260     G4cout << "G4EP: vposPre " << vposPre << G4endl << "G4EP: vposPost "
261            << vposPost << G4endl;
262     G4cout << "G4EP: vpPre " << vpPre << G4endl << "G4EP: vpPost " << vpPost
263            << G4endl;
264     G4cout << " err start step " << fError << G4endl;
265     G4cout << "G4EP: stepLengthCm " << stepLengthCm << G4endl;
266   }
267 #endif
268 
269   if(pPre == 0. || pPost == 0)
270     return 2;
271   G4double pInvPre   = 1. / pPre;
272   G4double pInvPost  = 1. / pPost;
273   G4double deltaPInv = pInvPost - pInvPre;
274   if(iverbose >= 2)
275     G4cout << "G4EP:  pInvPre" << pInvPre << "  pInvPost:" << pInvPost
276            << "  deltaPInv:" << deltaPInv << G4endl;
277 
278   G4Vector3D vpPreNorm  = vpPre * pInvPre;
279   G4Vector3D vpPostNorm = vpPost * pInvPost;
280   if(iverbose >= 2)
281     G4cout << "G4EP: vpPreNorm " << vpPreNorm << " vpPostNorm " << vpPostNorm
282            << G4endl;
283   // return if propagation along Z??
284   if(1. - std::fabs(vpPreNorm.z()) < kCarTolerance)
285     return 4;
286   if(1. - std::fabs(vpPostNorm.z()) < kCarTolerance)
287     return 4;
288   G4double sinpPre =
289     std::sin(vpPreNorm.theta());  // cosine perpendicular to pPre = sine pPre
290   G4double sinpPost =
291     std::sin(vpPostNorm.theta());  // cosine perpendicular to pPost = sine pPost
292   G4double sinpPostInv = 1. / std::sin(vpPostNorm.theta());
293 
294 #ifdef G4EVERBOSE
295   if(iverbose >= 2)
296     G4cout << "G4EP: cosl " << sinpPre << " cosl0 " << sinpPost << G4endl;
297 #endif
298   //* *** DEFINE TRANSFORMATION MATRIX BETWEEN X1 AND X2 FOR
299   //* *** NEUTRAL PARTICLE OR FIELDFREE REGION
300   G4ErrorMatrix transf(5, 5, 0);
301 
302   transf[3][2] = stepLengthCm * sinpPost;
303   transf[4][1] = stepLengthCm;
304   for(auto ii = 0; ii < 5; ++ii)
305   {
306     transf[ii][ii] = 1.;
307   }
308 #ifdef G4EVERBOSE
309   if(iverbose >= 2)
310   {
311     G4cout << "G4EP: transf matrix neutral " << transf;
312   }
313 #endif
314 
315   //  charge X propagation direction
316   G4double charge = aTrack->GetDynamicParticle()->GetCharge();
317   if(G4ErrorPropagatorData::GetErrorPropagatorData()->GetMode() ==
318      G4ErrorMode_PropBackwards)
319   {
320     charge *= -1.;
321   }
322   //  G4cout << " charge " << charge << G4endl;
323   // t check if particle has charge
324   // t  if( charge == 0 ) goto 45;
325   // check if the magnetic field is = 0.
326 
327   // position is from geant4, it is assumed to be in mm (for debugging,
328   // eventually it will not be transformed) it is assumed vposPre[] is in cm and
329   // pos1[] is in mm.
330   G4double pos1[3];
331   pos1[0] = vposPre.x() * cm;
332   pos1[1] = vposPre.y() * cm;
333   pos1[2] = vposPre.z() * cm;
334   G4double pos2[3];
335   pos2[0] = vposPost.x() * cm;
336   pos2[1] = vposPost.y() * cm;
337   pos2[2] = vposPost.z() * cm;
338   G4double h1[3], h2[3];
339 
340   const G4Field* field = G4TransportationManager::GetTransportationManager()
341                            ->GetFieldManager()
342                            ->GetDetectorField();
343   if(!field)
344     return 0;  // goto 45
345 
346   // calculate transformation except it NEUTRAL PARTICLE OR FIELDFREE REGION
347   if(charge != 0. && field)
348   {
349     field->GetFieldValue(pos1,
350                          h1);  // here pos1[], pos2[] are in mm, not changed
351     field->GetFieldValue(pos2, h2);
352     G4ThreeVector HPre =
353       G4ThreeVector(h1[0], h1[1], h1[2]) / tesla *
354       10.;  // 10. is to get same dimensions as GEANT3 (kilogauss)
355     G4ThreeVector HPost = G4ThreeVector(h2[0], h2[1], h2[2]) / tesla * 10.;
356     G4double magHPre    = HPre.mag();
357     G4double magHPost   = HPost.mag();
358 #ifdef G4EVERBOSE
359     if(iverbose >= 2)
360     {
361       G4cout << "G4EP: h1 = " << h1[0] << ", " << h1[1] << ", " << h1[2]
362              << G4endl;
363       G4cout << "G4EP: pos1/mm = " << pos1[0] << ", " << pos1[1] << ", "
364              << pos1[2] << G4endl;
365       G4cout << "G4EP: pos2/mm = " << pos2[0] << ", " << pos2[1] << ", "
366              << pos2[2] << G4endl;
367       G4cout << "G4EP: B-filed in KGauss HPre " << HPre << G4endl
368              << "G4EP: in KGauss HPost " << HPost << G4endl;
369     }
370 #endif
371 
372     if(magHPre + magHPost != 0.)
373     {
374       //* *** CHECK WHETHER H*ALFA/P IS TOO DIFFERENT AT X1 AND X2
375       G4double gam;
376       if(magHPost != 0.)
377       {
378         gam = HPost * vpPostNorm / magHPost;
379       }
380       else
381       {
382         gam = HPre * vpPreNorm / magHPre;
383       }
384 
385       // G4eMagneticLimitsProcess will limit the step, but based on an straight
386       // line trajectory
387       G4double alphaSqr  = 1. - gam * gam;
388       G4double diffHSqr  = (HPre * pInvPre - HPost * pInvPost).mag2();
389       G4double delhp6Sqr = 300. * 300.;
390 #ifdef G4EVERBOSE
391       if(iverbose >= 2)
392       {
393         G4cout << " G4EP: gam " << gam << " alphaSqr " << alphaSqr
394                << " diffHSqr " << diffHSqr << G4endl;
395         G4cout << " alpha= " << std::sqrt(alphaSqr) << G4endl;
396       }
397 #endif
398       if(diffHSqr * alphaSqr > delhp6Sqr)
399         return 3;
400 
401       //* *** DEFINE AVERAGE MAGNETIC FIELD AND GRADIENT
402       G4double pInvAver = 1. / (pInvPre + pInvPost);
403       G4double CFACT8   = 2.997925E-4;
404       // G4double HAver
405       G4ThreeVector vHAverNorm((HPre * pInvPre + HPost * pInvPost) * pInvAver *
406                                charge * CFACT8);
407       G4double HAver    = vHAverNorm.mag();
408       G4double invHAver = 1. / HAver;
409       vHAverNorm *= invHAver;
410 #ifdef G4EVERBOSE
411       if(iverbose >= 2)
412         G4cout << " G4EP: HaverNorm " << vHAverNorm << " magHAver " << HAver
413                << " charge " << charge << G4endl;
414 #endif
415 
416       G4double pAver        = (pPre + pPost) * 0.5;
417       G4double QAver        = -HAver / pAver;
418       G4double thetaAver    = QAver * stepLengthCm;
419       G4double sinThetaAver = std::sin(thetaAver);
420       G4double cosThetaAver = std::cos(thetaAver);
421       G4double gamma        = vHAverNorm * vpPostNorm;
422       G4ThreeVector AN2     = vHAverNorm.cross(vpPostNorm);
423 
424 #ifdef G4EVERBOSE
425       if(iverbose >= 2)
426         G4cout << " G4EP: AN2 " << AN2 << "  gamma:" << gamma
427                << "  theta=" << thetaAver << G4endl;
428 #endif
429       G4double AU = 1. / vpPreNorm.perp();
430       // t  G4ThreeVector vU( vpPreNorm.cross( G4ThreeVector(0.,0.,1.) ) * AU );
431       G4ThreeVector vUPre(-AU * vpPreNorm.y(), AU * vpPreNorm.x(), 0.);
432       G4ThreeVector vVPre(-vpPreNorm.z() * vUPre.y(), vpPreNorm.z() * vUPre.x(),
433                           vpPreNorm.x() * vUPre.y() -
434                             vpPreNorm.y() * vUPre.x());
435 
436       //
437       AU = 1. / vpPostNorm.perp();
438       // t  G4ThreeVector vU( vpPostNorm.cross( G4ThreeVector(0.,0.,1.) ) * AU
439       // );
440       G4ThreeVector vUPost(-AU * vpPostNorm.y(), AU * vpPostNorm.x(), 0.);
441       G4ThreeVector vVPost(
442         -vpPostNorm.z() * vUPost.y(), vpPostNorm.z() * vUPost.x(),
443         vpPostNorm.x() * vUPost.y() - vpPostNorm.y() * vUPost.x());
444 #ifdef G4EVERBOSE
445       G4cout << " vpPostNorm " << vpPostNorm << G4endl;
446       if(iverbose >= 2)
447         G4cout << " G4EP: AU " << AU << " vUPre " << vUPre << " vVPre " << vVPre
448                << " vUPost " << vUPost << " vVPost " << vVPost << G4endl;
449 #endif
450       G4Point3D deltaPos(vposPre - vposPost);
451 
452       // * *** COMPLETE TRANSFORMATION MATRIX BETWEEN ERRORS AT X1 AND X2
453       // * *** FIELD GRADIENT PERPENDICULAR TO TRACK IS PRESENTLY NOT
454       // * *** TAKEN INTO ACCOUNT
455 
456       G4double QP = QAver * pAver;  // = -HAver
457 #ifdef G4EVERBOSE
458       if(iverbose >= 2)
459         G4cout << " G4EP: QP " << QP << " QAver " << QAver << " pAver " << pAver
460                << G4endl;
461 #endif
462       G4double ANV =
463         -(vHAverNorm.x() * vUPost.x() + vHAverNorm.y() * vUPost.y());
464       G4double ANU =
465         (vHAverNorm.x() * vVPost.x() + vHAverNorm.y() * vVPost.y() +
466          vHAverNorm.z() * vVPost.z());
467       G4double OMcosThetaAver = 1. - cosThetaAver;
468 #ifdef G4EVERBOSE
469       if(iverbose >= 2)
470         G4cout << "G4EP: OMcosThetaAver " << OMcosThetaAver << " cosThetaAver "
471                << cosThetaAver << " thetaAver " << thetaAver << " QAver "
472                << QAver << " stepLengthCm " << stepLengthCm << G4endl;
473 #endif
474       G4double TMSINT = thetaAver - sinThetaAver;
475 #ifdef G4EVERBOSE
476       if(iverbose >= 2)
477         G4cout << " G4EP: ANV " << ANV << " ANU " << ANU << G4endl;
478 #endif
479 
480       G4ThreeVector vHUPre(
481         -vHAverNorm.z() * vUPre.y(), vHAverNorm.z() * vUPre.x(),
482         vHAverNorm.x() * vUPre.y() - vHAverNorm.y() * vUPre.x());
483 #ifdef G4EVERBOSE
484       //    if( iverbose >= 2 ) G4cout << "G4EP: HUPre(1) " << vHUPre.x() << " "
485       //    << vHAverNorm.z() << " " << vUPre.y() << G4endl;
486 #endif
487       G4ThreeVector vHVPre(
488         vHAverNorm.y() * vVPre.z() - vHAverNorm.z() * vVPre.y(),
489         vHAverNorm.z() * vVPre.x() - vHAverNorm.x() * vVPre.z(),
490         vHAverNorm.x() * vVPre.y() - vHAverNorm.y() * vVPre.x());
491 #ifdef G4EVERBOSE
492       if(iverbose >= 2)
493         G4cout << " G4EP: HUPre " << vHUPre << " HVPre " << vHVPre << G4endl;
494 #endif
495 
496       //------------------- COMPUTE MATRIX
497       //---------- 1/P
498 
499       transf[0][0] =
500         1. -
501         deltaPInv * pAver *
502           (1. + (vpPostNorm.x() * deltaPos.x() + vpPostNorm.y() * deltaPos.y() +
503                  vpPostNorm.z() * deltaPos.z()) /
504                   stepLengthCm) +
505         2. * deltaPInv * pAver;
506 
507       transf[0][1] =
508         -deltaPInv / thetaAver *
509         (TMSINT * gamma *
510            (vHAverNorm.x() * vVPre.x() + vHAverNorm.y() * vVPre.y() +
511             vHAverNorm.z() * vVPre.z()) +
512          sinThetaAver *
513            (vVPre.x() * vpPostNorm.x() + vVPre.y() * vpPostNorm.y() +
514             vVPre.z() * vpPostNorm.z()) +
515          OMcosThetaAver *
516            (vHVPre.x() * vpPostNorm.x() + vHVPre.y() * vpPostNorm.y() +
517             vHVPre.z() * vpPostNorm.z()));
518 
519       transf[0][2] =
520         -sinpPre * deltaPInv / thetaAver *
521         (TMSINT * gamma *
522            (vHAverNorm.x() * vUPre.x() + vHAverNorm.y() * vUPre.y()) +
523          sinThetaAver *
524            (vUPre.x() * vpPostNorm.x() + vUPre.y() * vpPostNorm.y()) +
525          OMcosThetaAver *
526            (vHUPre.x() * vpPostNorm.x() + vHUPre.y() * vpPostNorm.y() +
527             vHUPre.z() * vpPostNorm.z()));
528 
529       transf[0][3] = -deltaPInv / stepLengthCm *
530                      (vUPre.x() * vpPostNorm.x() + vUPre.y() * vpPostNorm.y());
531 
532       transf[0][4] = -deltaPInv / stepLengthCm *
533                      (vVPre.x() * vpPostNorm.x() + vVPre.y() * vpPostNorm.y() +
534                       vVPre.z() * vpPostNorm.z());
535 
536       // ***   Lambda
537       transf[1][0] =
538         -QP * ANV *
539         (vpPostNorm.x() * deltaPos.x() + vpPostNorm.y() * deltaPos.y() +
540          vpPostNorm.z() * deltaPos.z()) *
541         (1. + deltaPInv * pAver);
542 #ifdef G4EVERBOSE
543       if(iverbose >= 3)
544         G4cout << "ctransf10= " << transf[1][0] << " " << -QP << " " << ANV
545                << " " << vpPostNorm.x() << " " << deltaPos.x() << " "
546                << vpPostNorm.y() << " " << deltaPos.y() << " " << vpPostNorm.z()
547                << " " << deltaPos.z() << " " << deltaPInv << " " << pAver
548                << G4endl;
549 #endif
550 
551       transf[1][1] =
552         cosThetaAver * (vVPre.x() * vVPost.x() + vVPre.y() * vVPost.y() +
553                         vVPre.z() * vVPost.z()) +
554         sinThetaAver * (vHVPre.x() * vVPost.x() + vHVPre.y() * vVPost.y() +
555                         vHVPre.z() * vVPost.z()) +
556         OMcosThetaAver *
557           (vHAverNorm.x() * vVPre.x() + vHAverNorm.y() * vVPre.y() +
558            vHAverNorm.z() * vVPre.z()) *
559           (vHAverNorm.x() * vVPost.x() + vHAverNorm.y() * vVPost.y() +
560            vHAverNorm.z() * vVPost.z()) +
561         ANV * (-sinThetaAver *
562                  (vVPre.x() * vpPostNorm.x() + vVPre.y() * vpPostNorm.y() +
563                   vVPre.z() * vpPostNorm.z()) +
564                OMcosThetaAver * (vVPre.x() * AN2.x() + vVPre.y() * AN2.y() +
565                                  vVPre.z() * AN2.z()) -
566                TMSINT * gamma *
567                  (vHAverNorm.x() * vVPre.x() + vHAverNorm.y() * vVPre.y() +
568                   vHAverNorm.z() * vVPre.z()));
569 
570       transf[1][2] =
571         cosThetaAver * (vUPre.x() * vVPost.x() + vUPre.y() * vVPost.y()) +
572         sinThetaAver * (vHUPre.x() * vVPost.x() + vHUPre.y() * vVPost.y() +
573                         vHUPre.z() * vVPost.z()) +
574         OMcosThetaAver *
575           (vHAverNorm.x() * vUPre.x() + vHAverNorm.y() * vUPre.y()) *
576           (vHAverNorm.x() * vVPost.x() + vHAverNorm.y() * vVPost.y() +
577            vHAverNorm.z() * vVPost.z()) +
578         ANV * (-sinThetaAver *
579                  (vUPre.x() * vpPostNorm.x() + vUPre.y() * vpPostNorm.y()) +
580                OMcosThetaAver * (vUPre.x() * AN2.x() + vUPre.y() * AN2.y()) -
581                TMSINT * gamma *
582                  (vHAverNorm.x() * vUPre.x() + vHAverNorm.y() * vUPre.y()));
583       transf[1][2] = sinpPre * transf[1][2];
584 
585       transf[1][3] = -QAver * ANV *
586                      (vUPre.x() * vpPostNorm.x() + vUPre.y() * vpPostNorm.y());
587 
588       transf[1][4] = -QAver * ANV *
589                      (vVPre.x() * vpPostNorm.x() + vVPre.y() * vpPostNorm.y() +
590                       vVPre.z() * vpPostNorm.z());
591 
592       // ***   Phi
593 
594       transf[2][0] =
595         -QP * ANU *
596         (vpPostNorm.x() * deltaPos.x() + vpPostNorm.y() * deltaPos.y() +
597          vpPostNorm.z() * deltaPos.z()) *
598         sinpPostInv * (1. + deltaPInv * pAver);
599 #ifdef G4EVERBOSE
600       if(iverbose >= 3)
601         G4cout << "ctransf20= " << transf[2][0] << " " << -QP << " " << ANU
602                << " " << vpPostNorm.x() << " " << deltaPos.x() << " "
603                << vpPostNorm.y() << " " << deltaPos.y() << " " << vpPostNorm.z()
604                << " " << deltaPos.z() << " " << sinpPostInv << " " << deltaPInv
605                << " " << pAver << G4endl;
606 #endif
607       transf[2][1] =
608         cosThetaAver * (vVPre.x() * vUPost.x() + vVPre.y() * vUPost.y()) +
609         sinThetaAver * (vHVPre.x() * vUPost.x() + vHVPre.y() * vUPost.y()) +
610         OMcosThetaAver *
611           (vHAverNorm.x() * vVPre.x() + vHAverNorm.y() * vVPre.y() +
612            vHAverNorm.z() * vVPre.z()) *
613           (vHAverNorm.x() * vUPost.x() + vHAverNorm.y() * vUPost.y()) +
614         ANU * (-sinThetaAver *
615                  (vVPre.x() * vpPostNorm.x() + vVPre.y() * vpPostNorm.y() +
616                   vVPre.z() * vpPostNorm.z()) +
617                OMcosThetaAver * (vVPre.x() * AN2.x() + vVPre.y() * AN2.y() +
618                                  vVPre.z() * AN2.z()) -
619                TMSINT * gamma *
620                  (vHAverNorm.x() * vVPre.x() + vHAverNorm.y() * vVPre.y() +
621                   vHAverNorm.z() * vVPre.z()));
622       transf[2][1] = sinpPostInv * transf[2][1];
623 
624       transf[2][2] =
625         cosThetaAver * (vUPre.x() * vUPost.x() + vUPre.y() * vUPost.y()) +
626         sinThetaAver * (vHUPre.x() * vUPost.x() + vHUPre.y() * vUPost.y()) +
627         OMcosThetaAver *
628           (vHAverNorm.x() * vUPre.x() + vHAverNorm.y() * vUPre.y()) *
629           (vHAverNorm.x() * vUPost.x() + vHAverNorm.y() * vUPost.y()) +
630         ANU * (-sinThetaAver *
631                  (vUPre.x() * vpPostNorm.x() + vUPre.y() * vpPostNorm.y()) +
632                OMcosThetaAver * (vUPre.x() * AN2.x() + vUPre.y() * AN2.y()) -
633                TMSINT * gamma *
634                  (vHAverNorm.x() * vUPre.x() + vHAverNorm.y() * vUPre.y()));
635       transf[2][2] = sinpPostInv * sinpPre * transf[2][2];
636 
637       transf[2][3] = -QAver * ANU *
638                      (vUPre.x() * vpPostNorm.x() + vUPre.y() * vpPostNorm.y()) *
639                      sinpPostInv;
640 #ifdef G4EVERBOSE
641       if(iverbose >= 3)
642         G4cout << "ctransf23= " << transf[2][3] << " " << -QAver << " " << ANU
643                << " " << vUPre.x() << " " << vpPostNorm.x() << " " << vUPre.y()
644                << " " << vpPostNorm.y() << " " << sinpPostInv << G4endl;
645 #endif
646 
647       transf[2][4] = -QAver * ANU *
648                      (vVPre.x() * vpPostNorm.x() + vVPre.y() * vpPostNorm.y() +
649                       vVPre.z() * vpPostNorm.z()) *
650                      sinpPostInv;
651 
652       // ***   Yt
653 
654       transf[3][0] = pAver *
655                      (vUPost.x() * deltaPos.x() + vUPost.y() * deltaPos.y()) *
656                      (1. + deltaPInv * pAver);
657 #ifdef G4EVERBOSE
658       if(iverbose >= 3)
659         G4cout << "ctransf30= " << transf[3][0] << " " << pAver << " "
660                << vUPost.x() << " " << deltaPos.x() << " " << vUPost.y() << " "
661                << deltaPos.y() << " " << deltaPInv << " " << pAver << G4endl;
662 #endif
663 
664       transf[3][1] =
665         (sinThetaAver * (vVPre.x() * vUPost.x() + vVPre.y() * vUPost.y()) +
666          OMcosThetaAver * (vHVPre.x() * vUPost.x() + vHVPre.y() * vUPost.y()) +
667          TMSINT * (vHAverNorm.x() * vUPost.x() + vHAverNorm.y() * vUPost.y()) *
668            (vHAverNorm.x() * vVPre.x() + vHAverNorm.y() * vVPre.y() +
669             vHAverNorm.z() * vVPre.z())) /
670         QAver;
671 
672       transf[3][2] =
673         (sinThetaAver * (vUPre.x() * vUPost.x() + vUPre.y() * vUPost.y()) +
674          OMcosThetaAver * (vHUPre.x() * vUPost.x() + vHUPre.y() * vUPost.y()) +
675          TMSINT * (vHAverNorm.x() * vUPost.x() + vHAverNorm.y() * vUPost.y()) *
676            (vHAverNorm.x() * vUPre.x() + vHAverNorm.y() * vUPre.y())) *
677         sinpPre / QAver;
678 #ifdef G4EVERBOSE
679       if(iverbose >= 3)
680         G4cout << "ctransf32= " << transf[3][2] << " " << sinThetaAver << " "
681                << vUPre.x() << " " << vUPost.x() << " " << vUPre.y() << " "
682                << vUPost.y() << " " << OMcosThetaAver << " " << vHUPre.x()
683                << " " << vUPost.x() << " " << vHUPre.y() << " " << vUPost.y()
684                << " " << TMSINT << " " << vHAverNorm.x() << " " << vUPost.x()
685                << " " << vHAverNorm.y() << " " << vUPost.y() << " "
686                << vHAverNorm.x() << " " << vUPre.x() << " " << vHAverNorm.y()
687                << " " << vUPre.y() << " " << sinpPre << " " << QAver << G4endl;
688 #endif
689 
690       transf[3][3] = (vUPre.x() * vUPost.x() + vUPre.y() * vUPost.y());
691 
692       transf[3][4] = (vVPre.x() * vUPost.x() + vVPre.y() * vUPost.y());
693 
694       // ***   Zt
695       transf[4][0] = pAver *
696                      (vVPost.x() * deltaPos.x() + vVPost.y() * deltaPos.y() +
697                       vVPost.z() * deltaPos.z()) *
698                      (1. + deltaPInv * pAver);
699 
700       transf[4][1] =
701         (sinThetaAver * (vVPre.x() * vVPost.x() + vVPre.y() * vVPost.y() +
702                          vVPre.z() * vVPost.z()) +
703          OMcosThetaAver * (vHVPre.x() * vVPost.x() + vHVPre.y() * vVPost.y() +
704                            vHVPre.z() * vVPost.z()) +
705          TMSINT *
706            (vHAverNorm.x() * vVPost.x() + vHAverNorm.y() * vVPost.y() +
707             vHAverNorm.z() * vVPost.z()) *
708            (vHAverNorm.x() * vVPre.x() + vHAverNorm.y() * vVPre.y() +
709             vHAverNorm.z() * vVPre.z())) /
710         QAver;
711 #ifdef G4EVERBOSE
712       if(iverbose >= 3)
713         G4cout << "ctransf41= " << transf[4][1] << " " << sinThetaAver << " "
714                << OMcosThetaAver << " " << TMSINT << " " << vVPre << " "
715                << vVPost << " " << vHVPre << " " << vHAverNorm << " " << QAver
716                << G4endl;
717 #endif
718 
719       transf[4][2] =
720         (sinThetaAver * (vUPre.x() * vVPost.x() + vUPre.y() * vVPost.y()) +
721          OMcosThetaAver * (vHUPre.x() * vVPost.x() + vHUPre.y() * vVPost.y() +
722                            vHUPre.z() * vVPost.z()) +
723          TMSINT *
724            (vHAverNorm.x() * vVPost.x() + vHAverNorm.y() * vVPost.y() +
725             vHAverNorm.z() * vVPost.z()) *
726            (vHAverNorm.x() * vUPre.x() + vHAverNorm.y() * vUPre.y())) *
727         sinpPre / QAver;
728 
729       transf[4][3] = (vUPre.x() * vVPost.x() + vUPre.y() * vVPost.y());
730 
731       transf[4][4] = (vVPre.x() * vVPost.x() + vVPre.y() * vVPost.y() +
732                       vVPre.z() * vVPost.z());
733       //   if(iverbose >= 3) G4cout <<"ctransf44= " << transf[4][4] <<" "<<
734       //   vVPre.x()  <<" "<<vVPost.x() <<" "<< vVPre.y() <<" "<< vVPost.y() <<"
735       //   "<< vVPre.z() <<" "<< vVPost.z() << G4endl;
736 
737 #ifdef G4EVERBOSE
738       if(iverbose >= 1)
739         G4cout << "G4EP: transf matrix computed " << transf << G4endl;
740 #endif
741       /*    for( G4int ii=0;ii<5;ii++){
742         for( G4int jj=0;jj<5;jj++){
743           G4cout << transf[ii][jj] << " ";
744         }
745         G4cout << G4endl;
746         } */
747     }
748   }
749   // end of calculate transformation except it NEUTRAL PARTICLE OR FIELDFREE
750   // REGION
751   /*  if( iverbose >= 1 ) G4cout << "G4EP: transf not updated but initialized "
752   << theFirstStep << G4endl; if( theFirstStep ) { theTransfMat = transf;
753     theFirstStep = false;
754   }else{
755     theTransfMat = theTransfMat * transf;
756     if( iverbose >= 1 ) G4cout << "G4EP: transf matrix accumulated" <<
757   theTransfMat << G4endl;
758   }
759   */
760   theTransfMat = std::move(transf);
761 #ifdef G4EVERBOSE
762   if(iverbose >= 1)
763     G4cout << "G4EP: error matrix before transformation " << fError << G4endl;
764   if(iverbose >= 2)
765     G4cout << " tf * err " << theTransfMat * fError << G4endl
766            << " transf matrix " << theTransfMat.T() << G4endl;
767 #endif
768 
769   fError = fError.similarity(theTransfMat).T();
770   //-    fError = transf * fError * transf.T();
771 #ifdef G4EVERBOSE
772   if(iverbose >= 1)
773     G4cout << "G4EP: error matrix propagated " << fError << G4endl;
774 #endif
775 
776   //? S = B*S*BT S.similarity(B)
777   //? R = S
778   // not needed * *** TRANSFORM ERROR MATRIX FROM INTERNAL TO EXTERNAL
779   // VARIABLES;
780 
781   PropagateErrorMSC(aTrack);
782 
783   PropagateErrorIoni(aTrack);
784 
785   return 0;
786 }
787 
788 //------------------------------------------------------------------------
789 G4int G4ErrorFreeTrajState::PropagateErrorMSC(const G4Track* aTrack)
790 {
791   G4ThreeVector vpPre   = aTrack->GetMomentum() / GeV;
792   G4double pPre         = vpPre.mag();
793   G4double pBeta        = pPre * pPre / (aTrack->GetTotalEnergy() / GeV);
794   G4double stepLengthCm = aTrack->GetStep()->GetStepLength() / cm;
795 
796   G4Material* mate = aTrack->GetVolume()->GetLogicalVolume()->GetMaterial();
797   G4double effZ, effA;
798   CalculateEffectiveZandA(mate, effZ, effA);
799 
800 #ifdef G4EVERBOSE
801   if(iverbose >= 4)
802     G4cout << "material "
803            << mate->GetName()
804            //<< " " << mate->GetZ() << " "  << mate->GetA()
805            << " effZ:" << effZ << " effA:" << effA
806            << " dens(g/mole):" << mate->GetDensity() / g * mole
807            << " Radlen/cm:" << mate->GetRadlen() / cm << " nuclLen/cm"
808            << mate->GetNuclearInterLength() / cm << G4endl;
809 #endif
810 
811   G4double RI = stepLengthCm / (mate->GetRadlen() / cm);
812 #ifdef G4EVERBOSE
813   if(iverbose >= 4)
814     G4cout << std::setprecision(6) << std::setw(6) << "G4EP:MSC: RI=X/X0 " << RI
815            << " stepLengthCm " << stepLengthCm << " radlen/cm "
816            << (mate->GetRadlen() / cm) << " RI*1.e10:" << RI * 1.e10 << G4endl;
817 #endif
818   G4double charge = aTrack->GetDynamicParticle()->GetCharge();
819   G4double DD     = 1.8496E-4 * RI * (charge / pBeta * charge / pBeta);
820 #ifdef G4EVERBOSE
821   if(iverbose >= 3)
822     G4cout << "G4EP:MSC: D*1E6= " << DD * 1.E6 << " pBeta " << pBeta << G4endl;
823 #endif
824   G4double S1 = DD * stepLengthCm * stepLengthCm / 3.;
825   G4double S2 = DD;
826   G4double S3 = DD * stepLengthCm / 2.;
827 
828   G4double CLA =
829     std::sqrt(vpPre.x() * vpPre.x() + vpPre.y() * vpPre.y()) / pPre;
830 #ifdef G4EVERBOSE
831   if(iverbose >= 2)
832     G4cout << std::setw(6) << "G4EP:MSC: RI " << RI << " S1 " << S1 << " S2 "
833            << S2 << " S3 " << S3 << " CLA " << CLA << G4endl;
834 #endif
835   fError[1][1] += S2;
836   fError[1][4] -= S3;
837   fError[2][2] += S2 / CLA / CLA;
838   fError[2][3] += S3 / CLA;
839   fError[3][3] += S1;
840   fError[4][4] += S1;
841 
842 #ifdef G4EVERBOSE
843   if(iverbose >= 2)
844     G4cout << "G4EP:MSC: error matrix propagated msc " << fError << G4endl;
845 #endif
846 
847   return 0;
848 }
849 
850 //------------------------------------------------------------------------
851 void G4ErrorFreeTrajState::CalculateEffectiveZandA(const G4Material* mate,
852                                                    G4double& effZ,
853                                                    G4double& effA)
854 {
855   effZ = 0.;
856   effA = 0.;
857   auto nelem = mate->GetNumberOfElements();
858   const G4double* fracVec = mate->GetFractionVector();
859   for(G4int ii = 0; ii < (G4int)nelem; ++ii)
860   {
861     effZ += mate->GetElement(ii)->GetZ() * fracVec[ii];
862     effA += mate->GetElement(ii)->GetA() * fracVec[ii] / g * mole;
863   }
864 }
865 
866 //------------------------------------------------------------------------
867 G4int G4ErrorFreeTrajState::PropagateErrorIoni(const G4Track* aTrack)
868 {
869   G4double stepLengthCm = aTrack->GetStep()->GetStepLength() / cm;
870 #ifdef G4EVERBOSE
871   G4double DEDX2;
872   if(stepLengthCm < 1.E-7)
873   {
874     DEDX2 = 0.;
875   }
876 #endif
877   //  *     Calculate xi factor (KeV).
878   G4Material* mate = aTrack->GetVolume()->GetLogicalVolume()->GetMaterial();
879   G4double effZ, effA;
880   CalculateEffectiveZandA(mate, effZ, effA);
881 
882   G4double Etot  = aTrack->GetTotalEnergy() / GeV;
883   G4double beta  = aTrack->GetMomentum().mag() / GeV / Etot;
884   G4double mass  = aTrack->GetDynamicParticle()->GetMass() / GeV;
885   G4double gamma = Etot / mass;
886 
887   // *     Calculate xi factor (keV).
888   G4double XI = 153.5 * effZ * stepLengthCm * (mate->GetDensity() / mg * mole) /
889                 (effA * beta * beta);
890 
891 #ifdef G4EVERBOSE
892   if(iverbose >= 2)
893   {
894     G4cout << "G4EP:IONI: XI/keV " << XI << " beta " << beta << " gamma "
895            << gamma << G4endl;
896     G4cout << " density " << (mate->GetDensity() / mg * mole) << " effA "
897            << effA << " step " << stepLengthCm << G4endl;
898   }
899 #endif
900   // *     Maximum energy transfer to atomic electron (KeV).
901   G4double eta       = beta * gamma;
902   G4double etasq     = eta * eta;
903   G4double eMass     = 0.51099906 / GeV;
904   G4double massRatio = eMass / mass;
905   G4double F1        = 2 * eMass * etasq;
906   G4double F2        = 1. + 2. * massRatio * gamma + massRatio * massRatio;
907   G4double Emax      = 1.E+6 * F1 / F2;  // now in keV
908 
909   //  * *** and now sigma**2  in GeV
910   G4double dedxSq =
911     XI * Emax * (1. - (beta * beta / 2.)) * 1.E-12;  // now in GeV^2
912   /*The above  formula for var(1/p) good for dens scatterers. However, for MIPS
913     passing through a gas it leads to overestimation. Further more for incident
914     electrons the Emax is almost equal to incident energy. This leads  to
915     k=Xi/Emax  as small as e-6  and gradually the cov matrix  explodes.
916 
917     http://www2.pv.infn.it/~rotondi/kalman_1.pdf
918 
919     Since I do not have enough info at the moment to implement Landau &
920     sub-Landau models for k=Xi/Emax <0.01 I'll saturate k at this value for now
921   */
922 
923   if(XI / Emax < 0.01)
924     dedxSq *=
925       XI / Emax * 100;  // Quench for low Elos, see above: newVar=odVar *k/0.01
926 
927 #ifdef G4EVERBOSE
928   if(iverbose >= 2)
929     G4cout << "G4EP:IONI: DEDX^2(GeV^2) " << dedxSq << " emass/GeV: " << eMass
930            << " Emax/keV: " << Emax << "  k=Xi/Emax=" << XI / Emax << G4endl;
931 
932 #endif
933 
934   G4double pPre6 =
935     (aTrack->GetStep()->GetPreStepPoint()->GetMomentum() / GeV).mag();
936   pPre6 = std::pow(pPre6, 6);
937   // Apply it to error
938   fError[0][0] += Etot * Etot * dedxSq / pPre6;
939 #ifdef G4EVERBOSE
940   if(iverbose >= 2)
941     G4cout << "G4:IONI Etot/GeV: " << Etot << " err_dedx^2/GeV^2: " << dedxSq
942            << " p^6: " << pPre6 << G4endl;
943   if(iverbose >= 2)
944     G4cout << "G4EP:IONI: error2_from_ionisation "
945            << (Etot * Etot * dedxSq) / pPre6 << G4endl;
946 #endif
947 
948   return 0;
949 }
950