Commit 83baaaa0f2d4d8fec1cece23057af851c1b812de
1 parent
1b3ba53c
implement LAT PSF initialization
Showing
4 changed files
with
270 additions
and
29 deletions
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& 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& 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