1 | // $Id: MCRadiativeTransfer.cc 2767 2006-11-15 15:50:14Z moreggia $ |
---|
2 | // Author: Sylvain Moreggia 2005/08/16 |
---|
3 | |
---|
4 | /***************************************************************************** |
---|
5 | * ESAF: Euso Simulation and Analysis Framework * |
---|
6 | * * |
---|
7 | * Id: MCRadiativeTransfer * |
---|
8 | * Package: radiativetransfer * |
---|
9 | * Coordinator: Sylvain Moreggia * |
---|
10 | * * |
---|
11 | *****************************************************************************/ |
---|
12 | |
---|
13 | //_____________________________________________________________________________ |
---|
14 | // |
---|
15 | // MCRadiativeTransfer |
---|
16 | // |
---|
17 | // Detection from a ground detector is now possible in this mode |
---|
18 | // |
---|
19 | // |
---|
20 | // Config file parameters |
---|
21 | // ====================== |
---|
22 | // |
---|
23 | // <parameter name>: <parameter description> |
---|
24 | // |
---|
25 | // - fMScattAnalysis >0 means Detector geometry is completely switched off |
---|
26 | // - no direct photons |
---|
27 | // - scattered SinglePhotons are located at their last scattering position |
---|
28 | // - it is a pure Multiple Scattering Analysis : no propagation to detector (actually there is, but transmissions=1) |
---|
29 | // - MaxPhi=1 |
---|
30 | // - MaxOmega=1e-20 for fPropagator and =1 for PhotonsInOmega() |
---|
31 | // - if == 1 : simu checks if photon goes out freely of atmosphere. If it does, it is counted, if not it is lost |
---|
32 | // - if == 2 : does not check -> allow to study scattering without being biased by last transfer |
---|
33 | // |
---|
34 | |
---|
35 | #include "MCRadiativeTransfer.hh" |
---|
36 | #include "Atmosphere.hh" |
---|
37 | #include "RadiativeFactory.hh" |
---|
38 | #include "ListPhotonsInAtmosphere.hh" |
---|
39 | #include "ListPhotonsOnPupil.hh" |
---|
40 | #include "EsafRandom.hh" |
---|
41 | #include <TROOT.h> |
---|
42 | #include <TH1D.h> |
---|
43 | #include <TH2D.h> |
---|
44 | #include <TProfile.h> |
---|
45 | #include <math.h> |
---|
46 | #include "ParentPhoton.hh" |
---|
47 | #include "SinglePhoton.hh" |
---|
48 | #include "Config.hh" |
---|
49 | #include "LowtranRadiativeProcessesCalculator.hh" |
---|
50 | #include "FastRadiativeProcessesCalculator.hh" |
---|
51 | #include "EConst.hh" |
---|
52 | #include "BunchOfPhotons.hh" |
---|
53 | #include "Ground.hh" |
---|
54 | |
---|
55 | #include "EEvent.hh" |
---|
56 | #include "EAtmosphere.hh" |
---|
57 | #include "EAtmosphereBunchAdder.hh" |
---|
58 | #include "EAtmosphereSingleAdder.hh" |
---|
59 | |
---|
60 | #include "TBenchmark.h" |
---|
61 | |
---|
62 | ClassImp(MCRadiativeTransfer) |
---|
63 | |
---|
64 | using namespace TMath; |
---|
65 | using namespace sou; |
---|
66 | using namespace EConst; |
---|
67 | |
---|
68 | //_____________________________________________________________________________ |
---|
69 | MCRadiativeTransfer::MCRadiativeTransfer() : RadiativeTransfer() , fPhotons(0), fTotalList(0), fPropagator(0), fTransToDetec(0), |
---|
70 | fNbBunch(0), fNbTot(0), fNbSingles(0), fOmegaMax(0), fDistance_cut(0) { |
---|
71 | // |
---|
72 | // ctor |
---|
73 | // |
---|
74 | Msg(EsafMsg::Info) << "Enabled" << MsgDispatch; |
---|
75 | fGround = RadiativeFactory::Get()->GetGround(); |
---|
76 | if(!fGround) Msg(EsafMsg::Panic) << "Pb of memory allocation for fGround" << MsgDispatch; |
---|
77 | |
---|
78 | // init some DM |
---|
79 | Double_t maxtof = Conf()->GetNum("MCRadiativeTransfer.fTofCut")*microsecond; |
---|
80 | fMScattAnalysis = Int_t(Conf()->GetNum("MCRadiativeTransfer.fMScattAnalysis")); |
---|
81 | fKeepAll = Conf()->GetBool("MCRadiativeTransfer.fKeepAll"); |
---|
82 | Double_t TOA = Conf()->GetNum("MCRadiativeTransfer.fTOA")*km; |
---|
83 | fPropagator = new SinglePhotonPropagator(fGround,maxtof,TOA); |
---|
84 | |
---|
85 | // config for last trans to detector |
---|
86 | fTransMode = Conf()->GetStr("MCRadiativeTransfer.fTransMode"); |
---|
87 | if(fTransMode == "fast") |
---|
88 | fTransToDetec = new FastRadiativeProcessesCalculator(); |
---|
89 | else if(fTransMode == "lowtran") |
---|
90 | fTransToDetec = new LowtranRadiativeProcessesCalculator(); |
---|
91 | else Msg(EsafMsg::Panic) << "Wrong option for MCRadiativeTransfer.fTransMode" << MsgDispatch; |
---|
92 | |
---|
93 | |
---|
94 | fMaxPhNb = Conf()->GetNum("MCRadiativeTransfer.fMaxPhNb"); |
---|
95 | |
---|
96 | fScatOrder = Int_t(Conf()->GetNum("MCRadiativeTransfer.fScatOrder")); |
---|
97 | Msg(EsafMsg::Info) << "Max Scattering order to be simulated = " << fScatOrder << MsgDispatch; |
---|
98 | |
---|
99 | // detector geometry : decoupled or optimized |
---|
100 | // decoupled : - detector seems to be a sphere. Allows to study several detector geometries with the same RadiativeTransfer simulation |
---|
101 | // - MUST be used in ground detector mode |
---|
102 | // optimized : - true detector geometry is used in RadiativeTransfer simulation |
---|
103 | // - not available for ground detector |
---|
104 | string name = Conf()->GetStr("MCRadiativeTransfer.fDecoupled"); |
---|
105 | if(name == "decoupled") fDecoupled = true; |
---|
106 | else if(name == "optimized") fDecoupled = false; |
---|
107 | else Msg(EsafMsg::Panic) << "Wrong option for MCRadiativeTransfer.fDecoupled" << MsgDispatch; |
---|
108 | |
---|
109 | } |
---|
110 | |
---|
111 | //_____________________________________________________________________________ |
---|
112 | MCRadiativeTransfer::~MCRadiativeTransfer() { |
---|
113 | // |
---|
114 | // Destructor |
---|
115 | // |
---|
116 | SafeDelete(fPhotons); |
---|
117 | SafeDelete(fPropagator); |
---|
118 | SafeDelete(fTransToDetec); |
---|
119 | } |
---|
120 | |
---|
121 | //______________________________________________________________________________ |
---|
122 | Bool_t MCRadiativeTransfer::ClearMemory() { |
---|
123 | // |
---|
124 | // Release all the mem hold in the buffers |
---|
125 | // |
---|
126 | |
---|
127 | Reset(); |
---|
128 | vector<SinglePhoton*> emptySingle; |
---|
129 | emptySingle.swap(fTempList); |
---|
130 | |
---|
131 | return fPhotons ? fPhotons->ClearMemory() : kTRUE; |
---|
132 | } |
---|
133 | |
---|
134 | |
---|
135 | //_______________________________________________________________________________________________________________________ |
---|
136 | PhotonsOnPupil* MCRadiativeTransfer::Get(PhotonsInAtmosphere* photons, const DetectorGeometry* dg) { |
---|
137 | // |
---|
138 | // Transport photons from source to Euso pupil |
---|
139 | // |
---|
140 | |
---|
141 | |
---|
142 | |
---|
143 | //////////////////////////////////////////////////////////////////////////////////////////// |
---|
144 | ///////////////////////////////// Initializations ///////////////////////////////////////// |
---|
145 | //////////////////////////////////////////////////////////////////////////////////////////// |
---|
146 | |
---|
147 | |
---|
148 | // 1. Preprocesses |
---|
149 | // copy DetectorGeometry |
---|
150 | CopyDetectorGeometry(dg); |
---|
151 | |
---|
152 | // in case ground detector simulation |
---|
153 | if(EUSO().Zv() == 0) fDetAtGrnd = true; |
---|
154 | else fDetAtGrnd = false; |
---|
155 | if(fDetAtGrnd && !fDecoupled) Msg(EsafMsg::Panic) << "In Ground detector mode, decoupled mode must be switched on" << MsgDispatch; |
---|
156 | if(fDetAtGrnd) { |
---|
157 | Msg(EsafMsg::Warning) << "Ground detector mode enabled" << MsgDispatch; |
---|
158 | if(fTransMode == "lowtran") Msg(EsafMsg::Panic) << "Ground detector mode requires option : MCRadiativeTransfer.fTransMode = fast" << MsgDispatch; |
---|
159 | } |
---|
160 | |
---|
161 | // if given list of photons is empty |
---|
162 | if(!photons) return NULL; |
---|
163 | |
---|
164 | if(photons->GetType() == "empty") Msg(EsafMsg::Panic) <<"When NoLightSource used, NoRadiativeTransfer should be used"<< MsgDispatch; |
---|
165 | if(photons->GetType() != "list") Msg(EsafMsg::Panic) <<"Wrong PhotonsInAtmosphere format. ListPhotonsInAtmosphere expected."<< MsgDispatch; |
---|
166 | fTotalList = (ListPhotonsInAtmosphere*) photons; |
---|
167 | |
---|
168 | |
---|
169 | // if Lowtran FORTRAN code used : build a datacard of VERTICAL transmission for PropagateAllToDetector() and PropagateTempListToDetector(..) method |
---|
170 | // NB : internally checks if datacard already exists. If so, does not rebuild it |
---|
171 | if(!fDecoupled && !fMScattAnalysis && fTransMode == "lowtran") { |
---|
172 | Msg(EsafMsg::Info) <<"Building LOWTRAN vertical transmission datacard"<< MsgDispatch; |
---|
173 | LowtranRadiativeProcessesCalculator* LowtranToDetec = (LowtranRadiativeProcessesCalculator*)fTransToDetec; |
---|
174 | LowtranToDetec->MakeVerticalDatacard(fGround,EUSO().Zv()); |
---|
175 | Msg(EsafMsg::Info) <<"LOWTRAN datacard built"<< MsgDispatch; |
---|
176 | } |
---|
177 | else if((fDecoupled || fMScattAnalysis) && fTransMode == "lowtran") { |
---|
178 | Msg(EsafMsg::Warning) <<"Interface with LOWTRAN fortran code not well ADAPTED to decoupled mode (including ground mode) and MScattAnalysis mode"<< MsgDispatch; |
---|
179 | Msg(EsafMsg::Warning) <<"Should better use configuration : MCRadiativeTransfer.fTransMode = fast"<< MsgDispatch; |
---|
180 | } |
---|
181 | |
---|
182 | |
---|
183 | |
---|
184 | |
---|
185 | |
---|
186 | // 2. Get some infos about created light |
---|
187 | // look at number of bunches and photons |
---|
188 | fNbBunch = fTotalList->GetListOfBunch().size(); |
---|
189 | fNbTot = 0; |
---|
190 | fNbSingles = 0; |
---|
191 | Double_t nf(0), nc(0); |
---|
192 | for(size_t i=0; i<fNbBunch; i++) { |
---|
193 | fNbTot += (fTotalList->GetListOfBunch()[i])->GetWeight(); |
---|
194 | if(fTotalList->GetListOfBunch()[i]->GetType() == Fluo) |
---|
195 | nf += fTotalList->GetListOfBunch()[i]->GetWeight(); |
---|
196 | else nc += fTotalList->GetListOfBunch()[i]->GetWeight(); |
---|
197 | } |
---|
198 | |
---|
199 | // some prints |
---|
200 | #ifdef DEBUG |
---|
201 | Msg(EsafMsg::Debug) << "SIZE OF LIST OF BUNCHES = "<<fNbBunch << MsgDispatch; |
---|
202 | Msg(EsafMsg::Debug) << "Nb fluo = " <<nf << MsgDispatch; |
---|
203 | Msg(EsafMsg::Debug) << "Nb ckov = " <<nc << MsgDispatch; |
---|
204 | |
---|
205 | if ( fNbBunch >=1 ) { |
---|
206 | EarthVector track = fTotalList->GetListOfBunch()[fNbBunch - 1]->GetPos() |
---|
207 | - fTotalList->GetListOfBunch()[0]->GetPos(); |
---|
208 | Msg(EsafMsg::Debug) << "size of the photon track = "<<track.Mag()/km <<" km"<< MsgDispatch; |
---|
209 | } |
---|
210 | #endif |
---|
211 | Msg(EsafMsg::Info) << "TOTAL number of photons ="<<fNbTot << MsgDispatch; |
---|
212 | |
---|
213 | |
---|
214 | |
---|
215 | |
---|
216 | |
---|
217 | // 3. Prepare Monte Carlo algorithm |
---|
218 | // set omega max |
---|
219 | if(fMScattAnalysis == 0) { |
---|
220 | // fOmegaMax setting for space detector : last scattering layer is taken at 30km altitude |
---|
221 | //TOFIX : if a scattering exists higher in altitude |
---|
222 | fOmegaMax = EusoOmega(EarthVector(0,0,30*km)); |
---|
223 | if(fDetAtGrnd) { |
---|
224 | fDistance_cut = Conf()->GetNum("MCRadiativeTransfer.fDistance_cut")*km; |
---|
225 | fOmegaMax = EusoOmega(EarthVector(0,0,fDistance_cut)); |
---|
226 | } |
---|
227 | fPropagator->SetOmegaMax(fOmegaMax); |
---|
228 | } |
---|
229 | else { |
---|
230 | fOmegaMax = 1; |
---|
231 | fPropagator->SetOmegaMax(1e-20); // means that fPropagator will keep every photon that reaches the relevant scat order |
---|
232 | } |
---|
233 | |
---|
234 | |
---|
235 | // set phase function maximum value for the set of phase functions involved in the simulation : |
---|
236 | // molecular, ground, clouds, (aerosols to come) |
---|
237 | if(fMScattAnalysis == 0) { |
---|
238 | Double_t molecular_value = fPropagator->GetRadiativeCalculator()->GetMaxPhaseFunction("rayleigh"); |
---|
239 | Double_t clouds_value = Atmosphere::Get()->GetClouds()->GetMaxPhaseFunction("truncated"); |
---|
240 | Double_t aerosol_value = Atmosphere::Get()->GetAerosol()->GetMaxPhaseFunction(GetWlRangeMin(),GetWlRangeMax()); |
---|
241 | Double_t ground_value = fGround->GetMaxOutgoing_phase_function(); |
---|
242 | fMaxPhaseFunction = Max(molecular_value,aerosol_value); |
---|
243 | fMaxPhaseFunction = Max(fMaxPhaseFunction,clouds_value); |
---|
244 | fMaxPhaseFunction = Max(fMaxPhaseFunction,ground_value); |
---|
245 | Msg(EsafMsg::Info) << "MAXIMUM OF PHASE FUNCTION = "<<fMaxPhaseFunction << MsgDispatch; |
---|
246 | Msg(EsafMsg::Info) << "molecular_value = "<<molecular_value << MsgDispatch; |
---|
247 | Msg(EsafMsg::Info) << "clouds_value = "<<clouds_value << MsgDispatch; |
---|
248 | Msg(EsafMsg::Info) << "aerosol_value = "<<aerosol_value << MsgDispatch; |
---|
249 | Msg(EsafMsg::Info) << "ground_value = "<<ground_value << MsgDispatch; |
---|
250 | } |
---|
251 | else fMaxPhaseFunction = 1; |
---|
252 | fPropagator->SetMaxPhaseFunction(fMaxPhaseFunction); |
---|
253 | |
---|
254 | |
---|
255 | |
---|
256 | |
---|
257 | // 4. root output init |
---|
258 | EEvent* ev = EEvent::GetCurrent(); |
---|
259 | if(ev->GetAtmosphere()) ev->GetAtmosphere()->SetMaxScatOrder(fScatOrder); |
---|
260 | |
---|
261 | // if some SinglePhotons created directly by LightSource module, they are saved into root |
---|
262 | if ( ev ) { |
---|
263 | const vector<SinglePhoton*>& list_single_2 = fTotalList->GetListOfSingle(); |
---|
264 | size_t nbnotsaved = fTotalList->GetNbNotSaved(); |
---|
265 | for (size_t i = list_single_2.size() - nbnotsaved; i<list_single_2.size(); i++ ) { |
---|
266 | EAtmosphereSingleAdder sa( list_single_2[i],true,false,0 ); |
---|
267 | ev->Fill(sa); |
---|
268 | fTotalList->OneSingleSaved(); |
---|
269 | } |
---|
270 | } |
---|
271 | |
---|
272 | |
---|
273 | |
---|
274 | |
---|
275 | //////////////////////////////////////////////////////////////////////////////////////////// |
---|
276 | ///////////////////////////////// ALGO STARTS HERE ///////////////////////////////////////// |
---|
277 | //////////////////////////////////////////////////////////////////////////////////////////// |
---|
278 | BunchOfPhotons* bunch = 0; |
---|
279 | Bool_t next(0),subnext(0); |
---|
280 | Double_t nbTracked(0), fraction(0), left(0),right(10),subleft(0),subright(2.5); |
---|
281 | Int_t split_level = Int_t(ceil(fNbTot * fOmegaMax * fMaxPhaseFunction / fMaxPhNb)) + 1; // +1 in case of round-off |
---|
282 | Msg(EsafMsg::Warning) << "NB of photons to propagate after reduction "<<fNbTot * fOmegaMax * fMaxPhaseFunction<< MsgDispatch; |
---|
283 | Msg(EsafMsg::Warning) << "Each scattering order simu will be split in "<<split_level<<" parts" << MsgDispatch; |
---|
284 | |
---|
285 | // 1. Direct photons simulation |
---|
286 | while(true) { |
---|
287 | bunch = fTotalList->GetBunch(); |
---|
288 | if(!bunch) break; |
---|
289 | |
---|
290 | // saves bunch parameters at creation |
---|
291 | if ( ev ) { |
---|
292 | EAtmosphereBunchAdder ba( bunch, true ); |
---|
293 | ev->Fill(ba); |
---|
294 | } |
---|
295 | |
---|
296 | // photons going directly toward detector |
---|
297 | if(!fMScattAnalysis) DirectToEuso(*bunch); // no direct light in MScattAnalysis mode |
---|
298 | } |
---|
299 | |
---|
300 | // 2.3 Scan fTempList before filling fTotalList, applying relevant cuts : |
---|
301 | // - if photon status > 4, it is lost |
---|
302 | // - if GROUND detector, check if photon is a real candidate. If not, it is lost |
---|
303 | // - if fKeepAll == false, photons are propagated to detector and those absorbed are lost |
---|
304 | Msg(EsafMsg::Info) <<"Nb of direct photons before cuts = " <<fTempList.size() << MsgDispatch; |
---|
305 | ScanTempList(); |
---|
306 | fTotalList->Add(fTempList); |
---|
307 | |
---|
308 | |
---|
309 | |
---|
310 | // 2. SCATTERING SIMULATION loop |
---|
311 | for(Int_t ord=1; ord <= fScatOrder; ord++) { |
---|
312 | Msg(EsafMsg::Info) << "\nSCATTERING ORDER = " << ord<< MsgDispatch; |
---|
313 | #ifdef DEBUG |
---|
314 | TString jobMCRT = "Time spent for Scattering simu:"; |
---|
315 | TBenchmark gB; |
---|
316 | gB.Start(jobMCRT); |
---|
317 | #endif |
---|
318 | nbTracked = 0; |
---|
319 | fraction = 0; |
---|
320 | left = 0; |
---|
321 | right = 10; |
---|
322 | subleft = 0; |
---|
323 | subright = 2.5; |
---|
324 | fTotalList->ResetBunchCounter(); // for below extraction from list |
---|
325 | Int_t loop_j = 0; |
---|
326 | Int_t remainingPhotons = -1; |
---|
327 | for(Int_t level=0; level < split_level; level++) { |
---|
328 | Msg(EsafMsg::Info) << "************ Starting bunches transformation Level nb "<<level+1<<" ************"<< MsgDispatch; |
---|
329 | if(level == 0) Msg(EsafMsg::Info) << " : 0%" << MsgFlush; |
---|
330 | for(UInt_t i=loop_j; i <fTotalList->GetBunchEntries(); i++) { |
---|
331 | bunch = fTotalList->GetBunch(loop_j); |
---|
332 | loop_j++; |
---|
333 | nbTracked++; |
---|
334 | |
---|
335 | // 2.1 generate reduce nb of photons |
---|
336 | remainingPhotons = PhotonsInOmega(*bunch,remainingPhotons); |
---|
337 | |
---|
338 | // if huge nb of photons (>1e6), present scattering order simu is splitted |
---|
339 | if(remainingPhotons > -1) { |
---|
340 | Msg(EsafMsg::Warning) << "\nSplit level nb " <<level+1<<" reached" << MsgDispatch; |
---|
341 | loop_j--; |
---|
342 | nbTracked--; |
---|
343 | break; |
---|
344 | } |
---|
345 | |
---|
346 | // dump info |
---|
347 | fraction = 100*nbTracked/fNbBunch; |
---|
348 | if (left<fraction && fraction <=right) |
---|
349 | next = kFALSE; |
---|
350 | else if (fraction>right) { |
---|
351 | next = kTRUE; |
---|
352 | left = right; |
---|
353 | right += 10; |
---|
354 | } |
---|
355 | if (subleft<fraction && fraction <=subright) { |
---|
356 | subnext = kFALSE; |
---|
357 | } |
---|
358 | if (fraction > subright) { |
---|
359 | subnext = kTRUE; |
---|
360 | subleft = subright; |
---|
361 | subright +=2; |
---|
362 | } |
---|
363 | if (next) Msg(EsafMsg::Info) << left << "%" << MsgFlush; |
---|
364 | if (subnext) Msg(EsafMsg::Info)<< "." << MsgFlush; |
---|
365 | } |
---|
366 | Msg(EsafMsg::Info) << " -done" << MsgDispatch; |
---|
367 | Msg(EsafMsg::Info) << "NB of SinglePhoton to PROPAGATE = "<<fNbSingles<< MsgDispatch; |
---|
368 | fNbSingles = 0; // reset |
---|
369 | |
---|
370 | |
---|
371 | // 2.2 scattering simu for this bunch at the relevant scattering order |
---|
372 | fPropagator->Go(fTempList,ord); |
---|
373 | |
---|
374 | // 2.2' in MScattAnalysis MODE 1 |
---|
375 | // check if photons would scatter at next order |
---|
376 | // if not they are KEPT, otherwise they are flagged as "LostByCut" |
---|
377 | if(fMScattAnalysis == 1) fPropagator->CheckIfScatAgain(fTempList); |
---|
378 | |
---|
379 | |
---|
380 | // 2.3 Scan fTempList before filling fTotalList, applying relevant cuts : |
---|
381 | // - if photon status > 4, it is lost |
---|
382 | // - if GROUND detector, check if photon is a real candidate. If not, it is lost |
---|
383 | // - if fKeepAll == false, photons are propagated to detector and those absorbed are lost |
---|
384 | ScanTempList(); |
---|
385 | |
---|
386 | // 2.4 Move photons from fTempList to fTotalList : fTempList does not contain photons anymore |
---|
387 | // Only photons which have successfully scattered are written in fTotalList, others are lost |
---|
388 | fTotalList->Add(fTempList); |
---|
389 | |
---|
390 | #ifdef DEBUG |
---|
391 | gB.Stop(jobMCRT); |
---|
392 | MsgForm(EsafMsg::Info,"Time spent for this scattering order : REAL=%6.2f s CPU=%6.2f s",gB.GetRealTime(jobMCRT),gB.GetCpuTime(jobMCRT)); |
---|
393 | #endif |
---|
394 | } |
---|
395 | } |
---|
396 | |
---|
397 | |
---|
398 | |
---|
399 | |
---|
400 | // 3. saves single photon parameters after scattering simulation |
---|
401 | if ( ev ) { |
---|
402 | const vector<SinglePhoton*>& list_single = fTotalList->GetListOfSingle(); |
---|
403 | size_t nbnotsaved = fTotalList->GetNbNotSaved(); |
---|
404 | for (size_t i = list_single.size() - nbnotsaved; i<list_single.size(); i++ ) { |
---|
405 | EAtmosphereSingleAdder sa( list_single[i],true,true ); |
---|
406 | ev->Fill(sa); |
---|
407 | fTotalList->OneSingleSaved(); |
---|
408 | } |
---|
409 | } |
---|
410 | |
---|
411 | #ifdef DEBUG |
---|
412 | Msg(EsafMsg::Debug) <<"final list of single, size = " <<fTotalList->GetListOfSingle().size() <<MsgDispatch; |
---|
413 | #endif |
---|
414 | if(fTotalList->GetNbNotSaved()) Msg(EsafMsg::Warning) <<fTotalList->GetNbNotSaved()<<" SinglePhoton not saved into root" <<MsgDispatch; |
---|
415 | |
---|
416 | |
---|
417 | |
---|
418 | |
---|
419 | // 4. propagates all direct and scattered photons until detector (Lowtran is used, c.f. Ozone) |
---|
420 | // ALLOW to study transmission values along the last travel to detector |
---|
421 | // IS fake if fMScattAnalysis > 0 |
---|
422 | if(fKeepAll) PropagateAllToDetector(); |
---|
423 | |
---|
424 | |
---|
425 | // 5. Convert PinA in PonP |
---|
426 | ConvertIntoPonP(); |
---|
427 | |
---|
428 | // saves single photons after propagation until detector |
---|
429 | if ( ev ) { |
---|
430 | const vector<SinglePhoton*>& list_single_3 = fTotalList->GetListOfSingle(); |
---|
431 | for ( size_t i=0; i<list_single_3.size(); i++ ) { |
---|
432 | EAtmosphereSingleAdder sa( list_single_3[i],false,false,i ); |
---|
433 | ev->Fill(sa); |
---|
434 | } |
---|
435 | } |
---|
436 | |
---|
437 | |
---|
438 | return fPhotons; |
---|
439 | } |
---|
440 | |
---|
441 | //_______________________________________________________________________________________________________________________ |
---|
442 | void MCRadiativeTransfer::Reset() { |
---|
443 | // |
---|
444 | // get ready for next event |
---|
445 | // NB : when Lowtran used --> some fTransToDetec internal datacard not reset (used for all the events of a run) |
---|
446 | // |
---|
447 | if(fGround) fGround->Reset(); |
---|
448 | if(fPhotons) fPhotons->Clear(); |
---|
449 | if(fPropagator) fPropagator->Reset(); |
---|
450 | for(size_t i=0; i<fTempList.size(); i++) { |
---|
451 | SafeDelete(fTempList[i]); |
---|
452 | Msg(EsafMsg::Panic) <<"fTempList SHOULD BE EMPTY, remains : "<<fTempList.size()<<" photons inside"<<MsgDispatch; |
---|
453 | |
---|
454 | } |
---|
455 | if(fTransToDetec) fTransToDetec->Reset(); |
---|
456 | fTempList.clear(); |
---|
457 | fNbBunch = 0; |
---|
458 | fNbTot = 0; |
---|
459 | fNbSingles = 0; |
---|
460 | fOmegaMax = 0; |
---|
461 | } |
---|
462 | |
---|
463 | //_______________________________________________________________________________________________________________________ |
---|
464 | void MCRadiativeTransfer::DirectToEuso(const BunchOfPhotons& b) { |
---|
465 | // |
---|
466 | // Creates a list of SinglePhoton considering the EUSO solid angle |
---|
467 | // handles fluo and cerenkov (angular distrib used for the later) |
---|
468 | // THESE SINGLEPHOTON WILL NOT UNDERGO SCATTERING SIMU |
---|
469 | // |
---|
470 | |
---|
471 | Int_t nb = 0; |
---|
472 | EarthVector towardEUSO = (EUSO() - b.GetPos()).Unit(); |
---|
473 | Double_t theta = fabs(towardEUSO.Angle(b.GetDir())); // to keep theta within 0-Pi() |
---|
474 | if(theta > Pi()) Msg(EsafMsg::Warning) << "<DirectToEuso> Pb with angle definition" << MsgDispatch; |
---|
475 | |
---|
476 | Double_t angular_distrib_value = b.AngularDist_OverTwoPi(theta); |
---|
477 | nb = EsafRandom::Get()->Poisson(b.GetWeight() * EusoOmega(b.GetPos()) * angular_distrib_value); |
---|
478 | |
---|
479 | // SinglePhotons created and added to fTotalList (THEY WILL NOT UNDERGO SCATTERING SIMU) |
---|
480 | Double_t wl, date, tof; |
---|
481 | EarthVector showerpos, dir, diff; |
---|
482 | SinglePhoton* s = 0; |
---|
483 | |
---|
484 | UInt_t bid = b.GetId(); |
---|
485 | PhotonType type = b.GetType(); |
---|
486 | tof = 0; |
---|
487 | |
---|
488 | for(Int_t i=0; i<nb; i++) { |
---|
489 | // corrections for date and showerpos from BunchOfPhotons mean values and longitudinal dispersion |
---|
490 | showerpos = b.RandomPosInShower(); |
---|
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 | fTempList.push_back(s); |
---|
498 | } |
---|
499 | } |
---|
500 | |
---|
501 | //_______________________________________________________________________________________________________________________ |
---|
502 | Int_t MCRadiativeTransfer::PhotonsInOmega(const BunchOfPhotons& b, Int_t remainingPhotons) { |
---|
503 | // |
---|
504 | // Detector solid angle is applied here -> the resulting photons will undergo scattering simu |
---|
505 | // Photon features are set here (lambda, position, direction) |
---|
506 | // SinglePhoton are stored into fTempList for scattering simu |
---|
507 | // |
---|
508 | // if remainingPhotons > -1, means the nb of photons to create is specified |
---|
509 | // |
---|
510 | |
---|
511 | Int_t nb = 0; |
---|
512 | Int_t rtn = -1; |
---|
513 | Double_t wl, date, tof; |
---|
514 | EarthVector showerpos, dir, diff; |
---|
515 | SinglePhoton* s = 0; |
---|
516 | UInt_t bid = b.GetId(); |
---|
517 | PhotonType type = b.GetType(); |
---|
518 | tof = 0; |
---|
519 | |
---|
520 | if(fMScattAnalysis) nb = Int_t(b.GetWeight()); |
---|
521 | else if(remainingPhotons > -1) nb = remainingPhotons; |
---|
522 | else nb = EsafRandom::Get()->Poisson(b.GetWeight() * fOmegaMax * fMaxPhaseFunction); |
---|
523 | |
---|
524 | for(Int_t i=0; i<nb; i++) { |
---|
525 | // get features at creation |
---|
526 | showerpos = b.RandomPosInShower(); |
---|
527 | if(fGround->IsUnderGround(showerpos)) continue; |
---|
528 | diff = showerpos - b.GetShowerPos(); |
---|
529 | date = b.GetDate() + diff.Dot(b.GetDir().Unit())/Clight(); |
---|
530 | dir = b.RandomDirection(); |
---|
531 | wl = b.GetWlSpectrum().GetLambda(); |
---|
532 | s = new SinglePhoton(type,date,tof,wl,showerpos,showerpos,dir,None,bid,b.GetShowerAge()); |
---|
533 | fNbSingles++; |
---|
534 | fTempList.push_back(s); |
---|
535 | if(fNbSingles >= fMaxPhNb) { |
---|
536 | rtn = nb - 1 - i; |
---|
537 | break; |
---|
538 | } |
---|
539 | } |
---|
540 | |
---|
541 | #ifdef DEBUG |
---|
542 | //Msg(EsafMsg::Debug) <<" InOmega gives -> " <<nb <<" photons" << MsgDispatch; |
---|
543 | #endif |
---|
544 | |
---|
545 | return rtn; |
---|
546 | } |
---|
547 | |
---|
548 | //_______________________________________________________________________________________________________________________ |
---|
549 | void MCRadiativeTransfer::PropagateAllToDetector() { |
---|
550 | // |
---|
551 | // Final phase of transfer. Propagate all the SinglePhoton til EUSO pupil |
---|
552 | // USE LOWTRAN (because of Ozone transmission) |
---|
553 | // DISABLED if fKeepAll == false, PropagateTempListToDetector() method used instead |
---|
554 | // FAKE if fMScattAnalysis > 0 |
---|
555 | // |
---|
556 | |
---|
557 | EarthVector dirtest(1); |
---|
558 | Double_t Trans[4]; |
---|
559 | Double_t TotTrans(0.); |
---|
560 | TRandom* rndm = EsafRandom::Get(); |
---|
561 | SinglePhoton* p = 0; |
---|
562 | size_t nTotal(0),nTracked(0); |
---|
563 | Float_t fraction(0); |
---|
564 | Bool_t next(0),subnext(0); |
---|
565 | Float_t left(0),right(10),subleft(0),subright(2.5); |
---|
566 | nTotal = fTotalList->GetSingleEntries(); |
---|
567 | Msg(EsafMsg::Info) << "Propagation All photons to Detector: 0%" << MsgFlush; |
---|
568 | |
---|
569 | |
---|
570 | // loop over the list of SinglePhoton |
---|
571 | while(true) { |
---|
572 | p = fTotalList->GetSingle(); |
---|
573 | if(!p) break; |
---|
574 | nTracked++; |
---|
575 | |
---|
576 | // photon direction is toward EUSO |
---|
577 | p->SetDir((EUSO() - p->Pos()).Unit()); |
---|
578 | |
---|
579 | // calculate transmission from photon position to EUSO |
---|
580 | if(!fMScattAnalysis) TotTrans = fTransToDetec->Trans(*p,EUSO(),Trans); |
---|
581 | else {// MScatt analysis : does not propagate photons, detector does not exist |
---|
582 | TotTrans = 1; |
---|
583 | Trans[0] = 1; Trans[1] = 1; Trans[2] = 1; Trans[3] = 1; |
---|
584 | } |
---|
585 | p->SetLastTrans(TotTrans,"tot"); |
---|
586 | p->SetLastTrans(Trans[1],"rayl"); |
---|
587 | p->SetLastTrans(Trans[2],"ozone"); |
---|
588 | p->SetLastTrans(Trans[3],"aero"); |
---|
589 | p->SetLastTrans(TotTrans/(Trans[1]*Trans[2]*Trans[3]),"cloud"); |
---|
590 | |
---|
591 | // tell if photon is absorbed |
---|
592 | if(TotTrans < rndm->Rndm()) p->SetAbsorbed(); |
---|
593 | |
---|
594 | // Dump CPU commentaries |
---|
595 | fraction = 100*Float_t(nTracked)/Float_t(nTotal); |
---|
596 | if (left<fraction && fraction <=right) |
---|
597 | next = kFALSE; |
---|
598 | else if (fraction>right) { |
---|
599 | next = kTRUE; |
---|
600 | left = right; |
---|
601 | right += 10; |
---|
602 | } |
---|
603 | if (subleft<fraction && fraction <=subright) { |
---|
604 | subnext = kFALSE; |
---|
605 | } |
---|
606 | if (fraction > subright) { |
---|
607 | subnext = kTRUE; |
---|
608 | subleft = subright; |
---|
609 | subright +=2; |
---|
610 | } |
---|
611 | if (next) Msg(EsafMsg::Info) << left << "%" << MsgFlush; |
---|
612 | if (subnext) Msg(EsafMsg::Info)<< "." << MsgFlush; |
---|
613 | } |
---|
614 | Msg(EsafMsg::Info) << " -done" << MsgDispatch; |
---|
615 | } |
---|
616 | |
---|
617 | //_______________________________________________________________________________________________________________________ |
---|
618 | void MCRadiativeTransfer::ScanTempList() { |
---|
619 | // |
---|
620 | // remove unrelevant photons (status > 4) |
---|
621 | // if fKeepAll == false : call PropagateTempListToDetector() --> photons absorbed are not kept |
---|
622 | // |
---|
623 | // if GROUND detector mode : check geometrical cuts |
---|
624 | // check if photon is a candidate : if not, it is lost |
---|
625 | // |
---|
626 | |
---|
627 | SinglePhoton* p = 0; |
---|
628 | for(UInt_t m=0; m < fTempList.size(); m++) { |
---|
629 | p = fTempList[m]; |
---|
630 | if(p->Status() > 4) { |
---|
631 | SafeDelete(fTempList[m]); |
---|
632 | } |
---|
633 | else if(fDetAtGrnd && !IsSeenByGroundDetector(*p)) { |
---|
634 | SafeDelete(fTempList[m]); |
---|
635 | } |
---|
636 | } |
---|
637 | |
---|
638 | if(!fKeepAll) PropagateTempListToDetector(); |
---|
639 | } |
---|
640 | |
---|
641 | //_______________________________________________________________________________________________________________________ |
---|
642 | void MCRadiativeTransfer::PropagateTempListToDetector() { |
---|
643 | // |
---|
644 | // same as PropagateToDetector but : |
---|
645 | // - act on fTempList |
---|
646 | // - disable fine transmission study |
---|
647 | // |
---|
648 | |
---|
649 | // init |
---|
650 | EarthVector dirtest(1); |
---|
651 | Double_t Trans[4]; |
---|
652 | Double_t TotTrans(0.); |
---|
653 | TRandom* rndm = EsafRandom::Get(); |
---|
654 | SinglePhoton* p = 0; |
---|
655 | size_t nTotal(0),nTracked(0); |
---|
656 | Float_t fraction(0); |
---|
657 | Bool_t next(0),subnext(0); |
---|
658 | Float_t left(0),right(10),subleft(0),subright(2.5); |
---|
659 | nTotal = fTempList.size(); |
---|
660 | Msg(EsafMsg::Info) << "Propagation TempList to Detector: 0%" << MsgFlush; |
---|
661 | |
---|
662 | |
---|
663 | // loop over the list of SinglePhoton |
---|
664 | for(UInt_t m=0; m < fTempList.size(); m++) { |
---|
665 | p = fTempList[m]; |
---|
666 | nTracked++; |
---|
667 | if(!p) continue; |
---|
668 | |
---|
669 | // photon direction is toward EUSO |
---|
670 | p->SetDir((EUSO() - p->Pos()).Unit()); |
---|
671 | |
---|
672 | // calculate transmission from photon position to EUSO |
---|
673 | if(!fMScattAnalysis) TotTrans = fTransToDetec->Trans(*p,EUSO(),Trans); |
---|
674 | else {// MScatt analysis : does not propagate photons, detector does not exist |
---|
675 | TotTrans = 1; |
---|
676 | Trans[0] = 1; Trans[1] = 1; Trans[2] = 1; Trans[3] = 1; |
---|
677 | } |
---|
678 | // fine transmission study is disabled |
---|
679 | p->SetLastTrans(-1,"tot"); |
---|
680 | p->SetLastTrans(-1,"rayl"); |
---|
681 | p->SetLastTrans(-1,"ozone"); |
---|
682 | p->SetLastTrans(-1,"aero"); |
---|
683 | p->SetLastTrans(-1,"cloud"); |
---|
684 | |
---|
685 | // photon is transmitted or absorbed |
---|
686 | if(TotTrans < rndm->Rndm()) p->SetAbsorbed(); |
---|
687 | |
---|
688 | if(p->IsAbsorbed()) SafeDelete(fTempList[m]); |
---|
689 | |
---|
690 | |
---|
691 | // Dump CPU commentaries |
---|
692 | fraction = 100*Float_t(nTracked)/Float_t(nTotal); |
---|
693 | if (left<fraction && fraction <=right) |
---|
694 | next = kFALSE; |
---|
695 | else if (fraction>right) { |
---|
696 | next = kTRUE; |
---|
697 | left = right; |
---|
698 | right += 10; |
---|
699 | } |
---|
700 | if (subleft<fraction && fraction <=subright) { |
---|
701 | subnext = kFALSE; |
---|
702 | } |
---|
703 | if (fraction > subright) { |
---|
704 | subnext = kTRUE; |
---|
705 | subleft = subright; |
---|
706 | subright +=2; |
---|
707 | } |
---|
708 | if (next) Msg(EsafMsg::Info) << left << "%" << MsgFlush; |
---|
709 | if (subnext) Msg(EsafMsg::Info)<< "." << MsgFlush; |
---|
710 | } |
---|
711 | Msg(EsafMsg::Info) << " -done" << MsgDispatch; |
---|
712 | } |
---|
713 | |
---|
714 | //_______________________________________________________________________________________________________________________ |
---|
715 | Bool_t MCRadiativeTransfer::IsSeenByGroundDetector(const SinglePhoton& p) const { |
---|
716 | // |
---|
717 | // for ground detector only, assumed to be half a sphere |
---|
718 | // if dist(photon,detec) < fDistance_cut, photon is lost |
---|
719 | // distribute photons on a sphere : if photons are on the bottom hemisphere, they are lost |
---|
720 | // |
---|
721 | |
---|
722 | // photons with pos.Z < 0 won't be seen by ground detector |
---|
723 | if(p.Pos().Z() < 0) return false; |
---|
724 | |
---|
725 | Double_t dist_to_detec = (EUSO() - p.Pos()).Mag(); |
---|
726 | |
---|
727 | // check fDistance_cut |
---|
728 | if(dist_to_detec < fDistance_cut) return false; |
---|
729 | |
---|
730 | |
---|
731 | |
---|
732 | // distribute photon on a local sphere (radius = detector radius) |
---|
733 | // local frame is centered on sphere origin |
---|
734 | TRandom* rndm = EsafRandom::Get(); |
---|
735 | Double_t Rsphere = EusoRadius(); |
---|
736 | EarthVector pos_on_sphere(1); |
---|
737 | EarthVector pos_in_MESframe(1); |
---|
738 | EarthVector pos_local(0,0,dist_to_detec); // photon position in local frame |
---|
739 | EarthVector dir_local(1); |
---|
740 | |
---|
741 | // position of photon on a horizontal disk cutting sphere in two hemisphere (<=> as sphere is seen from photon position) |
---|
742 | // this disk contains the local frame origin |
---|
743 | Double_t r(0.), phi(0.); // polar coordinates |
---|
744 | r = Rsphere * sqrt(rndm->Rndm()); |
---|
745 | phi = TwoPi() * rndm->Rndm(); |
---|
746 | EarthVector pos_on_plane(r*cos(phi),r*sin(phi),0.); |
---|
747 | dir_local = (pos_on_plane - pos_local).Unit(); |
---|
748 | |
---|
749 | // then get photon position on the local sphere |
---|
750 | Double_t mag(0); |
---|
751 | Double_t b = pos_on_plane*dir_local; |
---|
752 | Double_t c = pos_on_plane.Mag2() - Rsphere*Rsphere; |
---|
753 | pair<Int_t,Double_t*>& solu = findRoots(1.,2*b,c); |
---|
754 | if(solu.first == 0) { |
---|
755 | Msg(EsafMsg::Warning) << "<IsSeenByGroundDetector> no impact on local sphere : SHOULD NOT OCCUR, photon is lost" << MsgDispatch; |
---|
756 | return false; |
---|
757 | } |
---|
758 | if(solu.first == 1) mag = solu.second[0]; |
---|
759 | else if(solu.first ==2) mag = min(solu.second[0],solu.second[1]); |
---|
760 | if((mag - kTolerance) > 0) { |
---|
761 | Msg(EsafMsg::Warning) << "<IsSeenByGroundDetector> mag should always be < 0" << MsgDispatch; |
---|
762 | Msg(EsafMsg::Warning) << "<IsSeenByGroundDetector> HERE mag = " <<mag <<" and it SHOUD NOT OCCUR" << MsgDispatch; |
---|
763 | } |
---|
764 | pos_on_sphere = pos_on_plane + mag*dir_local; |
---|
765 | |
---|
766 | // define rotation and apply it to pos_on_sphere in order to get photons position in MES |
---|
767 | EarthVector Uz(0,0,1); // main axis of local sphere |
---|
768 | EarthVector axis = p.Pos().Cross(Uz); |
---|
769 | pos_in_MESframe = pos_on_sphere; |
---|
770 | pos_in_MESframe.Rotate(-p.Pos().Theta(),axis); |
---|
771 | |
---|
772 | |
---|
773 | // check if pos_in_MESframe is in the upper hemisphere |
---|
774 | if(pos_in_MESframe.Z() >= 0) return true; |
---|
775 | else return false; |
---|
776 | } |
---|
777 | |
---|
778 | //_______________________________________________________________________________________________________________________ |
---|
779 | void MCRadiativeTransfer::ConvertIntoPonP() { |
---|
780 | // |
---|
781 | // generate PhotonsOnPupil (fPhotons) from ListPhotonsInAtmosphere (fTotalList) |
---|
782 | // SinglePhoton are destroyed after their conversion into ParentPhoton |
---|
783 | // |
---|
784 | |
---|
785 | // initializations |
---|
786 | if(!fPhotons) fPhotons = new ListPhotonsOnPupil((vector<ParentPhoton*>*)NULL); |
---|
787 | if(!fPhotons) Msg(EsafMsg::Panic) << "MCRadiativeTransfer::PropagateAllToDetector, NULL fPhotons : Memory pb" << MsgDispatch; |
---|
788 | |
---|
789 | size_t nTotal(0),nTracked(0); |
---|
790 | TVector3 local_dir, pos; |
---|
791 | Float_t fraction(0); |
---|
792 | Bool_t next(0),subnext(0); |
---|
793 | Float_t left(0),right(10),subleft(0),subright(2.5); |
---|
794 | nTotal = fTotalList->GetSingleEntries(); |
---|
795 | SinglePhoton* p = 0; |
---|
796 | |
---|
797 | // build PhotonsOnPupil's frame |
---|
798 | BuildPupilFrame(fPhotons); |
---|
799 | Msg(EsafMsg::Info) << "Convert PhotonsInAtmosphere into PhotonsOnPupil: 0%" << MsgFlush; |
---|
800 | |
---|
801 | |
---|
802 | // convert photons |
---|
803 | fTotalList->ResetSingleCounter(); // for below extraction from list |
---|
804 | while(true) { |
---|
805 | p = fTotalList->GetSingle(); |
---|
806 | if(!p) break; |
---|
807 | nTracked++; |
---|
808 | |
---|
809 | // Sample a random photon position on pupil |
---|
810 | pos = p->Pos(); |
---|
811 | local_dir = p->Dir(); |
---|
812 | p->SetPosInAtmo(p->Pos()); |
---|
813 | p->AddToPosTof(EUSO() - p->Pos()); |
---|
814 | RamdomPosOnPupil(fPhotons,pos,local_dir); |
---|
815 | |
---|
816 | |
---|
817 | // check if photon is within the FoV |
---|
818 | if(!GetDetGeometry()->IsInFoV(local_dir)) p->SetOutFoV(); |
---|
819 | else p->SetOutFoV(false); |
---|
820 | |
---|
821 | |
---|
822 | // if photon transmitted, becomes a photon on pupil |
---|
823 | // FoV 'status' not relevant here (too simply treated, ONLY a flag in RT part) |
---|
824 | // --> will be considered in detector part |
---|
825 | if(!p->IsAbsorbed()) fPhotons->Add(*p,pos,local_dir); |
---|
826 | |
---|
827 | |
---|
828 | // Dump CPU commentaries |
---|
829 | fraction = 100*Float_t(nTracked)/Float_t(nTotal); |
---|
830 | if (left<fraction && fraction <=right) |
---|
831 | next = kFALSE; |
---|
832 | else if (fraction>right) { |
---|
833 | next = kTRUE; |
---|
834 | left = right; |
---|
835 | right += 10; |
---|
836 | } |
---|
837 | if (subleft<fraction && fraction <=subright) { |
---|
838 | subnext = kFALSE; |
---|
839 | } |
---|
840 | if (fraction > subright) { |
---|
841 | subnext = kTRUE; |
---|
842 | subleft = subright; |
---|
843 | subright +=2; |
---|
844 | } |
---|
845 | if (next) Msg(EsafMsg::Info) << left << "%" << MsgFlush; |
---|
846 | if (subnext) Msg(EsafMsg::Info)<< "." << MsgFlush; |
---|
847 | } |
---|
848 | Msg(EsafMsg::Info) << " -done" << MsgDispatch; |
---|
849 | #ifdef DEBUG |
---|
850 | Msg(EsafMsg::Debug) << "Number of ParentPhoton = " << fPhotons->GetNphotons() << MsgDispatch; |
---|
851 | #endif |
---|
852 | } |
---|
853 | |
---|
854 | |
---|