#include <MuonPropagator.hh>
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. |
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.
|
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 } |