00001
00002
00003
00004
00005
00006
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
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;
00081 const float MCParticle::MAX_BEND=31;
00082 const int MCParticle::MAX_GENERATION=500;
00083 const int MCParticle::MAX_STEPS=10000;
00084
00085
00086
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();
00099
00100 while (status()==ALIVE)
00101 {
00102 const Medium * nextMedium=currentMedium;
00103
00104
00105 float maxStep = checkStep( );
00106
00107 if( maxStep==0) {
00108 step = 0;
00109 s_segment = 0;
00110 }
00111 else {
00112
00113
00114 s_segment=
00115 currentMedium->CreateRay( position(), momentum(), charge(), maxStep );
00116
00117
00118 s_segment->setFlag(stepcount);
00119
00120
00121
00122 step = currentMedium->distanceToLeave(*s_segment, nextMedium, maxStep);
00123
00124 if (step < maxStep) {
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
00134 step = maxStep;
00135 nextMedium = currentMedium;
00136 }
00137
00138
00139 if(step > 0) {
00140 stepBy(step, *s_segment );
00141 }
00142
00143 }
00144
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
00155 Detector* d =currentMedium->detector();
00156 if( d )
00157 d->score(this);
00158
00159
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
00176
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
00196 setMomentum(starting_momentum);
00197
00198
00199
00200 if(status() == STOPPED){
00201 return;
00202 }
00203
00204
00205
00206
00207
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
00216 if( generation > saveTrack) removeChildren();
00217 }
00218
00219 float MCParticle::checkStep()
00220
00221
00222
00223 {
00224 float pmagnitude = momentum().mag();
00225 float distance = FLT_MAX;
00226
00227
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
00250
00251 if (mass()>0. && timeOfDecay < MAX_TIME ) {
00252 float distToDecay =
00253 (timeOfDecay-properTime)*eta();
00254 if (distToDecay <= distance)
00255 { setStatus( DECAYED);
00256 distance = (distToDecay > 0.) ? distToDecay : 0.;
00257 }
00258 }
00259
00260
00261
00262 if (!currentMedium->material().isVacuum()) {
00263
00264 if (charge() && distance > 0. ) {
00265
00266
00267 float maxstep = interactor()->maxStepSize(this,currentMedium);
00268 if( maxstep < distance ) {
00269 distance = maxstep;
00270 setStatus(ALIVE);
00271 }
00272 }
00273
00274 double intlen =interactor()->interactionLength(this,currentMedium),
00275 distToInteract = distance;
00276 if( intlen !=FLT_MAX && intlen > 0.
00277 && intlen < 1E5 )
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);
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;
00300
00301 if( charge() ) {
00302 Vector dir = path.direction(step);
00303 setMomentum( paverage * dir);
00304
00305
00306 interactor()->afterStep(step, this,currentMedium);
00307 float pfinal = momentum().mag();
00308 if (pfinal==0.)
00309 {
00310
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
00342
00343 if (timeOfDecay > 0 && timeOfDecay < MAX_TIME)
00344 { setT(t() + timeOfDecay);
00345 setStatus( DECAYED );
00346 }
00347 else if( charge()
00348 && interactor()->interactionLength(this,currentMedium)==0 )
00349 {
00350
00351 setStatus( INTERACTED );
00352 }
00353
00354 }
00355
00356
00357 if (status()==DECAYED)
00358 decayOnce();
00359
00360 else if (status()==INTERACTED) {
00361
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
00395
00396 Ray * MCParticle::s_segment;
00397
00398 const Medium* MCParticle::currentMedium;
00399 float MCParticle::arcLength;
00400 float MCParticle::properTime;
00401 float MCParticle::turnAngle;
00402 float MCParticle::timeOfDecay;
00403 double MCParticle::startingEnergy;
00404
00405 float MCParticle::step;
00406 float MCParticle::ecut;
00407
00408 int MCParticle::stepcount;
00409 int MCParticle::generation;
00410
00411 int MCParticle::saveTrack=0;
00412
00413
00414