Main Page   Compound List   File List   Compound Members   File Members  

MuonPropagator Class Reference

MuonPropogator handles muon transit for ReactorEvent. More...

#include <MuonPropagator.hh>

List of all members.

Public Methods

 MuonPropagator (double newRmaxgen=RMAXGEN, double newDepth=450., double newEnergy=0., double newCosTheta=1.)
 MuonPropagator constructor. More...

 MuonPropagator (int test=0, double newRmaxgen=RMAXGEN, double newEnergy=0., double newX=0., double newY=0., double newZ=0., double newVx=0., double newVy=0., double newVz=0.)
 ~MuonPropagator ()
 MuonPropagator destructor.

 MuonPropagator (const MuonPropagator &Muon)
 MuonPropagator copy constructor.

MuonPropagator & operator= (const MuonPropagator &rhs)
 MuonPropagator overloaded = operator.

double * Intersection (double, double, double, double, double, double, double, double, double, double)
double * Rotate (char, double, double, double, double)
double RadCorr (double, double)
double GetMuonE () const
double GetMuonCosTheta () const
double GetMuonPhi () const
int GetNumNeutron () const
 Returns the neutron multiplicity.

double GetNeutronKE (int &n) const
double GetNeutronTime (int &n) const
double *const GetNeutronVertexXYZ ()
int GetNumElectron () const
 Returns the electron multiplicity.

double GetElectronKE (int &n) const
double GetElectronTime (int &n) const
double *const GetElectronVertexXYZ ()
int GetNumGamma () const
 Returns the number of photons.

double GetGammaKE (int &n) const
double GetGammaTime (int &n) const
double *const GetGammaVertexXYZ ()
double GetWeight () const

Static Public Methods

float IsotopeDistance (const float &r)
 The lateral activation profile of muons passing through the detector to produce radioactive isotopes, which describes the probability that an isotope is produced at a given distance r (in cm) perpendicular to the muon track.


Detailed Description

MuonPropogator handles muon transit for ReactorEvent.

It returns particle information from the muon itself, as well as any byproducts of the muon shower, including neutrons and electrons from 9Li/8He beta decay.

Definition at line 17 of file MuonPropagator.hh.


Constructor & Destructor Documentation

MuonPropagator::MuonPropagator double    newRmaxgen = RMAXGEN,
double    newDepth = 450.,
double    newEnergy = 0.,
double    newCosTheta = 1.
 

MuonPropagator constructor.

Generates a muon from a given energy and zenith angle. The muon starts at a random point above the detector and at a random azimuthal angle to decide the path of the muon track. Energy from the muon inside the detector is created incrementally along the muon tragectory as optical photons. One heavy isotope 9Li or 8He is produced per muon from the muon spallation and forced to beta decay to create and electron and neutron. The events are weighted by the 9Li/8He production cross sections and the decay branching ratio of the 9Li/8He beta decay. The neutron, electron, and photon energies, positions and times are saved.

Definition at line 402 of file MuonPropagator.cpp.

References MyHeSource::GetHeBetaEnergy, MyHeSource::GetHeDecayTime, MyHeSource::GetHeNeutronEnergy, MyLiSource::GetLiBetaEnergy, MyLiSource::GetLiDecayTime, MyLiSource::GetLiNeutronEnergy, and IsotopeDistance.

