Commit 83baaaa0f2d4d8fec1cece23057af851c1b812de

Authored by knodlseder
1 parent 1b3ba53c

implement LAT PSF initialization

include/GLATResponse.hpp
... ... @@ -68,21 +68,43 @@ public:
68 68 const double& time);
69 69  
70 70 void set_caldb(std::string caldb);
71   - void load(std::string rspname);
  71 + void load(std::string rspname, std::string rsptype);
72 72 void save(std::string rspname) const;
73 73 GLATResponse* clone(void) const;
74 74  
75 75 private:
  76 + // Private Effective Area methods
  77 + void aeff_init(void);
  78 +
  79 + // Private PSF methods
  80 + void psf_init(void);
  81 + double psf_scale(const double& energy);
  82 + double psf_base_value(const double& u, const double& gamma);
  83 + GVector psf_base_vector(const GVector& u, const double& gamma);
  84 +
  85 + // Private PSF data
  86 + int m_psf_angle_num;
  87 + double m_psf_angle_min;
  88 + double m_psf_angle_max;
  89 + double m_psf_angle_bin;
  90 + int m_psf_energy_num;
  91 + int m_psf_ctheta_num;
  92 + double* m_psf;
  93 + double* m_norm;
  94 + double* m_sigma;
  95 +
  96 + // Provate energy dissipation methods
  97 + void edisp_init(void);
  98 +
76 99 // Private methods
77 100 void init_members(void);
78 101 void copy_members(const GLATResponse& rsp);
79 102 void free_members(void);
80   - void init_aeff(void);
81   - void init_psf(void);
82   - void init_edisp(void);
83 103 GVector get_fits_vector(const GFitsHDU* hdu, const std::string& colname, int row = 0);
84 104  
85 105 // Private data area
  106 + std::string m_rsptype;
  107 + int m_section; // 0=front, 1=back
86 108  
87 109 };
88 110  
... ...
include/GResponse.hpp
... ... @@ -113,12 +113,12 @@ public:
113 113 /// Pure virtual method to load the instrument response from the calibration
114 114 /// database
115 115 /// @param rspname Name of the instrument response
116   - virtual void load(std::string rspname) = 0;
  116 +// virtual void load(std::string rspname) = 0;
117 117  
118 118 /// Pure virtual method to save the instrument response into the calibration
119 119 /// database
120 120 /// @param rspname Name of the instrument response
121   - virtual void save(std::string rspname) const = 0;
  121 +// virtual void save(std::string rspname) const = 0;
122 122  
123 123 /// Pure virtual method to clone the response instance
124 124 virtual GResponse* clone(void) const = 0;
... ...
src/rsp/GLATResponse.cpp
... ... @@ -34,6 +34,20 @@
34 34  
35 35 /* __ Debug definitions __________________________________________________ */
36 36  
  37 +/* __ Constants __________________________________________________________ */
  38 +const double scale_front_c0 = 3.77e-4;
  39 +const double scale_front_c1 = 5.8e-2;
  40 +const double scale_back_c0 = 1.3e-3;
  41 +const double scale_back_c1 = 9.6e-2;
  42 +
  43 +const double pi = 3.1415926535897931159979635;
  44 +const double pihalf = 1.5707963267948966;
  45 +const double twopi = 6.2831853071795862319959269;
  46 +const double sqrt2pi = 2.5066282746310002416123552;
  47 +const double twosqrt2ln2 = 2.3548200450309493270140138;
  48 +const double deg2rad = 0.0174532925199432954743717;
  49 +const double rad2deg = 57.295779513082322864647722;
  50 +const double ln10 = 2.3025850929940459010936138;
37 51  
38 52  
39 53 /*==========================================================================
... ... @@ -208,19 +222,28 @@ void GLATResponse::set_caldb(std::string caldb)
208 222 /**
209 223 * @brief Load a specified LAT response function.
210 224 */
211   -void GLATResponse::load(std::string rspname)
  225 +void GLATResponse::load(std::string rspname, std::string rsptype)
212 226 {
213 227 // Store response name
214 228 m_rspname = rspname;
  229 +
  230 + // Convert response type
  231 + if (rsptype == "front")
  232 + m_section = 0;
  233 + else if (rsptype == "back")
  234 + m_section = 1;
  235 + else
  236 + throw;
  237 + m_rsptype = rsptype;
215 238  
216 239 // Initialise effective area
217   - init_aeff();
  240 + aeff_init();
218 241  
219 242 // Initialise PSF
220   - init_psf();
  243 + psf_init();
221 244  
222 245 // Initialise energy dispersion
223   - init_edisp();
  246 + edisp_init();
224 247 }
225 248  
226 249  
... ... @@ -238,7 +261,7 @@ void GLATResponse::save(std::string rspname) const
238 261  
239 262 /*==========================================================================
240 263 = =
241   - = GLATResponse private methods =
  264 + = GLATResponse private effective area methods =
242 265 = =
243 266 ==========================================================================*/
244 267  
... ... @@ -246,10 +269,10 @@ void GLATResponse::save(std::string rspname) const
246 269 * Initialise effective area *
247 270 * ----------------------------------------------------------------------- *
248 271 ***************************************************************************/
249   -void GLATResponse::init_aeff(void)
  272 +void GLATResponse::aeff_init(void)
