Commit 83baaaa0f2d4d8fec1cece23057af851c1b812de

Authored by knodlseder
1 parent 1b3ba53c

implement LAT PSF initialization

include/GLATResponse.hpp
@@ -68,21 +68,43 @@ public: @@ -68,21 +68,43 @@ public:
68 const double& time); 68 const double& time);
69 69
70 void set_caldb(std::string caldb); 70 void set_caldb(std::string caldb);
71 - void load(std::string rspname); 71 + void load(std::string rspname, std::string rsptype);
72 void save(std::string rspname) const; 72 void save(std::string rspname) const;
73 GLATResponse* clone(void) const; 73 GLATResponse* clone(void) const;
74 74
75 private: 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 // Private methods 99 // Private methods
77 void init_members(void); 100 void init_members(void);
78 void copy_members(const GLATResponse& rsp); 101 void copy_members(const GLATResponse& rsp);
79 void free_members(void); 102 void free_members(void);
80 - void init_aeff(void);  
81 - void init_psf(void);  
82 - void init_edisp(void);  
83 GVector get_fits_vector(const GFitsHDU* hdu, const std::string& colname, int row = 0); 103 GVector get_fits_vector(const GFitsHDU* hdu, const std::string& colname, int row = 0);
84 104
85 // Private data area 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,12 +113,12 @@ public:
113 /// Pure virtual method to load the instrument response from the calibration 113 /// Pure virtual method to load the instrument response from the calibration
114 /// database 114 /// database
115 /// @param rspname Name of the instrument response 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 /// Pure virtual method to save the instrument response into the calibration 118 /// Pure virtual method to save the instrument response into the calibration
119 /// database 119 /// database
120 /// @param rspname Name of the instrument response 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 /// Pure virtual method to clone the response instance 123 /// Pure virtual method to clone the response instance
124 virtual GResponse* clone(void) const = 0; 124 virtual GResponse* clone(void) const = 0;
src/rsp/GLATResponse.cpp
@@ -34,6 +34,20 @@ @@ -34,6 +34,20 @@
34 34
35 /* __ Debug definitions __________________________________________________ */ 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,19 +222,28 @@ void GLATResponse::set_caldb(std::string caldb)
208 /** 222 /**
209 * @brief Load a specified LAT response function. 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 // Store response name 227 // Store response name
214 m_rspname = rspname; 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 // Initialise effective area 239 // Initialise effective area
217 - init_aeff(); 240 + aeff_init();
218 241
219 // Initialise PSF 242 // Initialise PSF
220 - init_psf(); 243 + psf_init();
221 244
222 // Initialise energy dispersion 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,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,10 +269,10 @@ void GLATResponse::save(std::string rspname) const
246 * Initialise effective area * 269 * Initialise effective area *
247 * ----------------------------------------------------------------------- * 270 * ----------------------------------------------------------------------- *
248 ***************************************************************************/ 271 ***************************************************************************/
249 -void GLATResponse::init_aeff(void) 272 +void GLATResponse::aeff_init(void)
250 { 273 {
251 // Build filename 274 // Build filename
252 - std::string filename = "aeff_" + m_rspname + ".fits"; 275 + std::string filename = "aeff_" + m_rspname + "_" + m_rsptype + ".fits";
253 276
254 // Open FITS file 277 // Open FITS file
255 GFits file; 278 GFits file;
@@ -272,14 +295,20 @@ void GLATResponse::init_aeff(void) @@ -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 * Initialise PSF * 305 * Initialise PSF *
277 * ----------------------------------------------------------------------- * 306 * ----------------------------------------------------------------------- *
278 ***************************************************************************/ 307 ***************************************************************************/
279 -void GLATResponse::init_psf(void) 308 +void GLATResponse::psf_init(void)
280 { 309 {
281 // Build filename 310 // Build filename
282 - std::string filename = "psf_" + m_rspname + ".fits"; 311 + std::string filename = "psf_" + m_rspname + "_" + m_rsptype + ".fits";
283 312
284 // Open FITS file 313 // Open FITS file
285 GFits file; 314 GFits file;
@@ -291,14 +320,103 @@ void GLATResponse::init_psf(void) @@ -291,14 +320,103 @@ void GLATResponse::init_psf(void)
291 throw GException::fits_hdu_not_found(G_INIT_PSF, "RPSF"); 320 throw GException::fits_hdu_not_found(G_INIT_PSF, "RPSF");
292 321
293 // Get the data 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 // Return 421 // Return
304 return; 422 return;
@@ -306,13 +424,91 @@ void GLATResponse::init_psf(void) @@ -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 * Initialise energy dispersion * 505 * Initialise energy dispersion *
310 * ----------------------------------------------------------------------- * 506 * ----------------------------------------------------------------------- *
311 ***************************************************************************/ 507 ***************************************************************************/
312 -void GLATResponse::init_edisp(void) 508 +void GLATResponse::edisp_init(void)
313 { 509 {
314 // Build filename 510 // Build filename
315 - std::string filename = "edisp_" + m_rspname + ".fits"; 511 + std::string filename = "edisp_" + m_rspname + "_" + m_rsptype + ".fits";
316 512
317 // Open FITS file 513 // Open FITS file
318 GFits file; 514 GFits file;
@@ -342,6 +538,12 @@ void GLATResponse::init_edisp(void) @@ -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 * Initialise class members * 548 * Initialise class members *
347 * ----------------------------------------------------------------------- * 549 * ----------------------------------------------------------------------- *
@@ -352,13 +554,23 @@ void GLATResponse::init_members(void) @@ -352,13 +554,23 @@ void GLATResponse::init_members(void)
352 //m_aeff_name.clear(); 554 //m_aeff_name.clear();
353 //m_psf_name.clear(); 555 //m_psf_name.clear();
354 //m_edisp_name.clear(); 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 // By default use HANDOFF response database. 569 // By default use HANDOFF response database.
357 char* handoff = getenv("HANDOFF_IRF_DIR"); 570 char* handoff = getenv("HANDOFF_IRF_DIR");
358 if (handoff != NULL) 571 if (handoff != NULL)
359 m_caldb.assign(handoff); 572 m_caldb.assign(handoff);
360 573
361 -  
362 // Return 574 // Return
363 return; 575 return;
364 } 576 }
@@ -388,9 +600,15 @@ void GLATResponse::copy_members(const GLATResponse&amp; rsp) @@ -388,9 +600,15 @@ void GLATResponse::copy_members(const GLATResponse&amp; rsp)
388 ***************************************************************************/ 600 ***************************************************************************/
389 void GLATResponse::free_members(void) 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 // Return 613 // Return
396 return; 614 return;
@@ -416,6 +634,7 @@ GVector GLATResponse::get_fits_vector(const GFitsHDU* hdu, const std::string&amp; co @@ -416,6 +634,7 @@ GVector GLATResponse::get_fits_vector(const GFitsHDU* hdu, const std::string&amp; co
416 GVector data(num); 634 GVector data(num);
417 for (int i = 0; i < num; ++i) 635 for (int i = 0; i < num; ++i)
418 data(i) = ptr->real(row,i); 636 data(i) = ptr->real(row,i);
  637 + //cout << colname << ": " << num << endl;
419 638
420 // Return vector 639 // Return vector
421 return data; 640 return data;
test/test_GResponse.cpp
@@ -30,7 +30,7 @@ void test_lat_response(void) @@ -30,7 +30,7 @@ void test_lat_response(void)
30 // Get HANDOFF Response 30 // Get HANDOFF Response
31 GLATResponse rsp; 31 GLATResponse rsp;
32 rsp.set_caldb("irf/lat"); 32 rsp.set_caldb("irf/lat");
33 - rsp.load("Pass5_v0_front"); 33 + rsp.load("Pass5_v0", "front");
34 /* 34 /*
35 // Open FITS file 35 // Open FITS file
36 GFits fits; 36 GFits fits;