source: trunk/MagicSoft/Mars/mhflux/MMcSpectrumWeight.cc@ 7169

Last change on this file since 7169 was 7144, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 12.4 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): Thomas Bretz 5/2005 <mailto:tbretz@astro.uni-wuerzburg.de>
19! Author(s): Marcos Lopez 10/2003 <mailto:marcos@gae.ucm.es>
20!
21! Copyright: MAGIC Software Development, 2000-2005
22!
23!
24\* ======================================================================== */
25
26//////////////////////////////////////////////////////////////////////////////
27//
28// MMcWeightEnergySlopeCalc
29//
30// Change the spectrum of the MC showers simulated with Corsika (a power law)
31// to a new one, which can be either, again a power law but with a different
32// spectral index, or a generalizeed spectrum. The new spectrum can be
33// pass to this class in different ways:
34//
35// 1. Is the new spectrum will be a power law, just introduce the slope
36// of this power law.
37// 2. Is the new spectrum will have a general shape:
38// The new spectrum is passed as a char* (SetFormula())
39//
40// Method:
41// -------
42//
43// - Corsika spectrun: dN/dE = A * E^(a)
44// with a = fOldSlope, and A = N/integral{E*de} from ELowLim to EUppLim
45//
46// - New spectrum: dN/dE = B * g(E)
47// where B = N/integral{g*dE} from ELowLim to EUppLim, and N=NumEvents
48//
49// For converting the spectrum simulated with Corsika to the new one, we
50// apply a weight to each event, given by:
51//
52// W(E) = B/A * g(E)/E^(a)
53//
54// In the case the new spectrum is simply a power law: dN/dE = B * E^(b), we
55// have:
56//
57// W(E) = B/A * E^(b-a)
58//
59// (The factor B/A is used in order both the original and new spectrum have
60// the same area (i.e. in order they represent the same number of showers))
61//
62//
63// Input Containers:
64// MMcEvt
65// MMcCorsikaRunHeader
66//
67// Output Container:
68// MWeight [MParameterD]
69//
70//////////////////////////////////////////////////////////////////////////////
71#include "MMcSpectrumWeight.h"
72
73#include <TF1.h>
74#include <TH1.h>
75
76#include "MLog.h"
77#include "MLogManip.h"
78
79#include "MParList.h"
80#include "MParameters.h"
81
82#include "MPointingPos.h"
83
84#include "MMcEvt.hxx"
85#include "MMcCorsikaRunHeader.h"
86
87ClassImp(MMcSpectrumWeight);
88
89using namespace std;
90
91void MMcSpectrumWeight::Init(const char *name, const char *title)
92{
93 fName = name ? name : "MMcSpectrumWeight";
94 fTitle = title ? title : "Task to calculate weights to change the energy spectrum";
95
96 AddToBranchList("MMcEvt.fEnergy");
97
98 fNameWeight = "MWeight";
99 fNameMcEvt = "MMcEvt";
100
101 fNewSlope = -1;
102 fOldSlope = -1;
103
104 fEnergyMin = -1;
105 fEnergyMax = -2;
106
107 fNorm = 1;
108
109 fAllowChange = kFALSE;
110
111 fFunc = NULL;
112 fMcEvt = NULL;
113 fWeight = NULL;
114 fZdWeights = NULL;
115 fPointing = NULL;
116}
117
118// ---------------------------------------------------------------------------
119//
120// Default Constructor.
121//
122MMcSpectrumWeight::MMcSpectrumWeight(const char *name, const char *title)
123{
124 Init(name,title);
125}
126
127// ---------------------------------------------------------------------------
128//
129// Destructor. If necessary delete fFunc
130//
131MMcSpectrumWeight::~MMcSpectrumWeight()
132{
133 if (fFunc)
134 delete fFunc;
135}
136
137// ---------------------------------------------------------------------------
138//
139// Search for
140// - fNameMcEvt [MMcEvtBasic]
141//
142// Find/Create:
143// - fNameWeight [MWeight]
144//
145Int_t MMcSpectrumWeight::PreProcess(MParList *pList)
146{
147 fMcEvt = (MMcEvt*)pList->FindObject(fNameMcEvt, "MMcEvtBasic");
148 if (!fMcEvt)
149 {
150 *fLog << err << fNameMcEvt << " [MMcEvtBasic] not found... abort." << endl;
151 return kFALSE;
152 }
153
154 fWeight = (MParameterD*)pList->FindCreateObj("MParameterD", fNameWeight);
155 if (!fWeight)
156 return kFALSE;
157
158 if (!fZdWeights)
159 return kTRUE;
160
161 fPointing = (MPointingPos*)pList->FindObject("MPointingPos");
162 if (!fPointing)
163 {
164 *fLog << err << "MPointingPos not found... abort." << endl;
165 return kFALSE;
166 }
167
168 return kTRUE;
169}
170
171// ---------------------------------------------------------------------------
172//
173// Replace {fNameMcEvt}.fEnergy by "(x)" and return the result.
174//
175TString MMcSpectrumWeight::ReplaceX(TString str) const
176{
177 return str.ReplaceAll(Form("%s.fEnergy", fNameMcEvt.Data()), "(x)");
178}
179
180// ---------------------------------------------------------------------------
181//
182// Return the function corresponding to the mc spectrum with
183// slope fOldSlope: pow({fNameMcEvt}.fEnergy, fOldSlope)
184//
185// The slope is returned as %.3f
186//
187TString MMcSpectrumWeight::GetFormulaSpecOld() const
188{
189 return Form("pow(%s.fEnergy, %.3f)", fNameMcEvt.Data(), fOldSlope);
190}
191
192// ---------------------------------------------------------------------------
193//
194// Return the function corresponding to the new spectrum with
195// slope fNewSlope: pow({fNameMcEvt}.fEnergy, fNewSlope)
196//
197// The slope is returned as %.3f
198//
199// If a different formula is set (SetFormula()) this formula is returned
200// unchanged.
201//
202TString MMcSpectrumWeight::GetFormulaSpecNew() const
203{
204 return fFormula.IsNull() ? Form("pow(%s.fEnergy, %.3f)", fNameMcEvt.Data(), fNewSlope) : fFormula;
205}
206
207// ---------------------------------------------------------------------------
208//
209// Return the formula to calculate weights.
210// Is is compiled by
211// o = integral(fEnergyMin, fEnergyMax, GetFormulaSpecOldX());
212// n = integral(fEnergyMin, fEnergyMax, GetFormulaSpecNewX());
213//
214// result: fNorm*o/n*GetFormulaNewSpec()/GetFormulaOldSpec()
215//
216// fNorm is 1 by default but can be overwritten using SetNorm()
217//
218// If the formulas GetFormulaSpecOldX() and GetFormulaSpecNewX()
219// are equal only fNorm is returned.
220//
221// The normalization constant is returned as %.16f
222//
223// Example: 0.3712780019*(pow(MMcEvt.fEnergy,-2.270))/(pow(MMcEvt.fEnergy,-2.600))
224//
225TString MMcSpectrumWeight::GetFormulaWeights() const
226{
227 if (GetFormulaSpecOld()==GetFormulaSpecNew())
228 return Form("%.16f", fNorm);
229
230 const Double_t iold = GetSpecOldIntegral();
231 const Double_t inew = GetSpecNewIntegral();
232
233 const Double_t norm = fNorm*iold/inew;
234
235 return Form("%.16f*(%s)/(%s)", norm, GetFormulaSpecNew().Data(), GetFormulaSpecOld().Data());
236}
237
238// ---------------------------------------------------------------------------
239//
240// Returns the integral between fEnergyMin and fEnergyMax of
241// GetFormulaSpecNewX() describing the destination spectrum
242//
243Double_t MMcSpectrumWeight::GetSpecNewIntegral() const
244{
245 TF1 funcnew("Dummy", GetFormulaSpecNewX());
246 return funcnew.Integral(fEnergyMin, fEnergyMax);
247}
248
249// ---------------------------------------------------------------------------
250//
251// Returns the integral between fEnergyMin and fEnergyMax of
252// GetFormulaSpecOldX() describing the simulated spectrum
253//
254Double_t MMcSpectrumWeight::GetSpecOldIntegral() const
255{
256 TF1 funcold("Dummy", GetFormulaSpecOldX());
257 return funcold.Integral(fEnergyMin, fEnergyMax);
258}
259
260// ---------------------------------------------------------------------------
261//
262// Initialize fEnergyMin, fEnergymax and fOldSlope from MMcCorsikaRunHeader
263// by GetELowLim(), GetEUppLim() and GetSlopeSpec().
264//
265// If fEnergyMax>fEnergyMin (means: the values have already been
266// initialized) and !fAllowChange the consistency of the new values
267// with the present values is checked with a numerical precision of 1e-10.
268// If one doesn't match kFALSE is returned.
269//
270// If the mc slope is -1 kFALSE is returned.
271//
272// If the new slope for the spectrum is -1 it is set to the original MC
273// slope.
274//
275// fFunc is set to the formula returned by GetFormulaWeightsX()
276//
277Bool_t MMcSpectrumWeight::Set(const MMcCorsikaRunHeader &rh)
278{
279 if (fEnergyMax>fEnergyMin && !fAllowChange)
280 {
281 if (TMath::Abs(fOldSlope-rh.GetSlopeSpec())>1e-10)
282 {
283 *fLog << err;
284 *fLog << "ERROR - The slope of the Monte Carlo is not allowed to change ";
285 *fLog << "(" << fOldSlope << " --> " << rh.GetSlopeSpec() << ")... abort." << endl;
286 return kFALSE;
287 }
288 if (TMath::Abs(fEnergyMin-rh.GetELowLim())>1e-10)
289 {
290 *fLog << err;
291 *fLog << "ERROR - The minimum simulated Monte Carlo energy is not allowed to change ";
292 *fLog << "(" << fEnergyMin << " --> " << rh.GetELowLim() << ")... abort." << endl;
293 return kFALSE;
294 }
295 if (TMath::Abs(fEnergyMax-rh.GetEUppLim())>1e-10)
296 {
297 *fLog << err;
298 *fLog << "ERROR - The maximum simulated Monte Carlo energy is not allowed to change (";
299 *fLog << "(" << fEnergyMax << " --> " << rh.GetEUppLim() << ")... abort." << endl;
300 return kFALSE;
301 }
302 return kTRUE;
303 }
304
305 //
306 // Sanity checks to be sure that we won't divide by zero later on
307 //
308 if (rh.GetSlopeSpec()==-1)
309 {
310 *fLog << err << "The MC Slope of the power law must be different of -1... exit" << endl;
311 return kFALSE;
312 }
313
314 fOldSlope = rh.GetSlopeSpec();
315 fEnergyMin = rh.GetELowLim();
316 fEnergyMax = rh.GetEUppLim();
317
318 if (fNewSlope==-1)
319 {
320 *fLog << inf << "The new slope of the power law is -1... no weighting applied." << endl;
321 fNewSlope = fOldSlope;
322 }
323
324 TString form(GetFormulaWeightsX());
325
326 if (fFunc)
327 delete fFunc;
328
329 fFunc = new TF1("", form);
330 gROOT->GetListOfFunctions()->Remove(fFunc);
331 fFunc->SetName("SpectralWeighs");
332
333 return kTRUE;
334}
335
336// ---------------------------------------------------------------------------
337//
338// The current contants are printed
339//
340void MMcSpectrumWeight::Print(Option_t *o) const
341{
342 *fLog << all << GetDescriptor() << endl;
343 *fLog << " Simulated energy range: " << fEnergyMin << "GeV - " << fEnergyMax << "GeV" << endl;
344 *fLog << " Simulated spectral slope: " << fOldSlope << endl;
345 *fLog << " New spectral slope: " << fNewSlope << endl;
346 *fLog << " User normalization: " << fNorm << endl;
347 *fLog << " Old Spectrum: " << GetFormulaSpecOldX() << " (I=" << GetSpecOldIntegral() << ")" << endl;
348 *fLog << " New Spectrum: " << GetFormulaSpecNewX() << " (I=" << GetSpecNewIntegral() << ")" << endl;
349 if (fFunc)
350 *fLog << " Weight function: " << fFunc->GetTitle() << endl;
351}
352
353// ----------------------------------------------------------------------------
354//
355// Executed each time a new root file is loaded
356// We will need fOldSlope and fE{Upp,Low}Lim to calculate the weights
357//
358Bool_t MMcSpectrumWeight::ReInit(MParList *plist)
359{
360 MMcCorsikaRunHeader *rh = (MMcCorsikaRunHeader*)plist->FindObject("MMcCorsikaRunHeader");
361 if (!rh)
362 {
363 *fLog << err << "MMcCorsikaRunHeader not found... abort." << endl;
364 return kFALSE;
365 }
366
367 return Set(*rh);
368}
369
370// ----------------------------------------------------------------------------
371//
372// Fill the result of the evaluation of fFunc at fEvEvt->GetEnergy
373// into the weights container.
374//
375Int_t MMcSpectrumWeight::Process()
376{
377 const Double_t e = fMcEvt->GetEnergy();
378
379 Double_t w = 1;
380
381 if (fZdWeights)
382 {
383 const Int_t i = fZdWeights->GetXaxis()->FindFixBin(fPointing->GetZd());
384 w = fZdWeights->GetBinContent(i);
385 }
386
387 fWeight->SetVal(fFunc->Eval(e)*w);
388
389 return kTRUE;
390}
391
392// --------------------------------------------------------------------------
393//
394// Read the setup from a TEnv, eg:
395// MMcSpectrumWeight.NewSlope: -2.6
396// MMcSpectrumWeight.Norm: 1.0
397// MMcSpectrumWeight.Formula: pow(MMcEvt.fEnergy, -2.6)
398//
399Int_t MMcSpectrumWeight::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
400{
401 Bool_t rc = kFALSE;
402 if (IsEnvDefined(env, prefix, "NewSlope", print))
403 {
404 rc = kTRUE;
405 SetNewSlope(GetEnvValue(env, prefix, "NewSlope", fNewSlope));
406 }
407 if (IsEnvDefined(env, prefix, "Norm", print))
408 {
409 rc = kTRUE;
410 SetNorm(GetEnvValue(env, prefix, "Norm", fNorm));
411 }
412 if (IsEnvDefined(env, prefix, "Formula", print))
413 {
414 rc = kTRUE;
415 SetFormula(GetEnvValue(env, prefix, "Formula", fFormula));
416 }
417
418 return rc;
419}
Note: See TracBrowser for help on using the repository browser.