Commit 2791cc64b148a2b43cd71d8795de405ba7f5ee27

Authored by Jürgen Knödlseder
1 parent e7137bed

Implement iterative adjustment of energy-dependent activation rate (#4209)

inst/com/include/GCOMDris.hpp
... ... @@ -83,7 +83,7 @@ public:
83 83 const GCOMSelection& select = GCOMSelection(),
84 84 const double& zetamin = 5.0,
85 85 const double& timebin = 300.0,
86   - const std::string& method = "vetorate");
  86 + const std::string& method = "phibar");
87 87 std::string print(const GChatter& chatter = NORMAL) const;
88 88  
89 89 // Likelihood function
... ... @@ -101,13 +101,13 @@ public:
101 101 protected:
102 102 int m_ieng; //!< DRW energy bin
103 103 double m_norm; //!< Normalisation value
104   - int m_noads; //!< Number of superpackets
  104 + int m_nsp; //!< Number of superpackets
105 105 int m_nphibar; //!< Number of phibar layers
106 106 GNdarray m_vetorate; //!< Vetorate array multiplied by EHA cut correction
107   - GNdarray m_constrate; //!< Constant rate array multiplied by EHA cut correction
108   - GNdarray m_diffrate; //!< Vetorate - Constant rate array
  107 + GNdarray m_activrate; //!< Activation rate array multiplied by EHA cut correction
  108 + GNdarray m_diffrate; //!< Vetorate - activation rate array
109 109 GNdarray m_vetorate_sum; //!< Time integrated vetorate array
110   - GNdarray m_constrate_sum; //!< Time integrated constant rate array
  110 + GNdarray m_activrate_sum; //!< Time integrated activation rate array
111 111 GNdarray m_diffrate_sum; //!< Time integrated difference rate array
112 112 double m_value; //!< Function value
113 113 GVector m_gradient; //!< Gradient vector
... ... @@ -139,9 +139,11 @@ protected:
139 139 const GCOMSelection& select,
140 140 const double& zetamin);
141 141 void vetorate_fit(void);
  142 + void vetorate_update_activ(void);
142 143 void vetorate_generate(const GCOMObservation& obs,
143 144 const GCOMSelection& select,
144 145 const double& zetamin);
  146 + void vetorate_finish(const GCOMObservation& obs);
145 147 void vetorate_save(const GFilename& filename) const;
146 148 void vetorate_load(const GFilename& filename);
147 149  
... ... @@ -152,7 +154,7 @@ protected:
152 154 GNdarray m_wrk_counts; //!< 3D event cube array
153 155 GNdarray m_wrk_ehacutcorr; //!< 2D geometry response array
154 156 GNdarray m_wrk_vetorate; //!< 1D vetorates array
155   - GNdarray m_wrk_constrate; //!< 1D constant rate array
  157 + GNdarray m_wrk_activrate; //!< 2D activation rate array
156 158 GNdarray m_wrk_rate; //!< 2D rate array
157 159 std::vector<bool> m_wrk_use_sp; //!< 1D superpacket usage array
158 160 };
... ...
inst/com/src/GCOMDris.cpp
... ... @@ -35,9 +35,12 @@
35 35 #include "GFits.hpp"
36 36 #include "GFitsImageDouble.hpp"
37 37 #include "GFitsImageShort.hpp"
  38 +#include "GFitsTableLongCol.hpp"
  39 +#include "GFitsTableDoubleCol.hpp"
38 40 #include "GOptimizerPars.hpp"
39 41 #include "GOptimizerPar.hpp"
40 42 #include "GOptimizerLM.hpp"
  43 +#include "GFft.hpp"
41 44 #include "GCOMTools.hpp"
42 45 #include "GCOMSupport.hpp"
43 46 #include "GCOMDri.hpp"
... ... @@ -64,8 +67,8 @@
64 67 #define G_COMPUTE_DRWS_EHACORR //!< Correct Earth horizon cut
65 68  
66 69 /* __ Debug definitions __________________________________________________ */
67   -#define G_DEBUG_COMPUTE_DRWS
68   -#define G_DEBUG_SAVE_WORKING_ARRAYS
  70 +//#define G_DEBUG_COMPUTE_DRWS
  71 +//#define G_DEBUG_SAVE_WORKING_ARRAYS
69 72  
70 73 /* __ Constants __________________________________________________________ */
71 74  
... ... @@ -531,7 +534,7 @@ void GCOMDris::init_members(void)
531 534 m_wrk_counts.clear();
532 535 m_wrk_ehacutcorr.clear();
533 536 m_wrk_vetorate.clear();
534   - m_wrk_constrate.clear();
  537 + m_wrk_activrate.clear();
535 538 m_wrk_rate.clear();
536 539 m_wrk_use_sp.clear();
537 540  
... ... @@ -554,7 +557,7 @@ void GCOMDris::copy_members(const GCOMDris&amp; dris)
554 557 m_wrk_counts = dris.m_wrk_counts;
555 558 m_wrk_ehacutcorr = dris.m_wrk_ehacutcorr;
556 559 m_wrk_vetorate = dris.m_wrk_vetorate;
557   - m_wrk_constrate = dris.m_wrk_constrate;
  560 + m_wrk_activrate = dris.m_wrk_activrate;
