Commit 6f9976c0e3401ab9243511c016e56eddb415871d

Authored by Jürgen Knödlseder
1 parent d0bfcda6

Implement GCOMDris::compute_drws() method

inst/com/include/GCOMDri.hpp
1 1 /***************************************************************************
2 2 * GCOMDri.hpp - COMPTEL Data Space class *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2017-2022 by Juergen Knoedlseder *
  4 + * copyright (C) 2017-2023 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -60,6 +60,8 @@ namespace gammalib {
60 60 ***************************************************************************/
61 61 class GCOMDri : public GBase {
62 62  
  63 + friend class GCOMDris;
  64 +
63 65 public:
64 66 // Constructors and destructors
65 67 GCOMDri(void);
... ...
inst/com/include/GCOMDris.hpp
... ... @@ -34,8 +34,6 @@
34 34 #include "GContainer.hpp"
35 35  
36 36 /* __ Forward declarations _______________________________________________ */
37   -//class GFilename;
38   -//class GFitsTable;
39 37  
40 38 /* __ Constants __________________________________________________________ */
41 39  
... ... @@ -75,6 +73,9 @@ public:
75 73 void remove(const int& index);
76 74 void reserve(const int& num);
77 75 void extend(const GCOMDris& dris);
  76 + void compute_drws(const GCOMObservation& obs,
  77 + const GCOMSelection& select = GCOMSelection(),
  78 + const double& zetamin = 5.0);
78 79 std::string print(const GChatter& chatter = NORMAL) const;
79 80  
80 81 protected:
... ...
inst/com/pyext/GCOMDris.i
... ... @@ -53,6 +53,9 @@ public:
53 53 void remove(const int& index);
54 54 void reserve(const int& num);
55 55 void extend(const GCOMDris& dris);
  56 + void compute_drws(const GCOMObservation& obs,
  57 + const GCOMSelection& select = GCOMSelection(),
  58 + const double& zetamin = 5.0);
56 59 };
57 60  
58 61  
... ...
inst/com/src/GCOMDri.cpp
... ... @@ -45,7 +45,6 @@
45 45 #include "GCOMOads.hpp"
46 46 #include "GCOMTim.hpp"
47 47 #include "GCOMStatus.hpp"
48   -#include "GCOMSupport.hpp"
49 48 #include "GCOMObservation.hpp"
50 49 #include "GCOMEventList.hpp"
51 50 #include "GCOMSelection.hpp"
... ...
inst/com/src/GCOMDris.cpp
... ... @@ -32,18 +32,28 @@
32 32 #include "GMath.hpp"
33 33 #include "GCOMTools.hpp"
34 34 #include "GCOMSupport.hpp"
  35 +#include "GCOMDri.hpp"
35 36 #include "GCOMDris.hpp"
  37 +#include "GCOMOad.hpp"
  38 +#include "GCOMOads.hpp"
  39 +#include "GCOMTim.hpp"
  40 +#include "GCOMStatus.hpp"
  41 +#include "GCOMObservation.hpp"
  42 +#include "GCOMSelection.hpp"
36 43  
37 44 /* __ Method name definitions ____________________________________________ */
38 45 #define G_AT "GCOMDris::at(int&)"
39 46 #define G_INSERT "GCOMDris::insert(int&, GCOMDri&)"
40 47 #define G_REMOVE "GCOMDris::remove(int&)"
  48 +#define G_COMPUTE_DRWS "GCOMDris::compute_drws(GCOMObservation&, "\
  49 + "GCOMSelection&, double&)"
41 50  
42 51 /* __ Macros _____________________________________________________________ */
43 52  
44 53 /* __ Coding definitions _________________________________________________ */
45 54  
46 55 /* __ Debug definitions __________________________________________________ */
  56 +#define G_DEBUG_COMPUTE_DRWS