00405                                                   {
00406 
00407   Rmaxgen = newRmaxgen;
00408   Depth = newDepth;
00409   energy = newEnergy;
00410   cosg = newCosTheta;
00411 
00412   //cout << "MuonPropagator::MuonPropagator(" << Rmaxgen << "," 
00413   //     << Depth << "," << energy << "," << cosg << ")" << endl;
00414 
00415   static double re  = RELECTRON;
00416   static double me  = MELECTRON;
00417   static double mmu = MMUON;
00418   static double Na  = NAVOGADRO;
00419   //
00420   // For electron density
00421   //
00422   static double nel[2];
00423   static double A[2] = {A0,A1};
00424   static double Z[2] = {Z0,Z1};
00425   static double f[2] = {f0,f1};
00426   static double I[2] = {I0,I1};
00427   //
00428   static double ncar;
00429   //
00430   // calculate the fluxes and densities
00431   //
00432   bool static first = true;
00433   double flux;
00434   int static muonstop;
00435   float static fspace[200];
00436   //
00437   if(first){
00438 
00439     // flux information
00440     if(Depth == 300.)
00441       flux = 0.374;  // per m**2 per sec
00442     else if(Depth == 450.)
00443       flux = 0.160;  // per m**2 per sec
00444     else if(Depth == 500.)
00445       flux = 0.145;  // per m**2 per sec
00446     else{
00447       cout << "  ERROR: no muon flux for depth of " << Depth << " mwe" << endl;
00448       return;
00449     }
00450   
00451     // electron density
00452     for(int i=0;i<2;i++) nel[i] = Na*density*f[i]*Z[i]/A[i];
00453     //cout << " nel " << nel[0]+nel[1] << endl;
00454       
00455     // 12C atom density
00456     ncar = Na*density*f[1]/A[1];
00457     //cout << " ncar " << ncar << endl;
00458       
00459     // prepare the lateral activation profile
00460     float xlo = 0.;
00461     float xhi = 50.;
00462     funlxp_(IsotopeDistance,fspace,xlo,xhi);
00463       
00464     Weight = 0.;
00465     muonstop = 0;
00466   
00467     first = false;
00468   }
00469 
00470   /* pick a starting point: define a square above the detector
00471      through which the muons must pass.  The square is centered 
00472      on the z-axis at Rmaxgen and the area is A = (Rmaxgen+delta)**2.  
00473      Randomly pick a point on the square to start the muon and use 
00474      cos(theta) and a randomly selected azimuthal angle to decide
00475      how the muon hits the detector.  Only keep events where the
00476      muon hits the scint.
00477   */
00478   int inter = 0;
00479   double r[6],t[3];
00480   double x[2],y[2],z[2];
00481   double delta = Rmaxgen*20.;
00482   bool passed = false;
00483   //
00484   while(!passed){
00485 
00486     const int len=3;
00487     float rv[len];
00488     ranlux_(rv,len);
00489     r[0] = (2*rv[0]-1)*delta;
00490     r[1] = (2*rv[1]-1)*delta;
00491     r[2] = Rmaxgen;
00492     phig = 2*PI*rv[2];
00493 
00494     // pick the direction
00495     t[0] = cos(phig)*sqrt(1-cosg*cosg);
00496     t[1] = sin(phig)*sqrt(1-cosg*cosg);
00497     t[2] = cosg;
00498     //for(int i=0;i<3;i++) cout << "t["<<i<<"] " << t[i] << " ";
00499     //cout << endl;
00500 
00501     // find the far end of the line a unit distance
00502     // from (x,y,z) along the t direction
00503     for(int i=0;i<3;i++) r[i+3] = r[i]-t[i];
00504     //
00505     //for(int i=0;i<6;i++) cout << "r["<<i<<"] " << r[i] << " ";
00506     //cout << endl;
00507 
00508     // solve for intersections with the scint region
00509     double p[7];
00510     double* ptr = p;
00511     int num;
00512 
00513     ptr = Intersection(r[0], r[1], r[2],  // first end of line
00514                        r[3], r[4], r[5],  // second end of line
00515                        0, 0, 0, Rmaxgen); // detector centered at 0
00516 
00517     num = (int)*ptr++;
00518     if(num>1){
00519 
00520       inter = 2;
00521       for(int i=0; i<inter; i++){
00522         x[i] = *ptr++;
00523         y[i] = *ptr++;
00524         z[i] = *ptr++;
00525       }
00526       passed = true;
00527     }
00528   }
00529   /*
00530   for(int i=0; i<inter; i++){
00531     cout << " X-coordinate of point " << i << " : " << x[i] << endl;
00532     cout << " Y-coordinate of point " << i << " : " << y[i] << endl;
00533     cout << " Z-coordinate of point " << i << " : " << z[i] << endl;
00534   }
00535   */
00536   // path length
00537   double L = sqrt((x[1]-x[0])*(x[1]-x[0])+
00538                   (y[1]-y[0])*(y[1]-y[0])+
00539                   (z[1]-z[0])*(z[1]-z[0]));
00540   //cout << " path length " << L << endl;
00541 
00542   /* iterate through the muon energy loss dE/dx in dx cm steps,
00543      making a gamma at the center of the dx cm segment of the 
00544      line along the muon path equal to the energy lost in that 
00545      segment; always check that the muon is still in the 
00546      detector and has not stopped
00547   */
00548   double step=5.0;
00549   double Emin=0.01;
00550   //
00551   double range = 0.;
00552   double time = 0.;
00553   //
00554   // define energy and position arrays
00555   //
00556   int maxgammafromisotope = 5;
00557   int maxgamma = int(Rmaxgen*2/step)+maxgammafromisotope;
00558   double* egamma = new double[maxgamma];
00559   double* rgamma = new double[maxgamma*3];
00560   double* tgamma = new double[maxgamma];
00561   //
00562   double* egptr=egamma;
00563   double* rgptr=rgamma;
00564   double* tgptr=tgamma;
00565   //
00566   // Begin energy loss loop
00567   //
00568   double dE=0;
00569   double eloss;
00570   int ngamma = 0;
00571   //
00572   bool done = false;
00573   while(!done){
00574 
00575     // zero the energy loss for this segment
00576     eloss = 0;
00577     //
00578     // check that the muon hasn't stopped
00579     //
00580     if(energy-dE > Emin){
00581       //
00582       // check that we aren't leaving the detector
00583       //
00584       if(range+step < L){
00585         //
00586         // iterate range and time
00587         //
00588         double gamma = 1+(energy-dE)/mmu;
00589         double beta = sqrt(1-1/gamma/gamma);
00590         range+=step;
00591         time+=step/beta/c;
00592         //
00593         // increment energy loss
00594         //
00595         double te = gamma-1;
00596         double tc = Emin/mmu;
00597         double tmax = te;
00598         double tup = tc;
00599         if(tc>tmax)tup=tmax;
00600         //
00601         for (int k=0;k<2;k++){
00602           eloss+=2*PI*re*re*me*nel[k]*step/beta/beta*
00603             (log(2*(gamma+1)/(I[k]*I[k]/me/me))
00604              +RadCorr(te,tup));
00605         }
00606         //
00607         // add the energy loss to dE and set the "photon" energy
00608         //
00609         if(dE+eloss > energy){
00610           *egptr++=energy-dE; // the muon stops, limit dE and egamma
00611           dE=energy;
00612         }
00613         else{
00614           *egptr++=eloss; // the muon is still travelling
00615           dE+=eloss;
00616         }
00617         //
00618         // put the photon at the center of the segment
00619         //
00620         *rgptr++ = x[1] - (range-(step/2))*t[0];
00621         *rgptr++ = y[1] - (range-(step/2))*t[1];
00622         *rgptr++ = z[1] - (range-(step/2))*t[2];
00623         //
00624         *tgptr++ = time;
00625         //
00626         // count the photon
00627         ngamma++;
00628       }
00629       else{
00630         /* we have reached the end of the detector; put one final 
00631            gamma to cover the last remaining segment of energy loss
00632         */
00633         double laststep = L-range;
00634         //
00635         double gamma = 1+(energy-dE)/mmu;
00636         double beta = sqrt(1-1/gamma/gamma);
00637         range+=laststep;
00638         time+=laststep/beta/c;
00639         //
00640         // increment energy loss
00641         //
00642         double te = gamma-1;
00643         double tc = Emin/mmu;
00644         double tmax = te;
00645         double tup = tc;
00646         if(tc>tmax)tup=tmax;
00647         //
00648         for (int k=0;k<2;k++){
00649           eloss+=2*PI*re*re*me*nel[k]*laststep/beta/beta*
00650             (log(2*(gamma+1)/(I[k]*I[k]/me/me))
00651              +RadCorr(te,tup));
00652         }
00653         //
00654         // add the energy loss to dE and set the "photon" energy
00655         //
00656         if(dE+eloss > energy){
00657           *egptr++=energy-dE; // the muon stops, limit dE and egamma
00658           dE=energy;
00659         }
00660         else{
00661           *egptr++=eloss; // the muon is still travelling
00662           dE+=eloss;
00663         }
00664         //
00665         // put the photon at the center of the segment
00666         //
00667         *rgptr++ = x[1] - (range-(laststep/2))*t[0];
00668         *rgptr++ = y[1] - (range-(laststep/2))*t[1];
00669         *rgptr++ = z[1] - (range-(laststep/2))*t[2];
00670         //
00671         *tgptr++ = time;
00672         //
00673         // count the last photon
00674         ngamma++;
00675         //
00676         // finish the loop
00677         done = true;
00678       }
00679     }
00680     else{
00681       /* the muon has stopped in the detector, make one last photon
00682          with energy equal the mass of the muon
00683       */
00684       muonstop++;
00685 
00686       // set the "photon" energy
00687       //
00688       *egptr++=mmu;
00689       //
00690       // put the photon at point the muon stopped
00691       //
00692       *rgptr++ = x[1] - range*t[0];
00693       *rgptr++ = y[1] - range*t[1];
00694       *rgptr++ = z[1] - range*t[2];
00695       //
00696       *tgptr++ = time;
00697       //
00698       // count the last photon
00699       ngamma++;
00700       //
00701       // finish the loop
00702       done = true;
00703 
00704       /*
00705       cout << "Muon " << muonstop << " has stopped at " 
00706            << x[1] - range*t[0] << ", "
00707            << y[1] - range*t[1] << ", "
00708            << z[1] - range*t[2] << " in "
00709            << time << " ns" << endl;
00710       */
00711     }
00712   }
00713   //cout << " muon range " << range << " cm, time " << time 
00714   //     << " ns and energy loss " << dE << " MeV" << endl;
00715 
00716   /* now deal with isotope production; start with the cross-section 
00717      for 9Li+8He prodution (as a function of incident muon energy 
00718      in MeV) and generate an isotope; this isn't perfect because the 
00719      muon changes energy throughout its path, altering the XC, but 
00720      it's okay for now
00721    */
00722   double XC;
00723   double mfp;
00724   double alpha = 0.73; // from the Hagner paper
00725   double XCmeas = 2.12;
00726   double Emeas = 190000.; // 190 GeV
00727   double ubarntocmsq = 1e-30;
00728   //cout << " sf " << (XCmeas/pow(Emeas,alpha))*ubarntocmsq << endl;
00729   //
00730   XC = (XCmeas/pow(Emeas,alpha))*pow(energy,alpha)*ubarntocmsq;
00731   //cout << " XC " << XC << " cm^2" << endl;
00732   //
00733   // compute mean free path to produce 9Li+8He
00734   //
00735   int ntrial = 0;
00736   passed = false;
00737   while(!passed){
00738 
00739     mfp = 1/ncar/XC;
00740     //
00741     // skip if ranlux doesn't have the necessary precision
00742     //
00743     double test = 1/pow(10.0,(range/mfp));
00744     if(test > 0.9999998){
00745       mfp = range/2.;
00746       ntrial = 0;
00747     }
00748     else{
00749       const int len=1;
00750       float rv[len];
00751       ranlux_(rv,len);
00752       mfp*=log(1/rv[0]);
00753     }
00754 
00755     // check that the isotope is inside the detector
00756     if(mfp <= range) passed = true;
00757 
00758     // count the attempt
00759     ntrial++;
00760   }
00761   //cout << " mfp " << mfp << " cm in " << ntrial << " trials" << endl;
00762 
00763   /* start at the mean free path distance from where the muon 
00764      entered the detector along the muon track in the direction 
00765      of the muon flight to produce the isotope; define a new 
00766      coordinate system with the muon track being the +z'-axis, 
00767      find the perpendicular distance from the muon track via 
00768      Hagner, and pick a random azimuthal angle; thus the 
00769      perpendicular distance and azimuthal angle give the new 
00770      x' and y' values for the isotope and the point of isotope 
00771      production along the muon track is z' = 0; then rotate the 
00772      new coordinate system into the detector x, y, and z
00773   */
00774   double ri[3];
00775   ri[0] = x[1] - mfp*t[0];
00776   ri[1] = y[1] - mfp*t[1];
00777   ri[2] = z[1] - mfp*t[2];
00778   //
00779   // pick the direction, relative to point ri
00780   //
00781   const int len=2;
00782   float rw[len];
00783   ranlux_(rw,len);
00784 
00785   double newphig = 2*PI*rw[0];
00786   double newcosg = 0.;
00787   double newt[3];
00788   newt[0] = cos(newphig)*sqrt(1-newcosg*newcosg);
00789   newt[1] = sin(newphig)*sqrt(1-newcosg*newcosg);
00790   newt[2] = newcosg;
00791   //
00792   // select the lateral distance from the muon track, relative to ri
00793   //
00794   float lateraldistance;
00795   int len2 = 1;
00796   funlux_(fspace,lateraldistance,len2);
00797   //
00798   // define point rt by x',y', and z' in the new coordinate system
00799   //
00800   double rt[3];
00801   rt[0] = lateraldistance*newt[0];
00802   rt[1] = lateraldistance*newt[1];
00803   rt[2] = lateraldistance*newt[2];
00804   //for(int i=0; i<3; i++)cout << " rt[" << i << "] " << rt[i];
00805   //cout << endl;
00806 
00807   /* always assume that the x'-axis of the new coordinate system is 
00808      in the direction chosen by angle phig of the muon track above; 
00809      thus we rotate point rt around the y'-axis (which is now chosen 
00810      always perpendicular to the detector coordinate system's x-y 
00811      plane) by the angle given by cosg above subtracted from pi; we 
00812      then rotate the new point qt around the z'-axis by angle pi 
00813      minus phig to get the new point pt, which is rt in the 
00814      detector coordinate system
00815   */
00816   double angle = PI - acos(cosg);
00817   double qt[3];
00818   double* qtptr = qt;
00819   qtptr = Rotate('Y',angle,rt[0],rt[1],rt[2]);
00820   for(int i=0; i<3; i++) qt[i] = *qtptr++;
00821   //
00822   // second rotation
00823   //
00824   angle = PI - phig;
00825   double pt[3];
00826   double* ptptr = pt;
00827   ptptr = Rotate('Z',angle,qt[0],qt[1],qt[2]);
00828   for(int i=0; i<3; i++) pt[i] = *ptptr++;
00829   //
00830   // add the new lateral displacement to the point on the muon 
00831   // track at which the isotope is produced
00832   //
00833   for(int i=0; i<3; i++)ri[i] += pt[i];
00834   //for(int i=0; i<3; i++)cout << " ri[" << i << "] " << ri[i];
00835   //cout << endl;
00836   //
00837   // decide if we have 9Li or 8He
00838   //
00839   char* isotope;
00840   if(rw[1] <= 0.5) 
00841     isotope = "9Li";
00842   else
00843     isotope = "8He";
00844   //
00845   // make energy and position arrays
00846   //
00847   int maxneutron = 1;
00848   double* eneutron = new double[maxneutron];
00849   double* rneutron = new double[maxneutron*3];
00850   double* tneutron = new double[maxneutron];
00851   //
00852   double* enptr = eneutron;
00853   double* rnptr = rneutron;
00854   double* tnptr = tneutron;
00855   //
00856   int maxelectron = 1;
00857   double* eelectron = new double[maxelectron];
00858   double* relectron = new double[maxelectron*3];
00859   double* telectron = new double[maxelectron];
00860   //
00861   double* eeptr = eelectron;
00862   double* reptr = relectron;
00863   double* teptr = telectron;
00864   //
00865   // let the isotope decay
00866   //
00867   int nneutron = 0;
00868   int nelectron = 0;
00869   //
00870   if(isotope == "9Li"){
00871     MyLiSource LiSource(9,Rmaxgen);
00872 
00873     nneutron = 1;
00874     *enptr++ = LiSource.GetLiNeutronEnergy();
00875     for(int i=0; i<3; i++) *rnptr++ = ri[i];
00876     *tnptr++ = LiSource.GetLiDecayTime();
00877 
00878     nelectron = 1;
00879     *eeptr++ = LiSource.GetLiBetaEnergy();
00880     for(int i=0; i<3; i++) *reptr++ = ri[i];
00881     *teptr++ = LiSource.GetLiDecayTime();
00882 
00883     //    Weight = 1./float(ntrial)*LiSource.GetLiWeight();
00884     Weight = 1./float(ntrial);
00885   }
00886   else if(isotope == "8He"){
00887     MyHeSource HeSource(8,Rmaxgen);
00888 
00889     nneutron = 1;
00890     *enptr++ = HeSource.GetHeNeutronEnergy();
00891     for(int i=0; i<3; i++) *rnptr++ = ri[i];
00892     *tnptr++ = HeSource.GetHeDecayTime();
00893 
00894     nelectron = 1;
00895     *eeptr++ = HeSource.GetHeBetaEnergy();
00896     for(int i=0; i<3; i++) *reptr++ = ri[i];
00897     *teptr++ = HeSource.GetHeDecayTime();
00898 
00899     //    Weight = 1./float(ntrial)*HeSource.GetHeWeight();
00900     Weight = 1./float(ntrial);
00901   }
00902   else{
00903     cout << "  ERROR: unknown isotope " << isotope 
00904          << ".  Options are '9Li' and '8He'." << endl;
00905   }
00906   //
00907   // transfer temp data to storage
00908   //
00909   Nneutron = nneutron;
00910   Nelectron = nelectron;
00911   Ngamma   = ngamma;
00912 
00913   Eneutron = new double[nneutron];
00914   Rneutron = new double[nneutron*3];
00915   Tneutron = new double[nneutron];
00916 
00917   Eelectron = new double[nelectron];
00918   Relectron = new double[nelectron*3];
00919   Telectron = new double[nelectron];
00920 
00921   Egamma = new double[ngamma];
00922   Rgamma = new double[ngamma*3];
00923   Tgamma = new double[ngamma];
00924 
00925   double* ptr;
00926 
00927   ptr = Eneutron+nneutron;
00928   while(ptr>Eneutron)*--ptr=*--enptr;
00929 
00930   ptr = Rneutron+3*nneutron;
00931   while(ptr>Rneutron)*--ptr=*--rnptr;
00932 
00933   ptr = Tneutron+nneutron;
00934   while(ptr>Tneutron)*--ptr=*--tnptr;
00935 
00936   ptr = Eelectron+nelectron;
00937   while(ptr>Eelectron)*--ptr=*--eeptr;
00938 
00939   ptr = Relectron+3*nelectron;
00940   while(ptr>Relectron)*--ptr=*--reptr;
00941 
00942   ptr = Telectron+nelectron;
00943   while(ptr>Telectron)*--ptr=*--teptr;
00944 
00945   ptr = Egamma+ngamma;
00946   while(ptr>Egamma)*--ptr=*--egptr;
00947 
00948   ptr = Rgamma+3*ngamma;
00949   while(ptr>Rgamma)*--ptr=*--rgptr;
00950 
00951   ptr = Tgamma+ngamma;
00952   while(ptr>Tgamma)*--ptr=*--tgptr;
00953 
00954   /*
00955   cout << Nneutron << " neutrons" << endl;
00956   for(int n=0; n<Nneutron; n++){
00957     cout << " neutron " << n << " energy " << Eneutron[n] << " MeV, and x, y, z:";
00958     for(int i=0; i<3; i++) cout << "  " << Rneutron[3*n+i];
00959     cout << endl << " and time " << Tneutron[n] << " nsec" << endl;
00960   }
00961 
00962   cout << Nelectron << " electrons" << endl;
00963   for(int n=0; n<Nelectron; n++){
00964     cout << " electron " << n << " energy " << Eelectron[n] << " MeV, and x, y, z:";
00965     for(int i=0; i<3; i++) cout << "  " << Relectron[3*n+i];
00966     cout << endl << " and time " << Telectron[n] << " nsec" << endl;
00967   }
00968 
00969   cout << Ngamma << " photons" << endl;
00970   for(int n=0; n<Ngamma; n++){
00971     cout << " photon " << n << " energy " << Egamma[n] << " MeV, and x, y, z:";
00972     for(int i=0; i<3; i++) cout << "  " << Rgamma[3*n+i];
00973     cout << endl << " and time " << Tgamma[n] << " nsec" << endl;
00974   }
00975   */
00976 
00977   // clean up
00978   delete[] eneutron;
00979   delete[] rneutron;
00980   delete[] tneutron;
00981   delete[] eelectron;
00982   delete[] relectron;
00983   delete[] telectron;
00984   delete[] egamma;
00985   delete[] rgamma;
00986   delete[] tgamma;
00987 }


The documentation for this class was generated from the following files:
Generated on Mon Feb 21 16:11:20 2005 for ReactorFsim by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002