1 | // ESAF : Euso Simulation and Analysis Framework |
---|
2 | // $Id: BunchRadiativeTransfer.cc 3023 2012-04-04 14:52:02Z mabl $ |
---|
3 | // Sylvain Moreggia created Jan, 15 2004 |
---|
4 | |
---|
5 | #include "BunchRadiativeTransfer.hh" |
---|
6 | #include "Atmosphere.hh" |
---|
7 | #include "RadiativeFactory.hh" |
---|
8 | #include "ListPhotonsInAtmosphere.hh" |
---|
9 | #include "ListPhotonsOnPupil.hh" |
---|
10 | #include "EsafRandom.hh" |
---|
11 | #include <TROOT.h> |
---|
12 | #include <TH1D.h> |
---|
13 | #include <TH2D.h> |
---|
14 | #include <TProfile.h> |
---|
15 | #include <math.h> |
---|
16 | #include "ParentPhoton.hh" |
---|
17 | #include "SinglePhoton.hh" |
---|
18 | #include "Config.hh" |
---|
19 | #include "LowtranRadiativeProcessesCalculator.hh" |
---|
20 | #include "EConst.hh" |
---|
21 | #include "BunchOfPhotons.hh" |
---|
22 | #include "Ground.hh" |
---|
23 | |
---|
24 | #include "EEvent.hh" |
---|
25 | #include "EAtmosphere.hh" |
---|
26 | #include "EAtmosphereBunchAdder.hh" |
---|
27 | #include "EAtmosphereSingleAdder.hh" |
---|
28 | |
---|
29 | #include "TBenchmark.h" |
---|
30 | |
---|
31 | ClassImp(BunchRadiativeTransfer) |
---|
32 | |
---|
33 | using namespace TMath; |
---|
34 | using namespace sou; |
---|
35 | using namespace EConst; |
---|
36 | |
---|
37 | //#define DEBUG |
---|
38 | |
---|
39 | //_______________________________________________________________________________________________________________________ |
---|
40 | BunchRadiativeTransfer::BunchRadiativeTransfer() : RadiativeTransfer(), fPhotons(0), fTotalList(0), |
---|
41 | fCSpropag(0), fICpropag(0), fNbBunch(0), fNbTot(0) { |
---|
42 | // |
---|
43 | // ctor |
---|
44 | // |
---|
45 | Msg(EsafMsg::Info) << "Enabled" << MsgDispatch; |
---|
46 | fGround = RadiativeFactory::Get()->GetGround(); |
---|
47 | if(!fGround) Msg(EsafMsg::Panic) << "Pb of memory allocation for fGround" << MsgDispatch; |
---|
48 | |
---|
49 | fCSpropag = RadiativeFactory::Get()->GetClearSkyPropagator(fGround); |
---|
50 | fICpropag = RadiativeFactory::Get()->GetInCloudsPropagator(fGround); |
---|
51 | if(!fCSpropag) Msg(EsafMsg::Panic) << "Problem of memory allocation for CSpropag" << MsgDispatch; |
---|
52 | if(!fICpropag) Msg(EsafMsg::Panic) << "Problem of memory allocation for ICpropag" << MsgDispatch; |
---|
53 | fTransToDetec = RadiativeFactory::Get()->GetRadiativeProcessesCalculator(); |
---|
54 | |
---|
55 | // detector geometry : decoupled or optimized |
---|
56 | // decoupled : detector seems to be a sphere. Allows to study several detector geometries with the same RadiativeTransfer simulation |
---|
57 | // optimized : true detector geometry is used in RadiativeTransfer simulation |
---|
58 | string name = Conf()->GetStr("BunchRadiativeTransfer.fDecoupled"); |
---|
59 | if(name == "decoupled") fDecoupled = true; |
---|
60 | else if(name == "optimized") fDecoupled = false; |
---|
61 | else Msg(EsafMsg::Panic) << "Wrong option for BunchRadiativeTransfer.fDecoupled" << MsgDispatch; |
---|
62 | |
---|
63 | // cloud treatment : if "yes" --> cloud scattering simu, if "no" --> just transmission effect |
---|
64 | fCloudStatus = Conf()->GetBool("BunchRadiativeTransfer.fCloudStatus"); |
---|
65 | if(!fCloudStatus && fCSpropag->GetOrder() > 1) |
---|
66 | Msg(EsafMsg::Panic) << "<ctor> No cloud scattering simulation possible only with O1_CskyPropagator" << MsgDispatch; |
---|
67 | |
---|
68 | } |
---|
69 | |
---|
70 | //_______________________________________________________________________________________________________________________ |
---|
71 | BunchRadiativeTransfer::~BunchRadiativeTransfer() { |
---|
72 | // |
---|
73 | // dtor |
---|
74 | // |
---|
75 | SafeDelete(fPhotons); |
---|
76 | SafeDelete(fCSpropag); |
---|
77 | SafeDelete(fICpropag); |
---|
78 | SafeDelete(fTransToDetec); |
---|
79 | } |
---|
80 | |
---|
81 | //_______________________________________________________________________________________________________________________ |
---|
82 | PhotonsOnPupil* BunchRadiativeTransfer::Get(PhotonsInAtmosphere* photons, const DetectorGeometry* dg) { |
---|
83 | // |
---|
84 | // Transport photons from source to Euso pupil |
---|
85 | // |
---|
86 | |
---|
87 | |
---|
88 | // set DetectorGeometry for all propagators |
---|
89 | CopyDetectorGeometry(dg); |
---|
90 | |
---|
91 | |
---|
92 | // in case ground detector simulation //GRNDetec |
---|
93 | if(EUSO().Zv() == 0) fDetAtGrnd = true; |
---|
94 | else fDetAtGrnd = false; |
---|
95 | if(fDetAtGrnd && !fDecoupled) Msg(EsafMsg::Panic) << "In Ground detector mode, decoupled mode must be switched on" << MsgDispatch; |
---|
96 | |
---|
97 | |
---|
98 | // if given list of photons is empty |
---|
99 | if(!photons) return NULL; |
---|
100 | |
---|
101 | |
---|
102 | #ifdef DEBUG |
---|
103 | TString jobRT = "Time spent for transfer process:"; |
---|
104 | TBenchmark gB; |
---|
105 | gB.Start(jobRT); |
---|
106 | #endif |
---|
107 | |
---|
108 | if(photons->GetType() == "empty") Msg(EsafMsg::Panic) <<"When NoLightSource used, NoRadiativeTransfer must be used"<< MsgDispatch; |
---|
109 | if(photons->GetType() != "list") Msg(EsafMsg::Panic) <<"Wrong PhotonsInAtmosphere format. ListPhotonsInAtmosphere expected."<< MsgDispatch; |
---|
110 | fTotalList = (ListPhotonsInAtmosphere*) photons; |
---|
111 | fCSpropag->SetEndFoV(fTotalList->GetTrackStep(fTotalList->GetNbTrackSteps()-1)); //TOFIX when general FoV handling |
---|
112 | fICpropag->SetEndFoV(fTotalList->GetTrackStep(fTotalList->GetNbTrackSteps()-1)); //TOFIX when general FoV handling |
---|
113 | |
---|
114 | |
---|
115 | // if fTransToDetec is LOWTRAN7 |
---|
116 | if(fTransToDetec->GetName() == "lowtran") { |
---|
117 | LowtranRadiativeProcessesCalculator* TransCalcul = (LowtranRadiativeProcessesCalculator*) fTransToDetec; |
---|
118 | // Build a datacard of VERTICAL Lowtran transmission for PropagateToDetector() method |
---|
119 | if(!fDecoupled) { |
---|
120 | Msg(EsafMsg::Info) <<"Building LOWTRAN vertical transmission datacard"<< MsgDispatch; |
---|
121 | TransCalcul->MakeVerticalDatacard(fGround,EUSO().Zv()); |
---|
122 | Msg(EsafMsg::Info) <<"LOWTRAN datacard built"<< MsgDispatch; |
---|
123 | } |
---|
124 | // Build a datacard of ALONG TRACK Lowtran transmission for PropagateToDetector() method |
---|
125 | else { |
---|
126 | Msg(EsafMsg::Info) <<"Building LOWTRAN datacard ALONG TRACK (not vertical)"<< MsgDispatch; |
---|
127 | TransCalcul->MakeTrackToDetectorDatacard(fGround,EUSO(),*fTotalList); |
---|
128 | Msg(EsafMsg::Info) <<"LOWTRAN datacard built"<< MsgDispatch; |
---|
129 | } |
---|
130 | } |
---|
131 | |
---|
132 | |
---|
133 | // number of bunches |
---|
134 | fNbBunch = fTotalList->GetListOfBunch().size(); |
---|
135 | fNbTot = 0; |
---|
136 | Double_t nf = 0; |
---|
137 | Double_t nc = 0; |
---|
138 | for(size_t i=0; i<fNbBunch; i++) { |
---|
139 | fNbTot += (fTotalList->GetListOfBunch()[i])->GetWeight(); |
---|
140 | if(fTotalList->GetListOfBunch()[i]->GetType() == Fluo) nf += fTotalList->GetListOfBunch()[i]->GetWeight(); |
---|
141 | else nc += fTotalList->GetListOfBunch()[i]->GetWeight(); |
---|
142 | } |
---|
143 | #ifdef DEBUG |
---|
144 | Msg(EsafMsg::Debug) << "SIZE OF LIST OF BUNCHES = "<<fNbBunch << MsgDispatch; |
---|
145 | Msg(EsafMsg::Debug) << "Nb fluo = " <<nf << MsgDispatch; |
---|
146 | Msg(EsafMsg::Debug) << "Nb ckov = " <<nc << MsgDispatch; |
---|
147 | #endif |
---|
148 | Msg(EsafMsg::Info) << "TOTAL number of photons ="<<fNbTot << MsgDispatch; |
---|
149 | |
---|
150 | if ( fNbBunch >=1 ) { |
---|
151 | EarthVector track = fTotalList->GetListOfBunch()[fNbBunch - 1]->GetPos() |
---|
152 | - fTotalList->GetListOfBunch()[0]->GetPos(); |
---|
153 | #ifdef DEBUG |
---|
154 | Msg(EsafMsg::Debug) << "size of the photon track = "<<track.Mag()/km <<" km"<< MsgDispatch; |
---|
155 | #endif |
---|
156 | } |
---|
157 | |
---|
158 | |
---|
159 | EEvent* ev = EEvent::GetCurrent(); |
---|
160 | if(ev && ev->GetAtmosphere()) ev->GetAtmosphere()->SetMaxScatOrder(1); |
---|
161 | |
---|
162 | |
---|
163 | // if some SinglePhotons created directly by LightSource module, they are saved into root |
---|
164 | if ( ev ) { |
---|
165 | const vector<SinglePhoton*>& list_single_2 = fTotalList->GetListOfSingle(); |
---|
166 | size_t nbnotsaved = fTotalList->GetNbNotSaved(); |
---|
167 | for (size_t i = list_single_2.size() - nbnotsaved; i<list_single_2.size(); i++ ) { |
---|
168 | EAtmosphereSingleAdder sa( list_single_2[i],true,false,0 ); |
---|
169 | ev->Fill(sa); |
---|
170 | fTotalList->OneSingleSaved(); |
---|
171 | } |
---|
172 | } |
---|
173 | |
---|
174 | |
---|
175 | // loop to transport all the bunches |
---|
176 | BunchOfPhotons* bunch = 0; |
---|
177 | Double_t nbTracked(0); |
---|
178 | Int_t progress = 0; |
---|
179 | |
---|
180 | while(true) { |
---|
181 | bunch = fTotalList->GetBunch(); |
---|
182 | if(!bunch) break; |
---|
183 | nbTracked++; |
---|
184 | |
---|
185 | // saves bunch parameters at creation |
---|
186 | if ( ev ) { |
---|
187 | EAtmosphereBunchAdder ba( bunch, true ); |
---|
188 | ev->Fill(ba); |
---|
189 | } |
---|
190 | // propagation of bunches and creation of single photons |
---|
191 | BunchPropagation(*bunch); |
---|
192 | |
---|
193 | #ifdef DEBUG |
---|
194 | Msg(EsafMsg::Debug) <<"after the process of this bunch, size of list of single = " <<fTotalList->GetListOfSingle().size() <<MsgDispatch; |
---|
195 | #endif |
---|
196 | |
---|
197 | // saves single photon parameters at creation |
---|
198 | if ( ev ) { |
---|
199 | const vector<SinglePhoton*>& list_single = fTotalList->GetListOfSingle(); |
---|
200 | size_t nbnotsaved = fTotalList->GetNbNotSaved(); |
---|
201 | for (size_t i = list_single.size() - nbnotsaved; i<list_single.size(); i++ ) { |
---|
202 | EAtmosphereSingleAdder sa( list_single[i],true,true ); |
---|
203 | ev->Fill(sa); |
---|
204 | fTotalList->OneSingleSaved(); |
---|
205 | } |
---|
206 | } |
---|
207 | |
---|
208 | if (100.*nbTracked/fNbBunch >= progress) { |
---|
209 | Msg(EsafMsg::Info).SetProgress(progress); |
---|
210 | Msg(EsafMsg::Info) << "Bunches Processing:" << MsgCount; |
---|
211 | progress+=10; |
---|
212 | } |
---|
213 | } |
---|
214 | |
---|
215 | #ifdef DEBUG |
---|
216 | Msg(EsafMsg::Debug) <<"final list of single, size = " <<fTotalList->GetListOfSingle().size() <<MsgDispatch; |
---|
217 | #endif |
---|
218 | if(fTotalList->GetNbNotSaved()) Msg(EsafMsg::Warning) <<fTotalList->GetNbNotSaved()<<" SinglePhoton not saved into root" <<MsgDispatch; |
---|
219 | |
---|
220 | // propagates single photons |
---|
221 | PropagationOfSingles(); |
---|
222 | |
---|
223 | // saves single photons after propagation in atmosphere |
---|
224 | if ( ev ) { |
---|
225 | const vector<SinglePhoton*>& list_single_3 = fTotalList->GetListOfSingle(); |
---|
226 | for ( size_t i=0; i<list_single_3.size(); i++ ) { |
---|
227 | EAtmosphereSingleAdder sa( list_single_3[i],false,false,i ); |
---|
228 | ev->Fill(sa); |
---|
229 | } |
---|
230 | } |
---|
231 | |
---|
232 | |
---|
233 | #ifdef DEBUG |
---|
234 | gB.Stop(jobRT); |
---|
235 | MsgForm(EsafMsg::Debug,"Time spent for transfer process: REAL=%6.2f s CPU=%6.2f s",gB.GetRealTime(jobRT),gB.GetCpuTime(jobRT)); |
---|
236 | #endif |
---|
237 | |
---|
238 | return fPhotons; |
---|
239 | } |
---|
240 | |
---|
241 | //______________________________________________________________________________ |
---|
242 | Bool_t BunchRadiativeTransfer::ClearMemory() { |
---|
243 | // |
---|
244 | // Release all the mem hold in the buffers |
---|
245 | // |
---|
246 | |
---|
247 | Reset(); |
---|
248 | return fPhotons ? fPhotons->ClearMemory() : kTRUE; |
---|
249 | } |
---|
250 | |
---|
251 | //______________________________________________________________________________ |
---|
252 | void BunchRadiativeTransfer::Reset() { |
---|
253 | // |
---|
254 | // get ready for next event |
---|
255 | // NB : if fTransToDetec is LOWTRAN7 --> not really reset, its datacard is used for all the events of a run |
---|
256 | // |
---|
257 | if(fGround) fGround->Reset(); |
---|
258 | if(fPhotons) fPhotons->Clear(); |
---|
259 | if(fCSpropag) fCSpropag->Reset(); |
---|
260 | if(fICpropag) fICpropag->Reset(); |
---|
261 | if(fTransToDetec) fTransToDetec->Reset(); |
---|
262 | fNbBunch = 0; |
---|
263 | fNbTot = 0; |
---|
264 | } |
---|
265 | |
---|
266 | //_______________________________________________________________________________________________________________________ |
---|
267 | void BunchRadiativeTransfer::DirectToEuso(const BunchOfPhotons& bigbunch) const { |
---|
268 | // |
---|
269 | // Creates a list of SinglePhoton considering the EUSO solid angle |
---|
270 | // handles fluo and cerenkov (angular distrib used for the later) |
---|
271 | // |
---|
272 | |
---|
273 | Int_t nb = 0; |
---|
274 | EarthVector towardEUSO = (EUSO() - bigbunch.GetPos()).Unit(); |
---|
275 | Double_t theta = fabs(towardEUSO.Angle(bigbunch.GetDir())); // to keep theta within 0-Pi() |
---|
276 | if(theta > Pi()) Msg(EsafMsg::Warning) << "<DirectToEuso> Pb with angle definition" << MsgDispatch; |
---|
277 | Double_t angular_distrib_value = bigbunch.AngularDist_OverTwoPi(theta); |
---|
278 | nb = EsafRandom::Get()->Poisson(bigbunch.GetWeight() * EusoOmega(bigbunch.GetPos()) * angular_distrib_value); |
---|
279 | GenerateDirectSingles(bigbunch,nb); |
---|
280 | |
---|
281 | #ifdef DEBUG |
---|
282 | Msg(EsafMsg::Debug) <<" Direct gives -> " <<nb <<" photons" << MsgDispatch; |
---|
283 | #endif |
---|
284 | } |
---|
285 | |
---|
286 | //_______________________________________________________________________________________________________________________ |
---|
287 | void BunchRadiativeTransfer::BunchPropagation( BunchOfPhotons& bigbunch ) { |
---|
288 | // |
---|
289 | // Propagation of a bunch through the atmosphere |
---|
290 | // |
---|
291 | // temp remark : bunch splitting not used so far, thus don't handle for root filling //TOFIX |
---|
292 | // |
---|
293 | |
---|
294 | #ifdef DEBUG |
---|
295 | Msg(EsafMsg::Debug) << "\nPropagation of the BUNCH nb " << bigbunch.GetId() <<MsgDispatch; |
---|
296 | Msg(EsafMsg::Debug) << "Weight = " << bigbunch.GetWeight() <<MsgDispatch; |
---|
297 | const ParentBunch* parentb = bigbunch.GetParent(); |
---|
298 | Double_t length = (parentb->GetShowerPosi() - parentb->GetShowerPosf()).Mag()/km; |
---|
299 | Msg(EsafMsg::Debug) << "Bunch longitudinal extension = "<<length <<" km" << MsgDispatch; |
---|
300 | #endif |
---|
301 | |
---|
302 | // if bunch is underground, its simulation stops here |
---|
303 | if(fGround->IsUnderGround(bigbunch.GetParent()->GetShowerPosf())) //TOFIX : a part can be above ground (also see related point in ListPinAtmo::fTrack, O2_CSPropag) |
---|
304 | bigbunch.SetFate(3); |
---|
305 | else { |
---|
306 | // photons directly emitted within the Euso solid angle |
---|
307 | DirectToEuso(bigbunch); |
---|
308 | Medium state = CLEARSKY; |
---|
309 | |
---|
310 | // if bunch weight < 1% "mean bunch weight" -> not propagated, because it doesn't contribute |
---|
311 | if( (bigbunch.GetWeight() < 0.001*fNbTot/fNbBunch)) { |
---|
312 | bigbunch.SetFate(2); |
---|
313 | state = NONE; |
---|
314 | } |
---|
315 | |
---|
316 | // relevant propagator called |
---|
317 | while(state > NONE) { |
---|
318 | switch(state) { |
---|
319 | |
---|
320 | case CLEARSKY : state = fCSpropag->Go(bigbunch,*fTotalList); |
---|
321 | break; |
---|
322 | |
---|
323 | case CLOUDY : if(!fCloudStatus) Msg(EsafMsg::Panic) << "<BunchPropagation> SHOULD NOT OCCUR, no cloud treatment" << MsgDispatch; |
---|
324 | state = fICpropag->Go(bigbunch,*fTotalList); |
---|
325 | break; |
---|
326 | |
---|
327 | case GROUND : GroundReflection(bigbunch); |
---|
328 | state = NONE; |
---|
329 | bigbunch.SetFate(4); |
---|
330 | break; |
---|
331 | |
---|
332 | case AEROSOLS : Msg(EsafMsg::Panic) << "AerosolsPropagator (for MS) not implemented" << MsgDispatch; |
---|
333 | break; |
---|
334 | |
---|
335 | default : Msg(EsafMsg::Panic) << "Invalid type of medium in bunch propagation = "<<state << MsgDispatch; |
---|
336 | } |
---|
337 | } |
---|
338 | } |
---|
339 | #ifdef DEBUG |
---|
340 | switch(bigbunch.GetFate()) { |
---|
341 | case 1 : Msg(EsafMsg::Debug) << "NOT PROPAGATED -> FLUO" << MsgDispatch; break; |
---|
342 | case 2 : Msg(EsafMsg::Debug) << "NOT PROPAGATED -> TOO SMALL WEIGHT" << MsgDispatch; break; |
---|
343 | case 3 : Msg(EsafMsg::Debug) << "NOT PROPAGATED -> CREATED UNDERGROUND" << MsgDispatch; break; |
---|
344 | case 4 : Msg(EsafMsg::Debug) << "HAS REACHED GROUND" << MsgDispatch; break; |
---|
345 | case 5 : Msg(EsafMsg::Debug) << "GONE OUT Euso FoV" << MsgDispatch; break; |
---|
346 | default : Msg(EsafMsg::Debug) << "PB with STATE, fate = "<< bigbunch.GetFate()<< MsgDispatch; |
---|
347 | } |
---|
348 | #endif |
---|
349 | |
---|
350 | |
---|
351 | // saves propagated bunch parameters |
---|
352 | EEvent* ev = EEvent::GetCurrent(); |
---|
353 | if ( ev ) { |
---|
354 | EAtmosphereBunchAdder ba(&bigbunch,false); |
---|
355 | ev->Fill(ba); |
---|
356 | } |
---|
357 | } |
---|
358 | |
---|
359 | //_____________________________________________________________________________________________________ |
---|
360 | void BunchRadiativeTransfer::GroundReflection(const BunchOfPhotons& b) const { |
---|
361 | // |
---|
362 | // Process of a bunch reaching ground |
---|
363 | // |
---|
364 | |
---|
365 | // initializations |
---|
366 | #ifdef DEBUG |
---|
367 | Msg(EsafMsg::Debug) << "GroundReflection" << MsgDispatch; |
---|
368 | #endif |
---|
369 | if(fabs(b.GetPos().Zv() - fGround->Altitude(b.GetPos())) > 1) |
---|
370 | Msg(EsafMsg::Warning) << "GroundReflection() must be called if bunch has reached the ground" << MsgDispatch; |
---|
371 | |
---|
372 | // determination of number of singlephotons produced |
---|
373 | Double_t phfunc = fGround->Outgoing_phase_function(b.GetPos(),b.GetDir(),(EUSO() - b.GetPos()).Unit()); |
---|
374 | Double_t weight = b.GetWeight(); |
---|
375 | if(!fCloudStatus) weight = b.GetWeightNocloud(); |
---|
376 | Int_t nb = EsafRandom::Get()->Poisson(weight * fGround->Albedo(b.GetPos()) * EusoOmega(b.GetPos()) * phfunc); |
---|
377 | |
---|
378 | // creation of singlephotons |
---|
379 | GenerateReflectedSingles(nb,b); |
---|
380 | } |
---|
381 | |
---|
382 | //_______________________________________________________________________________________________________________________ |
---|
383 | void BunchRadiativeTransfer::PropagationOfSingles() { |
---|
384 | // |
---|
385 | // Final phase of transfer. Propagate all the SinglePhoton til EUSO pupil |
---|
386 | // |
---|
387 | |
---|
388 | // initializations |
---|
389 | if(!fPhotons) fPhotons = new ListPhotonsOnPupil((vector<ParentPhoton*>*)NULL); |
---|
390 | if(!fPhotons) Msg(EsafMsg::Panic) << "BunchRadiativeTransfer::PropagationOfSingles, NULL fPhotons : Memory pb" << MsgDispatch; |
---|
391 | |
---|
392 | // build PhotonsOnPupil's frame |
---|
393 | BuildPupilFrame(fPhotons); |
---|
394 | |
---|
395 | EarthVector dirtest(1); |
---|
396 | Double_t Trans[4]; |
---|
397 | Double_t TotTrans(0.); |
---|
398 | TRandom* rndm = EsafRandom::Get(); |
---|
399 | SinglePhoton* p = 0; |
---|
400 | size_t nTotal(0),nTracked(0); |
---|
401 | Int_t progress = 0; |
---|
402 | TVector3 local_dir, pos; |
---|
403 | |
---|
404 | nTotal = fTotalList->GetSingleEntries(); |
---|
405 | |
---|
406 | // loop over the list of SinglePhoton |
---|
407 | while(true) { |
---|
408 | p = fTotalList->GetSingle(); |
---|
409 | if(!p) break; |
---|
410 | nTracked++; |
---|
411 | dirtest = (EUSO() - p->Pos()).Unit(); |
---|
412 | if((dirtest - p->Dir()).Mag() > TOLERANCE) Msg(EsafMsg::Warning) << "PropagationOfSingles : SinglePhoton must be directed toward EUSO" << MsgDispatch; |
---|
413 | |
---|
414 | // calculate transmission from photon position to EUSO |
---|
415 | TotTrans = fTransToDetec->Trans(*p,EUSO(),Trans); |
---|
416 | p->SetLastTrans(TotTrans,"tot"); |
---|
417 | p->SetLastTrans(Trans[1],"rayl"); |
---|
418 | p->SetLastTrans(Trans[2],"ozone"); |
---|
419 | p->SetLastTrans(Trans[3],"aero"); |
---|
420 | p->SetLastTrans(TotTrans/(Trans[1]*Trans[2]*Trans[3]),"cloud"); |
---|
421 | |
---|
422 | // check if photon has been absorbed previously during bunch propagation |
---|
423 | // only for the case of fCloudStatus = false (special mode !!) |
---|
424 | Double_t RNDM = rndm->Rndm(); |
---|
425 | if(!fCloudStatus && p->IsAbsorbed() && p->IsCloudAbsorbed()) p->SetAbsorbed(); |
---|
426 | |
---|
427 | // photon is transmitted or absorbed |
---|
428 | else if(TotTrans < RNDM) { |
---|
429 | p->SetAbsorbed(); |
---|
430 | // precise if absorbed by clouds, only for direct fluo and reflected cerenkov (single scattering) |
---|
431 | if(!fCloudStatus && ( Trans[1]*Trans[2]*Trans[3] > RNDM)) { |
---|
432 | if(p->Status() == 0 || (p->Status() == 1 && p->Type() == 1 && p->NbOfInteractions() == 1) ) |
---|
433 | p->SetCloudAbsorbed(); |
---|
434 | } |
---|
435 | } |
---|
436 | |
---|
437 | // Sample a random photon position on pupil |
---|
438 | pos = p->Pos(); |
---|
439 | local_dir = p->Dir(); |
---|
440 | p->SetPosInAtmo(p->Pos()); |
---|
441 | p->AddToPosTof(EUSO() - p->Pos()); |
---|
442 | RamdomPosOnPupil(fPhotons,pos,local_dir); |
---|
443 | |
---|
444 | // check if photon is within the FoV |
---|
445 | if(!GetDetGeometry()->IsInFoV(local_dir)) p->SetOutFoV(); |
---|
446 | else p->SetOutFoV(false); |
---|
447 | |
---|
448 | // if photon transmitted, becomes a photon on pupil |
---|
449 | // FoV 'status' not relevant here (too simply treated, ONLY a flag in RT part) |
---|
450 | // --> will be considered in detector part |
---|
451 | if(!p->IsAbsorbed() || p->IsCloudAbsorbed()) fPhotons->Add(*p,pos,local_dir); |
---|
452 | |
---|
453 | //GRNDetec |
---|
454 | // for ground detector simulation, cos(theta) effect is taken into account here |
---|
455 | if(fDetAtGrnd) { |
---|
456 | EarthVector enterdir = -dirtest; |
---|
457 | if((rndm->Rndm() > cos(enterdir.Theta())) || (enterdir.Theta() > PiOver2())) p->SetAbsorbed(); |
---|
458 | } |
---|
459 | |
---|
460 | // Dump CPU commentaries |
---|
461 | if (100.*nTracked/nTotal >= progress) { |
---|
462 | Msg(EsafMsg::Info).SetProgress(progress); |
---|
463 | Msg(EsafMsg::Info) << "Singles Processing:" << MsgCount; |
---|
464 | progress+=10; |
---|
465 | } |
---|
466 | } |
---|
467 | |
---|
468 | #ifdef DEBUG |
---|
469 | Msg(EsafMsg::Debug) << "Number of ParentPhoton = " << fPhotons->GetNphotons() << MsgDispatch; |
---|
470 | #endif |
---|
471 | } |
---|
472 | |
---|
473 | //_______________________________________________________________________________________________________________________ |
---|
474 | void BunchRadiativeTransfer::GenerateDirectSingles(const BunchOfPhotons& b,Int_t nb) const { |
---|
475 | // |
---|
476 | // SinglePhoton generation (BunchOfPhotons portion which is created within EUSO solid angle) |
---|
477 | // SinglePhotons created added to fTotalList |
---|
478 | // |
---|
479 | Double_t wl, date, tof; |
---|
480 | EarthVector showerpos, dir, diff; |
---|
481 | SinglePhoton* s = 0; |
---|
482 | |
---|
483 | UInt_t bid = b.GetId(); |
---|
484 | PhotonType type = b.GetType(); |
---|
485 | tof = 0; |
---|
486 | |
---|
487 | for(Int_t i=0; i<nb; i++) { |
---|
488 | // corrections for date and showerpos from BunchOfPhotons mean values and longitudinal dispersion |
---|
489 | //showerpos = b.RandomPosInShower(); |
---|
490 | showerpos = DistributeToDensity(b.GetShowerPosi(),b.GetShowerPosf());//random position in shower ACCORDING TO DENSITY |
---|
491 | if(fGround->IsUnderGround(showerpos)) continue; |
---|
492 | diff = showerpos - b.GetShowerPos(); |
---|
493 | date = b.GetDate() + diff.Dot(b.GetDir().Unit())/Clight(); |
---|
494 | dir = EUSO() - showerpos; |
---|
495 | wl = b.GetWlSpectrum().GetLambda(); |
---|
496 | s = new SinglePhoton(type,date,tof,wl,showerpos,showerpos,dir,Direct,bid,b.GetShowerAge()); |
---|
497 | fTotalList->Add(s); |
---|
498 | } |
---|
499 | } |
---|
500 | |
---|
501 | //_____________________________________________________________________________________________________ |
---|
502 | void BunchRadiativeTransfer::GenerateReflectedSingles(Int_t nb, const BunchOfPhotons& b) const { |
---|
503 | // |
---|
504 | // Creates SinglePhoton objects coming from a BunchOfPhotons reflection on ground |
---|
505 | // |
---|
506 | #ifdef DEBUG |
---|
507 | Msg(EsafMsg::Debug)<<"nb of single produced in reflexion process = "<<nb <<MsgDispatch; |
---|
508 | #endif |
---|
509 | TRandom* rndm = EsafRandom::Get(); |
---|
510 | Double_t wl, date, tof; |
---|
511 | EarthVector showerpos, pos, dir, diff; |
---|
512 | SinglePhoton* s = 0; |
---|
513 | |
---|
514 | UInt_t bid = b.GetId(); |
---|
515 | PhotonType type = b.GetType(); |
---|
516 | date = b.GetDate(); |
---|
517 | |
---|
518 | for(Int_t i=0; i<nb; i++) { |
---|
519 | // corrections for date and showerpos, from BunchOfPhotons mean values and longitudinal+lateral distributions at creation |
---|
520 | showerpos = b.RandomPosInShower(); |
---|
521 | |
---|
522 | // if showerpos is underground |
---|
523 | if(fGround->IsUnderGround(showerpos)) continue; |
---|
524 | |
---|
525 | diff = showerpos - b.GetShowerPos(); |
---|
526 | date = b.GetDate() + diff.Dot(b.GetDir().Unit())/Clight(); |
---|
527 | // tof and position corrections, due to angular distributions at creation |
---|
528 | pos = b.PosRandomAngCorrec(showerpos,b.GetPos()); // here is a fake correction in position, used to get direction for new impact calculation |
---|
529 | pos = fGround->GetImpact(showerpos,(pos - showerpos).Unit()); |
---|
530 | // if no impact |
---|
531 | if(pos.Z() == HUGE) continue; |
---|
532 | tof = b.GetTof() * (showerpos - pos).Mag()/(b.GetPos() - b.GetShowerPos()).Mag(); |
---|
533 | dir = EUSO() - pos; |
---|
534 | wl = b.GetWlSpectrum().GetLambda(); |
---|
535 | s = new SinglePhoton(type,date,tof,wl,showerpos,pos,dir,Reflected,bid,b.GetShowerAge()); |
---|
536 | s->AddInteraction(); |
---|
537 | s->AddHistory(Reflected); |
---|
538 | if(!fCloudStatus) { |
---|
539 | Double_t transcloud = b.GetWeight() / b.GetWeightNocloud(); |
---|
540 | if(rndm->Rndm() > transcloud) { |
---|
541 | s->SetAbsorbed(); |
---|
542 | s->SetCloudAbsorbed(); |
---|
543 | } |
---|
544 | } |
---|
545 | fTotalList->Add(s); |
---|
546 | } |
---|
547 | } |
---|
548 | |
---|
549 | EarthVector BunchRadiativeTransfer::DistributeToDensity(EarthVector initial,EarthVector final) const { |
---|
550 | // |
---|
551 | // This function distributes the photons according to the slant depth inside a |
---|
552 | // a step. This makes the photon production process more physical. |
---|
553 | // The light curves looks like smoother. |
---|
554 | // |
---|
555 | |
---|
556 | // FIXME: This assumes a monotone dependence of the Air Density between |
---|
557 | // initial and final position! |
---|
558 | |
---|
559 | const int numberOfSteps = 10000; |
---|
560 | |
---|
561 | |
---|
562 | |
---|
563 | const Atmosphere* atm= Atmosphere::Get(); |
---|
564 | const Double_t density1=atm->Air_Density(initial); |
---|
565 | const Double_t density2=atm->Air_Density(final); |
---|
566 | const Bool_t invertedDensityDirection = density2 < density1; |
---|
567 | |
---|
568 | const EarthVector v1 = invertedDensityDirection ? final : initial; |
---|
569 | const EarthVector v2 = invertedDensityDirection ? initial : final; |
---|
570 | const EarthVector stepSize = (v2 - v1) * (1.0 / numberOfSteps); |
---|
571 | |
---|
572 | TRandom* rndm = EsafRandom::Get(); |
---|
573 | const Double_t rndDepth = rndm->Rndm(); |
---|
574 | |
---|
575 | |
---|
576 | const Double_t density_FINAL=density1+rndDepth*(density2-density1);//random sampled density |
---|
577 | |
---|
578 | EarthVector pos = v1; |
---|
579 | |
---|
580 | int firstStep = 0; |
---|
581 | int lastStep = numberOfSteps; |
---|
582 | |
---|
583 | while (firstStep <= lastStep) { |
---|
584 | |
---|
585 | const int midStep = (firstStep + lastStep) / 2; |
---|
586 | pos = v1 + midStep * stepSize; |
---|
587 | const Double_t den_INTER=atm->Air_Density(pos); |
---|
588 | |
---|
589 | if (density_FINAL > den_INTER) { |
---|
590 | |
---|
591 | // repeat search in top half. |
---|
592 | firstStep = midStep + 1; |
---|
593 | |
---|
594 | } else if (density_FINAL < den_INTER) { |
---|
595 | // repeat search in bottom half. |
---|
596 | lastStep = midStep - 1; |
---|
597 | |
---|
598 | } else { |
---|
599 | |
---|
600 | // Found exact value, or return one step too low |
---|
601 | break; |
---|
602 | } |
---|
603 | } |
---|
604 | |
---|
605 | #ifdef DEBUG |
---|
606 | |
---|
607 | Msg(EsafMsg::Debug) << MsgDispatch; |
---|
608 | |
---|
609 | Msg(EsafMsg::Debug) << "Distributing bunch position over depth:" << MsgDispatch; |
---|
610 | Msg(EsafMsg::Debug) << "Initial: (" << initial.X() << ", " |
---|
611 | << initial.Y() << ", " |
---|
612 | << initial.Z() << ")" |
---|
613 | << "\t Density: " << density1 << MsgDispatch; |
---|
614 | |
---|
615 | Msg(EsafMsg::Debug) << "Final: (" << final.X() << ", " |
---|
616 | << final.Y() << ", " |
---|
617 | << final.Z() << ")" |
---|
618 | << "\t Density: " << density2 << MsgDispatch; |
---|
619 | |
---|
620 | Msg(EsafMsg::Debug) << "Random density: " << density_FINAL << MsgDispatch; |
---|
621 | Msg(EsafMsg::Debug) << "Position of rnd density: (" |
---|
622 | << pos.X() << ", " |
---|
623 | << pos.Y() << ", " |
---|
624 | << pos.Z() << ")" << MsgDispatch; |
---|
625 | |
---|
626 | // The desinity at the location should be equal to random density |
---|
627 | Msg(EsafMsg::Debug) << "Achived density: " << atm->Air_Density(pos) << MsgDispatch; |
---|
628 | |
---|
629 | // Newline for formating |
---|
630 | |
---|
631 | Msg(EsafMsg::Debug) << MsgDispatch; |
---|
632 | |
---|
633 | |
---|
634 | #endif |
---|
635 | |
---|
636 | return pos; |
---|
637 | } |
---|