47 57  
48 58  
49 59 /*==========================================================================
... ... @@ -328,6 +338,303 @@ void GCOMDris::extend(const GCOMDris& dris)
328 338  
329 339  
330 340 /***********************************************************************//**
  341 + * @brief Compute backgroud weighting cubes
  342 + *
  343 + * @param[in] obs COMPTEL observation.
  344 + * @param[in] select Selection set.
  345 + * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
  346 + *
  347 + * @exception GException::invalid_value
  348 + * DRW with mismatching definition encountered in container.
  349 + * @exception GException::invalid_argument
  350 + * No event list found in COMPTEL observation.
  351 + *
  352 + * Compute DRW cubes for a COMPTEL observation.
  353 + ***************************************************************************/
  354 +void GCOMDris::compute_drws(const GCOMObservation& obs,
  355 + const GCOMSelection& select,
  356 + const double& zetamin)
  357 +{
  358 + // Debug
  359 + #if defined(G_DEBUG_COMPUTE_DRWS)
  360 + std::cout << "GCOMDris::compute_drws" << std::endl;
  361 + std::cout << "======================" << std::endl;
  362 + #endif
  363 +
  364 + // Set constants
  365 + const double dtime = 5.0 * 60.0; // Event rate integration time in seconds
  366 +
  367 + // Continue only if there are DRWs in container
  368 + if (!is_empty()) {
  369 +
  370 + // Initialise D1 & D2 module status
  371 + GCOMStatus status;
  372 +
  373 + // Get pointer to first DRW in container (for convenient access to
  374 + // members of GCOMDri; we won't use it for modifications, hence we
  375 + // can declare it as constant)
  376 + const GCOMDri* dri = &(m_dris[0]);
  377 +
  378 + // Initialise all DRWs
  379 + for (int i = 0; i < size(); ++i) {
  380 +
  381 + // Throw an exception if the DRW definition differs
  382 + if (dri->m_dri != m_dris[i].m_dri) {
  383 + std::string msg = "Mismatch between definition of DRW "+
  384 + gammalib::str(i)+" and the first DRW. "
  385 + "Method only works on DRWs with identical "
  386 + "definitions.";
  387 + throw GException::invalid_value(G_COMPUTE_DRWS, msg);
  388 + }
  389 +
  390 + // Initialise superpacket statistics
  391 + m_dris[i].init_statistics();
  392 +
  393 + // Store selection set so that handling of failed PMT flag is
  394 + // correctly ritten into the FITS header
  395 + m_dris[i].m_selection = select;
  396 +
  397 + // Set all DRG bins to zero
  398 + m_dris[i].init_cube();
  399 +
  400 + } // endfor: looped over all DRWs
  401 +
  402 + // Get pointer to event list. Throw an exception if the observation
  403 + // did not contain an event list
  404 + const GCOMEventList* events = dynamic_cast<const GCOMEventList*>(obs.events());
  405 + if (events == NULL) {
  406 + std::string msg = "No event list found in COMPTEL observation. Please "
  407 + "specify an observation that contains an event list.";
  408 + throw GException::invalid_argument(G_COMPUTE_DRWS, msg);
  409 + }
  410 +
  411 + // Initialise current time and vectors for computation of node function
  412 + // and vectors for energy-dependent rate interpolation
  413 + double time;
  414 + double rate0 = 0.0;
  415 + double rate1 = 0.0;
  416 + double rate2 = 0.0;
  417 + GNodeArray times;
  418 + std::vector<double> rates0;
  419 + std::vector<double> rates1;
  420 + std::vector<double> rates2;
  421 +
  422 + // Set time of first event
  423 + if (events->size() > 0) {
  424 + time = (*events)[0]->time().secs();
  425 + }
  426 +
  427 + // Determine energy-dependent event rates. The standard event selection
  428 + // criteria and earth horizon cut is applied so that the event rate
  429 + // corresponds to the current selection, yet we do not consider any
  430 + // Good Time Intervals or OAD time information as we later only access
  431 + // relevant times (YET THERE COULD BE AN ISSUE WITH A GLITCH). Rates
  432 + // are computed for three hard-coded energy intervals.
  433 + for (int i_evt = 0; i_evt < events->size(); ++i_evt) {
  434 +
  435 + // Get pointer to event
  436 + const GCOMEventAtom* event = (*events)[i_evt];
  437 +
  438 + // Apply event selection
  439 + if (!select.use_event(*event)) {
  440 + continue;
  441 + }
  442 +
  443 + // Apply Earth horizon cut
  444 + if ((event->eha() - event->phibar()) < zetamin) {
  445 + continue;
  446 + }
  447 +
  448 + // If time exceeds time bin then add rates
  449 + while (event->time().secs() > (time + dtime)) {
  450 +
  451 + // If rates are not all zero then append rates to vectors
  452 + if ((rate0 != 0.0) || (rate1 != 0.0) || (rate2 != 0.0)) {
  453 +
  454 + // Append time at mid-point of interval
  455 + times.append(time + 0.5 * dtime);
  456 +
  457 + // Append rates
  458 + rates0.push_back(rate0);
  459 + rates1.push_back(rate1);
  460 + rates2.push_back(rate2);
  461 +
  462 + // Debug
  463 + #if defined(G_DEBUG_COMPUTE_DRWS)
  464 + std::cout << "t=" << time + 0.5 * dtime;
  465 + std::cout << " r0=" << rate0;
  466 + std::cout << " r1=" << rate1;
  467 + std::cout << " r2=" << rate2;
  468 + std::cout << std::endl;
  469 + #endif
  470 +
  471 + // Initialise rates for new accumulation
  472 + rate0 = 0.0;
  473 + rate1 = 0.0;
  474 + rate2 = 0.0;
  475 +
  476 + } // endif: there were rates to append
  477 +
  478 + // Increment time
  479 + time += dtime;
  480 +
  481 + } // endwhile: event time was after the current integration time stop
  482 +
  483 + // Accumulate rates
  484 + double energy = event->energy().MeV();
  485 + if (energy < 1.8) {
  486 + rate0 += 1.0;
  487 + }
  488 + else if (energy < 4.3) {
  489 + rate1 += 1.0;
  490 + }
  491 + else {
  492 + rate2 += 1.0;
  493 + }
  494 +
  495 + } // endfor: looped over events
  496 +
  497 + // Get Good Time Intervals. If a pulsar selection is specified then
  498 + // reduce the Good Time Intervals to the validity intervals of the
  499 + // pulsar emphemerides.
  500 + GCOMTim tim = obs.tim();
  501 + if (select.has_pulsar()) {
  502 + tim.reduce(select.pulsar().validity());
  503 + }
  504 +
  505 + // Loop over Orbit Aspect Data
  506 + for (int i_oad = 0; i_oad < obs.oads().size(); ++i_oad) {
  507 +
  508 + // Get reference to Orbit Aspect Data of superpacket
  509 + const GCOMOad &oad = obs.oads()[i_oad];
  510 +
  511 + // Check superpacket usage for all DRWs so that their statistics
  512 + // get correctly updated
  513 + bool skip = false;
  514 + for (int i = 0; i < size(); ++i) {
  515 + if (!m_dris[i].use_superpacket(oad, tim, select)) {
  516 + skip = true;
  517 + }
  518 + }
  519 + if (skip) {
  520 + continue;
  521 + }
  522 +
  523 + // Get Orbit Aspect Data mid-time in seconds
  524 + double time = oad.tstart().secs() + 0.5 * (oad.tstop() - oad.tstart());
  525 +
  526 + // Prepare Earth horizon angle computation. The celestial system
  527 + // is reinterpreted as the COMPTEL coordinate system, where the
  528 + // 90 degrees - zenith angle becomes the declination and the azimuth
  529 + // angle becomes Right Ascension. This allows us later to use the
  530 + // GSkyDir::dist method to compute the distance between the geocentre
  531 + // and the telescope Z-axis.
  532 + double theta_geocentre = double(oad.gcel());
  533 + double phi_geocentre = double(oad.gcaz());
  534 + GSkyDir geocentre_comptel;
  535 + geocentre_comptel.radec_deg(phi_geocentre, 90.0-theta_geocentre);
  536 +
  537 + // Compute geometrical factors for all (Chi, Psi). We assume here
  538 + // that their size and definition is identical, which checked on
  539 + // entry
  540 + for (int index = 0; index < dri->m_dri.npix(); ++index) {
  541 +
  542 + // Get sky direction for (Chi, Psi)
  543 + GSkyDir sky = dri->m_dri.inx2dir(index);
  544 +
  545 + // Convert sky direction to COMPTEL coordinates
  546 + double theta = oad.theta(sky);
  547 + double phi = oad.phi(sky);
  548 +
  549 + // Compute geometric factor summed over all D1, D2
  550 + double geometry = dri->compute_geometry(oad.tjd(), theta, phi, select, status);
  551 +
  552 + // Compute Earth horizon angle as the distance between the Earth
  553 + // centre in COMPTEL coordinates and the (Chi, Psi) pixel in
  554 + // COMPTEL coordinates minus the radius of the Earth.
  555 + GSkyDir chipsi_comptel;
  556 + chipsi_comptel.radec_deg(phi, 90.0-theta);
  557 + double eha = geocentre_comptel.dist_deg(chipsi_comptel) - oad.georad();
  558 +
  559 + // Loop over Phibar
  560 + for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
  561 +
  562 + // Compute minimum Earth horizon angle for Phibar layer
  563 + double ehamin = double(iphibar) * dri->m_phibin + zetamin;
  564 +
  565 + // Add up geometry if the Earth horizon angle is equal or
  566 + // larger than the minimum
  567 + if (eha >= ehamin) {
  568 +
  569 + // Get data space index
  570 + int inx = index + iphibar * dri->m_dri.npix();
  571 +
  572 + // Loop over DRWs and multiply with appopriate rates
  573 + for (int i = 0; i < size(); ++i) {
  574 +
  575 + // Set rate by interpolating the precomputed vectors
  576 + double rate = 0.0;
  577 + if (m_dris[i].m_ebounds.emin().MeV() > 4.3) {
  578 + rate = times.interpolate(time, rates2);
  579 + }
  580 + else if (m_dris[i].m_ebounds.emin().MeV() > 1.8) {
  581 + rate = times.interpolate(time, rates1);
  582 + }
  583 + else {
  584 + rate = times.interpolate(time, rates0);
  585 + }
  586 +
  587 + // Set DRW
  588 + m_dris[i][inx] += geometry * rate;
  589 +
  590 + } // endfor: looped over DRWs
  591 +
  592 + } // endif: Earth horizon cut passed
  593 +
  594 + } // endfor: looped over Phibar
  595 +
  596 + } // endfor: looped over (Chi, Psi)
  597 +
  598 + } // endfor: looped over Orbit Aspect Data
  599 +
  600 + // Normalisation Phibar layers of all DRWs to unity
  601 + for (int i = 0; i < size(); ++i) {
  602 +
  603 + // Loop over Phibar layers
  604 + for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
  605 +
  606 + // Compute sum in Phibar layer
  607 + double sum = 0.0;
  608 + int istart = iphibar * dri->m_dri.npix();
  609 + int istop = istart + dri->m_dri.npix();
  610 + for (int inx = istart; inx < istop; ++inx) {
  611 + sum += m_dris[i][inx];
  612 + }
  613 +
  614 + // Normalise by sum
  615 + if (sum != 0.0) {
  616 + for (int inx = istart; inx < istop; ++inx) {
  617 + m_dris[i][inx] /= sum;
  618 + }
  619 + }
  620 +
  621 + } // endfor: looped over Phibar layers
  622 +
  623 + // Set the Good Time interval for DRWs
  624 + if (m_dris[i].m_num_used_superpackets > 0) {
  625 + m_dris[i].m_gti = GGti(dri->m_tstart, dri->m_tstop);
  626 + }
  627 +
  628 + } // endfor: looped over DRWs
  629 +
  630 + } // endif: container was not empty
  631 +
  632 + // Return
  633 + return;
  634 +}
  635 +
  636 +
  637 +/***********************************************************************//**
331 638 * @brief Print Data Space container
332 639 *
333 640 * @param[in] chatter Chattiness.
... ...