source: tags/Mars-V0.9.2/mmontecarlo/MMcWeightEnergySpecCalc.cc

Last change on this file was 6915, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 11.0 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Marcos Lopez 10/2003 <mailto:marcos@gae.ucm.es>
19!
20! Copyright: MAGIC Software Development, 2000-2003
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MMcWeightEnergySlopeCalc
28//
29// Change the spectrum of the MC showers simulated with Corsika (a power law)
30// to a new one, which can be either, again a power law but with a different
31// spectral index, or a generalizeed spectrum. The new spectrum can be
32// pass to this class in different ways:
33// 1. Is the new spectrum will be a power law, just introduce the slope
34// of this power law.
35// 2. Is the new spectrum will have a general shape, different options are
36// available:
37// a) The new spectrum is pass as a TF1 function
38// b) The new spectrum is pass as a char*
39// c) The new spectrum is pass as a "interpreted function", i.e., a
40// function defined inside a ROOT macro, which will be invoked by the
41// ROOT Cint itself. This is the case when we use ROOT macros.
42// d) The new spectrum is pass as a "real function", i.e., a
43// function defined inside normal c++ file.
44//
45// Method:
46// ------
47//
48// -Corsika spectrun: dN/dE = A * E^(a)
49// with a = fCorsikaSlope, and A = N/integral{E*de} from ELowLim to EUppLim
50//
51// -New spectrum: dN/dE = B * g(E)
52// where B = N/integral{g*dE} from ELowLim to EUppLim, and N=NumEvents
53//
54// For converting the spectrum simulated with Corsika to the new one, we apply
55// a weight to each event, given by:
56//
57// W(E) = B/A * g(E)/E^(a)
58//
59// In the case the new spectrum is simply a power law: dN/dE = B * E^(b), we
60// have:
61//
62// W(E) = B/A * E^(b-a)
63//
64// (The factor B/A is used in order both the original and new spectrum have
65// the same area (i.e. in order they represent the same number of showers))
66//
67// Note:
68// ------
69// -If the the new spectrum is just a power law (i.e. the user only specify
70// the slope), the needed calculations (such as the integral of the
71// spectrum) are done analytically. But if the new spectrum is given as a
72// TF1 object, the calculations is done numerically.
73//
74// ToDo:
75// -----
76// -Give to the user also the possibility to specify the integral of the
77// spectrum as another TF1 object (or C++ function)
78//
79//
80// Input Containers:
81// MMcEvt, MMcRunHeader, MMcCorsikaRunHeader
82//
83// Output Container:
84// MWeight [MParameterD]
85//
86//////////////////////////////////////////////////////////////////////////////
87
88#include "MMcWeightEnergySpecCalc.h"
89
90#include "MParList.h"
91#include "MLog.h"
92#include "MLogManip.h"
93#include "MMcEvt.hxx"
94#include "MMcRunHeader.hxx"
95#include "MMcCorsikaRunHeader.h"
96#include "MParameters.h"
97
98#include "TF1.h"
99#include "TGraph.h"
100
101ClassImp(MMcWeightEnergySpecCalc);
102
103using namespace std;
104
105
106
107void MMcWeightEnergySpecCalc::Init(const char *name, const char *title)
108{
109
110 fName = name ? name : "MMcWeightEnergySpecCalc";
111 fTitle = title ? title : "Task to calculate weights to change the energy spectrum";
112
113 AddToBranchList("MMcEvt.fEnergy");
114
115 fAllEvtsTriggered = kFALSE;
116 fTotalNumSimulatedShowers = 0;
117}
118
119
120// ---------------------------------------------------------------------------
121//
122// Constructor. The new spectrum will be just a power law.
123//
124MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(Float_t slope,
125 const char *name, const char *title)
126{
127 fNewSpecIsPowLaw = kTRUE;
128 fNewSlope = slope;
129
130 fNewSpectrum = NULL;
131
132 Init(name,title);
133}
134
135// ---------------------------------------------------------------------------
136//
137// Constructor. The new spectrum will have a general shape, given by the user
138// as a TF1 function.
139//
140MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(const TF1& spectrum,
141 const char *name, const char *title)
142{
143 fNewSpecIsPowLaw = kFALSE;
144 fNewSpectrum = (TF1*)spectrum.Clone();
145
146 Init(name,title);
147}
148
149// ---------------------------------------------------------------------------
150//
151// As before, but the function which represent the new spectrum is given as
152// a char* . Starting from it, we build a TF1 function
153//
154MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(const char* spectrum,
155 const char *name, const char *title)
156{
157 fNewSpecIsPowLaw = kFALSE;
158 fNewSpectrum = new TF1("NewSpectrum",spectrum);
159
160 Init(name,title);
161}
162
163// ---------------------------------------------------------------------------
164//
165// As before, but the new spectrum is given as a intrepreted C++ function.
166// Starting from it we build a TF1 function.
167// This constructor is called for interpreted functions by CINT, i.e., when
168// the functions are declared inside a ROOT macro.
169//
170// NOTE: you muss do a casting to (void*) of the function that you pass to this
171// constructor before invoking it in a macro, e.g.
172//
173// Double_t myfunction(Double_t *x, Double_t *par)
174// {
175// ...
176// }
177//
178// MMcWeightEnergySpecCalc wcalc((void*)myfunction);
179//
180// tasklist.AddToList(&wcalc);
181//
182// otherwise ROOT will invoke the constructor McWeightEnergySpecCalc(
183// const char* spectrum, const char *name, const char *title)
184//
185MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(void* function,
186 const char *name, const char *title)
187{
188 fNewSpecIsPowLaw = kFALSE;
189 fNewSpectrum = new TF1("NewSpectrum",function,0,1,1);
190
191 Init(name,title);
192}
193
194// ---------------------------------------------------------------------------
195//
196// As before, but this is the constructor for real functions, i.e. it is called
197// when invoked with the normal C++ compiler, i.e. not inside a ROOT macro.
198//
199MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(Double_t (*function)(Double_t*x, Double_t* par), const Int_t npar, const char *name, const char *title)
200{
201 fNewSpecIsPowLaw = kFALSE;
202 fNewSpectrum = new TF1("NewSpectrum",function,0,1,1);
203
204 Init(name,title);
205}
206
207
208
209// ----------------------------------------------------------------------------
210//
211// Destructor. Deletes the cloned fNewSpectrum.
212//
213MMcWeightEnergySpecCalc::~MMcWeightEnergySpecCalc()
214{
215 if (fNewSpectrum)
216 delete fNewSpectrum;
217}
218
219
220
221// ---------------------------------------------------------------------------
222//
223//
224Int_t MMcWeightEnergySpecCalc::PreProcess (MParList *pList)
225{
226
227 fMcEvt = (MMcEvt*)pList->FindObject("MMcEvt");
228 if (!fMcEvt)
229 {
230 *fLog << err << dbginf << "MMcEvt not found... exit." << endl;
231 return kFALSE;
232 }
233
234 fWeight = (MParameterD*)pList->FindCreateObj("MParameterD", "MWeight");
235 if (!fWeight)
236 return kFALSE;
237
238 return kTRUE;
239}
240
241
242
243// ----------------------------------------------------------------------------
244//
245// Executed each time a new root file is loaded
246// We will need fCorsikaSlope and fE{Upp,Low}Lim to calculate the weights
247//
248Bool_t MMcWeightEnergySpecCalc::ReInit(MParList *plist)
249{
250 MMcRunHeader *runheader = (MMcRunHeader*)plist->FindObject("MMcRunHeader");
251 if (!runheader)
252 {
253 *fLog << err << dbginf << "Error - MMcRunHeader not found... exit." << endl;
254 return kFALSE;
255 }
256
257 MMcCorsikaRunHeader *corrunheader = (MMcCorsikaRunHeader*)plist->FindObject("MMcCorsikaRunHeader");
258 if (!corrunheader)
259 {
260 *fLog << err << dbginf << "Error - MMcCorsikaRunHeader not found... exit." << endl;
261 return kFALSE;
262 }
263
264
265 fCorsikaSlope = (Double_t)corrunheader->GetSlopeSpec();
266 fELowLim = (Double_t)corrunheader->GetELowLim();
267 fEUppLim = (Double_t)corrunheader->GetEUppLim();
268
269 fTotalNumSimulatedShowers += runheader->GetNumSimulatedShowers();
270 fAllEvtsTriggered |= runheader->GetAllEvtsTriggered();
271
272
273
274 *fLog << inf << "Slope of primaries' energy spectrum of Simulated showers: " << fCorsikaSlope << endl;
275 *fLog << inf << "Limits of energy range of Simulated showers: "
276 << fELowLim <<" - " << fEUppLim << endl;
277 *fLog << inf << "New Slope for Simulated showers: " << fNewSlope << endl;
278 *fLog << inf << "Total Number of Simulated showers: "
279 << fTotalNumSimulatedShowers << endl;
280 *fLog << inf << "Only triggered events avail: " << (fAllEvtsTriggered?"yes":"no") << endl;
281
282
283
284 //
285 // Sanity checks to be sure that we won't divide by zero later on
286 //
287 if(fCorsikaSlope == -1. || fNewSlope == -1.)
288 {
289 *fLog << err << "The Slope of the power law must be different of -1... exit" << endl;
290 return kFALSE;
291 }
292
293
294 //
295 // Starting from fCorsikaSlope and fE{Upp,Low}Lim, calculate the integrals
296 // of both, the original Corsika spectrum and the new one.
297 //
298 //
299 // For the Corsika simulated spectrum (just a power law), we have:
300 //
301 fCorSpecInt = ( pow(fEUppLim,1+fCorsikaSlope) - pow(fELowLim,1+fCorsikaSlope) ) / ( 1+fCorsikaSlope );
302
303
304 //
305 // For the new spectrum:
306 //
307 if (fNewSpecIsPowLaw) // just the integral of a power law
308 {
309 fNewSpecInt = ( pow(fEUppLim,1+fNewSlope) - pow(fELowLim,1+fNewSlope) )/ ( 1+fNewSlope );
310 }
311 else
312 {
313 fNewSpectrum->SetRange(fELowLim, fEUppLim);
314
315 // In this case we have to integrate the new spectrum numerically. We
316 // could do simply fNewSpectrum->Integral(fELowLim,fEUppLim), but ROOT
317 // fails integrating up to fEUppLim for a sharp cutoff spectrum
318
319 //
320 // Trick to calculate the integral numerically (it works better than
321 // fNewSpectrum->Integral(fELowLim,fEUppLim) (although not perfectlly)
322 //
323 fNewSpectrum->SetNpx(1000);
324 TGraph gr(fNewSpectrum,"i");
325 Int_t Npx = gr.GetN();
326 Double_t* y = gr.GetY();
327
328 const Double_t integral = y[Npx-1];
329 fNewSpecInt = integral;
330 }
331
332
333 return kTRUE;
334}
335
336
337
338// ----------------------------------------------------------------------------
339//
340//
341Int_t MMcWeightEnergySpecCalc::Process()
342{
343 const Double_t energy = fMcEvt->GetEnergy();
344
345 const Double_t C = fCorSpecInt / fNewSpecInt;
346 Double_t weight = C;
347
348
349 if (fNewSpecIsPowLaw)
350 weight *= pow(energy,fNewSlope-fCorsikaSlope);
351 else
352 weight *= fNewSpectrum->Eval(energy) / pow(energy,fCorsikaSlope);
353
354
355 fWeight->SetVal(weight);
356
357 return kTRUE;
358}
Note: See TracBrowser for help on using the repository browser.