558 561 m_wrk_rate = dris.m_wrk_rate;
559 562 m_wrk_use_sp = dris.m_wrk_use_sp;
560 563  
... ... @@ -1264,12 +1267,24 @@ void GCOMDris::compute_drws_vetorate(const GCOMObservation&amp; obs,
1264 1267 vetorate_load("debug_gcomdris_compute_drws_vetorate.fits");
1265 1268 #endif
1266 1269  
  1270 + // Initialise fprompt for all energies
  1271 + for (int i = 0; i < size(); ++i) {
  1272 + m_dris[i].m_drw_fprompt = 0.5; //!< Initial fprompt value
  1273 + }
  1274 +
1267 1275 // Fit working arrays to determine f_prompt parameter
1268 1276 vetorate_fit();
  1277 + for (int iter = 0; iter < 4; ++iter) { //!< Perform 4 iterations
  1278 + vetorate_update_activ();
  1279 + vetorate_fit();
  1280 + }
1269 1281  
1270 1282 // Generate DRWs
1271 1283 vetorate_generate(obs, select, zetamin);
1272 1284  
  1285 + // Finish DRWs
  1286 + vetorate_finish(obs);
  1287 +
1273 1288 // Return
1274 1289 return;
1275 1290 }
... ... @@ -1283,7 +1298,7 @@ void GCOMDris::compute_drws_vetorate(const GCOMObservation&amp; obs,
1283 1298 * @param[in] select Selection set.
1284 1299 * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
1285 1300 *
1286   - * Setup working arrays for vetorate DRW computation. There are four working
  1301 + * Setup working arrays for vetorate DRW computation. There are five working
1287 1302 * arrays:
1288 1303 *
1289 1304 * @c m_wrk_counts is a 3D working array spanned by superpacket index,
... ... @@ -1298,6 +1313,9 @@ void GCOMDris::compute_drws_vetorate(const GCOMObservation&amp; obs,
1298 1313 * @c m_wrk_vetorate is a 1D working array, containing the veto rate as
1299 1314 * function of superpacket index.
1300 1315 *
  1316 + * @c m_wrk_activrate is a 2D working array, containing the activation rate
  1317 + * as function of superpacket index and energy range.
  1318 + *
1301 1319 * @c m_wrk_use_sp is a 1D working array, signalling the usage of a given
1302 1320 * superpacket.
1303 1321 *
... ... @@ -1329,7 +1347,7 @@ void GCOMDris::vetorate_setup(const GCOMObservation&amp; obs,
1329 1347  
1330 1348 // Debug
1331 1349 #if defined(G_DEBUG_COMPUTE_DRWS)
1332   - std::cout << "Number of superpackets: " << noads << std::endl;
  1350 + std::cout << "Number of OAD superpackets: " << noads << std::endl;
1333 1351 std::cout << "Number of pixels: " << npix << std::endl;
1334 1352 std::cout << "Number of Phibar layers: " << nphibar << std::endl;
1335 1353 std::cout << "Number of energies: " << neng << std::endl;
... ... @@ -1339,8 +1357,14 @@ void GCOMDris::vetorate_setup(const GCOMObservation&amp; obs,
1339 1357 m_wrk_counts = GNdarray(noads, nphibar, neng);
1340 1358 m_wrk_ehacutcorr = GNdarray(noads, nphibar);
1341 1359 m_wrk_vetorate = GNdarray(noads);
  1360 + m_wrk_activrate = GNdarray(noads, neng);
1342 1361 m_wrk_use_sp = std::vector<bool>(noads);
1343 1362  
  1363 + // Initialise superpacket usage array
  1364 + for (int i_oad = 0; i_oad < noads; ++i_oad) {
  1365 + m_wrk_use_sp[i_oad] = false;
  1366 + }
  1367 +
1344 1368 // Allocate further working arrays
1345 1369 GNdarray geo(npix);
1346 1370 GNdarray eha(npix);
... ... @@ -1384,8 +1408,9 @@ void GCOMDris::vetorate_setup(const GCOMObservation&amp; obs,
1384 1408 tim.reduce(select.pulsar().validity());
1385 1409 }
1386 1410  
1387   - // Initialise event counter
  1411 + // Initialise event and superpacket counters
1388 1412 int i_evt = 0;
  1413 + int i_sp = 0;
1389 1414  
1390 1415 // Signal that loop should be terminated
1391 1416 bool terminate = false;
... ... @@ -1398,10 +1423,9 @@ void GCOMDris::vetorate_setup(const GCOMObservation&amp; obs,
1398 1423  
1399 1424 // Check superpacket usage for all DRWs so that their statistics
1400 1425 // get correctly updated
1401   - m_wrk_use_sp[i_oad] = true;
1402 1426 for (int i = 0; i < size(); ++i) {
1403   - if (!m_dris[i].use_superpacket(oad, tim, select)) {
1404   - m_wrk_use_sp[i_oad] = false;
  1427 + if (m_dris[i].use_superpacket(oad, tim, select)) {
  1428 + m_wrk_use_sp[i_oad] = true;
1405 1429 }
1406 1430 }
1407 1431 if (!m_wrk_use_sp[i_oad]) {
... ... @@ -1459,15 +1483,20 @@ void GCOMDris::vetorate_setup(const GCOMObservation&amp; obs,
1459 1483 accepted_geo += geo(index);
1460 1484 }
1461 1485 }
1462   - m_wrk_ehacutcorr(i_oad, iphibar) = accepted_geo / total_geo;
  1486 + m_wrk_ehacutcorr(i_sp, iphibar) = accepted_geo / total_geo;
1463 1487 }
1464 1488 }
1465 1489  
1466   - // Compute veto rate for superpacket time if rates are available
  1490 + // Compute veto rate and activation rates for superpacket time if rates
  1491 + // are available. The activation rates are initialised with a constant
  1492 + // rate.
1467 1493 if (!veto_times.is_empty()) {
1468 1494 double value = veto_times.interpolate(time, veto_rates);
1469 1495 if (value > 0.0) {
1470   - m_wrk_vetorate(i_oad) = value;
  1496 + m_wrk_vetorate(i_sp) = value;
  1497 + for (int ieng = 0; ieng < neng; ++ieng) {
  1498 + m_wrk_activrate(i_sp, ieng) = 1.0;
  1499 + }
1471 1500 }
1472 1501 }
1473 1502  
... ... @@ -1544,19 +1573,23 @@ void GCOMDris::vetorate_setup(const GCOMObservation&amp; obs,
1544 1573 }
1545 1574  
1546 1575 // Now fill the event in the 3D counts array
1547   - m_wrk_counts(i_oad, iphibar, ienergy) += 1.0;
  1576 + m_wrk_counts(i_sp, iphibar, ienergy) += 1.0;
1548 1577  
1549 1578 } // endfor: collected events
1550 1579  
1551 1580 // Debug
1552 1581 #if defined(G_DEBUG_COMPUTE_DRWS)
1553 1582 std::cout << "Superpacket " << i_oad;
  1583 + std::cout << " i_sp=" << i_sp;
1554 1584 std::cout << " time=" << time;
1555 1585 std::cout << " vetorate=" << m_wrk_vetorate(i_oad);
1556 1586 std::cout << " total_geo=" << total_geo;
1557 1587 std::cout << std::endl;
1558 1588 #endif
1559 1589  
  1590 + // Increment superpacket counter
  1591 + i_sp++;
  1592 +
1560 1593 // Break Orbit Aspect Data loop if termination was signalled or if there
1561 1594 // are no more events
1562 1595 if (terminate || i_evt >= events->size()) {
... ... @@ -1565,6 +1598,28 @@ void GCOMDris::vetorate_setup(const GCOMObservation&amp; obs,
1565 1598  
1566 1599 } // endfor: looped over Orbit Aspect Data
1567 1600  
  1601 + // Copy results in shortened Ndarrays
  1602 + GNdarray wrk_counts(i_sp, nphibar, neng);
  1603 + GNdarray wrk_ehacutcorr(i_sp, nphibar);
  1604 + GNdarray wrk_vetorate(i_sp);
  1605 + GNdarray wrk_activrate(i_sp, neng);
  1606 + for (int i = 0; i < i_sp; ++i) {
  1607 + for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
  1608 + for (int ieng = 0; ieng < neng; ++ieng) {
  1609 + wrk_counts(i, iphibar, ieng) = m_wrk_counts(i, iphibar, ieng);
  1610 + }
  1611 + wrk_ehacutcorr(i, iphibar) = m_wrk_ehacutcorr(i, iphibar);
  1612 + }
  1613 + for (int ieng = 0; ieng < neng; ++ieng) {
  1614 + wrk_activrate(i, ieng) = m_wrk_activrate(i, ieng);
  1615 + }
  1616 + wrk_vetorate(i) = m_wrk_vetorate(i);
  1617 + }
  1618 + m_wrk_counts = wrk_counts;
  1619 + m_wrk_ehacutcorr = wrk_ehacutcorr;
  1620 + m_wrk_vetorate = wrk_vetorate;
  1621 + m_wrk_activrate = wrk_activrate;
  1622 +
1568 1623 // Return
1569 1624 return;
1570 1625 }
... ... @@ -1581,8 +1636,7 @@ void GCOMDris::vetorate_setup(const GCOMObservation&amp; obs,
1581 1636 void GCOMDris::vetorate_fit(void)
1582 1637 {
1583 1638 // Set constants
1584   - const double fprompt_init = 0.5; // Initial f_prompt value
1585   - const double norm = 1.0; // Model normalisation
  1639 + const double norm = 1.0; // Model normalisation
1586 1640  
1587 1641 // Debug
1588 1642 #if defined(G_DEBUG_COMPUTE_DRWS)
... ... @@ -1591,39 +1645,45 @@ void GCOMDris::vetorate_fit(void)
1591 1645 #endif
1592 1646  
1593 1647 // Extract dimension from working arrays
1594   - int noads = m_wrk_counts.shape()[0];
  1648 + int nsp = m_wrk_counts.shape()[0];
1595 1649 int nphibar = m_wrk_counts.shape()[1];
1596 1650 int neng = m_wrk_counts.shape()[2];
1597 1651  
1598 1652 // Debug
1599 1653 #if defined(G_DEBUG_COMPUTE_DRWS)
1600   - std::cout << "Number of superpackets: " << noads << std::endl;
  1654 + std::cout << "Number of used superpackets: " << nsp << std::endl;
1601 1655 std::cout << "Number of Phibar layers: " << nphibar << std::endl;
1602 1656 std::cout << "Number of energies: " << neng << std::endl;
1603 1657 #endif
1604 1658  
1605 1659 // Setup rate result array
1606   - m_wrk_rate = GNdarray(noads, neng);
  1660 + m_wrk_rate = GNdarray(nsp, neng);
1607 1661  
1608   - // Setup normalised constant rate array and normalise veto rates
1609   - m_wrk_constrate = GNdarray(noads);
1610   - double nvetorate = 0.0;
1611   - double nconstrate = 0.0;
1612   - for (int ioad = 0; ioad < noads; ++ioad) {
1613   - if (m_wrk_vetorate(ioad) > 0.0) {
1614   - m_wrk_constrate(ioad) = 1.0;
1615   - nvetorate += m_wrk_vetorate(ioad);
1616   - nconstrate += m_wrk_constrate(ioad);
  1662 + // Normalise veto rates
  1663 + double nvetorate = 0.0;
  1664 + for (int isp = 0; isp < nsp; ++isp) {
  1665 + if (m_wrk_vetorate(isp) > 0.0) {
  1666 + nvetorate += m_wrk_vetorate(isp);
1617 1667 }
1618 1668 }
1619 1669 if (nvetorate > 0.0) {
1620   - for (int ioad = 0; ioad < noads; ++ioad) {
1621   - m_wrk_vetorate(ioad) /= nvetorate;
  1670 + for (int isp = 0; isp < nsp; ++isp) {
  1671 + m_wrk_vetorate(isp) /= nvetorate;
1622 1672 }
1623 1673 }
1624   - if (nconstrate > 0.0) {
1625   - for (int ioad = 0; ioad < noads; ++ioad) {
1626   - m_wrk_constrate(ioad) /= nconstrate;
  1674 +
  1675 + // Normalise activation rates
  1676 + for (int ieng = 0; ieng < neng; ++ieng) {
  1677 + double nactivrate = 0.0;
  1678 + for (int isp = 0; isp < nsp; ++isp) {
  1679 + if (m_wrk_activrate(isp, ieng) > 0.0) {
  1680 + nactivrate += m_wrk_activrate(isp, ieng);
  1681 + }
  1682 + }
  1683 + if (nactivrate > 0.0) {
  1684 + for (int isp = 0; isp < nsp; ++isp) {
  1685 + m_wrk_activrate(isp, ieng) /= nactivrate;
  1686 + }
1627 1687 }
1628 1688 }
1629 1689  
... ... @@ -1632,7 +1692,7 @@ void GCOMDris::vetorate_fit(void)
1632 1692  
1633 1693 // Set fprompt parameter
1634 1694 GOptimizerPars pars;
1635   - GOptimizerPar par("fprompt", fprompt_init);
  1695 + GOptimizerPar par("fprompt", m_dris[ieng].m_drw_fprompt);
1636 1696 par.range(0.0, 1.0);
1637 1697 par.factor_gradient(1.0); // To avoid zero gradient log message
1638 1698 pars.append(par);
... ... @@ -1659,15 +1719,15 @@ void GCOMDris::vetorate_fit(void)
1659 1719 // Recover fprompt parameter and errors
1660 1720 double fprompt = pars[0]->value();
1661 1721 double e_fprompt = pars[0]->error();
1662   - double fconst = 1.0 - fprompt;
  1722 + double factiv = 1.0 - fprompt;
1663 1723  
1664 1724 // Set resulting rate vector for this energy bin
1665   - for (int ioad = 0; ioad < noads; ++ioad) {
1666   - m_wrk_rate(ioad, ieng) = fprompt * m_wrk_vetorate(ioad) +
1667   - fconst * m_wrk_constrate(ioad);
  1725 + for (int isp = 0; isp < nsp; ++isp) {
  1726 + m_wrk_rate(isp, ieng) = fprompt * m_wrk_vetorate(isp) +
  1727 + factiv * m_wrk_activrate(isp, ieng);
1668 1728 }
1669 1729  
1670   - // Set DRW header parameters
  1730 + // Set DRW header members
1671 1731 m_dris[ieng].m_drw_status = opt.status_string();
1672 1732 m_dris[ieng].m_drw_fprompt = fprompt;
1673 1733 m_dris[ieng].m_drw_e_fprompt = e_fprompt;
... ... @@ -1689,6 +1749,136 @@ void GCOMDris::vetorate_fit(void)
1689 1749  
1690 1750  
1691 1751 /***********************************************************************//**
  1752 + * @brief Update activation rate
  1753 + ***************************************************************************/
  1754 +void GCOMDris::vetorate_update_activ(void)
  1755 +{
  1756 + // Set constants
  1757 + const double norm = 1.0; // Model normalisation
  1758 + const double t_hour = 1.0; // Smoothing duration (hours)
  1759 +
  1760 + // Debug
  1761 + #if defined(G_DEBUG_COMPUTE_DRWS)
  1762 + std::cout << "GCOMDris::vetorate_update_activ" << std::endl;
  1763 + std::cout << "===============================" << std::endl;
  1764 + #endif
  1765 +
  1766 + // Extract dimension from working arrays
  1767 + int nsp = m_wrk_counts.shape()[0];
  1768 + int nphibar = m_wrk_counts.shape()[1];
  1769 + int neng = m_wrk_counts.shape()[2];
  1770 +
  1771 + // Setup Gaussian smoothing kernel
  1772 + double nsmooth = 3600.0/16.384 * t_hour;
  1773 + double weight = -0.5 / (nsmooth * nsmooth);
  1774 + GNdarray kernel(nsp);
  1775 + double sum = 0.0;
  1776 + for (int isp = 0; isp < nsp/2; ++isp) {
  1777 + double kvalue = std::exp(weight*isp*isp);
  1778 + if (kvalue <= 0.0) {
  1779 + break;
  1780 + }
  1781 + kernel(isp) = kvalue;
  1782 + sum += kvalue;
  1783 + if (isp > 0) {
  1784 + kernel(nsp-isp) = kvalue;
  1785 + sum += kvalue;
  1786 + }
  1787 + }
  1788 + if (sum > 0.0) {
  1789 + for (int isp = 0; isp < nsp; ++isp) {
  1790 + kernel(isp) /= sum;
  1791 + }
  1792 + }
  1793 + GFft fft_kernel(kernel);
  1794 +
  1795 + // Loop over energy bins
  1796 + for (int ieng = 0; ieng < neng; ++ieng) {
  1797 +
  1798 + // Compute model normalised to number of events for each Phibar
  1799 + GNdarray model(nsp, nphibar);
  1800 + GNdarray n(nphibar);
  1801 + for (int isp = 0; isp < nsp; ++isp) {
  1802 + for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
  1803 + model(isp, iphibar) = m_wrk_rate(isp, ieng) * m_wrk_ehacutcorr(isp, iphibar);
  1804 + }
  1805 + }
  1806 + for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
  1807 + double nevents = 0.0;
  1808 + double nmodel = 0.0;
  1809 + for (int isp = 0; isp < nsp; ++isp) {
  1810 + if (model(isp, iphibar) > 0.0) {
  1811 + nevents += m_wrk_counts(isp, iphibar, ieng);
  1812 + nmodel += model(isp, iphibar);
  1813 + }
  1814 + }
  1815 + if (nmodel > 0.0) {
  1816 + n(iphibar) = norm * (nevents / nmodel);
  1817 + for (int isp = 0; isp < nsp; ++isp) {
  1818 + model(isp, iphibar) *= n(iphibar);
  1819 + }
  1820 + }
  1821 + }
  1822 +
  1823 + // Compute residual and Earth horizon correction cut by summing over
  1824 + // all Phibar layers
  1825 + GNdarray residual(nsp);
  1826 + GNdarray ehacutcorr(nsp);
  1827 + for (int isp = 0; isp < nsp; ++isp) {
  1828 + for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
  1829 + residual(isp) += m_wrk_counts(isp, iphibar, ieng) - model(isp, iphibar);
  1830 + ehacutcorr(isp) += n(iphibar) * m_wrk_ehacutcorr(isp, iphibar);
  1831 + }
  1832 + }
  1833 +
  1834 + // Smooth residual
  1835 + GFft fft_residual(residual);
  1836 + fft_residual = fft_residual * fft_kernel;
  1837 + residual = fft_residual.backward();
  1838 +
  1839 + // Smooth ehacutcorr
  1840 + GFft fft_ehacutcorr(ehacutcorr);
  1841 + fft_ehacutcorr = fft_ehacutcorr * fft_kernel;
  1842 + ehacutcorr = fft_ehacutcorr.backward();
  1843 +
  1844 + // Derive indicent residual background rate
  1845 + for (int isp = 0; isp < nsp; ++isp) {
  1846 + if (ehacutcorr(isp) > 0.0) {
  1847 + residual(isp) /= ehacutcorr(isp);
  1848 + }
  1849 + }
  1850 +
  1851 + // Update activation rate
  1852 + for (int isp = 0; isp < nsp; ++isp) {
  1853 + double activ = m_wrk_activrate(isp, ieng);
  1854 + if (activ > 0.0) {
  1855 + double update = activ + residual(isp);
  1856 + if (update < 0.05 * activ) { //!< Cap reduction at 5%
  1857 + update = 0.05 * activ;
  1858 + }
  1859 + m_wrk_activrate(isp, ieng) = update;
  1860 + }
  1861 + }
  1862 +
  1863 + // Normalise activation rate
  1864 + double nactivrate = 0.0;
  1865 + for (int isp = 0; isp < nsp; ++isp) {
  1866 + nactivrate += m_wrk_activrate(isp, ieng);
  1867 + }
  1868 + if (nactivrate > 0.0) {
  1869 + for (int isp = 0; isp < nsp; ++isp) {
  1870 + m_wrk_activrate(isp, ieng) /= nactivrate;
  1871 + }
  1872 + }
  1873 +
  1874 + } // endfor: looped over all energy bins
  1875 +
  1876 + // Return
  1877 + return;
  1878 +}
  1879 +
  1880 +
  1881 +/***********************************************************************//**
1692 1882 * @brief Generate DRWs
1693 1883 *
1694 1884 * @param[in] obs COMPTEL observation.
... ... @@ -1719,7 +1909,7 @@ void GCOMDris::vetorate_generate(const GCOMObservation&amp; obs,
1719 1909  
1720 1910 // Debug
1721 1911 #if defined(G_DEBUG_COMPUTE_DRWS)
1722   - std::cout << "Number of superpackets: " << noads << std::endl;
  1912 + std::cout << "Number of OAD superpackets: " << noads << std::endl;
1723 1913 std::cout << "Number of pixels: " << npix << std::endl;
1724 1914 std::cout << "Number of Phibar layers: " << nphibar << std::endl;
1725 1915 std::cout << "Number of energies: " << neng << std::endl;
... ... @@ -1747,6 +1937,9 @@ void GCOMDris::vetorate_generate(const GCOMObservation&amp; obs,
1747 1937 tim.reduce(select.pulsar().validity());
1748 1938 }
1749 1939  
  1940 + // Initialise superpacket counter
  1941 + int i_sp = 0;
  1942 +
1750 1943 // Loop over Orbit Aspect Data
1751 1944 for (int i_oad = 0; i_oad < noads; ++i_oad) {
1752 1945  
... ... @@ -1814,7 +2007,7 @@ void GCOMDris::vetorate_generate(const GCOMObservation&amp; obs,
1814 2007 int inx = index + iphibar * npix;
1815 2008  
1816 2009 // Store geometry weighted with rate as DRW
1817   - m_dris[i][inx] += geometry(index) * m_wrk_rate(i_oad, i);
  2010 + m_dris[i][inx] += geometry(index) * m_wrk_rate(i_sp, i);
1818 2011  
1819 2012 } // endif: Earth horizon cut passed
1820 2013  
... ... @@ -1822,12 +2015,12 @@ void GCOMDris::vetorate_generate(const GCOMObservation&amp; obs,
1822 2015  
1823 2016 } // endfor: looped over Phibar
1824 2017  
  2018 + // Set binary table information
  2019 +
1825 2020 } // endfor: looped over all DRWs
1826 2021  
1827   - // Debug
1828   - #if defined(G_DEBUG_COMPUTE_DRWS)
1829   - std::cout << "Superpacket " << i_oad << std::endl;
1830   - #endif
  2022 + // Increment superpacket counter
  2023 + i_sp++;
1831 2024  
1832 2025 } // endfor: looped over Orbit Aspect Data
1833 2026  
... ... @@ -1837,6 +2030,93 @@ void GCOMDris::vetorate_generate(const GCOMObservation&amp; obs,
1837 2030  
1838 2031  
1839 2032 /***********************************************************************//**
  2033 + * @brief Finish DRWs
  2034 + *
  2035 + * @param[in] obs COMPTEL observation.
  2036 + *
  2037 + * Set DRW binary tables
  2038 + ***************************************************************************/
  2039 +void GCOMDris::vetorate_finish(const GCOMObservation& obs)
  2040 +{
  2041 + // Debug
  2042 + #if defined(G_DEBUG_COMPUTE_DRWS)
  2043 + std::cout << "GCOMDris::vetorate_finish" << std::endl;
  2044 + std::cout << "=========================" << std::endl;
  2045 + #endif
  2046 +
  2047 + // Extract dimensions
  2048 + int noads = obs.oads().size();
  2049 +
  2050 + // Compute number of to-be-used superpackets
  2051 + int nsp = 0;
  2052 + for (int i_oad = 0; i_oad < noads; ++i_oad) {
  2053 + if (m_wrk_use_sp[i_oad]) {
  2054 + nsp++;
  2055 + }
  2056 + }
  2057 +
  2058 + // Debug
  2059 + #if defined(G_DEBUG_COMPUTE_DRWS)
  2060 + std::cout << "Number of OAD superpackets: " << noads << std::endl;
  2061 + std::cout << "Number of used superpackets: " << nsp << std::endl;
  2062 + #endif
  2063 +
  2064 + // Setup DRW binary tables
  2065 + for (int i = 0; i < size(); ++i) {
  2066 +
  2067 + // Get pointer to DRW
  2068 + GCOMDri* dri = &(m_dris[i]);
  2069 +
  2070 + // Allocate columns
  2071 + GFitsTableLongCol tjd("TJD", nsp);
  2072 + GFitsTableLongCol tics("TICS", nsp);
  2073 + GFitsTableDoubleCol rate("RATE", nsp);
  2074 + GFitsTableDoubleCol vetorate("VETORATE", nsp);
  2075 + GFitsTableDoubleCol activrate("ACTIVRATE", nsp);
  2076 +
  2077 + // Initialise superpacket counter
  2078 + int isp = 0;
  2079 +
  2080 + // Loop over Orbit Aspect Data
  2081 + for (int i_oad = 0; i_oad < noads; ++i_oad) {
  2082 +
  2083 + // Get reference to Orbit Aspect Data of superpacket
  2084 + const GCOMOad &oad = obs.oads()[i_oad];
  2085 +
  2086 + // Skip not-to-be-used superpackets
  2087 + if (!m_wrk_use_sp[i_oad]) {
  2088 + continue;
  2089 + }
  2090 +
  2091 + // Fill table columns
  2092 + tjd(isp) = oad.tjd();
  2093 + tics(isp) = oad.tics();
  2094 + rate(isp) = m_wrk_rate(isp, i);
  2095 + vetorate(isp) = m_wrk_vetorate(isp);
  2096 + activrate(isp) = m_wrk_activrate(isp, i);
  2097 +
  2098 + // Increment superpacket counter
  2099 + isp++;
  2100 +
  2101 + } // endfor: looped over Orbit Aspect Data
  2102 +
  2103 + // Append columns to binary table
  2104 + dri->m_drw_table.clear();
  2105 + dri->m_drw_table.extname("RATES");
  2106 + dri->m_drw_table.append(tjd);
  2107 + dri->m_drw_table.append(tics);
  2108 + dri->m_drw_table.append(rate);
  2109 + dri->m_drw_table.append(vetorate);
  2110 + dri->m_drw_table.append(activrate);
  2111 +
  2112 + } // endfor: looped over DRWs
  2113 +
  2114 + // Return
  2115 + return;
  2116 +}
  2117 +
  2118 +
  2119 +/***********************************************************************//**
1840 2120 * @brief Save working arrays for vetorate computation
1841 2121 *
1842 2122 * @param[in] filename FITS filename.
... ... @@ -1852,32 +2132,40 @@ void GCOMDris::vetorate_save(const GFilename&amp; filename) const
1852 2132 #endif
1853 2133  
1854 2134 // Extract dimension from working arrays
1855   - int noads = m_wrk_counts.shape()[0];
  2135 + int noads = m_wrk_use_sp.size();
  2136 + int nsp = m_wrk_counts.shape()[0];
1856 2137 int nphibar = m_wrk_counts.shape()[1];
1857 2138 int neng = m_wrk_counts.shape()[2];
1858 2139  
1859 2140 // Allocate FITS images
1860   - GFitsImageDouble image_counts(noads, nphibar, neng);
1861   - GFitsImageDouble image_ehacutcorr(noads, nphibar);
1862   - GFitsImageDouble image_vetorate(noads);
  2141 + GFitsImageDouble image_counts(nsp, nphibar, neng);
  2142 + GFitsImageDouble image_ehacutcorr(nsp, nphibar);
  2143 + GFitsImageDouble image_vetorate(nsp);
  2144 + GFitsImageDouble image_activrate(nsp, neng);
1863 2145 GFitsImageShort image_use_sp(noads);
1864 2146  
1865 2147 // Fill FITS images from working arrays
1866   - for (int ioad = 0; ioad < noads; ++ioad) {
  2148 + for (int isp = 0; isp < nsp; ++isp) {
1867 2149 for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1868   - for (int ienergy = 0; ienergy < neng; ++ienergy) {
1869   - image_counts(ioad, iphibar, ienergy) = m_wrk_counts(ioad, iphibar, ienergy);
  2150 + for (int ieng = 0; ieng < neng; ++ieng) {
  2151 + image_counts(isp, iphibar, ieng) = m_wrk_counts(isp, iphibar, ieng);
1870 2152 }
1871   - image_ehacutcorr(ioad, iphibar) = m_wrk_ehacutcorr(ioad, iphibar);
  2153 + image_ehacutcorr(isp, iphibar) = m_wrk_ehacutcorr(isp, iphibar);
1872 2154 }
1873   - image_vetorate(ioad) = m_wrk_vetorate(ioad);
1874   - image_use_sp(ioad) = (m_wrk_use_sp[ioad]) ? 1 : 0;
  2155 + for (int ieng = 0; ieng < neng; ++ieng) {
  2156 + image_activrate(isp, ieng) = m_wrk_activrate(isp, ieng);
  2157 + }
  2158 + image_vetorate(isp) = m_wrk_vetorate(isp);
  2159 + }
  2160 + for (int ioad = 0; ioad < noads; ++ioad) {
  2161 + image_use_sp(ioad) = (m_wrk_use_sp[ioad]) ? 1 : 0;
1875 2162 }
1876 2163  
1877 2164 // Set image attributes
1878 2165 image_counts.extname("COUNTS");
1879 2166 image_ehacutcorr.extname("EHACUTCORR");
1880 2167 image_vetorate.extname("VETORATE");
  2168 + image_activrate.extname("ACTIVRATE");
1881 2169 image_use_sp.extname("SPUSAGE");
1882 2170  
1883 2171 // Create FITS file and append images
... ... @@ -1885,6 +2173,7 @@ void GCOMDris::vetorate_save(const GFilename&amp; filename) const
1885 2173 fits.append(image_counts);
1886 2174 fits.append(image_ehacutcorr);
1887 2175 fits.append(image_vetorate);
  2176 + fits.append(image_activrate);
1888 2177 fits.append(image_use_sp);
1889 2178  
1890 2179 // Save FITS file
... ... @@ -1917,36 +2206,45 @@ void GCOMDris::vetorate_load(const GFilename&amp; filename)
1917 2206 const GFitsImage* image_counts = fits.image("COUNTS");
1918 2207 const GFitsImage* image_ehacutcorr = fits.image("EHACUTCORR");
1919 2208 const GFitsImage* image_vetorate = fits.image("VETORATE");
  2209 + const GFitsImage* image_activrate = fits.image("ACTIVRATE");
1920 2210 const GFitsImage* image_use_sp = fits.image("SPUSAGE");
1921 2211  
1922 2212 // Extract dimensions
1923   - int noads = image_counts->naxes(0);
  2213 + int noads = image_use_sp->naxes(0);
  2214 + int nsp = image_counts->naxes(0);
1924 2215 int nphibar = image_counts->naxes(1);
1925 2216 int neng = image_counts->naxes(2);
1926 2217  
1927 2218 // Debug
1928 2219 #if defined(G_DEBUG_COMPUTE_DRWS)
1929   - std::cout << "Number of superpackets: " << noads << std::endl;
  2220 + std::cout << "Number of OAD superpackets: " << noads << std::endl;
  2221 + std::cout << "Number of used superpackets: " << nsp << std::endl;
1930 2222 std::cout << "Number of Phibar layers: " << nphibar << std::endl;
1931 2223 std::cout << "Number of energies: " << neng << std::endl;
1932 2224 #endif
1933 2225  
1934 2226 // Allocate working array
1935   - m_wrk_counts = GNdarray(noads, nphibar, neng);
1936   - m_wrk_ehacutcorr = GNdarray(noads, nphibar);
1937   - m_wrk_vetorate = GNdarray(noads);
  2227 + m_wrk_counts = GNdarray(nsp, nphibar, neng);
  2228 + m_wrk_ehacutcorr = GNdarray(nsp, nphibar);
  2229 + m_wrk_vetorate = GNdarray(nsp);
  2230 + m_wrk_activrate = GNdarray(nsp, neng);
1938 2231 m_wrk_use_sp = std::vector<bool>(noads);
1939 2232  
1940 2233 // Extract data from images
1941   - for (int ioad = 0; ioad < noads; ++ioad) {
  2234 + for (int isp = 0; isp < nsp; ++isp) {
1942 2235 for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1943   - for (int ienergy = 0; ienergy < neng; ++ienergy) {
1944   - m_wrk_counts(ioad, iphibar, ienergy) = image_counts->pixel(ioad, iphibar, ienergy);
  2236 + for (int ieng = 0; ieng < neng; ++ieng) {
  2237 + m_wrk_counts(isp, iphibar, ieng) = image_counts->pixel(isp, iphibar, ieng);
1945 2238 }
1946   - m_wrk_ehacutcorr(ioad, iphibar) = image_ehacutcorr->pixel(ioad, iphibar);
  2239 + m_wrk_ehacutcorr(isp, iphibar) = image_ehacutcorr->pixel(isp, iphibar);
  2240 + }
  2241 + for (int ieng = 0; ieng < neng; ++ieng) {
  2242 + m_wrk_activrate(isp, ieng) = image_activrate->pixel(isp, ieng);
1947 2243 }
1948   - m_wrk_vetorate(ioad) = image_vetorate->pixel(ioad);
1949   - m_wrk_use_sp[ioad] = (image_use_sp->pixel(ioad) == 1);
  2244 + m_wrk_vetorate(isp) = image_vetorate->pixel(isp);
  2245 + }
  2246 + for (int ioad = 0; ioad < noads; ++ioad) {
  2247 + m_wrk_use_sp[ioad] = (image_use_sp->pixel(ioad) == 1);
1950 2248 }
1951 2249  
1952 2250 // Close FITS file
... ... @@ -1981,36 +2279,36 @@ GCOMDris::likelihood::likelihood(GCOMDris *dris,
1981 2279 m_curvature = GMatrixSparse(1,1);
1982 2280  
1983 2281 // Extract dimension from working array
1984   - m_noads = m_this->m_wrk_counts.shape()[0];
  2282 + m_nsp = m_this->m_wrk_counts.shape()[0];
1985 2283 m_nphibar = m_this->m_wrk_counts.shape()[1];
1986 2284  
1987 2285 // Multiply veto and constant rate by EHA cut correction. Rates are zero
1988 2286 // in case that the vetorate is zero.
1989   - m_vetorate = GNdarray(m_noads, m_nphibar);
1990   - m_constrate = GNdarray(m_noads, m_nphibar);
1991   - m_diffrate = GNdarray(m_noads, m_nphibar);
1992   - for (int ioad = 0; ioad < m_noads; ++ioad) {
1993   - double vetorate = m_this->m_wrk_vetorate(ioad);
  2287 + m_vetorate = GNdarray(m_nsp, m_nphibar);
  2288 + m_activrate = GNdarray(m_nsp, m_nphibar);
  2289 + m_diffrate = GNdarray(m_nsp, m_nphibar);
  2290 + for (int isp = 0; isp < m_nsp; ++isp) {
  2291 + double vetorate = m_this->m_wrk_vetorate(isp);
1994 2292 if (vetorate > 0.0) {
1995   - double constrate = m_this->m_wrk_constrate(ioad);
  2293 + double activrate = m_this->m_wrk_activrate(isp, ieng);
1996 2294 for (int iphibar = 0; iphibar < m_nphibar; ++iphibar) {
1997   - m_vetorate(ioad, iphibar) = vetorate * m_this->m_wrk_ehacutcorr(ioad, iphibar);
1998   - m_constrate(ioad, iphibar) = constrate * m_this->m_wrk_ehacutcorr(ioad, iphibar);
1999   - m_diffrate(ioad, iphibar) = m_vetorate(ioad, iphibar) - m_constrate(ioad, iphibar);
  2295 + m_vetorate(isp, iphibar) = vetorate * m_this->m_wrk_ehacutcorr(isp, iphibar);
  2296 + m_activrate(isp, iphibar) = activrate * m_this->m_wrk_ehacutcorr(isp, iphibar);
  2297 + m_diffrate(isp, iphibar) = m_vetorate(isp, iphibar) - m_activrate(isp, iphibar);
2000 2298 }
2001 2299 }
2002 2300 }
2003 2301  
2004 2302 // Compute rate sums
2005 2303 m_vetorate_sum = GNdarray(m_nphibar);
2006   - m_constrate_sum = GNdarray(m_nphibar);
  2304 + m_activrate_sum = GNdarray(m_nphibar);
2007 2305 m_diffrate_sum = GNdarray(m_nphibar);
2008 2306 for (int iphibar = 0; iphibar < m_nphibar; ++iphibar) {
2009   - for (int ioad = 0; ioad < m_noads; ++ioad) {
2010   - m_vetorate_sum(iphibar) += m_vetorate(ioad, iphibar);
2011   - m_constrate_sum(iphibar) += m_constrate(ioad, iphibar);
  2307 + for (int isp = 0; isp < m_nsp; ++isp) {
  2308 + m_vetorate_sum(iphibar) += m_vetorate(isp, iphibar);
  2309 + m_activrate_sum(iphibar) += m_activrate(isp, iphibar);
2012 2310 }
2013   - m_diffrate_sum(iphibar) = m_vetorate_sum(iphibar) - m_constrate_sum(iphibar);
  2311 + m_diffrate_sum(iphibar) = m_vetorate_sum(iphibar) - m_activrate_sum(iphibar);
2014 2312 }
2015 2313  
2016 2314 // Return
... ... @@ -2030,44 +2328,40 @@ void GCOMDris::likelihood::eval(const GOptimizerPars&amp; pars)
2030 2328 {
2031 2329 // Recover parameters
2032 2330 double fprompt = pars[0]->value();
2033   - double fconst = 1.0 - fprompt;
2034   -
2035   - // Extract dimension from working array
2036   - int noads = m_this->m_wrk_counts.shape()[0];
2037   - int nphibar = m_this->m_wrk_counts.shape()[1];
  2331 + double factiv = 1.0 - fprompt;
2038 2332  
2039 2333 // Allocate phibar normalisation arrays
2040   - GNdarray nevents(nphibar);
2041   - GNdarray nmodel(nphibar);
2042   - GNdarray norm(nphibar);
  2334 + GNdarray nevents(m_nphibar);
  2335 + GNdarray nmodel(m_nphibar);
  2336 + GNdarray norm(m_nphibar);
2043 2337  
2044 2338 // Compute model
2045   - GNdarray model = fprompt * m_vetorate + fconst * m_constrate;
  2339 + GNdarray model = fprompt * m_vetorate + factiv * m_activrate;
2046 2340  
2047 2341 // Compute Phibar normalised model
2048 2342 GNdarray model_norm = model;
2049 2343 for (int iphibar = 0; iphibar < m_nphibar; ++iphibar) {
2050   - for (int ioad = 0; ioad < m_noads; ++ioad) {
2051   - if (model(ioad, iphibar) > 0.0) {
2052   - nevents(iphibar) += m_this->m_wrk_counts(ioad, iphibar, m_ieng);
2053   - nmodel(iphibar) += model(ioad, iphibar);
  2344 + for (int isp = 0; isp < m_nsp; ++isp) {
  2345 + if (model(isp, iphibar) > 0.0) {
  2346 + nevents(iphibar) += m_this->m_wrk_counts(isp, iphibar, m_ieng);
  2347 + nmodel(iphibar) += model(isp, iphibar);
2054 2348 }
2055 2349 }
2056 2350 if (nmodel(iphibar) > 0.0) {
2057 2351 norm(iphibar) = m_norm * nevents(iphibar) / nmodel(iphibar);
2058   - for (int ioad = 0; ioad < m_noads; ++ioad) {
2059   - model_norm(ioad, iphibar) *= norm(iphibar);
  2352 + for (int isp = 0; isp < m_nsp; ++isp) {
  2353 + model_norm(isp, iphibar) *= norm(iphibar);
2060 2354 }
2061 2355 }
2062 2356 }
2063 2357  
2064 2358 // Compute LogL
2065 2359 m_value = 0.0;
2066   - for (int ioad = 0; ioad < m_noads; ++ioad) {
  2360 + for (int isp = 0; isp < m_nsp; ++isp) {
2067 2361 for (int iphibar = 0; iphibar < m_nphibar; ++iphibar) {
2068   - if (model_norm(ioad, iphibar) > 0.0) {
2069   - m_value -= m_this->m_wrk_counts(ioad, iphibar, m_ieng) *
2070   - std::log(model_norm(ioad, iphibar)) - model_norm(ioad, iphibar);
  2362 + if (model_norm(isp, iphibar) > 0.0) {
  2363 + m_value -= m_this->m_wrk_counts(isp, iphibar, m_ieng) *
  2364 + std::log(model_norm(isp, iphibar)) - model_norm(isp, iphibar);
2071 2365 }
2072 2366 }
2073 2367 }
... ... @@ -2080,18 +2374,18 @@ void GCOMDris::likelihood::eval(const GOptimizerPars&amp; pars)
2080 2374 double g_norm = -m_norm * nevents(iphibar) / nmodel2 * m_diffrate_sum(iphibar);
2081 2375  
2082 2376 // Loop over superpackets
2083   - for (int ioad = 0; ioad < m_noads; ++ioad) {
  2377 + for (int isp = 0; isp < m_nsp; ++isp) {
2084 2378  
2085 2379 // Continue only if model is positive
2086   - if (model_norm(ioad, iphibar) > 0.0) {
  2380 + if (model_norm(isp, iphibar) > 0.0) {
2087 2381  
2088 2382 // Pre computation
2089   - double fb = m_this->m_wrk_counts(ioad, iphibar, m_ieng) / model_norm(ioad, iphibar);
  2383 + double fb = m_this->m_wrk_counts(isp, iphibar, m_ieng) / model_norm(isp, iphibar);
2090 2384 double fc = (1.0 - fb);
2091   - double fa = fb / model_norm(ioad, iphibar);
  2385 + double fa = fb / model_norm(isp, iphibar);
2092 2386  
2093 2387 // Compute parameter gradient
2094   - double g = norm(iphibar) * m_diffrate(ioad, iphibar) + g_norm * model(ioad, iphibar);
  2388 + double g = norm(iphibar) * m_diffrate(isp, iphibar) + g_norm * model(isp, iphibar);
2095 2389  
2096 2390 // Update gradient
2097 2391 m_gradient[0] += fc * g;
... ...