00001
00002
00003
00004
00006 #include <iostream>
00007 #include <TMath.h>
00008 #include <TRandom.h>
00009
00010 #include "ScintPhoton.h"
00011
00012 #include "Conventions/Munits.h"
00013 #include "UgliGeometry/UgliStripHandle.h"
00014 #include "MessageService/MsgService.h"
00015
00016 CVSID( " $Id: ScintPhoton.cxx,v 1.8 2006/12/01 20:12:11 rhatcher Exp $" );
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 ClassImp(ScintPhoton)
00038
00039
00040 Double_t ScintPhoton::fsOuterCladdingIndex = 1.42;
00041 Double_t ScintPhoton::fsInnerCladdingIndex = 1.49;
00042 Double_t ScintPhoton::fsFibreIndex = 1.59;
00043 Double_t ScintPhoton::fsFibreRadius = 0.6 * Munits::mm;
00044 Double_t ScintPhoton::fsScintIndex = 1.6;
00045 Double_t ScintPhoton::fsScintAttenLength = 0.33;
00046 Double_t ScintPhoton::fsTiO2ReflecDiffuse = 0.93;
00047 Double_t ScintPhoton::fsGrooveReflecCoeff = 0.5;
00048 Double_t ScintPhoton::fsGrooveHalfWidth = 0.7 * Munits::mm;
00049 Double_t ScintPhoton::fsReflectorScintReflec = 0.0;
00050 Int_t ScintPhoton::fsLambertianReflection = 1;
00051
00052 const double kTooLong = 999. * Munits::meter;
00053
00054
00055
00056
00057 ScintPhoton::ScintPhoton() :
00058 DigiPhoton(),
00059 fRandom(gRandom),
00060 fStart(0.,0.,0.),
00061 fStartT(0.),
00062 fStartV(0.,0.,1.),
00063 fHalfHeight(0.005),
00064 fHalfLength(4.00),
00065 fHalfWidth(0.02083),
00066 fHitSurface(0),
00067 fInFibre(false),
00068 fSpecularReflected(false),
00069 fDiffuseReflected(false),
00070 fAttenuated(false),
00071 fAbsorbed(false),
00072 fGeomError(false),
00073 fBounces(0),
00074 fTrackLength(0.),
00075 fNormal(0,0,0),
00076 fScintAttenLength(fsScintAttenLength),
00077 fTiO2ReflecDiffuse(fsTiO2ReflecDiffuse)
00078 {
00079 }
00080
00081
00082
00083 ScintPhoton::ScintPhoton(TRandom* random,
00084 const DigiScintHit* hit,
00085 const UgliStripHandle& ush,
00086 const TVector3& startPos,
00087 Double_t t,
00088 const TVector3& startDir) : DigiPhoton()
00089 {
00090 Reset( random, hit, ush, startPos, t, startDir );
00091 }
00092
00093
00094
00095
00096 ScintPhoton::ScintPhoton(TRandom* random,
00097 const DigiScintHit* hit,
00098 const UgliStripHandle& ush,
00099 const TVector3& startPos, Double_t t) : DigiPhoton()
00100 {
00101 TVector3 startDir(0,0,0);
00102 Reset( random, hit, ush, startPos, t, startDir );
00103 }
00104
00105
00106
00107
00108 ScintPhoton::ScintPhoton(TRandom* random,
00109 const DigiScintHit* hit,
00110 const UgliStripHandle& ush,
00111 Double_t x, Double_t y, Double_t z, Double_t t,
00112 Double_t u, Double_t v, Double_t w ) : DigiPhoton()
00113 {
00114 TVector3 startPos(x,y,z);
00115 TVector3 startDir(u,v,w);
00116 Reset( random, hit, ush, startPos, t, startDir );
00117 }
00118
00119
00120
00121
00122
00123
00124 void ScintPhoton::Reset(TRandom* random,
00125 const DigiScintHit* hit,
00126 const UgliStripHandle& ush,
00127 const TVector3& startPos, Double_t t,
00128 const TVector3& startDir)
00129 {
00130
00131 if(random) fRandom = random;
00132 else fRandom = gRandom;
00133
00134 SetParentHit(hit);
00135
00136 fUgliStrip = ush;
00137 if(fUgliStrip.IsValid()) {
00138 fHalfHeight = fUgliStrip.GetHalfThickness();
00139 fHalfLength = fUgliStrip.GetHalfLength();
00140 fHalfWidth = fUgliStrip.GetHalfWidth();
00141 } else {
00142
00143 fHalfHeight=(0.005);
00144 fHalfLength=(4.00);
00145 fHalfWidth=(0.02083);
00146 }
00147
00148 fHitSurface = 0;
00149 fInFibre = false;
00150 fSpecularReflected = false;
00151 fDiffuseReflected = false;
00152 fAttenuated = false;
00153 fAbsorbed = false;
00154 fGeomError = false;
00155 fBounces = 0;
00156 fTrackLength = 0;
00157
00158 fStart = startPos;
00159 fStartT = t;
00160
00161 if(startDir.Mag2()==0) {
00162
00163 double cosTheta = 1. - 2.*fRandom->Rndm();
00164 double sinTheta = TMath::Sin(TMath::ACos(cosTheta));
00165 double phi = 2.*TMath::Pi()*fRandom->Rndm();
00166
00167 fStartV.SetXYZ( sinTheta*TMath::Cos(phi),
00168 sinTheta*TMath::Sin(phi),
00169 cosTheta );
00170 }
00171
00172
00173 fPos = fStart ;
00174 fDir = fStartV;
00175 fT = fStartT;
00176
00177
00178 fScintAttenLength =fsScintAttenLength;
00179 fTiO2ReflecDiffuse =fsTiO2ReflecDiffuse;
00180 }
00181
00182
00183
00184
00185 ScintPhoton::~ScintPhoton()
00186 {
00187 }
00188
00189 void ScintPhoton::Configure( const Registry& r )
00190 {
00191
00192
00193
00194 Double_t tmpd;
00195 if (r.Get("ScintIndex",tmpd)) fsScintIndex = tmpd;
00196 if (r.Get("FibreIndex",tmpd)) fsFibreIndex = tmpd;
00197 if (r.Get("OuterCladdingIndex",tmpd)) fsOuterCladdingIndex = tmpd;
00198 if (r.Get("InnerCladdingIndex",tmpd)) fsInnerCladdingIndex = tmpd;
00199
00200 if (r.Get("FibreRadius",tmpd)) fsFibreRadius = tmpd;
00201 if (r.Get("ScintAttenLength",tmpd)) fsScintAttenLength = tmpd;
00202 if (r.Get("TiO2ReflecDiffuse",tmpd)) fsTiO2ReflecDiffuse = tmpd;
00203 if (r.Get("GrooveReflecCoeff",tmpd)) fsGrooveReflecCoeff = tmpd;
00204 if (r.Get("GrooveHalfWidth",tmpd)) fsGrooveHalfWidth = tmpd;
00205 if (r.Get("ReflectorScintReflec",tmpd)) fsReflectorScintReflec = tmpd;
00206
00207 Int_t tmpi;
00208 if (r.Get("LambertianReflection",tmpi)) fsLambertianReflection = tmpi;
00209 }
00210
00211
00212
00213 Bool_t ScintPhoton::PropagateOneLeg()
00214 {
00215
00216
00217
00218
00219
00220 fAttenuated = false;
00221 fSpecularReflected = false;
00222 fDiffuseReflected = false;
00223 fAttenuated = false;
00224 fAbsorbed = false;
00225 fGeomError = false;
00226
00227
00228 bool bounceOk = FindNextSurface();
00229 if(!bounceOk) {
00230 MSG("Photon",Msg::kWarning) << "Bounce failed." << endl;
00231 fGeomError = true;
00232 return false;
00233 }
00234
00235
00236 Attenuate();
00237 Move();
00238
00239 if(fAttenuated) return true;
00240
00241
00242 InteractAtSurface();
00243
00244
00245 if(fInFibre) return true;
00246 if(fAbsorbed) return true;
00247
00248
00249 if(fSpecularReflected || fDiffuseReflected) {
00250 FindReflectedDirection();
00251 return true;
00252 }
00253
00254 return false;
00255 }
00256
00257
00258 Bool_t ScintPhoton::Propagate()
00259 {
00260
00261
00262
00263
00264
00265 fBounces = 0;
00266 while(true) {
00267
00268 PropagateOneLeg();
00269 if(fGeomError) return false;
00270 if(fAttenuated) return true;
00271 if(fAbsorbed) return true;
00272 if(fInFibre) return true;
00273
00274
00275
00276 fBounces++;
00277 }
00278
00279 return false;
00280 }
00281
00282
00283 void ScintPhoton::Print(Option_t* ) const
00284 {
00285 cout << "ScintPhoton: (Units in cm)" << endl;
00286 cout << " Started: " << fStart.X() << "\t" << fStart.Y() << "\t" << fStart.Z() << endl;
00287 cout << " StartDir: " << fStartV.X() << "\t" << fStartV.Y() << "\t" << fStartV.Z() << endl;
00288
00289 cout << " Pos: " << X() << "\t" << Y() << "\t" << Z() << endl;
00290 cout << " Dir After: " << fDir.X() << "\t" << fDir.Y() << "\t" << fDir.Z() << endl;
00291 cout << " Hit surface: " << fHitSurface << "\t Track length: " << fTrackLength << endl;
00292 if(fInFibre) cout << " In fibre. ";
00293 if(fSpecularReflected) cout << " SpecReflec. ";
00294 if(fDiffuseReflected) cout << " DiffuseReflec. ";
00295 if(fAttenuated) cout << " Attenuated. ";
00296 if(fAbsorbed) cout << " Absorbed. ";
00297 if(fGeomError) cout << " GeomError. ";
00298 cout << endl;
00299 }
00300
00301
00302
00303 Bool_t ScintPhoton::FindNextSurface()
00304 {
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 fTrackLength = kTooLong;
00327 fHitSurface = 0;
00328 double lengths[8];
00329 lengths[1] = DistanceToSurfaceI();
00330 lengths[2] = DistanceToSurfaceII();
00331 lengths[3] = DistanceToSurfaceIII();
00332 lengths[4] = DistanceToSurfaceIV();
00333 lengths[5] = DistanceToSurfaceV();
00334 lengths[6] = DistanceToSurfaceVI();
00335 lengths[7] = DistanceToFibre();
00336
00337 for(int isurface = 1; isurface<=7; isurface++) {
00338 if( ( lengths[isurface] < fTrackLength ) && (lengths[isurface]>=0) ){
00339 fHitSurface = isurface;
00340 fTrackLength = lengths[isurface];
00341 }
00342 }
00343
00344 if(fHitSurface == 0) {
00345 MSG("Photon",Msg::kWarning) << "Photon hit no surface!" << endl;
00346 fGeomError = true;
00347 return false;
00348 }
00349
00350 return true;
00351 }
00352
00353
00355 Bool_t ScintPhoton::Attenuate()
00356 {
00357
00358
00359
00360
00361
00362 double distance = fRandom->Exp(fScintAttenLength);
00363
00364 if(distance < fTrackLength) {
00365
00366 fAttenuated = true;
00367
00368 fTrackLength = distance;
00369 }
00370
00371 return fAttenuated;
00372 }
00373
00374
00376 Bool_t ScintPhoton::Move()
00377 {
00378 fPos += fDir*fTrackLength;
00379 fT += TimeOfFlight(fTrackLength);
00380 return true;
00381 }
00382
00384 Double_t ScintPhoton::TimeOfFlight( Double_t distance )
00385 {
00386
00387 return distance * fsScintIndex / Munits::c_light;
00388 }
00389
00390
00392 Bool_t ScintPhoton::InteractAtSurface()
00393 {
00394
00395
00396
00397
00398
00399
00400 fNormal.SetXYZ(0,0,0);
00401
00402
00403
00404 if(fHitSurface == 7) {
00405
00406
00407
00408
00409 fNormal.SetXYZ(0,
00410 Y(),
00411 Z()- (fHalfHeight-fsFibreRadius));
00412 fNormal.SetMag(1.0);
00413
00414
00415 double n_dot_v = fNormal.Dot(fDir);
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 double incidentAngle = TMath::ACos(- n_dot_v);
00426 if(incidentAngle<TMath::ASin(fsOuterCladdingIndex/fsScintIndex)){
00427
00428
00429
00430
00431
00432
00433 fInFibre = true;
00434
00435 } else {
00436 fSpecularReflected = true;
00437 }
00438
00439 return true;
00440 }
00441
00442
00443
00444 if( ( fHitSurface >=1 ) && (fHitSurface <=4) ) {
00445 if( fHitSurface == 1 ) {
00446
00447 fNormal.SetXYZ(0,0,-1);
00448
00449
00450 if( (TMath::Abs(Y()) < fsGrooveHalfWidth) ) {
00451 if(fRandom->Rndm()>fsGrooveReflecCoeff)
00452 fSpecularReflected = true;
00453 else
00454 fAbsorbed = true;
00455 return true;
00456 }
00457 } else if ( fHitSurface == 2 ) {
00458 fNormal.SetXYZ(0,-1,0);
00459 } else if ( fHitSurface == 3 ) {
00460 fNormal.SetXYZ(0,0,1);
00461 } else if ( fHitSurface == 4 ) {
00462 fNormal.SetXYZ(0,1,0);
00463 }
00464
00465
00466 double rand = fRandom->Rndm();
00467 if(rand < fTiO2ReflecDiffuse) {
00468 fDiffuseReflected = true;
00469 } else {
00470 fAbsorbed = true;
00471 }
00472
00473 return true;
00474 }
00475
00476
00477
00478 if( (fHitSurface == 5) || (fHitSurface == 6)) {
00479
00480
00481
00482 StripEnd::StripEnd_t end = StripEnd::kPositive;
00483 fNormal.SetXYZ(-1,0,0);
00484
00485 if( fHitSurface == 6 ) {
00486 fNormal.SetXYZ(1,0,0);
00487 end = StripEnd::kNegative;
00488 }
00489
00490 if( fUgliStrip.IsMirrored(end) ) {
00491 if(fRandom->Rndm()<=fsReflectorScintReflec)
00492 fSpecularReflected = true;
00493 else
00494 fAbsorbed = true;
00495 } else {
00496 fAbsorbed = true;
00497 }
00498
00499 return true;
00500 }
00501
00502 MSG("Photon",Msg::kError) << "Error in InteractAtSurface: surface unrecognized." << endl;
00503 return false;
00504 }
00505
00507 void ScintPhoton::FindReflectedDirection()
00508 {
00509
00510
00511
00512 double n_dot_v = fNormal.Dot(fDir);
00513
00514 if(fSpecularReflected) {
00515 fDir = fDir - 2.0*n_dot_v*fNormal;
00516 return;
00517 }
00518
00519 if(fDiffuseReflected) {
00520
00521
00522
00523 TVector3 a = fNormal.Orthogonal();
00524 TVector3 b = fNormal.Cross(a);
00525
00526 double cosTheta;
00527 if(fsLambertianReflection==0) {
00528 cosTheta = fRandom->Rndm();
00529 } else {
00530 cosTheta = sqrt(fRandom->Rndm());
00531 }
00532 double phi = 2.*TMath::Pi()*fRandom->Rndm();
00533 double sinTheta = TMath::Sqrt(1.0-cosTheta*cosTheta);
00534 double sinPhi = TMath::Sin(phi);
00535 double cosPhi = TMath::Cos(phi);
00536
00537 fDir = fNormal*cosTheta
00538 + a*sinTheta*cosPhi
00539 + b*sinTheta*sinPhi;
00540 if(fDir.Mag2()==0) {
00541 cout << "mag0: " << fNormal.X() << "\t" << fNormal.Y() << "\t" << fNormal.Z() << endl;
00542 cout << "mag0: " << a.x() << "\t" << a.y() << "\t" << a.z() << endl;
00543 cout << "mag0: " << b.x() << "\t" << b.y() << "\t" << b.z() << endl;
00544 }
00545 }
00546 }
00547
00548
00549
00551 Double_t ScintPhoton::DistanceToSurfaceI()
00552 {
00553
00554
00555 if(fDir.Z()<=0) return kTooLong;
00556 double lambda = ( fHalfHeight - fPos.Z() )/fDir.Z();
00557 return lambda;
00558 }
00559
00561 Double_t ScintPhoton::DistanceToSurfaceII()
00562 {
00563
00564
00565 if(fDir.Y()<=0) return kTooLong;
00566 double lambda = ( fHalfWidth - fPos.Y() )/fDir.Y();
00567 return lambda;
00568 }
00569
00571 Double_t ScintPhoton::DistanceToSurfaceIII()
00572 {
00573
00574
00575 if(fDir.Z()>=0) return kTooLong;
00576 double lambda = ( -fHalfHeight - fPos.Z() )/fDir.Z();
00577 return lambda;
00578 }
00579
00580
00582 Double_t ScintPhoton::DistanceToSurfaceIV()
00583 {
00584
00585
00586 if(fDir.Y()>=0) return kTooLong;
00587 double lambda = ( -fHalfWidth - fPos.Y() )/fDir.Y();
00588 return lambda;
00589 }
00590
00592
00593 Double_t ScintPhoton::DistanceToSurfaceV()
00594 {
00595
00596
00597 if(fDir.X() <= 0.) return kTooLong;
00598 double lambda = ( fHalfLength - fPos.X() )/fDir.X();
00599 return lambda;
00600 }
00601
00603 Double_t ScintPhoton::DistanceToSurfaceVI()
00604 {
00605
00606
00607 if(fDir.X() >= 0.) return kTooLong;
00608 double lambda = ( -fHalfLength - fPos.X() )/fDir.X();
00609 return lambda;
00610 }
00611
00612
00614 Double_t ScintPhoton::DistanceToFibre()
00615 {
00616
00617
00618
00619
00620 double dy = fPos.Y();
00621 double dz = fPos.Z() - (fHalfHeight-fsFibreRadius);
00622
00623
00624
00625
00626 double v2 = (fDir.Y()*fDir.Y() + fDir.Z()*fDir.Z());
00627 if(v2==0) return kTooLong;
00628
00629 double vdotdx = (fDir.Y() * dy) + (fDir.Z() * dz);
00630 double insqrt = (vdotdx*vdotdx) -
00631 (v2)*((dy*dy) + (dz*dz) - (fsFibreRadius*fsFibreRadius));
00632
00633
00634 if(insqrt<0) return kTooLong;
00635
00636
00637 double soln1 = (-vdotdx - TMath::Sqrt(insqrt))/v2;
00638 if(soln1>=0) return soln1;
00639
00640
00641
00642
00643 return kTooLong;
00644 }
00645
00646