Commit 34b8b420acc979d8ffbbf95a923e98203cb871f2
1 parent
ad650400
Add kludge to handle noisy CTA 2D energy dispersion (#2342)
Showing
7 changed files
with
335 additions
and
45 deletions
ChangeLog
NEWS
| 1 | 1 | New Features and Important Changes in GammaLib 1.5.1 |
| 2 | 2 | |
| 3 | -15 February 2018 | |
| 3 | +23 February 2018 | |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | 1. Introduction |
| ... | ... | @@ -148,6 +148,11 @@ None |
| 148 | 148 | |
| 149 | 149 | 20. CTA interface |
| 150 | 150 | ----------------- |
| 151 | +Add a kludge to handle the noisy energy dispersion that is shipped with the 1DC | |
| 152 | +data and that is included in the Prod3 release. Noisy pixel values are skipped | |
| 153 | +and a slight smoothing is applied in true energy to reduce the noise level | |
| 154 | +(#2342). | |
| 155 | + | |
| 151 | 156 | The GCTAObservation::response() and GCTAOnOffObservation::response() methods |
| 152 | 157 | now only deallocate the previous content if the reference to the argument |
| 153 | 158 | differs from the reference of the previous content. Otherwise the method would | ... | ... |
doc/source/admin/release_history/1.5.1.rst
| ... | ... | @@ -10,6 +10,8 @@ GammaLib 1.5.1 is a bug fix release for GammaLib release 1.5. |
| 10 | 10 | |
| 11 | 11 | The following bugs were fixed: |
| 12 | 12 | |
| 13 | +* [`2342 <https://cta-redmine.irap.omp.eu/issues/2342>`_] - | |
| 14 | + Add kludge to handle noisy CTA 2D energy dispersion | |
| 13 | 15 | * [`2340 <https://cta-redmine.irap.omp.eu/issues/2340>`_] - |
| 14 | 16 | Prevent unintentional deallocation of arguments |
| 15 | 17 | * Correct sky map smoothing | ... | ... |
inst/cta/include/GCTAEdisp2D.hpp
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * GCTAEdisp2D.hpp - CTA 2D energy dispersion class * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2015-2017 by Florent Forest * | |
| 4 | + * copyright (C) 2015-2018 by Florent Forest * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -35,6 +35,7 @@ |
| 35 | 35 | #include "GCTAResponseTable.hpp" |
| 36 | 36 | |
| 37 | 37 | /* __ Forward declarations _______________________________________________ */ |
| 38 | +class GFft; | |
| 38 | 39 | class GRan; |
| 39 | 40 | class GFits; |
| 40 | 41 | class GFitsBinTable; |
| ... | ... | @@ -119,10 +120,16 @@ private: |
| 119 | 120 | const double& phi = 0.0, |
| 120 | 121 | const double& zenith = 0.0, |
| 121 | 122 | const double& azimuth = 0.0) const; |
| 122 | - void set_indices(void); | |
| 123 | + void set_table(void); | |
| 123 | 124 | void set_boundaries(void); |
| 124 | 125 | void set_max_edisp(void) const; |
| 125 | 126 | void normalize_table(void); |
| 127 | + void clip_table(const int& threshold); | |
| 128 | + void smooth_table(const double& sigma, const double& threshold); | |
| 129 | + GFft fft_smooth_kernel(const int& netrue, | |
| 130 | + const int& nmigra, | |
| 131 | + const double& sigma) const; | |
| 132 | + GNdarray clip_array(const GNdarray& array, const double& threshold) const; | |
| 126 | 133 | |
| 127 | 134 | // Protected classes |
| 128 | 135 | class edisp_kern : public GFunction { | ... | ... |
inst/cta/src/GCTAEdisp2D.cpp
| 1 | 1 | /*************************************************************************** |
| 2 | 2 | * GCTAEdisp2D.cpp - CTA 2D energy dispersion class * |
| 3 | 3 | * ----------------------------------------------------------------------- * |
| 4 | - * copyright (C) 2015-2017 by Florent Forest * | |
| 4 | + * copyright (C) 2015-2018 by Florent Forest * | |
| 5 | 5 | * ----------------------------------------------------------------------- * |
| 6 | 6 | * * |
| 7 | 7 | * This program is free software: you can redistribute it and/or modify * |
| ... | ... | @@ -32,6 +32,8 @@ |
| 32 | 32 | #include <vector> |
| 33 | 33 | #include "GTools.hpp" |
| 34 | 34 | #include "GMath.hpp" |
| 35 | +#include "GNdarray.hpp" | |
| 36 | +#include "GFft.hpp" | |
| 35 | 37 | #include "GException.hpp" |
| 36 | 38 | #include "GIntegral.hpp" |
| 37 | 39 | #include "GFilename.hpp" |
| ... | ... | @@ -50,6 +52,7 @@ |
| 50 | 52 | /* __ Macros _____________________________________________________________ */ |
| 51 | 53 | |
| 52 | 54 | /* __ Coding definitions _________________________________________________ */ |
| 55 | +#define G_SMOOTH_EDISP_KLUDGE //!< Get rid of noise in energy dispersion | |
| 53 | 56 | |
| 54 | 57 | /* __ Debug definitions __________________________________________________ */ |
| 55 | 58 | |
| ... | ... | @@ -282,23 +285,8 @@ void GCTAEdisp2D::table(const GCTAResponseTable& table) |
| 282 | 285 | // Assign response table |
| 283 | 286 | m_edisp = table; |
| 284 | 287 | |
| 285 | - // Set indices | |
| 286 | - set_indices(); | |
| 287 | - | |
| 288 | - // Set true energy axis to logarithmic scale | |
| 289 | - m_edisp.axis_log10(m_inx_etrue); | |
| 290 | - | |
| 291 | - // Set offset angle axis to radians | |
| 292 | - m_edisp.axis_radians(m_inx_theta); | |
| 293 | - | |
| 294 | - // Set table boundaries | |
| 295 | - set_boundaries(); | |
| 296 | - | |
| 297 | - // Normalize energy dispersion table | |
| 298 | - normalize_table(); | |
| 299 | - | |
| 300 | - // Set maximum energy dispersion value | |
| 301 | - set_max_edisp(); | |
| 288 | + // Set table | |
| 289 | + set_table(); | |
| 302 | 290 | |
| 303 | 291 | // Return |
| 304 | 292 | return; |
| ... | ... | @@ -347,23 +335,8 @@ void GCTAEdisp2D::read(const GFitsTable& table) |
| 347 | 335 | throw GException::invalid_value(G_READ, msg); |
| 348 | 336 | } |
| 349 | 337 | |
| 350 | - // Set table indices | |
| 351 | - set_indices(); | |
| 352 | - | |
| 353 | - // Set true energy axis to logarithmic scale | |
| 354 | - m_edisp.axis_log10(m_inx_etrue); | |
| 355 | - | |
| 356 | - // Set offset angle axis to radians | |
| 357 | - m_edisp.axis_radians(m_inx_theta); | |
| 358 | - | |
| 359 | - // Set table boundaries | |
| 360 | - set_boundaries(); | |
| 361 | - | |
| 362 | - // Normalize energy dispersion table | |
| 363 | - normalize_table(); | |
| 364 | - | |
| 365 | - // Set maximum energy dispersion value | |
| 366 | - set_max_edisp(); | |
| 338 | + // Set table | |
| 339 | + set_table(); | |
| 367 | 340 | |
| 368 | 341 | // Return |
| 369 | 342 | return; |
| ... | ... | @@ -1181,19 +1154,54 @@ void GCTAEdisp2D::compute_ebounds_src(const double& theta, |
| 1181 | 1154 | |
| 1182 | 1155 | |
| 1183 | 1156 | /***********************************************************************//** |
| 1184 | - * @brief Set table indices | |
| 1157 | + * @brief Set table | |
| 1185 | 1158 | * |
| 1186 | - * Sets the data members m_inx_etrue, m_inx_migra, m_inx_theta, and | |
| 1187 | - * m_inx_matrix. | |
| 1159 | + * After assigning or loading a response table, performs all necessary steps | |
| 1160 | + * to set the table. The method also smoothes the table get rid of numerical | |
| 1161 | + * fluctuations and normalises the table properly. | |
| 1162 | + * | |
| 1163 | + * Sets the data members | |
| 1164 | + * m_inx_etrue | |
| 1165 | + * m_inx_migra | |
| 1166 | + * m_inx_theta | |
| 1167 | + * m_inx_matrix | |
| 1168 | + * m_logEsrc_min | |
| 1169 | + * m_logEsrc_max | |
| 1170 | + * m_migra_min | |
| 1171 | + * m_migra_max | |
| 1172 | + * m_theta_min | |
| 1173 | + * m_theta_max | |
| 1174 | + * m_max_edisp | |
| 1188 | 1175 | ***************************************************************************/ |
| 1189 | -void GCTAEdisp2D::set_indices(void) | |
| 1176 | +void GCTAEdisp2D::set_table(void) | |
| 1190 | 1177 | { |
| 1191 | - // Get mandatory indices (throw exception if not found) | |
| 1178 | + // Set table indices | |
| 1192 | 1179 | m_inx_etrue = m_edisp.axis("ETRUE"); |
| 1193 | 1180 | m_inx_migra = m_edisp.axis("MIGRA"); |
| 1194 | 1181 | m_inx_theta = m_edisp.axis("THETA"); |
| 1195 | 1182 | m_inx_matrix = m_edisp.table("MATRIX"); |
| 1196 | 1183 | |
| 1184 | + // Set true energy axis to logarithmic scale | |
| 1185 | + m_edisp.axis_log10(m_inx_etrue); | |
| 1186 | + | |
| 1187 | + // Set offset angle axis to radians | |
| 1188 | + m_edisp.axis_radians(m_inx_theta); | |
| 1189 | + | |
| 1190 | + // Set table boundaries | |
| 1191 | + set_boundaries(); | |
| 1192 | + | |
| 1193 | + // Smooth energy dispersion table | |
| 1194 | + #if defined(G_SMOOTH_EDISP_KLUDGE) | |
| 1195 | + clip_table(15); | |
| 1196 | + smooth_table(3.0, 0.0001); | |
| 1197 | + #endif | |
| 1198 | + | |
| 1199 | + // Normalize energy dispersion table | |
| 1200 | + normalize_table(); | |
| 1201 | + | |
| 1202 | + // Set maximum energy dispersion value | |
| 1203 | + set_max_edisp(); | |
| 1204 | + | |
| 1197 | 1205 | // Return |
| 1198 | 1206 | return; |
| 1199 | 1207 | } |
| ... | ... | @@ -1341,6 +1349,273 @@ void GCTAEdisp2D::normalize_table(void) |
| 1341 | 1349 | |
| 1342 | 1350 | |
| 1343 | 1351 | /***********************************************************************//** |
| 1352 | + * @brief Clip energy dispersion table | |
| 1353 | + * | |
| 1354 | + * @param[in] threshold Minimum number of consecutive non-zeros | |
| 1355 | + * | |
| 1356 | + * Clips noise in the energy dispersion table. | |
| 1357 | + * | |
| 1358 | + * For each offset angle and true energy, the method determines the maximum | |
| 1359 | + * value of the energy dispersion table and then walks towards smaller and | |
| 1360 | + * larger migration value to determine the first pixel for which the energy | |
| 1361 | + * dispersion becomes zero. All pixels beyond these pixels are then clipped | |
| 1362 | + * to zero. This removes noise that is at small or large migration values. | |
| 1363 | + * | |
| 1364 | + * The method then computes the number of remaining contiguos non-zero pixels | |
| 1365 | + * for each offset angle and true energy, and if this number is smaller than | |
| 1366 | + * 10, all pixels are set to zero. This removes true energy bins that are | |
| 1367 | + * sparesely filled. | |
| 1368 | + ***************************************************************************/ | |
| 1369 | +void GCTAEdisp2D::clip_table(const int& threshold) | |
| 1370 | +{ | |
| 1371 | + // Get axes dimensions | |
| 1372 | + int netrue = m_edisp.axis_bins(m_inx_etrue); | |
| 1373 | + int nmigra = m_edisp.axis_bins(m_inx_migra); | |
| 1374 | + int ntheta = m_edisp.axis_bins(m_inx_theta); | |
| 1375 | + | |
| 1376 | + // Loop over all offset angles | |
| 1377 | + for (int itheta = 0; itheta < ntheta; ++itheta) { | |
| 1378 | + | |
| 1379 | + // Loop ober all true energies | |
| 1380 | + for (int ietrue = 0; ietrue < netrue; ++ietrue) { | |
| 1381 | + | |
| 1382 | + // Compute base index | |
| 1383 | + int ibase = ietrue + itheta * netrue * nmigra; | |
| 1384 | + | |
| 1385 | + // Determine index of maximum value | |
| 1386 | + int imax = 0; | |
| 1387 | + double max = m_edisp(m_inx_matrix,ibase+ietrue); | |
| 1388 | + for (int imigra = 1; imigra < nmigra; ++imigra) { | |
| 1389 | + int inx = ibase + imigra*netrue; | |
| 1390 | + double value = m_edisp(m_inx_matrix, inx); | |
| 1391 | + if (value > max) { | |
| 1392 | + imax = imigra; | |
| 1393 | + max = value; | |
| 1394 | + } | |
| 1395 | + } | |
| 1396 | + | |
| 1397 | + // Do nothing if all pixels are zero | |
| 1398 | + if (max == 0.0) { | |
| 1399 | + continue; | |
| 1400 | + } | |
| 1401 | + | |
| 1402 | + // Walk from maximum to the first pixel | |
| 1403 | + bool clip = false; | |
| 1404 | + for (int imigra = imax; imigra >= 0; imigra--) { | |
| 1405 | + int inx = ibase + imigra*netrue; | |
| 1406 | + if (clip) { | |
| 1407 | + m_edisp(m_inx_matrix, inx) = 0.0; | |
| 1408 | + } | |
| 1409 | + else { | |
| 1410 | + double value = m_edisp(m_inx_matrix, inx); | |
| 1411 | + if (value == 0.0) { | |
| 1412 | + clip = true; | |
| 1413 | + } | |
| 1414 | + } | |
| 1415 | + } | |
| 1416 | + | |
| 1417 | + // Walk from maximum to the last pixel | |
| 1418 | + clip = false; | |
| 1419 | + for (int imigra = imax; imigra < nmigra; ++imigra) { | |
| 1420 | + int inx = ibase + imigra*netrue; | |
| 1421 | + if (clip) { | |
| 1422 | + m_edisp(m_inx_matrix, inx) = 0.0; | |
| 1423 | + } | |
| 1424 | + else { | |
| 1425 | + double value = m_edisp(m_inx_matrix, inx); | |
| 1426 | + if (value == 0.0) { | |
| 1427 | + clip = true; | |
| 1428 | + } | |
| 1429 | + } | |
| 1430 | + } | |
| 1431 | + | |
| 1432 | + // Determine number of contiguous non-zero pixels | |
| 1433 | + int nonzero = 0; | |
| 1434 | + int contiguous_nonzero = 0; | |
| 1435 | + for (int imigra = 0; imigra < nmigra; ++imigra) { | |
| 1436 | + int inx = ibase + imigra*netrue; | |
| 1437 | + double value = m_edisp(m_inx_matrix, inx); | |
| 1438 | + if (value != 0.0) { | |
| 1439 | + nonzero++; | |
| 1440 | + if (nonzero > contiguous_nonzero) { | |
| 1441 | + contiguous_nonzero = nonzero; | |
| 1442 | + } | |
| 1443 | + } | |
| 1444 | + else { | |
| 1445 | + nonzero = 0; | |
| 1446 | + } | |
| 1447 | + } | |
| 1448 | + | |
| 1449 | + // If there are less than threshold contiguous non-zero pixels we | |
| 1450 | + // only have noise, hence all pixels are set to zero | |
| 1451 | + if (contiguous_nonzero < threshold) { | |
| 1452 | + for (int imigra = 0; imigra < nmigra; ++imigra) { | |
| 1453 | + int inx = ibase + imigra*netrue; | |
| 1454 | + m_edisp(m_inx_matrix, inx) = 0.0; | |
| 1455 | + } | |
| 1456 | + } | |
| 1457 | + | |
| 1458 | + } // endfor: looped over all true energies | |
| 1459 | + | |
| 1460 | + } // endfor: looped over all offset angles | |
| 1461 | + | |
| 1462 | + // Return | |
| 1463 | + return; | |
| 1464 | +} | |
| 1465 | + | |
| 1466 | + | |
| 1467 | +/***********************************************************************//** | |
| 1468 | + * @brief Smooth energy dispersion table | |
| 1469 | + * | |
| 1470 | + * @param[in] sigma Smoothing width (number of bins in true energy) | |
| 1471 | + * @param[in] threshold Clipping threshold | |
| 1472 | + * | |
| 1473 | + * Smooth the energy dispersion table in true energy. The smoothing is done | |
| 1474 | + * using a fast-fourrier transform. For this purpose the energy disperison | |
| 1475 | + * table for each offset angle is copied into a 2D array, padded with some | |
| 1476 | + * zero pixels on the left and the right to avoid wrap around. After | |
| 1477 | + * smoothing the array is clipped using the clip_array() method to avoid | |
| 1478 | + * marginal non-zero energy dispersion values. | |
| 1479 | + ***************************************************************************/ | |
| 1480 | +void GCTAEdisp2D::smooth_table(const double& sigma, const double& threshold) | |
| 1481 | +{ | |
| 1482 | + // Get axes dimensions | |
| 1483 | + int netrue = m_edisp.axis_bins(m_inx_etrue); | |
| 1484 | + int nmigra = m_edisp.axis_bins(m_inx_migra); | |
| 1485 | + int ntheta = m_edisp.axis_bins(m_inx_theta); | |
| 1486 | + int netrue_pad = int(3.0*sigma); | |
| 1487 | + int netrue_padded = netrue + 2*netrue_pad; // Array padded with zeros | |
| 1488 | + int npix = netrue * nmigra; | |
| 1489 | + | |
| 1490 | + // Get smoothing kernel | |
| 1491 | + GFft fft_kernel = fft_smooth_kernel(netrue_padded, nmigra, sigma); | |
| 1492 | + | |
| 1493 | + // Loop over all offset angles | |
| 1494 | + for (int itheta = 0; itheta < ntheta; ++itheta) { | |
| 1495 | + | |
| 1496 | + // Compute base index | |
| 1497 | + int ibase = itheta * npix; | |
| 1498 | + | |
| 1499 | + // Extract matrix in GNdarray | |
| 1500 | + GNdarray array(netrue_padded, nmigra); | |
| 1501 | + for (int imigra = 0, i = 0; imigra < nmigra; ++imigra) { | |
| 1502 | + double* ptr = array.data() + imigra * netrue_padded + netrue_pad; | |
| 1503 | + for (int ietrue = 0; ietrue < netrue; ++ietrue, ++i) { | |
| 1504 | + *ptr++ = m_edisp(m_inx_matrix, ibase+i); | |
| 1505 | + } | |
| 1506 | + } | |
| 1507 | + | |
| 1508 | + // FFT of array | |
| 1509 | + GFft fft_array(array); | |
| 1510 | + | |
| 1511 | + // Smooth array | |
| 1512 | + GFft fft_smooth = fft_array * fft_kernel; | |
| 1513 | + | |
| 1514 | + // Backward transform array | |
| 1515 | + GNdarray smooth = fft_smooth.backward(); | |
| 1516 | + | |
| 1517 | + // Clip array | |
| 1518 | + smooth = clip_array(smooth, threshold); | |
| 1519 | + | |
| 1520 | + // Put back array values in matrix | |
| 1521 | + for (int imigra = 0, i = 0; imigra < nmigra; ++imigra) { | |
| 1522 | + double* ptr = smooth.data() + imigra * netrue_padded + netrue_pad; | |
| 1523 | + for (int ietrue = 0; ietrue < netrue; ++ietrue, ++i) { | |
| 1524 | + m_edisp(m_inx_matrix, ibase+i) = *ptr++; | |
| 1525 | + } | |
| 1526 | + } | |
| 1527 | + | |
| 1528 | + } // endfor: looped over all offset angles | |
| 1529 | + | |
| 1530 | + // Return | |
| 1531 | + return; | |
| 1532 | +} | |
| 1533 | + | |
| 1534 | + | |
| 1535 | +/***********************************************************************//** | |
| 1536 | + * @brief Get FFT of smoothing kernel | |
| 1537 | + * | |
| 1538 | + * @return FFT of smoothing kernel | |
| 1539 | + * | |
| 1540 | + * Returns the fast-fourrier transform of a Gaussian smoothing kernel in | |
| 1541 | + * true energy. | |
| 1542 | + ***************************************************************************/ | |
| 1543 | +GFft GCTAEdisp2D::fft_smooth_kernel(const int& netrue, | |
| 1544 | + const int& nmigra, | |
| 1545 | + const double& sigma) const | |
| 1546 | +{ | |
| 1547 | + // Allocate kernel | |
| 1548 | + GNdarray kernel(netrue, nmigra); | |
| 1549 | + | |
| 1550 | + // Initialise sum and compute Gaussian normalisation | |
| 1551 | + double sum = 0.0; | |
| 1552 | + double norm = -0.5 / (sigma * sigma); | |
| 1553 | + | |
| 1554 | + // Set Gaussian kernel | |
| 1555 | + for (int i = 0; i < netrue; ++i) { | |
| 1556 | + double value = std::exp(norm*double(i*i)); | |
| 1557 | + kernel(i,0) += value; | |
| 1558 | + sum += value; | |
| 1559 | + if (i > 0) { | |
| 1560 | + kernel(netrue-i,0) += value; | |
| 1561 | + sum += value; | |
| 1562 | + } | |
| 1563 | + } | |
| 1564 | + | |
| 1565 | + // Normalize kernel | |
| 1566 | + if (sum > 0.0) { | |
| 1567 | + for (int i = 0; i < netrue; ++i) { | |
| 1568 | + kernel(i,0) /= sum; | |
| 1569 | + } | |
| 1570 | + } | |
| 1571 | + | |
| 1572 | + // Return FFT of kernel | |
| 1573 | + return (GFft(kernel)); | |
| 1574 | +} | |
| 1575 | + | |
| 1576 | + | |
| 1577 | +/***********************************************************************//** | |
| 1578 | + * @brief Clip array | |
| 1579 | + * | |
| 1580 | + * @param[in] array Ndarray that should be clipped. | |
| 1581 | + * @param[in] threshold Clipping threshold in fraction of maximum value. | |
| 1582 | + * @return Clipped Ndarray | |
| 1583 | + * | |
| 1584 | + * Clips all values below a threshold of 10 to zero. | |
| 1585 | + ***************************************************************************/ | |
| 1586 | +GNdarray GCTAEdisp2D::clip_array(const GNdarray& array, | |
| 1587 | + const double& threshold) const | |
| 1588 | +{ | |
| 1589 | + // Set clipped array | |
| 1590 | + GNdarray clipped = array; | |
| 1591 | + | |
| 1592 | + // Initialise variables | |
| 1593 | + int nsize = clipped.size(); | |
| 1594 | + | |
| 1595 | + // Determine maximum value in array | |
| 1596 | + double max = 0.0; | |
| 1597 | + double* cptr = clipped.data(); | |
| 1598 | + for (int i = 0; i < nsize; ++i, cptr++) { | |
| 1599 | + if (*cptr > max) { | |
| 1600 | + max = *cptr; | |
| 1601 | + } | |
| 1602 | + } | |
| 1603 | + | |
| 1604 | + // Clip values below threshold | |
| 1605 | + double clip_value = max * threshold; | |
| 1606 | + cptr = clipped.data(); | |
| 1607 | + for (int i = 0; i < nsize; ++i, cptr++) { | |
| 1608 | + if (std::abs(*cptr) < clip_value) { | |
| 1609 | + *cptr = 0.0; | |
| 1610 | + } | |
| 1611 | + } | |
| 1612 | + | |
| 1613 | + // Return clipped array | |
| 1614 | + return clipped; | |
| 1615 | +} | |
| 1616 | + | |
| 1617 | + | |
| 1618 | +/***********************************************************************//** | |
| 1344 | 1619 | * @brief Integration kernel for edisp_kern() class |
| 1345 | 1620 | * |
| 1346 | 1621 | * @param[in] x Function value. | ... | ... |
inst/cta/test/caldb/edisp_matrix.fits.gz
No preview for this file type
inst/cta/test/test_CTA.cpp
| ... | ... | @@ -1226,7 +1226,7 @@ void TestGCTAResponse::test_edisp_integration(const GCTAEdisp& edisp, |
| 1226 | 1226 | // Set message string |
| 1227 | 1227 | GEnergy eng(e_src, "TeV"); |
| 1228 | 1228 | std::string msg = edisp.classname()+" integration for "+eng.print(); |
| 1229 | - test_value(sum, 1.0, 0.03, msg); | |
| 1229 | + test_value(sum, 1.0, 0.01, msg); | |
| 1230 | 1230 | |
| 1231 | 1231 | } |
| 1232 | 1232 | ... | ... |