source: trunk/MagicSoft/Mars/mmontecarlo/MMcWeightEnergySpecCalc.cc@ 3827

Last change on this file since 3827 was 2474, checked in by marcos, 21 years ago
*** empty log message ***
File size: 10.6 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
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 "MWeight.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// Constructor. The new spectrum will have a general shape, given by the user
137// as a TF1 function.
138//
139MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(const TF1& spectrum,
140 const char *name, const char *title)
141{
142 fNewSpecIsPowLaw = kFALSE;
143 fNewSpectrum = (TF1*)spectrum.Clone();
144
145 Init(name,title);
146}
147
148//
149// As before, but the function which represent the new spectrum is given as
150// a char* . Starting from it, we build a TF1 function
151//
152MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(const char* spectrum,
153 const char *name, const char *title)
154{
155 fNewSpecIsPowLaw = kFALSE;
156 fNewSpectrum = new TF1("NewSpectrum",spectrum);
157
158 Init(name,title);
159}
160
161//
162// As before, but the new spectrum is given as a intrepreted C++ function.
163// Starting from it we build a TF1 function.
164// This constructor is called for interpreted functions by CINT, i.e., when
165// the functions are declared inside a ROOT macro.
166//
167// NOTE: you muss do a casting to (void*) of the function that you pass to this
168// constructor before invoking it in a macro, e.g.
169//
170// Double_t myfunction(Double_t *x, Double_t *par)
171// {
172// ...
173// }
174//
175// MMcWeightEnergySpecCalc wcalc((void*)myfunction);
176//
177// tasklist.AddToList(&wcalc);
178//
179// otherwise ROOT will invoke the constructor McWeightEnergySpecCalc(
180// const char* spectrum, const char *name, const char *title)
181//
182MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(void* function,
183 const char *name, const char *title)
184{
185 fNewSpecIsPowLaw = kFALSE;
186 fNewSpectrum = new TF1("NewSpectrum",function,0,1,1);
187
188 Init(name,title);
189}
190
191//
192// As before, but this is the constructor for real functions, i.e. it is called
193// when invoked with the normal C++ compiler, i.e. not inside a ROOT macro.
194//
195MMcWeightEnergySpecCalc::MMcWeightEnergySpecCalc(Double_t (*function)(Double_t*x, Double_t* par), const Int_t npar, const char *name, const char *title)
196{
197 fNewSpecIsPowLaw = kFALSE;
198 fNewSpectrum = new TF1("NewSpectrum",function,0,1,1);
199
200 Init(name,title);
201}
202
203
204
205// ----------------------------------------------------------------------------
206//
207// Destructor. Deletes the cloned fNewSpectrum.
208//
209MMcWeightEnergySpecCalc::~MMcWeightEnergySpecCalc()
210{
211 if (fNewSpectrum)
212 delete fNewSpectrum;
213}
214
215
216
217// ---------------------------------------------------------------------------
218//
219//
220Int_t MMcWeightEnergySpecCalc::PreProcess (MParList *pList)
221{
222
223 fMcEvt = (MMcEvt*)pList->FindObject("MMcEvt");
224 if (!fMcEvt)
225 {
226 *fLog << err << dbginf << "MMcEvt not found... exit." << endl;
227 return kFALSE;
228 }
229
230 fWeight = (MWeight*)pList->FindCreateObj("MWeight");
231 if (!fWeight)
232 {
233 *fLog << err << dbginf << "MWeight not found... exit." << endl;
234 return kFALSE;
235 }
236
237 return kTRUE;
238}
239
240
241
242// ----------------------------------------------------------------------------
243//
244// Executed each time a new root file is loaded
245// We will need fCorsikaSlope and fE{Upp,Low}Lim to calculate the weights
246//
247Bool_t MMcWeightEnergySpecCalc::ReInit(MParList *plist)
248{
249 MMcRunHeader *runheader = (MMcRunHeader*)plist->FindObject("MMcRunHeader");
250 if (!runheader)
251 {
252 *fLog << err << dbginf << "Error - MMcRunHeader not found... exit." << endl;
253 return kFALSE;
254 }
255
256 MMcCorsikaRunHeader *corrunheader = (MMcCorsikaRunHeader*)plist->FindObject("MMcCorsikaRunHeader");
257 if (!corrunheader)
258 {
259 *fLog << err << dbginf << "Error - MMcCorsikaRunHeader not found... exit." << endl;
260 return kFALSE;
261 }
262
263
264 fCorsikaSlope = (Double_t)corrunheader->GetSlopeSpec();
265 fELowLim = (Double_t)corrunheader->GetELowLim();
266 fEUppLim = (Double_t)corrunheader->GetEUppLim();
267
268 fTotalNumSimulatedShowers += runheader->GetNumSimulatedShowers();
269 fAllEvtsTriggered |= runheader->GetAllEvtsTriggered();
270
271
272
273 *fLog << inf << "Slope of primaries' energy spectrum of Simulated showers: " << fCorsikaSlope << endl;
274 *fLog << inf << "Limits of energy range of Simulated showers: "
275 << fELowLim <<" - " << fEUppLim << endl;
276 *fLog << inf << "New Slope for Simulated showers: " << fNewSlope << endl;
277 *fLog << inf << "Total Number of Simulated showers: "
278 << fTotalNumSimulatedShowers << endl;
279 *fLog << inf << "Only triggered events avail: " << (fAllEvtsTriggered?"yes":"no") << endl;
280
281
282
283 //
284 // Sanity checks to be sure that we won't divide by zero later on
285 //
286 if(fCorsikaSlope == -1. || fNewSlope == -1.)
287 {
288 *fLog << err << "The Slope of the power law must be different of -1... exit" << endl;
289 return kFALSE;
290 }
291
292
293 //
294 // Starting from fCorsikaSlope and fE{Upp,Low}Lim, calculate the integrals
295 // of both, the original Corsika spectrum and the new one.
296 //
297 //
298 // For the Corsika simulated spectrum (just a power law), we have:
299 //
300 fCorSpecInt = ( pow(fEUppLim,1+fCorsikaSlope) - pow(fELowLim,1+fCorsikaSlope) ) / ( 1+fCorsikaSlope );
301
302
303 //
304 // For the new spectrum:
305 //
306 if (fNewSpecIsPowLaw) // just the integral of a power law
307 {
308 fNewSpecInt = ( pow(fEUppLim,1+fNewSlope) - pow(fELowLim,1+fNewSlope) )/ ( 1+fNewSlope );
309 }
310 else
311 {
312 fNewSpectrum->SetRange(fELowLim, fEUppLim);
313
314 // In this case we have to integrate the new spectrum numerically. We
315 // could do simply fNewSpectrum->Integral(fELowLim,fEUppLim), but ROOT
316 // fails integrating up to fEUppLim for a sharp cutoff spectrum
317
318 //
319 // Trick to calculate the integral numerically (it works better than
320 // fNewSpectrum->Integral(fELowLim,fEUppLim) (although not perfectlly)
321 //
322 fNewSpectrum->SetNpx(1000);
323 TGraph gr(fNewSpectrum,"i");
324 Int_t Npx = gr.GetN();
325 Double_t* y = gr.GetY();
326
327 const Double_t integral = y[Npx-1];
328 fNewSpecInt = integral;
329 }
330
331
332 return kTRUE;
333}
334
335
336
337// ----------------------------------------------------------------------------
338//
339//
340Int_t MMcWeightEnergySpecCalc::Process()
341{
342 const Double_t energy = fMcEvt->GetEnergy();
343
344 const Double_t C = fCorSpecInt / fNewSpecInt;
345 Double_t weight;
346
347
348 if (fNewSpecIsPowLaw)
349 weight = C * pow(energy,fNewSlope-fCorsikaSlope);
350 else
351 weight = C * fNewSpectrum->Eval(energy) / pow(energy,fCorsikaSlope);
352
353
354 fWeight->SetWeight( weight );
355
356 return kTRUE;
357}
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
Note: See TracBrowser for help on using the repository browser.