Commit 2b15414b0e064f68e1e769ebe916db5ea0c506e6
1 parent
3b8c6607
Implement energy dispersion replacement by Gaussian in GCTAEdisp2D (#2403)
Showing
2 changed files
with
58 additions
and
467 deletions
inst/cta/include/GCTAEdisp2D.hpp
| @@ -127,28 +127,15 @@ private: | @@ -127,28 +127,15 @@ private: | ||
| 127 | 127 | ||
| 128 | // Kludge | 128 | // Kludge |
| 129 | void clean_table(const int& threshold); | 129 | void clean_table(const int& threshold); |
| 130 | - GFft fft_smooth_kernel(const int& nbins, | ||
| 131 | - const double& sigma) const; | ||
| 132 | void clip_table(const double& threshold); | 130 | void clip_table(const double& threshold); |
| 133 | - void denoise_table(void); | ||
| 134 | - GNdarray smooth_array(const GNdarray& array, const double& mean, | ||
| 135 | - const double& rms) const; | 131 | + void denoise_table(const double& sigma); |
| 136 | GNdarray gaussian_array(const double& mean, const double& rms) const; | 132 | GNdarray gaussian_array(const double& mean, const double& rms) const; |
| 137 | GNdarray get_gaussian_pars(const double& sigma) const; | 133 | GNdarray get_gaussian_pars(const double& sigma) const; |
| 134 | + GFft fft_smooth_kernel(const int& nbins, | ||
| 135 | + const double& sigma) const; | ||
| 138 | void get_mean_rms(const GNdarray& array, double* mean, double* rms) const; | 136 | void get_mean_rms(const GNdarray& array, double* mean, double* rms) const; |
| 139 | double get_single_event_value(const GNdarray& array) const; | 137 | double get_single_event_value(const GNdarray& array) const; |
| 140 | 138 | ||
| 141 | - // Obsolete kludge | ||
| 142 | - void smooth_table(const double& sigma); | ||
| 143 | - void smooth_table2(const double& sigma_etrue, const double& sigma_migra); | ||
| 144 | - GFft fft_smooth_kernel(const int& netrue, | ||
| 145 | - const int& nmigra, | ||
| 146 | - const double& sigma) const; | ||
| 147 | - GFft fft_smooth_kernel2(const int& netrue, | ||
| 148 | - const int& nmigra, | ||
| 149 | - const double& sigma_etrue, | ||
| 150 | - const double& sigma_migra) const; | ||
| 151 | - | ||
| 152 | // Protected classes | 139 | // Protected classes |
| 153 | class edisp_kern : public GFunction { | 140 | class edisp_kern : public GFunction { |
| 154 | public: | 141 | public: |
inst/cta/src/GCTAEdisp2D.cpp
| @@ -53,7 +53,7 @@ | @@ -53,7 +53,7 @@ | ||
| 53 | 53 | ||
| 54 | /* __ Coding definitions _________________________________________________ */ | 54 | /* __ Coding definitions _________________________________________________ */ |
| 55 | #define G_SMOOTH_EDISP_KLUDGE //!< Get rid of noise in energy dispersion | 55 | #define G_SMOOTH_EDISP_KLUDGE //!< Get rid of noise in energy dispersion |
| 56 | -#define G_SMOOTH_EDISP_SAVE_TEST //!< Save test matrix | 56 | +//#define G_SMOOTH_EDISP_SAVE_TEST //!< Save test matrix |
| 57 | 57 | ||
| 58 | /* __ Debug definitions __________________________________________________ */ | 58 | /* __ Debug definitions __________________________________________________ */ |
| 59 | 59 | ||
| @@ -1200,15 +1200,9 @@ void GCTAEdisp2D::set_table(void) | @@ -1200,15 +1200,9 @@ void GCTAEdisp2D::set_table(void) | ||
| 1200 | 1200 | ||
| 1201 | // Smooth energy dispersion table | 1201 | // Smooth energy dispersion table |
| 1202 | #if defined(G_SMOOTH_EDISP_KLUDGE) | 1202 | #if defined(G_SMOOTH_EDISP_KLUDGE) |
| 1203 | - denoise_table(); | 1203 | + denoise_table(10.0); |
| 1204 | clean_table(15); | 1204 | clean_table(15); |
| 1205 | clip_table(0.001); | 1205 | clip_table(0.001); |
| 1206 | - /* | ||
| 1207 | - denoise_table(); | ||
| 1208 | - clean_table(20); | ||
| 1209 | - smooth_table(5.0); | ||
| 1210 | - clip_table(0.01); | ||
| 1211 | - */ | ||
| 1212 | #endif | 1206 | #endif |
| 1213 | 1207 | ||
| 1214 | // Normalize energy dispersion table | 1208 | // Normalize energy dispersion table |
| @@ -1369,11 +1363,11 @@ void GCTAEdisp2D::normalize_table(void) | @@ -1369,11 +1363,11 @@ void GCTAEdisp2D::normalize_table(void) | ||
| 1369 | 1363 | ||
| 1370 | 1364 | ||
| 1371 | /***********************************************************************//** | 1365 | /***********************************************************************//** |
| 1372 | - * @brief Clip energy dispersion table | 1366 | + * @brief Clean energy dispersion table |
| 1373 | * | 1367 | * |
| 1374 | * @param[in] threshold Minimum number of consecutive non-zeros | 1368 | * @param[in] threshold Minimum number of consecutive non-zeros |
| 1375 | * | 1369 | * |
| 1376 | - * Clips noise in the energy dispersion table. | 1370 | + * Removes noise from the energy dispersion table. |
| 1377 | * | 1371 | * |
| 1378 | * For each offset angle and true energy, the method determines the maximum | 1372 | * For each offset angle and true energy, the method determines the maximum |
| 1379 | * value of the energy dispersion table and then walks towards smaller and | 1373 | * value of the energy dispersion table and then walks towards smaller and |
| @@ -1485,282 +1479,9 @@ void GCTAEdisp2D::clean_table(const int& threshold) | @@ -1485,282 +1479,9 @@ void GCTAEdisp2D::clean_table(const int& threshold) | ||
| 1485 | 1479 | ||
| 1486 | 1480 | ||
| 1487 | /***********************************************************************//** | 1481 | /***********************************************************************//** |
| 1488 | - * @brief Smooth energy dispersion table | ||
| 1489 | - * | ||
| 1490 | - * @param[in] sigma Smoothing width (number of bins in true energy) | ||
| 1491 | - * | ||
| 1492 | - * Smooth the energy dispersion table in true energy. The smoothing is done | ||
| 1493 | - * using a fast-fourrier transform. For this purpose the energy disperison | ||
| 1494 | - * table for each offset angle is copied into a 2D array, padded with some | ||
| 1495 | - * zero pixels on the left and the right to avoid wrap around. | ||
| 1496 | - ***************************************************************************/ | ||
| 1497 | -void GCTAEdisp2D::smooth_table(const double& sigma) | ||
| 1498 | -{ | ||
| 1499 | - // Get axes dimensions | ||
| 1500 | - int netrue = m_edisp.axis_bins(m_inx_etrue); | ||
| 1501 | - int nmigra = m_edisp.axis_bins(m_inx_migra); | ||
| 1502 | - int ntheta = m_edisp.axis_bins(m_inx_theta); | ||
| 1503 | - int netrue_pad = int(3.0*sigma); | ||
| 1504 | - int netrue_padded = netrue + 2*netrue_pad; // Array padded with zeros | ||
| 1505 | - int npix = netrue * nmigra; | ||
| 1506 | - | ||
| 1507 | - // Get smoothing kernel | ||
| 1508 | - GFft fft_kernel = fft_smooth_kernel(netrue_padded, nmigra, sigma); | ||
| 1509 | - | ||
| 1510 | - // Loop over all offset angles | ||
| 1511 | - for (int itheta = 0; itheta < ntheta; ++itheta) { | ||
| 1512 | - | ||
| 1513 | - // Compute base index | ||
| 1514 | - int ibase = itheta * npix; | ||
| 1515 | - | ||
| 1516 | - // Extract matrix in GNdarray | ||
| 1517 | - GNdarray array(netrue_padded, nmigra); | ||
| 1518 | - for (int imigra = 0, i = ibase; imigra < nmigra; ++imigra) { | ||
| 1519 | - double* ptr = array.data() + imigra * netrue_padded + netrue_pad; | ||
| 1520 | - for (int ietrue = 0; ietrue < netrue; ++ietrue, ++i) { | ||
| 1521 | - *ptr++ = m_edisp(m_inx_matrix, i); | ||
| 1522 | - } | ||
| 1523 | - } | ||
| 1524 | - | ||
| 1525 | - // FFT of array | ||
| 1526 | - GFft fft_array(array); | ||
| 1527 | - | ||
| 1528 | - // Smooth array | ||
| 1529 | - GFft fft_smooth = fft_array * fft_kernel; | ||
| 1530 | - | ||
| 1531 | - // Backward transform array | ||
| 1532 | - GNdarray smooth = fft_smooth.backward(); | ||
| 1533 | - | ||
| 1534 | - // Put back array values in matrix | ||
| 1535 | - for (int imigra = 0, i = ibase; imigra < nmigra; ++imigra) { | ||
| 1536 | - double* ptr = smooth.data() + imigra * netrue_padded + netrue_pad; | ||
| 1537 | - for (int ietrue = 0; ietrue < netrue; ++ietrue, ++i) { | ||
| 1538 | - m_edisp(m_inx_matrix, i) = *ptr++; | ||
| 1539 | - } | ||
| 1540 | - } | ||
| 1541 | - | ||
| 1542 | - } // endfor: looped over all offset angles | ||
| 1543 | - | ||
| 1544 | - // Return | ||
| 1545 | - return; | ||
| 1546 | -} | ||
| 1547 | - | ||
| 1548 | - | ||
| 1549 | -/***********************************************************************//** | ||
| 1550 | - * @brief Smooth energy dispersion table | ||
| 1551 | - * | ||
| 1552 | - * @param[in] sigma Smoothing width (number of bins in true energy) | ||
| 1553 | - * | ||
| 1554 | - * Smooth the energy dispersion table in true energy. The smoothing is done | ||
| 1555 | - * using a fast-fourrier transform. For this purpose the energy disperison | ||
| 1556 | - * table for each offset angle is copied into a 2D array, padded with some | ||
| 1557 | - * zero pixels on the left and the right to avoid wrap around. | ||
| 1558 | - ***************************************************************************/ | ||
| 1559 | -void GCTAEdisp2D::smooth_table2(const double& sigma_etrue, | ||
| 1560 | - const double& sigma_migra) | ||
| 1561 | -{ | ||
| 1562 | - // Get axes dimensions | ||
| 1563 | - int netrue = m_edisp.axis_bins(m_inx_etrue); | ||
| 1564 | - int nmigra = m_edisp.axis_bins(m_inx_migra); | ||
| 1565 | - int ntheta = m_edisp.axis_bins(m_inx_theta); | ||
| 1566 | - int netrue_pad = int(3.0*sigma_etrue); | ||
| 1567 | - int netrue_padded = netrue + 2*netrue_pad; // Array padded with zeros | ||
| 1568 | - int npix = netrue * nmigra; | ||
| 1569 | - | ||
| 1570 | - // Get smoothing kernel | ||
| 1571 | - GFft fft_kernel = fft_smooth_kernel2(netrue_padded, nmigra, sigma_etrue, sigma_migra); | ||
| 1572 | - | ||
| 1573 | - // Loop over all offset angles | ||
| 1574 | - for (int itheta = 0; itheta < ntheta; ++itheta) { | ||
| 1575 | - | ||
| 1576 | - // Compute base index | ||
| 1577 | - int ibase = itheta * npix; | ||
| 1578 | - | ||
| 1579 | - // Extract matrix in GNdarray | ||
| 1580 | - GNdarray array(netrue_padded, nmigra); | ||
| 1581 | - for (int imigra = 0, i = ibase; imigra < nmigra; ++imigra) { | ||
| 1582 | - double* ptr = array.data() + imigra * netrue_padded + netrue_pad; | ||
| 1583 | - for (int ietrue = 0; ietrue < netrue; ++ietrue, ++i) { | ||
| 1584 | - *ptr++ = m_edisp(m_inx_matrix, i); | ||
| 1585 | - } | ||
| 1586 | - } | ||
| 1587 | - | ||
| 1588 | - // FFT of array | ||
| 1589 | - GFft fft_array(array); | ||
| 1590 | - | ||
| 1591 | - // Smooth array | ||
| 1592 | - GFft fft_smooth = fft_array * fft_kernel; | ||
| 1593 | - | ||
| 1594 | - // Backward transform array | ||
| 1595 | - GNdarray smooth = fft_smooth.backward(); | ||
| 1596 | - | ||
| 1597 | - // Put back array values in matrix | ||
| 1598 | - for (int imigra = 0, i = ibase; imigra < nmigra; ++imigra) { | ||
| 1599 | - double* ptr = smooth.data() + imigra * netrue_padded + netrue_pad; | ||
| 1600 | - for (int ietrue = 0; ietrue < netrue; ++ietrue, ++i) { | ||
| 1601 | - m_edisp(m_inx_matrix, i) = *ptr++; | ||
| 1602 | - } | ||
| 1603 | - } | ||
| 1604 | - | ||
| 1605 | - } // endfor: looped over all offset angles | ||
| 1606 | - | ||
| 1607 | - // Return | ||
| 1608 | - return; | ||
| 1609 | -} | ||
| 1610 | - | ||
| 1611 | - | ||
| 1612 | -/***********************************************************************//** | ||
| 1613 | - * @brief Get FFT of smoothing kernel | ||
| 1614 | - * | ||
| 1615 | - * @param[in] nbins Number of kernel bins. | ||
| 1616 | - * @param[in] sigma Gaussian kernel sigma in bins. | ||
| 1617 | - * @return FFT of smoothing kernel | ||
| 1618 | - * | ||
| 1619 | - * Returns the fast-fourrier transform of a Gaussian smoothing kernel. | ||
| 1620 | - ***************************************************************************/ | ||
| 1621 | -GFft GCTAEdisp2D::fft_smooth_kernel(const int& nbins, | ||
| 1622 | - const double& sigma) const | ||
| 1623 | -{ | ||
| 1624 | - // Allocate kernel | ||
| 1625 | - GNdarray kernel(nbins); | ||
| 1626 | - | ||
| 1627 | - // Initialise sum and compute Gaussian normalisation | ||
| 1628 | - double sum = 0.0; | ||
| 1629 | - double norm = -0.5 / (sigma * sigma); | ||
| 1630 | - | ||
| 1631 | - // Set Gaussian kernel | ||
| 1632 | - for (int i = 0; i < nbins; ++i) { | ||
| 1633 | - double value = std::exp(norm*double(i*i)); | ||
| 1634 | - kernel(i) += value; | ||
| 1635 | - sum += value; | ||
| 1636 | - if (i > 0) { | ||
| 1637 | - kernel(nbins-i) += value; | ||
| 1638 | - sum += value; | ||
| 1639 | - } | ||
| 1640 | - } | ||
| 1641 | - | ||
| 1642 | - // Normalize kernel | ||
| 1643 | - if (sum > 0.0) { | ||
| 1644 | - for (int i = 0; i < nbins; ++i) { | ||
| 1645 | - kernel(i) /= sum; | ||
| 1646 | - } | ||
| 1647 | - } | ||
| 1648 | - | ||
| 1649 | - // Return FFT of kernel | ||
| 1650 | - return (GFft(kernel)); | ||
| 1651 | -} | ||
| 1652 | - | ||
| 1653 | - | ||
| 1654 | -/***********************************************************************//** | ||
| 1655 | - * @brief Get FFT of smoothing kernel for true energy smoothing | ||
| 1656 | - * | ||
| 1657 | - * @param[in] netrue Number of true energy bins. | ||
| 1658 | - * @param[in] nmigra Number of migration bins bins. | ||
| 1659 | - * @param[in] sigma Gaussian kernel sigma in true energy direction. | ||
| 1660 | - * @return FFT of smoothing kernel | ||
| 1661 | - * | ||
| 1662 | - * Returns the fast-fourrier transform of a Gaussian smoothing kernel in | ||
| 1663 | - * true energy. | ||
| 1664 | - ***************************************************************************/ | ||
| 1665 | -GFft GCTAEdisp2D::fft_smooth_kernel(const int& netrue, | ||
| 1666 | - const int& nmigra, | ||
| 1667 | - const double& sigma) const | ||
| 1668 | -{ | ||
| 1669 | - // Allocate kernel | ||
| 1670 | - GNdarray kernel(netrue, nmigra); | ||
| 1671 | - | ||
| 1672 | - // Initialise sum and compute Gaussian normalisation | ||
| 1673 | - double sum = 0.0; | ||
| 1674 | - double norm = -0.5 / (sigma * sigma); | ||
| 1675 | - | ||
| 1676 | - // Set Gaussian kernel | ||
| 1677 | - for (int i = 0; i < netrue; ++i) { | ||
| 1678 | - double value = std::exp(norm*double(i*i)); | ||
| 1679 | - kernel(i,0) += value; | ||
| 1680 | - sum += value; | ||
| 1681 | - if (i > 0) { | ||
| 1682 | - kernel(netrue-i,0) += value; | ||
| 1683 | - sum += value; | ||
| 1684 | - } | ||
| 1685 | - } | ||
| 1686 | - | ||
| 1687 | - // Normalize kernel | ||
| 1688 | - if (sum > 0.0) { | ||
| 1689 | - for (int i = 0; i < netrue; ++i) { | ||
| 1690 | - kernel(i,0) /= sum; | ||
| 1691 | - } | ||
| 1692 | - } | ||
| 1693 | - | ||
| 1694 | - // Return FFT of kernel | ||
| 1695 | - return (GFft(kernel)); | ||
| 1696 | -} | ||
| 1697 | - | ||
| 1698 | - | ||
| 1699 | -/***********************************************************************//** | ||
| 1700 | - * @brief Get FFT of smoothing kernel for 2D smoothing | ||
| 1701 | - * | ||
| 1702 | - * @param[in] netrue Number of true energy bins. | ||
| 1703 | - * @param[in] nmigra Number of migration bins bins. | ||
| 1704 | - * @param[in] sigma_etrue Gaussian kernel sigma in true energy direction. | ||
| 1705 | - * @param[in] sigma_migra Gaussian kernel sigma in migration direction. | ||
| 1706 | - * @return FFT of smoothing kernel | ||
| 1707 | - * | ||
| 1708 | - * Returns the fast-fourrier transform of a Gaussian smoothing kernel in | ||
| 1709 | - * true energy and migration. | ||
| 1710 | - ***************************************************************************/ | ||
| 1711 | -GFft GCTAEdisp2D::fft_smooth_kernel2(const int& netrue, | ||
| 1712 | - const int& nmigra, | ||
| 1713 | - const double& sigma_etrue, | ||
| 1714 | - const double& sigma_migra) const | ||
| 1715 | -{ | ||
| 1716 | - // Allocate kernel | ||
| 1717 | - GNdarray kernel(netrue, nmigra); | ||
| 1718 | - | ||
| 1719 | - // Initialise sum and compute Gaussian normalisation | ||
| 1720 | - double sum = 0.0; | ||
| 1721 | - double norm_etrue = -0.5 / (sigma_etrue * sigma_etrue); | ||
| 1722 | - double norm_migra = -0.5 / (sigma_migra * sigma_migra); | ||
| 1723 | - | ||
| 1724 | - // Set Gaussian kernel | ||
| 1725 | - for (int itrue = 0; itrue < netrue; ++itrue) { | ||
| 1726 | - double value_true = std::exp(norm_etrue*double(itrue*itrue)); | ||
| 1727 | - for (int imigra = 0; imigra < nmigra; ++imigra) { | ||
| 1728 | - double value = std::exp(norm_migra*double(imigra*imigra)) * value_true; | ||
| 1729 | - kernel(itrue,imigra) += value; | ||
| 1730 | - sum += value; | ||
| 1731 | - if (itrue > 0) { | ||
| 1732 | - kernel(netrue-itrue,imigra) += value; | ||
| 1733 | - sum += value; | ||
| 1734 | - } | ||
| 1735 | - if (imigra > 0) { | ||
| 1736 | - kernel(itrue,nmigra-imigra) += value; | ||
| 1737 | - sum += value; | ||
| 1738 | - } | ||
| 1739 | - if ((itrue > 0) && (imigra > 0)) { | ||
| 1740 | - kernel(netrue-itrue,nmigra-imigra) += value; | ||
| 1741 | - sum += value; | ||
| 1742 | - } | ||
| 1743 | - } | ||
| 1744 | - } | ||
| 1745 | - | ||
| 1746 | - // Normalize kernel | ||
| 1747 | - if (sum > 0.0) { | ||
| 1748 | - for (int itrue = 0; itrue < netrue; ++itrue) { | ||
| 1749 | - for (int imigra = 0; imigra < nmigra; ++imigra) { | ||
| 1750 | - kernel(itrue,imigra) /= sum; | ||
| 1751 | - } | ||
| 1752 | - } | ||
| 1753 | - } | ||
| 1754 | - | ||
| 1755 | - // Return FFT of kernel | ||
| 1756 | - return (GFft(kernel)); | ||
| 1757 | -} | ||
| 1758 | - | ||
| 1759 | - | ||
| 1760 | -/***********************************************************************//** | ||
| 1761 | * @brief Clip energy dispersion table | 1482 | * @brief Clip energy dispersion table |
| 1762 | * | 1483 | * |
| 1763 | - * @param[in] threshold Clipping threshold in fraction of maximum value. | 1484 | + * @param[in] threshold Clipping threshold as fraction of maximum value. |
| 1764 | * | 1485 | * |
| 1765 | * Clips all migration vectors at a threshold that is a fraction of the | 1486 | * Clips all migration vectors at a threshold that is a fraction of the |
| 1766 | * maximum value in the migration vector. | 1487 | * maximum value in the migration vector. |
| @@ -1808,58 +1529,19 @@ void GCTAEdisp2D::clip_table(const double& threshold) | @@ -1808,58 +1529,19 @@ void GCTAEdisp2D::clip_table(const double& threshold) | ||
| 1808 | 1529 | ||
| 1809 | 1530 | ||
| 1810 | /***********************************************************************//** | 1531 | /***********************************************************************//** |
| 1811 | - * @brief Clip array | ||
| 1812 | - * | ||
| 1813 | - * @param[in] array Ndarray that should be clipped. | ||
| 1814 | - * @param[in] threshold Clipping threshold in fraction of maximum value. | ||
| 1815 | - * @return Clipped Ndarray | ||
| 1816 | - * | ||
| 1817 | - * Clips all values below a threshold to zero. | ||
| 1818 | - ***************************************************************************/ | ||
| 1819 | -/* | ||
| 1820 | -GNdarray GCTAEdisp2D::clip_array(const GNdarray& array, | ||
| 1821 | - const double& threshold) const | ||
| 1822 | -{ | ||
| 1823 | - // Set clipped array | ||
| 1824 | - GNdarray clipped = array; | ||
| 1825 | - | ||
| 1826 | - // Initialise variables | ||
| 1827 | - int nsize = clipped.size(); | ||
| 1828 | - | ||
| 1829 | - // Determine maximum value in array | ||
| 1830 | - double max = 0.0; | ||
| 1831 | - double* cptr = clipped.data(); | ||
| 1832 | - for (int i = 0; i < nsize; ++i, cptr++) { | ||
| 1833 | - if (*cptr > max) { | ||
| 1834 | - max = *cptr; | ||
| 1835 | - } | ||
| 1836 | - } | ||
| 1837 | - | ||
| 1838 | - // Clip values below threshold | ||
| 1839 | - double clip_value = max * threshold; | ||
| 1840 | - cptr = clipped.data(); | ||
| 1841 | - for (int i = 0; i < nsize; ++i, cptr++) { | ||
| 1842 | - if (std::abs(*cptr) < clip_value) { | ||
| 1843 | - *cptr = 0.0; | ||
| 1844 | - } | ||
| 1845 | - } | ||
| 1846 | - | ||
| 1847 | - // Return clipped array | ||
| 1848 | - return clipped; | ||
| 1849 | -} | ||
| 1850 | -*/ | ||
| 1851 | - | ||
| 1852 | - | ||
| 1853 | -/***********************************************************************//** | ||
| 1854 | * @brief Denoise energy dispersion table | 1532 | * @brief Denoise energy dispersion table |
| 1855 | * | 1533 | * |
| 1856 | - * Denoise the energy dispersion table by smoothing the energy dispersion | ||
| 1857 | - * for each offset angle and true energy using the smooth_array() method. | 1534 | + * @param[in] sigma Gaussian smoothing single in true energy. |
| 1535 | + * | ||
| 1536 | + * Denoise the energy dispersion table by replacing the energy dispersion | ||
| 1537 | + * for each offset angle and true energy by a Gaussian function. The mean | ||
| 1538 | + * and rms of the Gaussian is smoothed as function of true energy using a | ||
| 1539 | + * Gaussian smoothing kernel with a width of @p sigma pixels. | ||
| 1858 | * | 1540 | * |
| 1859 | * True energy values with no energy dispersion information are interpolated | 1541 | * True energy values with no energy dispersion information are interpolated |
| 1860 | * from neighbouring energy dispersion values. | 1542 | * from neighbouring energy dispersion values. |
| 1861 | ***************************************************************************/ | 1543 | ***************************************************************************/ |
| 1862 | -void GCTAEdisp2D::denoise_table(void) | 1544 | +void GCTAEdisp2D::denoise_table(const double& sigma) |
| 1863 | { | 1545 | { |
| 1864 | // Log entrance | 1546 | // Log entrance |
| 1865 | //std::cout << "GCTAEdisp2D::denoise_table in" << std::endl; | 1547 | //std::cout << "GCTAEdisp2D::denoise_table in" << std::endl; |
| @@ -1871,7 +1553,7 @@ void GCTAEdisp2D::denoise_table(void) | @@ -1871,7 +1553,7 @@ void GCTAEdisp2D::denoise_table(void) | ||
| 1871 | int npix = netrue * nmigra; | 1553 | int npix = netrue * nmigra; |
| 1872 | 1554 | ||
| 1873 | // Get Gaussian parameters for all offset angles and true energies | 1555 | // Get Gaussian parameters for all offset angles and true energies |
| 1874 | - GNdarray gpars = get_gaussian_pars(5.0); | 1556 | + GNdarray gpars = get_gaussian_pars(sigma); |
| 1875 | 1557 | ||
| 1876 | // Loop over all offset angles | 1558 | // Loop over all offset angles |
| 1877 | for (int itheta = 0; itheta < ntheta; ++itheta) { | 1559 | for (int itheta = 0; itheta < ntheta; ++itheta) { |
| @@ -1974,119 +1656,6 @@ void GCTAEdisp2D::denoise_table(void) | @@ -1974,119 +1656,6 @@ void GCTAEdisp2D::denoise_table(void) | ||
| 1974 | 1656 | ||
| 1975 | 1657 | ||
| 1976 | /***********************************************************************//** | 1658 | /***********************************************************************//** |
| 1977 | - * @brief Smooth array | ||
| 1978 | - * | ||
| 1979 | - * @param[in] array Energy dispersion array. | ||
| 1980 | - * @param[in] mean Mean of Gaussian. | ||
| 1981 | - * @param[in] rms Root mean square of Gaussian. | ||
| 1982 | - * @return Smoothed energy dispersion array. | ||
| 1983 | - ***************************************************************************/ | ||
| 1984 | -GNdarray GCTAEdisp2D::smooth_array(const GNdarray& array, | ||
| 1985 | - const double& mean, | ||
| 1986 | - const double& rms) const | ||
| 1987 | -{ | ||
| 1988 | - // Get reference to migration values | ||
| 1989 | - const GNodeArray& migras = m_edisp.axis_nodes(m_inx_migra); | ||
| 1990 | - int nmigra = migras.size(); | ||
| 1991 | - | ||
| 1992 | - // Initialise empty smoothed array | ||
| 1993 | - GNdarray smoothed_array(nmigra); | ||
| 1994 | - | ||
| 1995 | - // Set required number of events and minimum and maximum sigma | ||
| 1996 | - double num_events = 200.0; // required number of events under Gaussian | ||
| 1997 | - double min_events = 2.0; // at least 2 events are required | ||
| 1998 | - double sigma_min = 1.0; // minimum sigma | ||
| 1999 | - double sigma_max = 0.1 * nmigra; // maximum sigma (< 20) | ||
| 2000 | - if (sigma_max > 20.0) { | ||
| 2001 | - sigma_max = 20.0; | ||
| 2002 | - } | ||
| 2003 | - | ||
| 2004 | - // Compute single event value | ||
| 2005 | - double event_value = get_single_event_value(array); | ||
| 2006 | - | ||
| 2007 | - // Continue only there are pixels with the requested minimum number of | ||
| 2008 | - // events (otherwise the returned vector will be zero) | ||
| 2009 | - if (max(array) >= min_events*event_value) { | ||
| 2010 | - | ||
| 2011 | - // Get Gaussian approximation | ||
| 2012 | - GNdarray gaussian = gaussian_array(mean, rms); | ||
| 2013 | - | ||
| 2014 | - // Get residual by subtracting Gaussian from array | ||
| 2015 | - GNdarray residual = array - gaussian; | ||
| 2016 | - | ||
| 2017 | - // Initialise smoothed residual | ||
| 2018 | - GNdarray smoothed_residual(nmigra); | ||
| 2019 | - | ||
| 2020 | - // Loop over all migration pixels | ||
| 2021 | - for (int imigra = 0; imigra < nmigra; ++imigra) { | ||
| 2022 | - | ||
| 2023 | - // Get pixel value | ||
| 2024 | - double value = array(imigra); | ||
| 2025 | - | ||
| 2026 | - // Fall through if pixel value is empty | ||
| 2027 | - if (value == 0.0) { | ||
| 2028 | - continue; | ||
| 2029 | - } | ||
| 2030 | - | ||
| 2031 | - // Set Gaussian sigma. Make sure that sigma is within the allowed | ||
| 2032 | - // range | ||
| 2033 | - double sigma = num_events * event_value / value; | ||
| 2034 | - if (sigma < sigma_min) { | ||
| 2035 | - sigma = sigma_min; | ||
| 2036 | - } | ||
| 2037 | - else if (sigma > sigma_max) { | ||
| 2038 | - sigma = sigma_max; | ||
| 2039 | - } | ||
| 2040 | - | ||
| 2041 | - // Convolve residual with a Gaussian function | ||
| 2042 | - double total = 0.0; | ||
| 2043 | - double norm = -0.5 / (sigma * sigma); | ||
| 2044 | - GNdarray work(nmigra); | ||
| 2045 | - for (int k = 0; k < nmigra; ++k) { | ||
| 2046 | - double weight = std::exp(norm*k*k); | ||
| 2047 | - if (weight > 1.0e-30) { | ||
| 2048 | - if (k == 0) { | ||
| 2049 | - work(imigra) = weight; | ||
| 2050 | - total += weight; | ||
| 2051 | - } | ||
| 2052 | - else { | ||
| 2053 | - int ileft = imigra - k; | ||
| 2054 | - if (ileft >= 0) { | ||
| 2055 | - work(ileft) = weight; | ||
| 2056 | - total += weight; | ||
| 2057 | - } | ||
| 2058 | - int iright = imigra + k; | ||
| 2059 | - if (iright < nmigra) { | ||
| 2060 | - work(iright) = weight; | ||
| 2061 | - total += weight; | ||
| 2062 | - } | ||
| 2063 | - } | ||
| 2064 | - } | ||
| 2065 | - } | ||
| 2066 | - if (total > 0.0) { | ||
| 2067 | - smoothed_residual += work * residual(imigra) / total; | ||
| 2068 | - } | ||
| 2069 | - | ||
| 2070 | - } // endfor: looped over all migration pixels | ||
| 2071 | - | ||
| 2072 | - // Set smoothed array | ||
| 2073 | - smoothed_array = gaussian; // + smoothed_residual; | ||
| 2074 | - | ||
| 2075 | - // Make sure that smooth array is not negative | ||
| 2076 | - for (int imigra = 0; imigra < nmigra; ++imigra) { | ||
| 2077 | - if (smoothed_array(imigra) < 0.0) { | ||
| 2078 | - smoothed_array(imigra) = 0.0; | ||
| 2079 | - } | ||
| 2080 | - } | ||
| 2081 | - | ||
| 2082 | - } // endif: single event value was positive | ||
| 2083 | - | ||
| 2084 | - // Return smoothed array | ||
| 2085 | - return smoothed_array; | ||
| 2086 | -} | ||
| 2087 | - | ||
| 2088 | - | ||
| 2089 | -/***********************************************************************//** | ||
| 2090 | * @brief Return Gaussian approximation of energy dispersion array | 1659 | * @brief Return Gaussian approximation of energy dispersion array |
| 2091 | * | 1660 | * |
| 2092 | * @param[in] mean Gaussian mean. | 1661 | * @param[in] mean Gaussian mean. |
| @@ -2105,13 +1674,6 @@ GNdarray GCTAEdisp2D::gaussian_array(const double& mean, const double& rms) cons | @@ -2105,13 +1674,6 @@ GNdarray GCTAEdisp2D::gaussian_array(const double& mean, const double& rms) cons | ||
| 2105 | int nmigra = m_edisp.axis_bins(m_inx_migra); | 1674 | int nmigra = m_edisp.axis_bins(m_inx_migra); |
| 2106 | GNdarray gaussian(nmigra); | 1675 | GNdarray gaussian(nmigra); |
| 2107 | 1676 | ||
| 2108 | - // Get mean and rms of migration values in array | ||
| 2109 | - /* | ||
| 2110 | - double mean = 0.0; | ||
| 2111 | - double rms = 0.0; | ||
| 2112 | - get_mean_rms(array, &mean, &rms); | ||
| 2113 | - */ | ||
| 2114 | - | ||
| 2115 | // If the array contains information then compute a Gaussian | 1677 | // If the array contains information then compute a Gaussian |
| 2116 | // approximation | 1678 | // approximation |
| 2117 | if (rms > 0.0) { | 1679 | if (rms > 0.0) { |
| @@ -2257,6 +1819,48 @@ GNdarray GCTAEdisp2D::get_gaussian_pars(const double& sigma) const | @@ -2257,6 +1819,48 @@ GNdarray GCTAEdisp2D::get_gaussian_pars(const double& sigma) const | ||
| 2257 | 1819 | ||
| 2258 | 1820 | ||
| 2259 | /***********************************************************************//** | 1821 | /***********************************************************************//** |
| 1822 | + * @brief Get FFT of smoothing kernel | ||
| 1823 | + * | ||
| 1824 | + * @param[in] nbins Number of kernel bins. | ||
| 1825 | + * @param[in] sigma Gaussian kernel sigma in bins. | ||
| 1826 | + * @return FFT of smoothing kernel | ||
| 1827 | + * | ||
| 1828 | + * Returns the fast-fourrier transform of a Gaussian smoothing kernel. | ||
| 1829 | + ***************************************************************************/ | ||
| 1830 | +GFft GCTAEdisp2D::fft_smooth_kernel(const int& nbins, | ||
| 1831 | + const double& sigma) const | ||
| 1832 | +{ | ||
| 1833 | + // Allocate kernel | ||
| 1834 | + GNdarray kernel(nbins); | ||
| 1835 | + | ||
| 1836 | + // Initialise sum and compute Gaussian normalisation | ||
| 1837 | + double sum = 0.0; | ||
| 1838 | + double norm = -0.5 / (sigma * sigma); | ||
| 1839 | + | ||
| 1840 | + // Set Gaussian kernel | ||
| 1841 | + for (int i = 0; i < nbins; ++i) { | ||
| 1842 | + double value = std::exp(norm*double(i*i)); | ||
| 1843 | + kernel(i) += value; | ||
| 1844 | + sum += value; | ||
| 1845 | + if (i > 0) { | ||
| 1846 | + kernel(nbins-i) += value; | ||
| 1847 | + sum += value; | ||
| 1848 | + } | ||
| 1849 | + } | ||
| 1850 | + | ||
| 1851 | + // Normalize kernel | ||
| 1852 | + if (sum > 0.0) { | ||
| 1853 | + for (int i = 0; i < nbins; ++i) { | ||
| 1854 | + kernel(i) /= sum; | ||
| 1855 | + } | ||
| 1856 | + } | ||
| 1857 | + | ||
| 1858 | + // Return FFT of kernel | ||
| 1859 | + return (GFft(kernel)); | ||
| 1860 | +} | ||
| 1861 | + | ||
| 1862 | + | ||
| 1863 | +/***********************************************************************//** | ||
| 2260 | * @brief Compute mean and root mean square of migration array | 1864 | * @brief Compute mean and root mean square of migration array |
| 2261 | * | 1865 | * |
| 2262 | * @param[in] array Energy dispersion array. | 1866 | * @param[in] array Energy dispersion array. |