Main Page   Compound List   File List   Compound Members   File Members  

MuonPropagator.cpp

Go to the documentation of this file.
00001 
00006 #include <math.h>
00007 #include <iostream.h>
00008 #include <fstream.h>   // file I/O
00009 #include <iomanip.h>   // format manipulation
00010 #include <string>
00011 #include <stdio.h>
00012 #include "ReactorConstants.hh"
00013 #include "ReactorFortran.hh"
00014 #include "MuonPropagator.hh"
00015 #include "MyHeSource.hh"
00016 #include "MyLiSource.hh"
00017 
00018 MuonPropagator::MuonPropagator(int test, double newRmaxgen, double newEnergy,
00019                                double newX, double newY, double newZ,
00020                                double newVx, double newVy, double newVz){
00021 
00022   Rmaxgen = newRmaxgen;
00023   energy = newEnergy;
00024 
00025   double ri[3];
00026   ri[0] = newX;
00027   ri[1] = newY;
00028   ri[2] = newZ;
00029 
00030   double pi[3];
00031   pi[0] = newVx;
00032   pi[1] = newVy;
00033   pi[2] = newVz;
00034 
00035   /*
00036   cout << "MuonPropagator::MuonPropagator(" 
00037        << Rmaxgen << ","  << energy << "," 
00038        << ri[0] << "," << ri[1] << "," << ri[2] << ","
00039        << pi[0] << "," << pi[1] << "," << pi[2] << ")" << endl;
00040   */
00041 
00042   static double re  = RELECTRON;
00043   static double me  = MELECTRON;
00044   static double mmu = MMUON;
00045   static double Na  = NAVOGADRO;
00046   //
00047   // For electron density
00048   //
00049   static double nel[2];
00050   static double A[2] = {A0,A1};
00051   static double Z[2] = {Z0,Z1};
00052   static double f[2] = {f0,f1};
00053   static double I[2] = {I0,I1};
00054   //
00055   static double ncar;
00056   //
00057   // calculate the fluxes and densities
00058   //
00059   int static muonstop;
00060   bool static first = true;
00061   if(first){
00062 
00063     // electron density
00064     for(int i=0;i<2;i++) nel[i] = Na*density*f[i]*Z[i]/A[i];
00065     //cout << " nel " << nel[0]+nel[1] << endl;
00066       
00067     // 12C atom density
00068     ncar = Na*density*f[1]/A[1];
00069     //cout << " ncar " << ncar << endl;
00070       
00071     Weight = 0.;
00072     muonstop = 0;
00073   
00074     first = false;
00075   }
00076   //
00077   // find where the muon enters and leaves the detector
00078   //
00079   int inter = 0;
00080   double x[2],y[2],z[2];
00081 
00082   // create the unit vector along the direction of momentum
00083   //
00084   double pdotp = sqrt(pi[0]*pi[0] + pi[1]*pi[1] + pi[2]*pi[2]);
00085   double t[3];
00086   for(int i=0;i<3;i++) t[i] = pi[i]/pdotp;
00087   //for(int i=0;i<3;i++) cout << " t[" << i << "] " << t[i];
00088   //cout << endl;
00089 
00090   // find the far end of the line a unit distance
00091   // from (x,y,z) along the t direction
00092   //
00093   double rf[3];
00094   for(int i=0;i<3;i++) rf[i] = ri[i]-t[i];
00095   //for(int i=0;i<3;i++) cout << " rf[" << i << "] " << rf[i] << " ";
00096   //cout << endl;
00097 
00098   // solve for intersections with the scint region
00099   double p[7];
00100   double* pptr = p;
00101   int num;
00102 
00103   pptr = Intersection(ri[0], ri[1], ri[2],  // first end of line
00104                       rf[0], rf[1], rf[2],  // second end of line
00105                       0, 0, 0, Rmaxgen);    // detector centered at 0
00106 
00107   num = (int)*pptr++;
00108   if(num>1){
00109 
00110     inter = 2;
00111     for(int i=0; i<inter; i++){
00112       x[i] = *pptr++;
00113       y[i] = *pptr++;
00114       z[i] = *pptr++;
00115     }
00116   }
00117   /*
00118   for(int i=0; i<inter; i++){
00119     cout << " X-coordinate of point " << i << " : " << x[i] << endl;
00120     cout << " Y-coordinate of point " << i << " : " << y[i] << endl;
00121     cout << " Z-coordinate of point " << i << " : " << z[i] << endl;
00122   }
00123   */
00124   // path length
00125   double L = sqrt((x[1]-x[0])*(x[1]-x[0])+
00126                   (y[1]-y[0])*(y[1]-y[0])+
00127                   (z[1]-z[0])*(z[1]-z[0]));
00128   //cout << " path length " << L << endl;
00129 
00130   /* iterate through the muon energy loss dE/dx in dx cm steps,
00131      making a gamma at the center of the dx cm segment of the 
00132      line along the muon path equal to the energy lost in that 
00133      segment; always check that the muon is still in the 
00134      detector and has not stopped
00135   */
00136   double step=5.0;
00137   double Emin=0.01;
00138   //
00139   double range = 0.;
00140   double time = 0.;
00141   //
00142   // define energy and position arrays
00143   //
00144   int maxgammafromisotope = 5;
00145   int maxgamma = int(Rmaxgen*2/step)+maxgammafromisotope;
00146   double* egamma = new double[maxgamma];
00147   double* rgamma = new double[maxgamma*3];
00148   double* tgamma = new double[maxgamma];
00149   //
00150   double* egptr=egamma;
00151   double* rgptr=rgamma;
00152   double* tgptr=tgamma;
00153   //
00154   // Begin energy loss loop
00155   //
00156   double dE=0;
00157   double eloss;
00158   int ngamma = 0;
00159   //
00160   bool done = false;
00161   while(!done){
00162 
00163     // zero the energy loss for this segment
00164     eloss = 0;
00165     //
00166     // check that the muon hasn't stopped
00167     //
00168     if(energy-dE > Emin){
00169       //
00170       // check that we aren't leaving the detector
00171       //
00172       if(range+step < L){
00173         //
00174         // iterate range and time
00175         //
00176         double gamma = 1+(energy-dE)/mmu;
00177         double beta = sqrt(1-1/gamma/gamma);
00178         range+=step;
00179         time+=step/beta/c;
00180         //
00181         // increment energy loss
00182         //
00183         double te = gamma-1;
00184         double tc = Emin/mmu;
00185         double tmax = te;
00186         double tup = tc;
00187         if(tc>tmax)tup=tmax;
00188         //
00189         for (int k=0;k<2;k++){
00190           eloss+=2*PI*re*re*me*nel[k]*step/beta/beta*
00191             (log(2*(gamma+1)/(I[k]*I[k]/me/me))
00192              +RadCorr(te,tup));
00193         }
00194         //
00195         // add the energy loss to dE and set the "photon" energy
00196         //
00197         if(dE+eloss > energy){
00198           *egptr++=energy-dE; // the muon stops, limit dE and egamma
00199           dE=energy;
00200         }
00201         else{
00202           *egptr++=eloss; // the muon is still travelling
00203           dE+=eloss;
00204         }
00205         //
00206         // put the photon at the center of the segment
00207         //
00208         *rgptr++ = x[1] - (range-(step/2))*t[0];
00209         *rgptr++ = y[1] - (range-(step/2))*t[1];
00210         *rgptr++ = z[1] - (range-(step/2))*t[2];
00211         //
00212         *tgptr++ = time;
00213         //
00214         // count the photon
00215         ngamma++;
00216       }
00217       else{
00218         /* we have reached the end of the detector; put one final 
00219            gamma to cover the last remaining segment of energy loss
00220         */
00221         double laststep = L-range;
00222         //
00223         double gamma = 1+(energy-dE)/mmu;
00224         double beta = sqrt(1-1/gamma/gamma);
00225         range+=laststep;
00226         time+=laststep/beta/c;
00227         //
00228         // increment energy loss
00229         //
00230         double te = gamma-1;
00231         double tc = Emin/mmu;
00232         double tmax = te;
00233         double tup = tc;
00234         if(tc>tmax)tup=tmax;
00235         //
00236         for (int k=0;k<2;k++){
00237           eloss+=2*PI*re*re*me*nel[k]*laststep/beta/beta*
00238             (log(2*(gamma+1)/(I[k]*I[k]/me/me))
00239              +RadCorr(te,tup));
00240         }
00241         //
00242         // add the energy loss to dE and set the "photon" energy
00243         //
00244         if(dE+eloss > energy){
00245           *egptr++=energy-dE; // the muon stops, limit dE and egamma
00246           dE=energy;
00247         }
00248         else{
00249           *egptr++=eloss; // the muon is still travelling
00250           dE+=eloss;
00251         }
00252         //
00253         // put the photon at the center of the segment
00254         //
00255         *rgptr++ = x[1] - (range-(laststep/2))*t[0];
00256         *rgptr++ = y[1] - (range-(laststep/2))*t[1];
00257         *rgptr++ = z[1] - (range-(laststep/2))*t[2];
00258         //
00259         *tgptr++ = time;
00260         //
00261         // count the last photon
00262         ngamma++;
00263         //
00264         // finish the loop
00265         done = true;
00266       }
00267     }
00268     else{
00269       /* the muon has stopped in the detector, make one last photon
00270          with energy equal the mass of the muon
00271       */
00272       muonstop++;
00273 
00274       // set the "photon" energy
00275       //
00276       *egptr++=mmu;
00277       //
00278       // put the photon at point the muon stopped
00279       //
00280       *rgptr++ = x[1] - range*t[0];
00281       *rgptr++ = y[1] - range*t[1];
00282       *rgptr++ = z[1] - range*t[2];
00283       //
00284       *tgptr++ = time;
00285       //
00286       // count the last photon
00287       ngamma++;
00288       //
00289       // finish the loop
00290       done = true;
00291 
00292       /*
00293       cout << "Muon " << muonstop << " has stopped at " 
00294            << x[1] - range*t[0] << ", "
00295            << y[1] - range*t[1] << ", "
00296            << z[1] - range*t[2] << " in "
00297            << time << " ns" << endl;
00298       */
00299     }
00300   }
00301   //cout << " muon range " << range << " cm, time " << time 
00302   //     << " ns and energy loss " << dE << " MeV" << endl;
00303 
00304   // don't yet do isotope or other secondary production
00305 
00306   //
00307   // transfer temp data to storage
00308   //
00309   //Nneutron = nneutron;
00310   //Nelectron = nelectron;
00311   Ngamma   = ngamma;
00312 
00313   //Eneutron = new double[nneutron];
00314   //Rneutron = new double[nneutron*3];
00315   //Tneutron = new double[nneutron];
00316 
00317   //Eelectron = new double[nelectron];
00318   //Relectron = new double[nelectron*3];
00319   //Telectron = new double[nelectron];
00320 
00321   Egamma = new double[ngamma];
00322   Rgamma = new double[ngamma*3];
00323   Tgamma = new double[ngamma];
00324 
00325   double* ptr;
00326 
00327   //ptr = Eneutron+nneutron;
00328   //while(ptr>Eneutron)*--ptr=*--enptr;
00329 
00330   //ptr = Rneutron+3*nneutron;
00331   //while(ptr>Rneutron)*--ptr=*--rnptr;
00332 
00333   //ptr = Tneutron+nneutron;
00334   //while(ptr>Tneutron)*--ptr=*--tnptr;
00335 
00336   //ptr = Eelectron+nelectron;
00337   //while(ptr>Eelectron)*--ptr=*--eeptr;
00338 
00339   //ptr = Relectron+3*nelectron;
00340   //while(ptr>Relectron)*--ptr=*--reptr;
00341 
00342   //ptr = Telectron+nelectron;
00343   //while(ptr>Telectron)*--ptr=*--teptr;
00344 
00345   ptr = Egamma+ngamma;
00346   while(ptr>Egamma)*--ptr=*--egptr;
00347 
00348   ptr = Rgamma+3*ngamma;
00349   while(ptr>Rgamma)*--ptr=*--rgptr;
00350 
00351   ptr = Tgamma+ngamma;
00352   while(ptr>Tgamma)*--ptr=*--tgptr;
00353 
00354   /*
00355   cout << Nneutron << " neutrons" << endl;
00356   for(int n=0; n<Nneutron; n++){
00357     cout << " neutron " << n << " energy " << Eneutron[n] << " MeV, and x, y, z:";
00358     for(int i=0; i<3; i++) cout << "  " << Rneutron[3*n+i];
00359     cout << endl << " and time " << Tneutron[n] << " nsec" << endl;
00360   }
00361 
00362   cout << Nelectron << " electrons" << endl;
00363   for(int n=0; n<Nelectron; n++){
00364     cout << " electron " << n << " energy " << Eelectron[n] << " MeV, and x, y, z:";
00365     for(int i=0; i<3; i++) cout << "  " << Relectron[3*n+i];
00366     cout << endl << " and time " << Telectron[n] << " nsec" << endl;
00367   }
00368 
00369   cout << Ngamma << " photons" << endl;
00370   for(int n=0; n<Ngamma; n++){
00371     cout << " photon " << n << " energy " << Egamma[n] << " MeV, and x, y, z:";
00372     for(int i=0; i<3; i++) cout << "  " << Rgamma[3*n+i];
00373     cout << endl << " and time " << Tgamma[n] << " nsec" << endl;
00374   }
00375   */
00376 
00377   // clean up
00378   //delete[] eneutron;
00379   //delete[] rneutron;
00380   //delete[] tneutron;
00381   //delete[] eelectron;
00382   //delete[] relectron;
00383   //delete[] telectron;
00384   delete[] egamma;
00385   delete[] rgamma;
00386   delete[] tgamma;
00387 }
00388 
00389 
00390 /*
00391   Generates a muon from a given energy and zenith angle.  The muon 
00392   starts at a random point above the detector and at a random 
00393   azimuthal angle to decide the path of the muon track.  Energy 
00394   from the muon inside the detector is created incrementally along 
00395   the muon tragectory as optical photons.  One heavy isotope 9Li or 
00396   8He is produced per muon from the muon spallation and forced to 
00397   beta decay to create and electron and neutron.  The events are 
00398   weighted by the 9Li/8He production cross sections and the decay 
00399   branching ratio of the 9Li/8He beta decay.  The neutron, 
00400   electron, and photon energies, positions and times are saved.
00401 */
00402 MuonPropagator::MuonPropagator(double newRmaxgen,
00403                                double newDepth,
00404                                double newEnergy,
00405                                double newCosTheta){
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 }
00988 
00989 MuonPropagator::~MuonPropagator(){
00990   delete[] Eneutron;
00991   delete[] Rneutron;
00992   delete[] Tneutron;
00993   delete[] Eelectron;
00994   delete[] Relectron;
00995   delete[] Telectron;
00996   delete[] Egamma;
00997   delete[] Rgamma;
00998   delete[] Tgamma;
00999 }
01000 
01001 MuonPropagator::MuonPropagator(const MuonPropagator& Muon){
01002 
01003   Rmaxgen = Muon.Rmaxgen;
01004 
01005   Nmuon = Muon.Nmuon;
01006   energy = Muon.energy;
01007   cosg = Muon.cosg;
01008   phig = Muon.phig;
01009 
01010   Nneutron = Muon.Nneutron;
01011   Nelectron = Muon.Nelectron;
01012   Ngamma = Muon.Ngamma;
01013 
01014   double* pold;
01015   double* pnew;
01016 
01017   Eneutron = new double[Nneutron];
01018   pold = Muon.Eneutron+Nneutron;
01019   pnew = Eneutron+Nneutron;
01020   while(pnew>Eneutron)*--pnew=*--pold;
01021 
01022   Rneutron = new double[3*Nneutron];
01023   pold = Muon.Rneutron+3*Nneutron;
01024   pnew = Rneutron+3*Nneutron;
01025   while(pnew>Rneutron)*--pnew=*--pold;
01026 
01027   Tneutron = new double[Nneutron];
01028   pold = Muon.Tneutron+Nneutron;
01029   pnew = Tneutron+Nneutron;
01030   while(pnew>Tneutron)*--pnew=*--pold;
01031 
01032   Eelectron = new double[Nelectron];
01033   pold = Muon.Eelectron+Nelectron;
01034   pnew = Eelectron+Nelectron;
01035   while(pnew>Eelectron)*--pnew=*--pold;
01036 
01037   Relectron = new double[3*Nelectron];
01038   pold = Muon.Relectron+3*Nelectron;
01039   pnew = Relectron+3*Nelectron;
01040   while(pnew>Relectron)*--pnew=*--pold;
01041 
01042   Telectron = new double[Nelectron];
01043   pold = Muon.Telectron+Nelectron;
01044   pnew = Telectron+Nelectron;
01045   while(pnew>Telectron)*--pnew=*--pold;
01046 
01047   Egamma = new double[Ngamma];
01048   pold = Muon.Egamma+Ngamma;
01049   pnew = Egamma+Ngamma;
01050   while(pnew>Egamma)*--pnew=*--pold;
01051 
01052   Rgamma = new double[3*Ngamma];
01053   pold = Muon.Rgamma+3*Ngamma;
01054   pnew = Rgamma+3*Ngamma;
01055   while(pnew>Rgamma)*--pnew=*--pold;
01056 
01057   Tgamma = new double[Ngamma];
01058   pold = Muon.Tgamma+Ngamma;
01059   pnew = Tgamma+Ngamma;
01060   while(pnew>Tgamma)*--pnew=*--pold;
01061 
01062   Weight = Muon.Weight;
01063 }    
01064 
01065 MuonPropagator& MuonPropagator::operator=(const MuonPropagator& rhs){
01066 
01067   if(this == &rhs)return *this;
01068 
01069   Rmaxgen = rhs.Rmaxgen;
01070 
01071   Nmuon = rhs.Nmuon;
01072   energy = rhs.energy;
01073   cosg = rhs.cosg;
01074   phig = rhs.phig;
01075 
01076   Nneutron = rhs.Nneutron;
01077   Nelectron = rhs.Nelectron;
01078   Ngamma = rhs.Ngamma;
01079 
01080   double* pold;
01081   double* pnew;
01082 
01083   delete[] Eneutron;
01084   Eneutron = new double[Nneutron];
01085   pold = rhs.Eneutron+Nneutron;
01086   pnew = Eneutron+Nneutron;
01087   while(pnew>Eneutron)*--pnew=*--pold;
01088 
01089   delete[] Rneutron;
01090   Rneutron = new double[3*Nneutron];
01091   pold = rhs.Rneutron+3*Nneutron;
01092   pnew = Rneutron+3*Nneutron;
01093   while(pnew>Rneutron)*--pnew=*--pold;
01094 
01095   delete[] Tneutron;
01096   Tneutron = new double[Nneutron];
01097   pold = rhs.Tneutron+Nneutron;
01098   pnew = Tneutron+Nneutron;
01099   while(pnew>Tneutron)*--pnew=*--pold;
01100 
01101   delete[] Eelectron;
01102   Eelectron = new double[Nelectron];
01103   pold = rhs.Eelectron+Nelectron;
01104   pnew = Eelectron+Nelectron;
01105   while(pnew>Eelectron)*--pnew=*--pold;
01106 
01107   delete[] Relectron;
01108   Relectron = new double[3*Nelectron];
01109   pold = rhs.Relectron+3*Nelectron;
01110   pnew = Relectron+3*Nelectron;
01111   while(pnew>Relectron)*--pnew=*--pold;
01112 
01113   delete[] Telectron;
01114   Telectron = new double[Nelectron];
01115   pold = rhs.Telectron+Nelectron;
01116   pnew = Telectron+Nelectron;
01117   while(pnew>Telectron)*--pnew=*--pold;
01118 
01119   delete[] Egamma;
01120   Egamma = new double[Ngamma];
01121   pold = rhs.Egamma+Ngamma;
01122   pnew = Egamma+Ngamma;
01123   while(pnew>Egamma)*--pnew=*--pold;
01124 
01125   delete[] Rgamma;
01126   Rgamma = new double[3*Ngamma];
01127   pold = rhs.Rgamma+3*Ngamma;
01128   pnew = Rgamma+3*Ngamma;
01129   while(pnew>Rgamma)*--pnew=*--pold;
01130 
01131   delete[] Tgamma;
01132   Tgamma = new double[Ngamma];
01133   pold = rhs.Tgamma+Ngamma;
01134   pnew = Tgamma+Ngamma;
01135   while(pnew>Tgamma)*--pnew=*--pold;
01136 
01137   Weight = rhs.Weight;
01138 
01139   return *this;
01140 }
01141 
01142 double* MuonPropagator::Intersection(double x1, double y1, double z1,
01143                                      double x2, double y2, double z2,
01144                                      double x3, double y3, double z3, double r){
01145 
01146   // x1,y1,z1  P1 coordinates (point of line)
01147   // x2,y2,z2  P2 coordinates (point of line)
01148   // x3,y3,z3, r  P3 coordinates and radius (sphere)
01149   // x,y,z   intersection coordinates
01150   //
01151   // This function returns a pointer array which first index indicates
01152   // the number of intersection point, followed by coordinate pairs.
01153 
01154   double a, b, c, mu, i ;
01155   // array containing number of points and its coordinates
01156   double point[7];
01157   double* p = point;
01158 
01159   a = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
01160   b = 2*((x2-x1)*(x1-x3) + (y2-y1)*(y1-y3) + (z2-z1)*(z1-z3));
01161   c = (x3*x3 + y3*y3 + z3*z3 + x1*x1 + y1*y1 + z1*z1 - 
01162        2*(x3*x1 + y3*y1 + z3*z1) - r*r);
01163   i = b*b - 4*a*c;
01164   //cout << "intersection " << i << endl;
01165 
01166   if(i < 0.0){
01167     // no intersection
01168     p[0] = 0.0;
01169   }
01170   if(i ==0.0){
01171     // one intersection
01172     p[0] = 1.0;
01173 
01174     mu = -b/(2*a) ;
01175     p[1] = x1 + mu*(x2-x1);
01176     p[2] = y1 + mu*(y2-y1);
01177     p[3] = z1 + mu*(z2-z1);
01178   }
01179   if(i>0.0){
01180     // two intersections
01181     p[0] = 2.0;
01182 
01183     // first intersection
01184     mu = (-b + sqrt(b*b - 4*a*c))/(2*a);
01185     p[1] = x1 + mu*(x2-x1);
01186     p[2] = y1 + mu*(y2-y1);
01187     p[3] = z1 + mu*(z2-z1);
01188 
01189     // second intersection
01190     mu = (-b - sqrt(b*b - 4*a*c))/(2*a);
01191     p[4] = x1 + mu*(x2-x1);
01192     p[5] = y1 + mu*(y2-y1);
01193     p[6] = z1 + mu*(z2-z1);
01194   }
01195   return(p);
01196 }
01197 
01198 double* MuonPropagator::Rotate(char axis,double angle,
01199                                double x1, double y1, double z1){
01200 
01201   // axis      axis about which to rotate
01202   // angle     angle of rotation in radians
01203   // x1,y1,z1  cartesian coordinates of point to rotate
01204 
01205   double x2,y2,z2;
01206   double p[3];
01207   double* ptr = p;
01208 
01209   if(axis == 'X'){
01210     x2 = x1;
01211     y2 = cos(angle)*y1-sin(angle)*z1;
01212     z2 = sin(angle)*y1+cos(angle)*z1;
01213   }
01214   else if(axis == 'Y'){
01215     x2 = cos(angle)*x1+sin(angle)*z1;
01216     y2 = y1;
01217     z2 = -sin(angle)*x1+cos(angle)*z1;
01218   }
01219   else if(axis == 'Z'){
01220     x2 = cos(angle)*x1-sin(angle)*y1;
01221     y2 = sin(angle)*x1+cos(angle)*y1;
01222     z2 = z1;
01223   }
01224   else{
01225     cout << "ERROR: Unknown axis " << axis 
01226          << ".  Axis of rotation must be 'X', 'Y', or 'Z'." << endl;
01227     x2 = 0;
01228     y2 = 0;
01229     z2 = 0;
01230   }
01231 
01232   p[0] = x2;
01233   p[1] = y2;
01234   p[2] = z2;
01235 
01236   return(ptr);
01237 }
01238 
01239 double MuonPropagator::RadCorr(double t,double tup){
01240 
01241   if(t<=0 || tup<=0 || t<=tup) return 0;
01242   //
01243   double y = 1/(2+t);
01244   //
01245   return log(t*tup)
01246     -tup*tup*(t+2*tup-3*tup*tup*y/2
01247               -(tup-exp(3*log(tup))/3)*y*y
01248               -(tup*tup/2
01249                 -t*exp(3*log(tup))/2
01250                 +exp(4*log(tup))/4)*exp(3*log(y)));
01251 }
01252 
01253 float MuonPropagator::IsotopeDistance(const float& r){
01254 
01255   // from Hagner et al, Astropart Phys 14, 37 (2000)
01256   float phi = 1/166.0*exp(-0.0403*r*r)+1/1223.0*exp(-0.098*r);
01257   return phi;
01258 }

Generated on Mon Feb 21 16:11:18 2005 for ReactorFsim by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002