250 273 {
251 274 // Build filename
252   - std::string filename = "aeff_" + m_rspname + ".fits";
  275 + std::string filename = "aeff_" + m_rspname + "_" + m_rsptype + ".fits";
253 276  
254 277 // Open FITS file
255 278 GFits file;
... ... @@ -272,14 +295,20 @@ void GLATResponse::init_aeff(void)
272 295 }
273 296  
274 297  
  298 +/*==========================================================================
  299 + = =
  300 + = GLATResponse private PSF methods =
  301 + = =
  302 + ==========================================================================*/
  303 +
275 304 /***************************************************************************
276 305 * Initialise PSF *
277 306 * ----------------------------------------------------------------------- *
278 307 ***************************************************************************/
279   -void GLATResponse::init_psf(void)
  308 +void GLATResponse::psf_init(void)
280 309 {
281 310 // Build filename
282   - std::string filename = "psf_" + m_rspname + ".fits";
  311 + std::string filename = "psf_" + m_rspname + "_" + m_rsptype + ".fits";
283 312  
284 313 // Open FITS file
285 314 GFits file;
... ... @@ -291,14 +320,103 @@ void GLATResponse::init_psf(void)
291 320 throw GException::fits_hdu_not_found(G_INIT_PSF, "RPSF");
292 321  
293 322 // Get the data
294   - GVector energ_lo = get_fits_vector(hdu, "ENERG_LO");
295   - GVector energ_hi = get_fits_vector(hdu, "ENERG_HI");
296   - GVector ctheta_lo = get_fits_vector(hdu, "CTHETA_LO");
297   - GVector ctheta_hi = get_fits_vector(hdu, "CTHETA_HI");
298   - GVector ncore = get_fits_vector(hdu, "NCORE");
299   - GVector sigma = get_fits_vector(hdu, "SIGMA");
300   - GVector gcore = get_fits_vector(hdu, "GCORE");
301   - GVector gtail = get_fits_vector(hdu, "GTAIL");
  323 + GVector v_energy_lo = get_fits_vector(hdu, "ENERG_LO");
  324 + GVector v_energy_hi = get_fits_vector(hdu, "ENERG_HI");
  325 + GVector v_ctheta_lo = get_fits_vector(hdu, "CTHETA_LO");
  326 + GVector v_ctheta_hi = get_fits_vector(hdu, "CTHETA_HI");
  327 + GVector v_ncore = get_fits_vector(hdu, "NCORE");
  328 + GVector v_sigma = get_fits_vector(hdu, "SIGMA");
  329 + GVector v_gcore = get_fits_vector(hdu, "GCORE");
  330 + GVector v_gtail = get_fits_vector(hdu, "GTAIL");
  331 +
  332 + // Set binning in angle, energy and cos theta
  333 + m_psf_angle_num = 2000;
  334 + m_psf_angle_min = 0.01;
  335 + m_psf_angle_bin = 0.01;
  336 + m_psf_energy_num = v_energy_lo.size();
  337 + m_psf_ctheta_num = v_ctheta_lo.size();
  338 +
  339 + // Free old PSF memory
  340 + if (m_psf != NULL) delete [] m_psf;
  341 + if (m_norm != NULL) delete [] m_norm;
  342 + if (m_sigma != NULL) delete [] m_sigma;
  343 +
  344 + // Allocate memory for PSF
  345 + int psf_size = m_psf_angle_num * m_psf_energy_num * m_psf_ctheta_num;
  346 + int bin_size = m_psf_energy_num * m_psf_ctheta_num;
  347 + m_psf = new double[psf_size];
  348 + m_norm = new double[bin_size];
  349 + m_sigma = new double[bin_size];
  350 +
  351 + // Setup PSF vector axis
  352 + GVector xaxis(m_psf_angle_num);
  353 + GVector u(m_psf_angle_num);
  354 + double x = m_psf_angle_min;
  355 + for (int i = 0; i < m_psf_angle_num; ++i, x += m_psf_angle_bin) {
  356 + xaxis(i) = x;
  357 + u(i) = 0.5*x*x;
  358 + }
  359 +
  360 + // Get maximum angle
  361 + m_psf_angle_max = xaxis(m_psf_angle_num-1);
  362 +
  363 + // Loop over all energy bins
  364 + for (int ie = 0; ie < m_psf_energy_num; ++ie) {
  365 +
  366 + // Get mean energy of bin
  367 + // NOTE: This should be replaced by a logarithmic mean
  368 + double energy = 0.5 * (v_energy_lo(ie) + v_energy_hi(ie));
  369 +
  370 + // Get scale at specified energy
  371 + double scale = psf_scale(energy);
  372 +
  373 + // Loop over all cos theta bins
  374 + for (int ic = 0; ic < m_psf_ctheta_num; ++ic) {
  375 +
  376 + // Extract PSF parameters
  377 + int inx = ic * m_psf_energy_num + ie;
  378 + double ncore = v_ncore(inx);
  379 + double sigma = v_sigma(inx);
  380 + double gcore = v_gcore(inx);
  381 + double gtail = v_gtail(inx);
  382 +
  383 + // Evaluate ntail
  384 + double denom = psf_base_value(10.0, gtail);
  385 + double ntail = (denom != 0.0) ? ncore * psf_base_value(10.0, gcore) / denom : 0.0;
  386 +
  387 + // Calculate PSF dependence
  388 + GVector psf = ncore * psf_base_vector(u, gcore) + ntail * psf_base_vector(u, gtail);
  389 +
  390 + // Normalize PSF vector to identical amplitudes at smallest angular
  391 + // distance. This allows for accurate interpolation afterwards
  392 + double norm = 1.0 / psf(0);
  393 + psf *= norm;
  394 +
  395 + // Evaluate angular separation
  396 + double stretch = sigma * scale;
  397 + GVector delta = xaxis * stretch;
  398 +
  399 + // Calculate PSF normalization factor
  400 + double sum = 0.0;
  401 + for (int i = 0; i < m_psf_angle_num; ++i) {
  402 + if (delta(i) >= pihalf)
  403 + break;
  404 + sum += psf(i) * sin(delta(i));
  405 + }
  406 + sum *= twopi;
  407 + norm = scale / sum;
  408 +
  409 + // Store PSF information
  410 + m_norm[inx] = norm;
  411 + m_sigma[inx] = sigma;
  412 +
  413 + // Store PSF vector
  414 + int ipsf = inx * m_psf_angle_num;
  415 + for (int i = 0; i < m_psf_angle_num; ++i, ++ipsf)
  416 + m_psf[ipsf] = psf(i);
  417 +
  418 + } // endfor: looped over cos theta
  419 + } // endfor: looped over energies
302 420  
303 421 // Return
304 422 return;
... ... @@ -306,13 +424,91 @@ void GLATResponse::init_psf(void)
306 424  
307 425  
308 426 /***************************************************************************
  427 + * Returns PSF scale *
  428 + * ----------------------------------------------------------------------- *
  429 + ***************************************************************************/
  430 +/// PSF size scale as
  431 +/// scale = sqrt(c0^2 + (c1*t)^2)
  432 +/// with
  433 +/// t = (0.01*E)^-0.8
  434 +/// where E is the energy in MeV
  435 +/// The coefficients c0 and c1 dependend on the section:
  436 +/// Front: c0 = 3.77e-4, c1 = 5.8e-2
  437 +/// Back: c0 = 1.3e-3, c1 = 9.6e-2
  438 +double GLATResponse::psf_scale(const double& energy)
  439 +{
  440 + // Get section dependent coefficients
  441 + const double *c0;
  442 + const double *c1;
  443 + if (m_section == 0) { // front
  444 + c0 = &scale_front_c0;
  445 + c1 = &scale_front_c1;
  446 + }
  447 + else { // back
  448 + c0 = &scale_back_c0;
  449 + c1 = &scale_back_c1;
  450 + }
  451 +
  452 + // Angular resolution scales as a powerlaw with index -0.80
  453 + double t = pow(0.01*energy,-0.80);
  454 +
  455 + // Get scaling
  456 + double c1t = *c1 * t;
  457 + double scale = sqrt(*c0 * *c0 + c1t * c1t);
  458 +
  459 + // Return scaling
  460 + return scale;
  461 +}
  462 +
  463 +
  464 +/***************************************************************************
  465 + * Returns PSF basis function *
  466 + * ----------------------------------------------------------------------- *
  467 + ***************************************************************************/
  468 +/// This method returns the PSF basis function for a single value.
  469 +/// The PSF basis functions is defined by
  470 +/// psf(u,gamma) = (1.0 - 1.0/gamma) * (1.0 + u/gamma)^(-gamma)
  471 +/// where
  472 +/// u is an angle^2 (typically the scaled angular distance squared)
  473 +/// gamma is a powerlaw index
  474 +double GLATResponse::psf_base_value(const double& u, const double& gamma)
  475 +{
  476 + // Evaluate PSF basis function
  477 + double invgamma = 1.0/gamma;
  478 + double c0 = 1.0 - invgamma;
  479 + double c1 = 1.0 + u * invgamma;
  480 + double result = c0 * pow(c1,-gamma);
  481 +
  482 + // Return result
  483 + return result;
  484 +}
  485 +/// This method returns the PSF basis function for a vector.
  486 +GVector GLATResponse::psf_base_vector(const GVector& u, const double& gamma)
  487 +{
  488 + // Evaluate PSF basis function
  489 + double invgamma = 1.0/gamma;
  490 + double c0 = 1.0 - invgamma;
  491 + GVector c1 = 1.0 + u * invgamma;
  492 + GVector result = c0 * pow(c1,-gamma);
  493 +
  494 + // Return result
  495 + return result;
  496 +}
  497 +
  498 +/*==========================================================================
  499 + = =
  500 + = GLATResponse private energy dispersion methods =
  501 + = =
  502 + ==========================================================================*/
  503 +
  504 +/***************************************************************************
309 505 * Initialise energy dispersion *
310 506 * ----------------------------------------------------------------------- *
311 507 ***************************************************************************/
312   -void GLATResponse::init_edisp(void)
  508 +void GLATResponse::edisp_init(void)
313 509 {
314 510 // Build filename
315   - std::string filename = "edisp_" + m_rspname + ".fits";
  511 + std::string filename = "edisp_" + m_rspname + "_" + m_rsptype + ".fits";
316 512  
317 513 // Open FITS file
318 514 GFits file;
... ... @@ -342,6 +538,12 @@ void GLATResponse::init_edisp(void)
342 538 }
343 539  
344 540  
  541 +/*==========================================================================
  542 + = =
  543 + = GLATResponse private methods =
  544 + = =
  545 + ==========================================================================*/
  546 +
345 547 /***************************************************************************
346 548 * Initialise class members *
347 549 * ----------------------------------------------------------------------- *
... ... @@ -352,13 +554,23 @@ void GLATResponse::init_members(void)
352 554 //m_aeff_name.clear();
353 555 //m_psf_name.clear();
354 556 //m_edisp_name.clear();
  557 +
  558 + // Initialise PSF members
  559 + m_psf_angle_num = 0;
  560 + m_psf_angle_min = 0.0;
  561 + m_psf_angle_max = 0.0;
  562 + m_psf_angle_bin = 0.0;
  563 + m_psf_energy_num = 0;
  564 + m_psf_ctheta_num = 0;
  565 + m_psf = NULL;
  566 + m_norm = NULL;
  567 + m_sigma = NULL;
355 568  
356 569 // By default use HANDOFF response database.
357 570 char* handoff = getenv("HANDOFF_IRF_DIR");
358 571 if (handoff != NULL)
359 572 m_caldb.assign(handoff);
360 573  
361   -
362 574 // Return
363 575 return;
364 576 }
... ... @@ -388,9 +600,15 @@ void GLATResponse::copy_members(const GLATResponse&amp; rsp)
388 600 ***************************************************************************/
389 601 void GLATResponse::free_members(void)
390 602 {
391   - // Free memory
  603 + // Free PSF memory
  604 + if (m_psf != NULL) delete [] m_psf;
  605 + if (m_norm != NULL) delete [] m_norm;
  606 + if (m_sigma != NULL) delete [] m_sigma;
392 607  
393   - // Signal free pointers
  608 + // Signal that PSF memory is free
  609 + m_psf = NULL;
  610 + m_norm = NULL;
  611 + m_sigma = NULL;
394 612  
395 613 // Return
396 614 return;
... ... @@ -416,6 +634,7 @@ GVector GLATResponse::get_fits_vector(const GFitsHDU* hdu, const std::string&amp; co
416 634 GVector data(num);
417 635 for (int i = 0; i < num; ++i)
418 636 data(i) = ptr->real(row,i);
  637 + //cout << colname << ": " << num << endl;
419 638  
420 639 // Return vector
421 640 return data;
... ...
test/test_GResponse.cpp
... ... @@ -30,7 +30,7 @@ void test_lat_response(void)
30 30 // Get HANDOFF Response
31 31 GLATResponse rsp;
32 32 rsp.set_caldb("irf/lat");
33   - rsp.load("Pass5_v0_front");
  33 + rsp.load("Pass5_v0", "front");
34 34 /*
35 35 // Open FITS file
36 36 GFits fits;
... ...