Commit 63c88ec6ec67ce4aa92c9a44b629b518f2725e65
Merge branch '2342-smooth-cta-edisp' into integration
# Conflicts: # ChangeLog # NEWS
Showing
6 changed files
with
329 additions
and
44 deletions
ChangeLog
| @@ -7,11 +7,12 @@ | @@ -7,11 +7,12 @@ | ||
| 7 | Add GCTABackground::rate_ebin() method (#2308) | 7 | Add GCTABackground::rate_ebin() method (#2308) |
| 8 | 8 | ||
| 9 | 9 | ||
| 10 | -2018-02-15 | 10 | +2018-02-23 |
| 11 | 11 | ||
| 12 | * Bug fix version 1.5.1 released | 12 | * Bug fix version 1.5.1 released |
| 13 | ================================ | 13 | ================================ |
| 14 | 14 | ||
| 15 | + Add kludge to handle noisy CTA 2D energy dispersion (#2342). | ||
| 15 | Prevent unintentional deallocation of arguments (#2340). | 16 | Prevent unintentional deallocation of arguments (#2340). |
| 16 | Correct sky map smoothing. | 17 | Correct sky map smoothing. |
| 17 | 18 |
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,6 +10,8 @@ GammaLib 1.5.1 is a bug fix release for GammaLib release 1.5. | ||
| 10 | 10 | ||
| 11 | The following bugs were fixed: | 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 | * [`2340 <https://cta-redmine.irap.omp.eu/issues/2340>`_] - | 15 | * [`2340 <https://cta-redmine.irap.omp.eu/issues/2340>`_] - |
| 14 | Prevent unintentional deallocation of arguments | 16 | Prevent unintentional deallocation of arguments |
| 15 | * Correct sky map smoothing | 17 | * Correct sky map smoothing |
inst/cta/include/GCTAEdisp2D.hpp
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * GCTAEdisp2D.hpp - CTA 2D energy dispersion class * | 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 | * This program is free software: you can redistribute it and/or modify * | 7 | * This program is free software: you can redistribute it and/or modify * |
| @@ -35,6 +35,7 @@ | @@ -35,6 +35,7 @@ | ||
| 35 | #include "GCTAResponseTable.hpp" | 35 | #include "GCTAResponseTable.hpp" |
| 36 | 36 | ||
| 37 | /* __ Forward declarations _______________________________________________ */ | 37 | /* __ Forward declarations _______________________________________________ */ |
| 38 | +class GFft; | ||
| 38 | class GRan; | 39 | class GRan; |
| 39 | class GFits; | 40 | class GFits; |
| 40 | class GFitsBinTable; | 41 | class GFitsBinTable; |
| @@ -119,10 +120,16 @@ private: | @@ -119,10 +120,16 @@ private: | ||
| 119 | const double& phi = 0.0, | 120 | const double& phi = 0.0, |
| 120 | const double& zenith = 0.0, | 121 | const double& zenith = 0.0, |
| 121 | const double& azimuth = 0.0) const; | 122 | const double& azimuth = 0.0) const; |
| 122 | - void set_indices(void); | 123 | + void set_table(void); |
| 123 | void set_boundaries(void); | 124 | void set_boundaries(void); |
| 124 | void set_max_edisp(void) const; | 125 | void set_max_edisp(void) const; |
| 125 | void normalize_table(void); | 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 | // Protected classes | 134 | // Protected classes |
| 128 | class edisp_kern : public GFunction { | 135 | class edisp_kern : public GFunction { |
inst/cta/src/GCTAEdisp2D.cpp
| 1 | /*************************************************************************** | 1 | /*************************************************************************** |
| 2 | * GCTAEdisp2D.cpp - CTA 2D energy dispersion class * | 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 | * This program is free software: you can redistribute it and/or modify * | 7 | * This program is free software: you can redistribute it and/or modify * |
| @@ -32,6 +32,8 @@ | @@ -32,6 +32,8 @@ | ||
| 32 | #include <vector> | 32 | #include <vector> |
| 33 | #include "GTools.hpp" | 33 | #include "GTools.hpp" |
| 34 | #include "GMath.hpp" | 34 | #include "GMath.hpp" |
| 35 | +#include "GNdarray.hpp" | ||
| 36 | +#include "GFft.hpp" | ||
| 35 | #include "GException.hpp" | 37 | #include "GException.hpp" |
| 36 | #include "GIntegral.hpp" | 38 | #include "GIntegral.hpp" |
| 37 | #include "GFilename.hpp" | 39 | #include "GFilename.hpp" |
| @@ -50,6 +52,7 @@ | @@ -50,6 +52,7 @@ | ||
| 50 | /* __ Macros _____________________________________________________________ */ | 52 | /* __ Macros _____________________________________________________________ */ |
| 51 | 53 | ||
| 52 | /* __ Coding definitions _________________________________________________ */ | 54 | /* __ Coding definitions _________________________________________________ */ |
| 55 | +#define G_SMOOTH_EDISP_KLUDGE //!< Get rid of noise in energy dispersion | ||
| 53 | 56 | ||
| 54 | /* __ Debug definitions __________________________________________________ */ | 57 | /* __ Debug definitions __________________________________________________ */ |
| 55 | 58 | ||
| @@ -282,23 +285,8 @@ void GCTAEdisp2D::table(const GCTAResponseTable& table) | @@ -282,23 +285,8 @@ void GCTAEdisp2D::table(const GCTAResponseTable& table) | ||
| 282 | // Assign response table | 285 | // Assign response table |
| 283 | m_edisp = table; | 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 | // Return | 291 | // Return |
| 304 | return; | 292 | return; |
| @@ -347,23 +335,8 @@ void GCTAEdisp2D::read(const GFitsTable& table) | @@ -347,23 +335,8 @@ void GCTAEdisp2D::read(const GFitsTable& table) | ||
| 347 | throw GException::invalid_value(G_READ, msg); | 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 | // Return | 341 | // Return |
| 369 | return; | 342 | return; |
| @@ -1181,19 +1154,54 @@ void GCTAEdisp2D::compute_ebounds_src(const double& theta, | @@ -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 | m_inx_etrue = m_edisp.axis("ETRUE"); | 1179 | m_inx_etrue = m_edisp.axis("ETRUE"); |
| 1193 | m_inx_migra = m_edisp.axis("MIGRA"); | 1180 | m_inx_migra = m_edisp.axis("MIGRA"); |
| 1194 | m_inx_theta = m_edisp.axis("THETA"); | 1181 | m_inx_theta = m_edisp.axis("THETA"); |
| 1195 | m_inx_matrix = m_edisp.table("MATRIX"); | 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 | // Return | 1205 | // Return |
| 1198 | return; | 1206 | return; |
| 1199 | } | 1207 | } |
| @@ -1341,6 +1349,273 @@ void GCTAEdisp2D::normalize_table(void) | @@ -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 | * @brief Integration kernel for edisp_kern() class | 1619 | * @brief Integration kernel for edisp_kern() class |
| 1345 | * | 1620 | * |
| 1346 | * @param[in] x Function value. | 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
| @@ -1421,7 +1421,7 @@ void TestGCTAResponse::test_edisp_integration(const GCTAEdisp& edisp, | @@ -1421,7 +1421,7 @@ void TestGCTAResponse::test_edisp_integration(const GCTAEdisp& edisp, | ||
| 1421 | // Set message string | 1421 | // Set message string |
| 1422 | GEnergy eng(e_src, "TeV"); | 1422 | GEnergy eng(e_src, "TeV"); |
| 1423 | std::string msg = edisp.classname()+" integration for "+eng.print(); | 1423 | std::string msg = edisp.classname()+" integration for "+eng.print(); |
| 1424 | - test_value(sum, 1.0, 0.03, msg); | 1424 | + test_value(sum, 1.0, 0.01, msg); |
| 1425 | 1425 | ||
| 1426 | } | 1426 | } |
| 1427 | 1427 |