Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

MCParticle.cxx

Go to the documentation of this file.
00001 //  $Id: MCParticle.cxx,v 1.8 2001/09/21 18:38:54 atwood Exp $
00002 //
00003 // This file is part of Gismo 2
00004 //
00005 //
00006 // Implemention of all MCParticle member functions
00007 
00008 #include "gismo/MCParticle.h"
00009 
00010 #include "gismo/Medium.h"
00011 #include "gismo/Material.h"
00012 #include "gismo/Detector.h"
00013 #include "gismo/Units.h"
00014 #include "gismo/Interactor.h"
00015 #include "gismo/PDT.h"
00016 
00017 #include "geometry/Ray.h"
00018 #include "geometry/Track.h"
00019 #include "geometry/Volume.h"
00020 
00021 #include "facilities/error.h"
00022 #include "geomrep/TrackRep.h"
00023 #include "Random.h"
00024 
00025 
00026 /********************************************************************
00027  *                MCParticle                                        *
00028  ********************************************************************/
00029 #ifdef DUMP_STEP // special debug output
00030 # include <fstream>
00031  static std::ofstream fout("dump_step.prn");
00032 #endif
00033 
00034 MCParticle::MCParticle(const PData* data, float mass)
00035         : GParticle(data,mass)
00036         , _track(0)
00037         , _status(ALIVE)
00038         {}
00039 MCParticle::MCParticle(long id, float mass)
00040         : GParticle(id,mass)
00041         , _track(0)
00042         , _status(ALIVE)
00043         {}
00044 MCParticle::MCParticle(const char* name, float mass)
00045         : GParticle(name,mass)
00046         , _track(0)
00047         , _status(ALIVE)
00048         {}
00049 MCParticle::MCParticle(const MCParticle& p)
00050         : GParticle(p)
00051         , _track(0)
00052         , _status(ALIVE)
00053         {}
00054 
00055 MCParticle::~MCParticle()
00056 {
00057         if(_track)
00058                 delete _track;
00059 }
00060 GParticle*
00061 MCParticle::addChild(const PData* childData, float mass)
00062 {
00063     MCParticle* child = new MCParticle(childData, mass);
00064     GParticle::addChild(child);
00065     return child;
00066 }
00067 //
00068 MCParticle*
00069 MCParticle::child(int n)const
00070 {
00071     return (MCParticle*)(GParticle::child(n));
00072 }
00073 const MCParticle*
00074 MCParticle::parent()const
00075 {
00076     return (const MCParticle*)(GParticle::parent());
00077 }
00078 
00079 
00080 const float MCParticle::MAX_TIME=1000;      //cm...
00081 const float MCParticle::MAX_BEND=31;       //radians .. 5 loops...
00082 const int MCParticle::MAX_GENERATION=500;
00083 const int MCParticle::MAX_STEPS=10000;
00084 
00085 //  MCParticle::propagate -- propagate the particle,and all its progeny,
00086 //   out of the medium
00087 //
00088 void MCParticle::propagate(const Medium * medium) {
00089 
00090   currentMedium = medium;
00091   arcLength = properTime = turnAngle = 0.;
00092   timeOfDecay = GenerateTimeOfDecay();
00093   startingEnergy = e();
00094   if( ! parent() ) generation =0;
00095   stepcount = 0;
00096   Medium::setLastMedium(0);
00097   lastMedium = medium;
00098   Vector starting_momentum = momentum(); // save to restore when we are done
00099 
00100   while (status()==ALIVE)
00101   {
00102     const Medium * nextMedium=currentMedium;  // a temporary for new medium
00103 
00104     //  find maximum step, reflecting decay or interaction
00105     float maxStep =  checkStep( );
00106 
00107     if( maxStep==0)    {
00108         step = 0;  // means that it stopped: skip the next stuff
00109         s_segment = 0;
00110     }
00111     else {
00112         // return a Ray that estimates the trajectory (or a point)
00113 
00114         s_segment=
00115             currentMedium->CreateRay( position(), momentum(), charge(), maxStep );
00116 
00117         // flag the segment for use by geometry
00118         s_segment->setFlag(stepcount); 
00119 
00120         // ask the Medium for a distance along that ray, (unless
00121         // the particle is at rest),and for possible detector
00122         step = currentMedium->distanceToLeave(*s_segment, nextMedium, maxStep);
00123 
00124         if (step < maxStep) {  // hit a boundary: cancel decay or interaction
00125             setStatus( ALIVE );
00126         }       
00127         if (step == FLT_MAX || (step<=0 && currentMedium==nextMedium) ) {
00128             WARNING( "MCParticle::propagate -- we are lost or stuck!");
00129             setStatus( STUCK );
00130             break;
00131         }
00132         else if( step > maxStep) {
00133             // maxStep was ignored above: assume still in same medium
00134             step = maxStep;
00135             nextMedium = currentMedium;
00136         }
00137         
00138         // perform the  step, taking all physics into account, and
00139         if(step > 0) {
00140             stepBy(step, *s_segment );
00141         }
00142 
00143     }
00144     // peform decays or interactions at end of step
00145     endStep();
00146 
00147 
00148 #ifdef DUMP_STEP
00149     fout << z() << '\t' << step << '\t' << currentMedium->title() << '\t'
00150         << currentMedium->material().name()<< '\t'
00151         << energyLoss()*1e6 << '\n';
00152 #endif
00153 
00154     // notify the associated detector, if any
00155     Detector* d =currentMedium->detector();
00156     if( d )
00157       d->score(this);
00158 
00159     // add the segment for this step to the track, or delete it
00160     if(s_segment) {
00161        if( saveTrack && step > 0) {
00162           if( !_track )
00163              _track = new Track(s_segment, charge()!=0);
00164           else
00165              _track->addSegment(s_segment);
00166         }
00167        else
00168           delete s_segment;
00169     }
00170 
00171     startingEnergy = e();
00172     Medium::setLastMedium(currentMedium);
00173     lastMedium = currentMedium;
00174 
00175     // if particle didn't stop, decay, or interact, it must have
00176     // reached the boundary: update current medium and see if left
00177 
00178 #if 0  // special debug code to enable by hand to study geometry problems
00179     if( status()==ALIVE && nextMedium != 0 ) {
00180         const Medium* temp;
00181         float d = nextMedium->distanceToLeave( Ray(position(),direction()),temp, 1000.);
00182         if( d>= 1000.)
00183             cerr << "MCParticle::propagate--misstep from "<< currentMedium->title()
00184                 << " to " << nextMedium->title() << '\n';
00185         
00186     }
00187 #endif
00188 
00189     if ( status()==ALIVE && (currentMedium=nextMedium)==0 )
00190         setStatus(LEFT);
00191     else
00192       stepcount ++;
00193 
00194   }
00195   // Finished stepping this particle. Restore initial momentum (and energy) for user access
00196   setMomentum(starting_momentum);
00197 
00198   // Note that a "Stopping" particle may have children! This can be used by
00199   // score() to ignore children and stop propagating
00200   if(status() == STOPPED){
00201       return;
00202   }
00203 
00204 
00205   // Now  recurse: make sure that all of the children
00206   // of a particle's  decays or interactions propagate out of
00207   // the medium in which they were created
00208   const Medium* parentMedium = currentMedium;
00209   generation ++;
00210   for( int i=0;i<numChildren(); i++ ) {
00211      child(i)->propagate(parentMedium);
00212   }
00213   generation --;
00214 
00215   // Finally, if not displaying, get rid of children here
00216   if( generation > saveTrack) removeChildren();
00217 }
00218 
00219 float MCParticle::checkStep()
00220 
00221 //  calculate maximum step, allowing for decay, or interaction
00222 
00223 {
00224     float pmagnitude =  momentum().mag();
00225     float distance = FLT_MAX;
00226 
00227     // get minimum energy allowed by medium for this part.
00228     float eCutMin = currentMedium->kECutOff() + mass();
00229     ecut = currentMedium->material().isVacuum()? 0: interactor()->ecut(this,currentMedium);
00230     if( ecut>0 &&  ecut < eCutMin) ecut = eCutMin;
00231         
00232     if( ( e() < ecut )
00233          || generation >= MAX_GENERATION
00234         || stepcount > MAX_STEPS)
00235     {
00236         if( generation >= MAX_GENERATION )
00237             WARNING("MCParticle::propagate - stopped particle because too many generations");
00238         if( stepcount > MAX_STEPS )
00239             WARNING("MCParticle::propagate - too many steps, stopping");
00240         
00241 
00242         setStatus( STOPPED );
00243         if( charge() && pmagnitude > 0. )
00244             setMomentum(Vector(0.,0.,0.));
00245 
00246         distance = 0.;
00247     }
00248 
00249     // see if decayed before taking step
00250 
00251     if (mass()>0. && timeOfDecay < MAX_TIME )  {
00252         float distToDecay =
00253                  (timeOfDecay-properTime)*eta();
00254         if (distToDecay <= distance)  // will catch decay at rest
00255         {   setStatus( DECAYED);
00256             distance = (distToDecay > 0.) ? distToDecay : 0.;
00257         }
00258     }
00259 
00260     // if in material, check range and distance to interact, compare w/ decay
00261 
00262     if (!currentMedium->material().isVacuum())    {
00263 
00264         if (charge() && distance > 0. ) {
00265 
00266             // compare with maximum from Material or Medium
00267             float maxstep = interactor()->maxStepSize(this,currentMedium);
00268             if( maxstep < distance ) {
00269                 distance = maxstep;
00270                 setStatus(ALIVE);  // cutting back: cancel decay if any
00271             }
00272          }
00273 
00274          double intlen =interactor()->interactionLength(this,currentMedium),
00275                 distToInteract = distance;
00276          if( intlen !=FLT_MAX && intlen > 0.
00277                 && intlen < 1E5    ) // avoid problem with exponential
00278               distToInteract = Random::exponential( intlen );
00279 
00280          if (distToInteract < distance) {
00281              setStatus( INTERACTED);
00282              distance = distToInteract;
00283          }
00284     }
00285     else if (distance != 0 && status()!= DECAYED )
00286         distance = currentMedium->maxStep();
00287     else if ( status()==DECAYED && distance >currentMedium->maxStep() ){
00288         setStatus(ALIVE); // cancel decay if too far
00289         distance = currentMedium->maxStep();
00290     }
00291     return  distance;
00292 }
00293 
00294 void
00295 MCParticle::stepBy(float step, Ray & path)
00296 {
00297 
00298     double paverage = momentum().mag();
00299     if (paverage==0 || step==0 ) return; // shouldn't happen
00300 
00301     if( charge() ) {
00302         Vector dir = path.direction(step);
00303         setMomentum( paverage * dir);
00304         //  apply energy loss, if appropriate
00305 
00306         interactor()->afterStep(step, this,currentMedium);
00307         float pfinal   = momentum().mag();
00308         if (pfinal==0.)
00309         {
00310             // special case: at rest, so decay it or declare it stopped
00311             if (timeOfDecay > 0 && timeOfDecay < MAX_TIME)
00312             {
00313                 setT( t() + timeOfDecay );
00314                 setStatus( DECAYED );
00315             }else
00316                 setStatus( STOPPED );
00317         }
00318         paverage = ( paverage + pfinal)/2.;
00319         turnAngle  += step*path.curvature();
00320         if ( fabs(turnAngle) > MAX_BEND )
00321                         setStatus( LOOPING );
00322     }
00323 
00324     setPosition(path.position(step));
00325     path.setArcLength(step);
00326 
00327     arcLength  += step;
00328     if( paverage ) {
00329         properTime += step * mass() / paverage;
00330         setT( t() + step * e() / paverage);
00331     }
00332 
00333 }
00334 
00335 void
00336 MCParticle::endStep()
00337 {
00338     if( status() ==STOPPED )
00339     {
00340 
00341         // if at rest, it might decay or annihilate
00342 
00343         if (timeOfDecay > 0 && timeOfDecay < MAX_TIME)
00344         {  setT(t() + timeOfDecay);   // is this right????
00345                         setStatus( DECAYED );
00346         }
00347         else if( charge()
00348                          && interactor()->interactionLength(this,currentMedium)==0 )
00349         {
00350                 // this case for a stopped positron or anti-proton
00351                 setStatus( INTERACTED );
00352         }
00353 
00354      }
00355      // Now actually perform interaction or decay
00356 
00357     if  (status()==DECAYED)
00358                 decayOnce();
00359 
00360     else if  (status()==INTERACTED) {
00361          // status has been set to interacted, but if only E-loss,turn if off
00362         if( !interactor()->interact(this,currentMedium))
00363                 setStatus( ALIVE );
00364     }
00365     return;
00366 
00367 }
00368 
00369 void
00370 MCParticle::printOn(std::ostream& str )const
00371 {
00372   GParticle::printOn(str);
00373   str << " status: ";
00374   switch( _status ) {
00375      case ALIVE:      str << "alive";    break;
00376      case STOPPED:    str << "stopped";  break;
00377      case DECAYED:    str << "decayed";  break;
00378      case INTERACTED: str << "interacted";break;
00379      case LOOPING:    str << "looping";  break;
00380      case LEFT:       str << "left";     break;
00381      case STUCK:      str << "stuck";    break;
00382      case PRIMARY:    str << "primary";  break;
00383      case SHOWER:     str << "shower";  break;
00384      default:         str << "unknown";  break;
00385         }
00386 }
00387 
00388 void MCParticle::addInteractor(Interactor * i)
00389 {
00390    thePDT()->addInteractor(i);
00391 }
00392 
00393 
00394 // allocate static variables
00395 
00396 Ray * MCParticle::s_segment;               // Trajectory of last step
00397 
00398 const Medium* MCParticle::currentMedium; // the current Medium for propagation
00399 float MCParticle::arcLength;             // total distance swum so far
00400 float MCParticle::properTime;            // total proper time since creation.
00401 float MCParticle::turnAngle;             // total angular deflection so far
00402 float MCParticle::timeOfDecay;           // actual proper time of decay
00403 double MCParticle::startingEnergy;        // keep track of last reported energy
00404                                          // for eloss calculation
00405 float MCParticle::step;                  // current step length
00406 float MCParticle::ecut;                  // minimum energy allowed
00407 
00408 int MCParticle::stepcount;               // step counter
00409 int MCParticle::generation;              // generation counter
00410 
00411 int MCParticle::saveTrack=0;
00412 
00413 
00414 

Generated at Mon Nov 26 18:18:33 2001 by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000