Commit 6f9976c0e3401ab9243511c016e56eddb415871d
1 parent
d0bfcda6
Implement GCOMDris::compute_drws() method
Showing
5 changed files
with
316 additions
and
4 deletions
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
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. | ... | ... |