GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GCOMDris.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GCOMDris.cpp - COMPTEL Data Space container class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2023 by Juergen Knodlseder *
5  * ----------------------------------------------------------------------- *
6  * *
7  * This program is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 /**
22  * @file GCOMDris.hpp
23  * @brief COMPTEL Data Space container class implementation
24  * @author Juergen Knodlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <fstream>
32 #include <iostream>
33 #include "GException.hpp"
34 #include "GMath.hpp"
35 #include "GFits.hpp"
36 #include "GFitsImageDouble.hpp"
37 #include "GFitsImageShort.hpp"
38 #include "GFitsTableLongCol.hpp"
39 #include "GFitsTableDoubleCol.hpp"
40 #include "GOptimizerPars.hpp"
41 #include "GOptimizerPar.hpp"
42 #include "GOptimizerLM.hpp"
43 #include "GFft.hpp"
44 #include "GCOMTools.hpp"
45 #include "GCOMSupport.hpp"
46 #include "GCOMDri.hpp"
47 #include "GCOMDris.hpp"
48 #include "GCOMOad.hpp"
49 #include "GCOMOads.hpp"
50 #include "GCOMTim.hpp"
51 #include "GCOMStatus.hpp"
52 #include "GCOMObservation.hpp"
53 #include "GCOMEventList.hpp"
54 #include "GCOMEventAtom.hpp"
55 #include "GCOMSelection.hpp"
56 
57 /* __ Method name definitions ____________________________________________ */
58 #define G_AT "GCOMDris::at(int&)"
59 #define G_INSERT "GCOMDris::insert(int&, GCOMDri&)"
60 #define G_REMOVE "GCOMDris::remove(int&)"
61 #define G_COMPUTE_DRWS "GCOMDris::compute_drws(GCOMObservation&,"\
62  " GCOMSelection&, double&, double&, std::string&)"
63 
64 /* __ Macros _____________________________________________________________ */
65 
66 /* __ Coding definitions _________________________________________________ */
67 #define G_COMPUTE_DRWS_EHACORR //!< Correct Earth horizon cut
68 
69 /* __ Debug definitions __________________________________________________ */
70 //#define G_DEBUG_COMPUTE_DRWS
71 //#define G_DEBUG_SAVE_WORKING_ARRAYS
72 
73 /* __ Constants __________________________________________________________ */
74 
75 
76 /*==========================================================================
77  = =
78  = Constructors/destructors =
79  = =
80  ==========================================================================*/
81 
82 /***********************************************************************//**
83  * @brief Void constructor
84  *
85  * Constructs an empty Data Space container.
86  ***************************************************************************/
88 {
89  // Initialise class members
90  init_members();
91 
92  // Return
93  return;
94 }
95 
96 
97 /***********************************************************************//**
98  * @brief Copy constructor
99  *
100  * @param[in] dris Data Space container.
101  ***************************************************************************/
103 {
104  // Initialise class members
105  init_members();
106 
107  // Copy members
108  copy_members(dris);
109 
110  // Return
111  return;
112 }
113 
114 
115 /***********************************************************************//**
116  * @brief Destructor
117  ***************************************************************************/
119 {
120  // Free members
121  free_members();
122 
123  // Return
124  return;
125 }
126 
127 
128 /*==========================================================================
129  = =
130  = Operators =
131  = =
132  ==========================================================================*/
133 
134 /***********************************************************************//**
135  * @brief Assignment operator
136  *
137  * @param[in] dris Data Space container.
138  * @return Data Space container.
139  ***************************************************************************/
141 {
142  // Execute only if object is not identical
143  if (this != &dris) {
144 
145  // Free members
146  free_members();
147 
148  // Initialise private members
149  init_members();
150 
151  // Copy members
152  copy_members(dris);
153 
154  } // endif: object was not identical
155 
156  // Return this object
157  return *this;
158 }
159 
160 
161 /*==========================================================================
162  = =
163  = Public methods =
164  = =
165  ==========================================================================*/
166 
167 /***********************************************************************//**
168  * @brief Clear Data Space container
169  ***************************************************************************/
170 void GCOMDris::clear(void)
171 {
172  // Free members
173  free_members();
174 
175  // Initialise private members
176  init_members();
177 
178  // Return
179  return;
180 }
181 
182 
183 /***********************************************************************//**
184  * @brief Clone Data Space container
185  *
186  * @return Pointer to deep copy of Data Space container.
187  ***************************************************************************/
189 {
190  return new GCOMDris(*this);
191 }
192 
193 
194 /***********************************************************************//**
195  * @brief Return reference to Data Space
196  *
197  * @param[in] index Data Space index [0,...,size()-1].
198  *
199  * @exception GException::out_of_range
200  * Data Space index is out of range.
201  *
202  * Returns a reference to the Data Space with the specified @p index.
203  ***************************************************************************/
204 GCOMDri& GCOMDris::at(const int& index)
205 {
206  // Raise exception if index is out of range
207  if (index < 0 || index >= size()) {
208  throw GException::out_of_range(G_AT, "Data Space index",
209  index, size());
210  }
211 
212  // Return reference
213  return m_dris[index];
214 }
215 
216 
217 /***********************************************************************//**
218  * @brief Return reference to Data Space (const version)
219  *
220  * @param[in] index Data Space index [0,...,size()-1].
221  *
222  * @exception GException::out_of_range
223  * Data Space index is out of range.
224  *
225  * Returns a reference to the Data Space with the specified @p index.
226  ***************************************************************************/
227 const GCOMDri& GCOMDris::at(const int& index) const
228 {
229  // Raise exception if index is out of range
230  if (index < 0 || index >= size()) {
231  throw GException::out_of_range(G_AT, "Data Space index",
232  index, size());
233  }
234 
235  // Return reference
236  return m_dris[index];
237 }
238 
239 
240 /***********************************************************************//**
241  * @brief Append Data Space to container
242  *
243  * @param[in] dri Data Space.
244  * @return Reference to appended Data Space.
245  *
246  * Appends Data Space to the container by making a deep copy of the Data
247  * Space.
248  ***************************************************************************/
250 {
251  // Append dri to list
252  m_dris.push_back(dri);
253 
254  // Return reference
255  return m_dris[size()-1];
256 }
257 
258 
259 /***********************************************************************//**
260  * @brief Insert Data Space into container
261  *
262  * @param[in] index Data Space index (0,...,size()-1).
263  * @param[in] dri Data Space.
264  *
265  * @exception GException::out_of_range
266  * Data Space index is out of range.
267  *
268  * Inserts a Data Space into the container before the Data Space with the
269  * specified @p index.
270  ***************************************************************************/
271 GCOMDri& GCOMDris::insert(const int& index, const GCOMDri& dri)
272 {
273  // Compile option: raise exception if index is out of range
274  #if defined(G_RANGE_CHECK)
275  if (is_empty()) {
276  if (index > 0) {
277  throw GException::out_of_range(G_INSERT, "Data Space index",
278  index, size());
279  }
280  }
281  else {
282  if (index < 0 || index >= size()) {
283  throw GException::out_of_range(G_INSERT, "Data Space index",
284  index, size());
285  }
286  }
287  #endif
288 
289  // Inserts Data Space
290  m_dris.insert(m_dris.begin()+index, dri);
291 
292  // Return reference
293  return m_dris[index];
294 }
295 
296 
297 /***********************************************************************//**
298  * @brief Remove Data Space from container
299  *
300  * @param[in] index Data Space index (0,...,size()-1).
301  *
302  * @exception GException::out_of_range
303  * Data Space index is out of range.
304  *
305  * Remove Data Space of specified @p index from container.
306  ***************************************************************************/
307 void GCOMDris::remove(const int& index)
308 {
309  // Compile option: raise exception if index is out of range
310  #if defined(G_RANGE_CHECK)
311  if (index < 0 || index >= size()) {
312  throw GException::out_of_range(G_REMOVE, "Data Space index",
313  index, size());
314  }
315  #endif
316 
317  // Erase Data Space from container
318  m_dris.erase(m_dris.begin() + index);
319 
320  // Return
321  return;
322 }
323 
324 
325 /***********************************************************************//**
326  * @brief Append Data Space container
327  *
328  * @param[in] oads Data Space container.
329  *
330  * Append Data Space container to the container.
331  ***************************************************************************/
332 void GCOMDris::extend(const GCOMDris& dris)
333 {
334  // Do nothing if Data Space container is empty
335  if (!dris.is_empty()) {
336 
337  // Get size. Note that we extract the size first to avoid an
338  // endless loop that arises when a container is appended to
339  // itself.
340  int num = dris.size();
341 
342  // Reserve enough space
343  reserve(size() + num);
344 
345  // Loop over all elements and append them to container
346  for (int i = 0; i < num; ++i) {
347  m_dris.push_back(dris[i]);
348  }
349 
350  } // endif: Data Space container was not empty
351 
352  // Return
353  return;
354 }
355 
356 
357 /***********************************************************************//**
358  * @brief Compute background weighting cubes
359  *
360  * @param[in] obs COMPTEL observation.
361  * @param[in] select Selection set.
362  * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
363  * @param[in] timebin Time binning for rate determination (sec).
364  * @param[in] method Method to compute DRWs ("energy", "phibar" or "vetorate").
365  *
366  * @exception GException::invalid_value
367  * DRW with mismatching definition encountered in container.
368  * @exception GException::invalid_argument
369  * No event list found in COMPTEL observation.
370  *
371  * Compute DRW cubes for a COMPTEL observation. DRW cubes are event-rate
372  * weighted geometry cubes which were multiplied by the solid angle of
373  * the (Chi,Psi) pixels.
374  *
375  * The DRW cubes are normalised so that the sum of each Phibar layer equals
376  * to unity.
377  ***************************************************************************/
379  const GCOMSelection& select,
380  const double& zetamin,
381  const double& timebin,
382  const std::string& method)
383 {
384  // Continue only if there are DRWs in container
385  if (!is_empty()) {
386 
387  // Debug
388  #if defined(G_DEBUG_COMPUTE_DRWS)
389  std::cout << "Initialisation" << std::endl;
390  std::cout << "--------------" << std::endl;
391  #endif
392 
393  // Get pointer to first DRW in container (for convenient access to
394  // members of GCOMDri; we won't use it for modifications, hence we
395  // can declare it as constant)
396  const GCOMDri* dri = &(m_dris[0]);
397 
398  // Initialise all DRWs
399  for (int i = 0; i < size(); ++i) {
400 
401  // Throw an exception if the DRW definition differs
402  if (dri->m_dri != m_dris[i].m_dri) {
403  std::string msg = "Mismatch between definition of DRW "+
404  gammalib::str(i)+" and the first DRW. "
405  "Method only works on DRWs with identical "
406  "definitions.";
408  }
409 
410  // Initialise superpacket statistics
411  m_dris[i].init_statistics();
412 
413  // Store selection set so that handling of failed PMT flag is
414  // correctly ritten into the FITS header
415  m_dris[i].m_selection = select;
416 
417  // Set all DRG bins to zero
418  m_dris[i].init_cube();
419 
420  // Set DRW header method parameter
421  m_dris[i].m_drw_method = method;
422 
423  // Debug
424  #if defined(G_DEBUG_COMPUTE_DRWS)
425  std::cout << m_dris[i].print() << std::endl;
426  #endif
427 
428  } // endfor: looped over all DRWs
429 
430  // Get pointer to event list. Throw an exception if the observation
431  // did not contain an event list
432  const GCOMEventList* events = dynamic_cast<const GCOMEventList*>(obs.events());
433  if (events == NULL) {
434  std::string msg = "No event list found in COMPTEL observation. Please "
435  "specify an observation that contains an event list.";
437  }
438 
439  // Method A: energy-dependent weighting
440  if (method == "energy") {
441  compute_drws_energy(obs, events, select, zetamin, timebin);
442  }
443 
444  // Method B: Phibar-dependent weighting
445  else if (method == "phibar") {
446  compute_drws_phibar(obs, events, select, zetamin, timebin);
447  }
448 
449  // Method C: Veto rate weighting
450  else if (method == "vetorate") {
451  compute_drws_vetorate(obs, events, select, zetamin);
452  }
453 
454  // Normalise Phibar layers of all DRWs to unity
455  for (int i = 0; i < size(); ++i) {
456 
457  // Loop over Phibar layers
458  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
459 
460  // Compute sum in Phibar layer
461  double sum = 0.0;
462  int istart = iphibar * dri->m_dri.npix();
463  int istop = istart + dri->m_dri.npix();
464  for (int inx = istart; inx < istop; ++inx) {
465  sum += m_dris[i][inx];
466  }
467 
468  // Normalise by sum
469  if (sum != 0.0) {
470  for (int inx = istart; inx < istop; ++inx) {
471  m_dris[i][inx] /= sum;
472  }
473  }
474 
475  } // endfor: looped over Phibar layers
476 
477  // Set the Good Time interval for DRWs
478  if (m_dris[i].m_num_used_superpackets > 0) {
479  m_dris[i].m_gti = GGti(dri->m_tstart, dri->m_tstop);
480  }
481 
482  } // endfor: looped over DRWs
483 
484  } // endif: there were DRWs in container
485 
486  // Return
487  return;
488 }
489 
490 
491 /***********************************************************************//**
492  * @brief Print Data Space container
493  *
494  * @param[in] chatter Chattiness.
495  * @return String containing Data Space container information.
496  ***************************************************************************/
497 std::string GCOMDris::print(const GChatter& chatter) const
498 {
499  // Initialise result string
500  std::string result;
501 
502  // Continue only if chatter is not silent
503  if (chatter != SILENT) {
504 
505  // Append header
506  result.append("=== GCOMDris ===");
507 
508  // Append container information
509  result.append("\n"+gammalib::parformat("Number of DRIs"));
510  result.append(gammalib::str(size()));
511 
512  } // endif: chatter was not silent
513 
514  // Return result
515  return result;
516 }
517 
518 
519 /*==========================================================================
520  = =
521  = Private methods =
522  = =
523  ==========================================================================*/
524 
525 /***********************************************************************//**
526  * @brief Initialise class members
527  ***************************************************************************/
529 {
530  // Initialise members
531  m_dris.clear();
532 
533  // Initialise working arrays
538  m_wrk_rate.clear();
539  m_wrk_use_sp.clear();
540 
541  // Return
542  return;
543 }
544 
545 
546 /***********************************************************************//**
547  * @brief Copy class members
548  *
549  * @param[in] dris Data Space container.
550  ***************************************************************************/
552 {
553  // Copy members
554  m_dris = dris.m_dris;
555 
556  // Copy working arrays
557  m_wrk_counts = dris.m_wrk_counts;
561  m_wrk_rate = dris.m_wrk_rate;
562  m_wrk_use_sp = dris.m_wrk_use_sp;
563 
564  // Return
565  return;
566 }
567 
568 
569 /***********************************************************************//**
570  * @brief Delete class members
571  ***************************************************************************/
573 {
574  // Return
575  return;
576 }
577 
578 
579 /***********************************************************************//**
580  * @brief Compute background weighting cubes using energy dependent rates
581  *
582  * @param[in] obs COMPTEL observation.
583  * @param[in] events COMPTEL event list.
584  * @param[in] select Selection set.
585  * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
586  * @param[in] timebin Time binning for rate determination (sec).
587  *
588  * Compute DRW cubes for a COMPTEL observation. DRW cubes are event-rate
589  * weighted geometry cubes which were multiplied by the solid angle of
590  * the (Chi,Psi) pixels.
591  *
592  * For this method the event rates depend on time and energy. Three
593  * hard-wired energy ranges are defined for which the event rate is
594  * determined:
595  *
596  * E < 1.8 MeV
597  * 1.8 < E < 4.3 MeV
598  * E > 4.3 MeV
599  *
600  * For each superpacket, the event rates are linearly interpolated to the
601  * relevant superpacket time.
602  *
603  * The DRW cubes are normalised so that the sum of each Phibar layer equals
604  * to unity.
605  ***************************************************************************/
607  const GCOMEventList* events,
608  const GCOMSelection& select,
609  const double& zetamin,
610  const double& timebin)
611 {
612  // Debug
613  #if defined(G_DEBUG_COMPUTE_DRWS)
614  std::cout << "GCOMDris::compute_drws_energy" << std::endl;
615  std::cout << "=============================" << std::endl;
616  #endif
617 
618  // Initialise D1 & D2 module status
619  GCOMStatus status;
620 
621  // Get pointer to first DRW in container (for convenient access to members
622  // of GCOMDri; we won't use it for modifications, hence we can declare it
623  // as constant)
624  const GCOMDri* dri = &(m_dris[0]);
625 
626  // Debug
627  #if defined(G_DEBUG_COMPUTE_DRWS)
628  std::cout << "Determine energy-dependent event rates" << std::endl;
629  std::cout << "--------------------------------------" << std::endl;
630  #endif
631 
632  // Initialise current time and vectors for computation of node function
633  // and vectors for energy-dependent rate interpolation
634  double time;
635  double rate0 = 0.0;
636  double rate1 = 0.0;
637  double rate2 = 0.0;
638  GNodeArray times;
639  std::vector<double> rates0;
640  std::vector<double> rates1;
641  std::vector<double> rates2;
642  bool set = false;
643 
644  // Set time of first event
645  if (events->size() > 0) {
646  time = (*events)[0]->time().secs();
647  }
648 
649  // Determine energy-dependent event rates. The standard event selection
650  // criteria and earth horizon cut is applied so that the event rate
651  // corresponds to the current selection, yet we do not consider any
652  // Good Time Intervals or OAD time information as we later only access
653  // relevant times (YET THERE COULD BE AN ISSUE WITH A GLITCH). Rates
654  // are computed for three hard-coded energy intervals.
655  for (int i_evt = 0; i_evt < events->size(); ++i_evt) {
656 
657  // Get pointer to event
658  const GCOMEventAtom* event = (*events)[i_evt];
659 
660  // Apply event selection
661  if (!select.use_event(*event)) {
662  continue;
663  }
664 
665  // Apply Earth horizon cut. Note that we need to correct later
666  // for this cut to remove the additional time variation coming
667  // from the cut.
668  if ((event->eha() - event->phibar()) < zetamin) {
669  continue;
670  }
671 
672  // If time exceeds time bin then add rates
673  while (event->time().secs() > (time + timebin)) {
674 
675  // If rates are not all zero then append rates to vectors
676  if (set) {
677 
678  // Append time at mid-point of interval
679  times.append(time + 0.5 * timebin);
680 
681  // Append rates
682  rates0.push_back(rate0);
683  rates1.push_back(rate1);
684  rates2.push_back(rate2);
685 
686  // Debug
687  #if defined(G_DEBUG_COMPUTE_DRWS)
688  std::cout << "t=" << time + 0.5 * timebin;
689  std::cout << " r0=" << rate0;
690  std::cout << " r1=" << rate1;
691  std::cout << " r2=" << rate2;
692  std::cout << std::endl;
693  #endif
694 
695  // Initialise rates for new accumulation
696  rate0 = 0.0;
697  rate1 = 0.0;
698  rate2 = 0.0;
699  set = false;
700 
701  } // endif: there were rates to append
702 
703  // Increment time
704  time += timebin;
705 
706  } // endwhile: event time was after the current integration time stop
707 
708  // Accumulate rates
709  double energy = event->energy().MeV();
710  if (energy < 1.8) {
711  rate0 += 1.0;
712  set = true;
713  }
714  else if (energy < 4.3) {
715  rate1 += 1.0;
716  set = true;
717  }
718  else {
719  rate2 += 1.0;
720  set = true;
721  }
722 
723  } // endfor: looped over events
724 
725  // Append remaining rates
726  if (set) {
727 
728  // Append time at mid-point of interval
729  times.append(time + 0.5 * timebin);
730 
731  // Append rates
732  rates0.push_back(rate0);
733  rates1.push_back(rate1);
734  rates2.push_back(rate2);
735 
736  } // endif: appended remaining rates
737 
738  // Debug
739  #if defined(G_DEBUG_COMPUTE_DRWS)
740  std::cout << "Compute DRWs" << std::endl;
741  std::cout << "------------" << std::endl;
742  #endif
743 
744  // Allocate geometry factor and Earth horizon angle working arrays
745  std::vector<double> geometry(dri->m_dri.npix());
746  std::vector<double> eha(dri->m_dri.npix());
747 
748  // Get Good Time Intervals. If a pulsar selection is specified then
749  // reduce the Good Time Intervals to the validity intervals of the
750  // pulsar emphemerides.
751  GCOMTim tim = obs.tim();
752  if (select.has_pulsar()) {
753  tim.reduce(select.pulsar().validity());
754  }
755 
756  // Loop over Orbit Aspect Data
757  for (int i_oad = 0; i_oad < obs.oads().size(); ++i_oad) {
758 
759  // Get reference to Orbit Aspect Data of superpacket
760  const GCOMOad &oad = obs.oads()[i_oad];
761 
762  // Check superpacket usage for all DRWs so that their statistics
763  // get correctly updated
764  bool skip = false;
765  for (int i = 0; i < size(); ++i) {
766  if (!m_dris[i].use_superpacket(oad, tim, select)) {
767  skip = true;
768  }
769  }
770  if (skip) {
771  continue;
772  }
773 
774  // Get Orbit Aspect Data mid-time in seconds
775  double time = oad.tstart().secs() + 0.5 * (oad.tstop() - oad.tstart());
776 
777  // Compute energy-dependent rates
778  std::vector<double> rates;
779  for (int i = 0; i < size(); ++i) {
780  if (m_dris[i].m_ebounds.emin().MeV() > 4.3) {
781  rates.push_back(times.interpolate(time, rates2));
782  }
783  else if (m_dris[i].m_ebounds.emin().MeV() > 1.8) {
784  rates.push_back(times.interpolate(time, rates1));
785  }
786  else {
787  rates.push_back(times.interpolate(time, rates0));
788  }
789  }
790 
791  // Debug
792  #if defined(G_DEBUG_COMPUTE_DRWS)
793  std::cout << "time=" << time;
794  for (int i = 0; i < size(); ++i) {
795  std::cout << " r[" << i << "]=" << rates[i];
796  }
797  std::cout << std::endl;
798  #endif
799 
800  // Prepare Earth horizon angle computation. The celestial system
801  // is reinterpreted as the COMPTEL coordinate system, where the
802  // 90 degrees - zenith angle becomes the declination and the azimuth
803  // angle becomes Right Ascension. This allows us later to use the
804  // GSkyDir::dist method to compute the distance between the geocentre
805  // and the telescope Z-axis.
806  double theta_geocentre = double(oad.gcel());
807  double phi_geocentre = double(oad.gcaz());
808  GSkyDir geocentre_comptel;
809  geocentre_comptel.radec_deg(phi_geocentre, 90.0-theta_geocentre);
810 
811  // Compute solid-angle-corrected geometry factors and Earth horizon
812  // angles for all (Chi,Psi) pixels
813  for (int index = 0; index < dri->m_dri.npix(); ++index) {
814 
815  // Get sky direction and solid angle for (Chi, Psi)
816  GSkyDir sky = dri->m_dri.inx2dir(index);
817  double omega = dri->m_dri.solidangle(index);
818 
819  // Convert sky direction to COMPTEL coordinates
820  double theta = oad.theta(sky);
821  double phi = oad.phi(sky);
822 
823  // Compute geometric factor summed over all D1, D2 times
824  // the solid angle of the weighting cube pixel
825  geometry[index] = dri->compute_geometry(oad.tjd(), theta, phi,
826  select, status) * omega;
827 
828  // Compute Earth horizon angle as the distance between the Earth
829  // centre in COMPTEL coordinates and the (Chi, Psi) pixel in
830  // COMPTEL coordinates minus the radius of the Earth.
831  GSkyDir chipsi_comptel;
832  chipsi_comptel.radec_deg(phi, 90.0-theta);
833  eha[index] = geocentre_comptel.dist_deg(chipsi_comptel) - oad.georad();
834 
835  } // endfor: computed solid-angle-corrected geometry factors
836 
837  // Loop over all DRWs
838  for (int i = 0; i < size(); ++i) {
839 
840  // Compute Earth horizon cut correction factor
841  double rates_sum_all = 0.0;
842  double rates_sum_cut = 0.0;
843  double ehacorr = 1.0;
844  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
845 
846  // Sum product of geometry and rates for all pixels
847  for (int index = 0; index < dri->m_dri.npix(); ++index) {
848  rates_sum_all += geometry[index] * rates[i];
849  }
850 
851  // Sum product of geometry and rates for pixels passing
852  // the Earth horizon cut
853  double ehamin = double(iphibar) * dri->m_phibin + zetamin;
854  for (int index = 0; index < dri->m_dri.npix(); ++index) {
855  if (eha[index] >= ehamin) {
856  rates_sum_cut += geometry[index] * rates[i];
857  }
858  }
859 
860  } // endfor: looped over Phibar
861 
862  // If something passes the Earth horizon cut then compute the
863  // correction factor now
864  if (rates_sum_cut != 0.0) {
865  ehacorr = rates_sum_all / rates_sum_cut;
866  }
867 
868  // Loop over all Phibar layers
869  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
870 
871  // Compute minimum Earth horizon angle for Phibar layer
872  double ehamin = double(iphibar) * dri->m_phibin + zetamin;
873 
874  // Loop over all (Chi,Psi) pixels
875  for (int index = 0; index < dri->m_dri.npix(); ++index) {
876 
877  // If Earth horizon angle is equal or larger than the minimum
878  // requirement then add up the rate weighted geometry factor
879  if (eha[index] >= ehamin) {
880 
881  // Get data space index
882  int inx = index + iphibar * dri->m_dri.npix();
883 
884  // Store product as DRW value
885  m_dris[i][inx] += geometry[index] * rates[i] * ehacorr;
886 
887  } // endif: Earth horizon cut passed
888 
889  } // endfor: looped over (Chi, Psi)
890 
891  } // endfor: looped over Phibar
892 
893  } // endfor: looped over all DRWs
894 
895  } // endfor: looped over Orbit Aspect Data
896 
897  // Return
898  return;
899 }
900 
901 
902 /***********************************************************************//**
903  * @brief Compute background weighting cubes using Phibar dependent rates
904  *
905  * @param[in] obs COMPTEL observation.
906  * @param[in] events COMPTEL event list.
907  * @param[in] select Selection set.
908  * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
909  * @param[in] timebin Time binning for rate determination (sec).
910  *
911  * Compute DRW cubes for a COMPTEL observation. DRW cubes are event-rate
912  * weighted geometry cubes which were multiplied by the solid angle of
913  * the (Chi,Psi) pixels.
914  *
915  * For this method the event rates depend on time and Phibar angle. For
916  * each superpacket, the event rates are linearly interpolated to the
917  * relevant superpacket time.
918  *
919  * The DRW cubes are normalised so that the sum of each Phibar layer equals
920  * to unity.
921  ***************************************************************************/
923  const GCOMEventList* events,
924  const GCOMSelection& select,
925  const double& zetamin,
926  const double& timebin)
927 {
928  // Set constants
929  const double ehacorrmax = 10.0; //!< Maximum EHA correction factor
930 
931  // Debug
932  #if defined(G_DEBUG_COMPUTE_DRWS)
933  std::cout << "GCOMDris::compute_drws_phibar" << std::endl;
934  std::cout << "=============================" << std::endl;
935  #endif
936 
937  // Initialise D1 & D2 module status
938  GCOMStatus status;
939 
940  // Get pointer to first DRW in container (for convenient access to members
941  // of GCOMDri; we won't use it for modifications, hence we can declare it
942  // as constant)
943  const GCOMDri* dri = &(m_dris[0]);
944 
945  // Debug
946  #if defined(G_DEBUG_COMPUTE_DRWS)
947  std::cout << "Determine Phibar-dependent event rates" << std::endl;
948  std::cout << "--------------------------------------" << std::endl;
949  #endif
950 
951  // Initialise current time and vectors for computation of node function
952  // and vectors for energy-dependent rate interpolation
953  double time;
954  std::vector<double> rate(dri->nphibar());
955  GNodeArray times;
956  std::vector<std::vector<double> > rates(dri->nphibar());
957  bool set = false;
958 
959  // Set time of first event
960  if (events->size() > 0) {
961  time = (*events)[0]->time().secs();
962  }
963 
964  // Determine energy-dependent event rates. The standard event selection
965  // criteria and earth horizon cut is applied so that the event rate
966  // corresponds to the current selection, yet we do not consider any
967  // Good Time Intervals or OAD time information as we later only access
968  // relevant times.
969  for (int i_evt = 0; i_evt < events->size(); ++i_evt) {
970 
971  // Get pointer to event
972  const GCOMEventAtom* event = (*events)[i_evt];
973 
974  // Apply event selection
975  if (!select.use_event(*event)) {
976  continue;
977  }
978 
979  // Apply Earth horizon cut. Note that we need to correct later
980  // for this cut to remove the additional time variation coming
981  // from the cut.
982  #if defined(G_COMPUTE_DRWS_EHACORR)
983  if ((event->eha() - event->phibar()) < zetamin) {
984  continue;
985  }
986  #endif
987 
988  // If time exceeds time bin then add rates
989  while (event->time().secs() > (time + timebin)) {
990 
991  // If rates are set then append rates to vectors
992  if (set) {
993 
994  // Append time at mid-point of interval
995  times.append(time + 0.5 * timebin);
996 
997  // Append rates and initialise for new accumulation
998  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
999  rates[iphibar].push_back(rate[iphibar]);
1000  rate[iphibar] = 0.0;
1001  }
1002 
1003  // Signal that rates were not yet set
1004  set = false;
1005 
1006  } // endif: there were rates to append
1007 
1008  // Increment time
1009  time += timebin;
1010 
1011  } // endwhile: event time was after the current integration time stop
1012 
1013  // Accumulate rates
1014  int iphibar = int((event->phibar() - dri->phimin()) / dri->phibin());
1015  if (iphibar >= 0 and iphibar < dri->nphibar()) {
1016  rate[iphibar] += 1.0;
1017  set = true;
1018  }
1019 
1020  } // endfor: looped over events
1021 
1022  // Append remaining rates
1023  if (set) {
1024 
1025  // Append time at mid-point of interval
1026  times.append(time + 0.5 * timebin);
1027 
1028  // Append rates
1029  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
1030  rates[iphibar].push_back(rate[iphibar]);
1031  }
1032 
1033  } // endif: appended remaining rates
1034 
1035  // Debug: write debug file
1036  #if defined(G_DEBUG_COMPUTE_DRWS)
1037  std::ofstream debugfile;
1038  debugfile.open("compute_drws_phibar_tbin_rates.csv");
1039  debugfile.precision(12);
1040  for (int i = 0; i < times.size(); ++i) {
1041  debugfile << times[i];
1042  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
1043  debugfile << "," << rates[iphibar][i];
1044  }
1045  debugfile << std::endl;
1046  }
1047  debugfile.close();
1048  #endif
1049 
1050  // Debug
1051  #if defined(G_DEBUG_COMPUTE_DRWS)
1052  std::cout << "Compute DRWs" << std::endl;
1053  std::cout << "------------" << std::endl;
1054  #endif
1055 
1056  // Allocate geometry factor and Earth horizon angle working arrays
1057  std::vector<double> geometry(dri->m_dri.npix());
1058  std::vector<double> eha(dri->m_dri.npix());
1059 
1060  // Get Good Time Intervals. If a pulsar selection is specified then
1061  // reduce the Good Time Intervals to the validity intervals of the
1062  // pulsar emphemerides.
1063  GCOMTim tim = obs.tim();
1064  if (select.has_pulsar()) {
1065  tim.reduce(select.pulsar().validity());
1066  }
1067 
1068  // Debug: open debug files file
1069  #if defined(G_DEBUG_COMPUTE_DRWS)
1070  std::ofstream debugfile1;
1071  std::ofstream debugfile2;
1072  debugfile1.open("compute_drws_phibar_sp_rates.csv");
1073  debugfile2.open("compute_drws_phibar_sp_ehacorr.csv");
1074  debugfile1.precision(12);
1075  debugfile2.precision(12);
1076  #endif
1077 
1078  // Loop over Orbit Aspect Data
1079  for (int i_oad = 0; i_oad < obs.oads().size(); ++i_oad) {
1080 
1081  // Get reference to Orbit Aspect Data of superpacket
1082  const GCOMOad &oad = obs.oads()[i_oad];
1083 
1084  // Check superpacket usage for all DRWs so that their statistics
1085  // get correctly updated
1086  bool skip = false;
1087  for (int i = 0; i < size(); ++i) {
1088  if (!m_dris[i].use_superpacket(oad, tim, select)) {
1089  skip = true;
1090  }
1091  }
1092  if (skip) {
1093  continue;
1094  }
1095 
1096  // Get Orbit Aspect Data mid-time in seconds
1097  double time = oad.tstart().secs() + 0.5 * (oad.tstop() - oad.tstart());
1098 
1099  // Compute Phibar-dependent rates by interpolation of precomputed
1100  // rate vectors. Make sure that rates never become negative.
1101  std::vector<double> rate_oad(dri->nphibar());
1102  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
1103  rate_oad[iphibar] = times.interpolate(time, rates[iphibar]);
1104  if (rate_oad[iphibar] < 0.0) {
1105  rate_oad[iphibar] = 0.0;
1106  }
1107  }
1108 
1109  // Prepare Earth horizon angle computation. The celestial system
1110  // is reinterpreted as the COMPTEL coordinate system, where the
1111  // 90 degrees - zenith angle becomes the declination and the azimuth
1112  // angle becomes Right Ascension. This allows us later to use the
1113  // GSkyDir::dist method to compute the distance between the geocentre
1114  // and the telescope Z-axis.
1115  double theta_geocentre = double(oad.gcel());
1116  double phi_geocentre = double(oad.gcaz());
1117  GSkyDir geocentre_comptel;
1118  geocentre_comptel.radec_deg(phi_geocentre, 90.0-theta_geocentre);
1119 
1120  // Compute solid-angle-corrected geometry factors and Earth horizon
1121  // angles for all (Chi,Psi) pixels
1122  for (int index = 0; index < dri->m_dri.npix(); ++index) {
1123 
1124  // Get sky direction and solid angle for (Chi, Psi)
1125  GSkyDir sky = dri->m_dri.inx2dir(index);
1126  double omega = dri->m_dri.solidangle(index);
1127 
1128  // Convert sky direction to COMPTEL coordinates
1129  double theta = oad.theta(sky);
1130  double phi = oad.phi(sky);
1131 
1132  // Compute geometric factor summed over all D1, D2 times
1133  // the solid angle of the weighting cube pixel
1134  geometry[index] = dri->compute_geometry(oad.tjd(), theta, phi,
1135  select, status) * omega;
1136 
1137  // Compute Earth horizon angle as the distance between the Earth
1138  // centre in COMPTEL coordinates and the (Chi, Psi) pixel in
1139  // COMPTEL coordinates minus the radius of the Earth.
1140  GSkyDir chipsi_comptel;
1141  chipsi_comptel.radec_deg(phi, 90.0-theta);
1142  eha[index] = geocentre_comptel.dist_deg(chipsi_comptel) - oad.georad();
1143 
1144  } // endfor: computed solid-angle-corrected geometry factors
1145 
1146  // Debug: write time in debug files
1147  #if defined(G_DEBUG_COMPUTE_DRWS)
1148  debugfile1 << time;
1149  debugfile2 << time;
1150  #endif
1151 
1152  // Correct rates for Earth horizon cut
1153  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
1154 
1155  // Compute minimum Earth Horizon angle for Phibar layer
1156  double ehamin = double(iphibar) * dri->m_phibin + zetamin;
1157 
1158  // Initialise sums
1159  double rates_sum_all = 0.0;
1160  double rates_sum_cut = 0.0;
1161 
1162  // Sum geometry for all pixels and pixels passing the Earth horizon cut
1163  for (int index = 0; index < dri->m_dri.npix(); ++index) {
1164  rates_sum_all += geometry[index];
1165  if (eha[index] >= ehamin) {
1166  rates_sum_cut += geometry[index];
1167  }
1168  }
1169 
1170  // Compute Earth horizon cut correction, limited to a maximum of ehacorrmax
1171  double ehacorr = (rates_sum_cut != 0.0) ? rates_sum_all / rates_sum_cut : ehacorrmax;
1172  if (ehacorr > ehacorrmax) {
1173  ehacorr = ehacorrmax;
1174  }
1175 
1176  // Correct rate
1177  #if defined(G_COMPUTE_DRWS_EHACORR)
1178  rate_oad[iphibar] *= ehacorr;
1179  #endif
1180 
1181  // Debug: write rate and correction in debug files
1182  #if defined(G_DEBUG_COMPUTE_DRWS)
1183  debugfile1 << "," << rate_oad[iphibar];
1184  debugfile2 << "," << ehacorr;
1185  #endif
1186 
1187  } // endfor: looped over Phibar
1188 
1189  // Debug: write linefeeds in debug files
1190  #if defined(G_DEBUG_COMPUTE_DRWS)
1191  debugfile1 << std::endl;
1192  debugfile2 << std::endl;
1193  #endif
1194 
1195  // Loop over all DRWs
1196  for (int i = 0; i < size(); ++i) {
1197 
1198  // Loop over all Phibar layers
1199  for (int iphibar = 0; iphibar < dri->nphibar(); ++iphibar) {
1200 
1201  // Compute minimum Earth horizon angle for Phibar layer
1202  double ehamin = double(iphibar) * dri->m_phibin + zetamin;
1203 
1204  // Loop over all (Chi,Psi) pixels
1205  for (int index = 0; index < dri->m_dri.npix(); ++index) {
1206 
1207  // If Earth horizon angle is equal or larger than the minimum
1208  // requirement then add up the rate weighted geometry factor
1209  if (eha[index] >= ehamin) {
1210 
1211  // Get data space index
1212  int inx = index + iphibar * dri->m_dri.npix();
1213 
1214  // Store product as DRW value
1215  m_dris[i][inx] += geometry[index] * rate_oad[iphibar];
1216 
1217  } // endif: Earth horizon cut passed
1218 
1219  } // endfor: looped over (Chi, Psi)
1220 
1221  } // endfor: looped over Phibar
1222 
1223  } // endfor: looped over all DRWs
1224 
1225  } // endfor: looped over Orbit Aspect Data
1226 
1227  // Debug: close debug files
1228  #if defined(G_DEBUG_COMPUTE_DRWS)
1229  debugfile1.close();
1230  debugfile2.close();
1231  #endif
1232 
1233  // Return
1234  return;
1235 }
1236 
1237 
1238 /***********************************************************************//**
1239  * @brief Compute background weighting cubes using veto rates
1240  *
1241  * @param[in] obs COMPTEL observation.
1242  * @param[in] events COMPTEL event list.
1243  * @param[in] select Selection set.
1244  * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
1245  *
1246  * Compute DRW cubes for a COMPTEL observation. DRW cubes are event-rate
1247  * weighted geometry cubes which were multiplied by the solid angle of
1248  * the (Chi,Psi) pixels.
1249  ***************************************************************************/
1251  const GCOMEventList* events,
1252  const GCOMSelection& select,
1253  const double& zetamin)
1254 {
1255  // Debug
1256  #if defined(G_DEBUG_COMPUTE_DRWS)
1257  std::cout << "GCOMDris::compute_drws_vetorate" << std::endl;
1258  std::cout << "===============================" << std::endl;
1259  #endif
1260 
1261  // Setup working arrays
1262  vetorate_setup(obs, events, select, zetamin);
1263 
1264  // Debug: Save working arrays in FITS file
1265  #if defined(G_DEBUG_SAVE_WORKING_ARRAYS)
1266  vetorate_save("debug_gcomdris_compute_drws_vetorate.fits");
1267  vetorate_load("debug_gcomdris_compute_drws_vetorate.fits");
1268  #endif
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 
1275  // Fit working arrays to determine f_prompt parameter
1276  vetorate_fit();
1277  for (int iter = 0; iter < 4; ++iter) { //!< Perform 4 iterations
1279  vetorate_fit();
1280  }
1281 
1282  // Generate DRWs
1283  vetorate_generate(obs, select, zetamin);
1284 
1285  // Finish DRWs
1286  vetorate_finish(obs);
1287 
1288  // Return
1289  return;
1290 }
1291 
1292 
1293 /***********************************************************************//**
1294  * @brief Setup working arrays for vetorate computation
1295  *
1296  * @param[in] obs COMPTEL observation.
1297  * @param[in] events COMPTEL event list.
1298  * @param[in] select Selection set.
1299  * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
1300  *
1301  * Setup working arrays for vetorate DRW computation. There are five working
1302  * arrays:
1303  *
1304  * @c m_wrk_counts is a 3D working array spanned by superpacket index,
1305  * phibar layer and energy bin, containing the number of events passing the
1306  * event selections for the specified bin.
1307  *
1308  * @c m_wrk_ehacutcorr is a 2D working array spanned by superpacket index
1309  * and phibar layer, containing the fraction of the solid-angle weighted
1310  * geometry that passes the Earth horizon cut for the specified bin. This
1311  * array represents the response to a given incident event rate.
1312  *
1313  * @c m_wrk_vetorate is a 1D working array, containing the veto rate as
1314  * function of superpacket index.
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  *
1319  * @c m_wrk_use_sp is a 1D working array, signalling the usage of a given
1320  * superpacket.
1321  *
1322  * Note that the method also sets the superpacket usage and event selection
1323  * statistics of all DRWs.
1324  ***************************************************************************/
1326  const GCOMEventList* events,
1327  const GCOMSelection& select,
1328  const double& zetamin)
1329 {
1330  // Debug
1331  #if defined(G_DEBUG_COMPUTE_DRWS)
1332  std::cout << "GCOMDris::vetorate_setup" << std::endl;
1333  std::cout << "========================" << std::endl;
1334  #endif
1335 
1336  // Initialise D1 & D2 module status
1337  GCOMStatus status;
1338 
1339  // Get pointer to first DRW (assume their definition is identical)
1340  const GCOMDri* dri0 = &(m_dris[0]);
1341 
1342  // Extract dimensions
1343  int noads = obs.oads().size();
1344  int npix = dri0->m_dri.npix();
1345  int nphibar = dri0->nphibar();
1346  int neng = size();
1347 
1348  // Debug
1349  #if defined(G_DEBUG_COMPUTE_DRWS)
1350  std::cout << "Number of OAD superpackets: " << noads << std::endl;
1351  std::cout << "Number of pixels: " << npix << std::endl;
1352  std::cout << "Number of Phibar layers: " << nphibar << std::endl;
1353  std::cout << "Number of energies: " << neng << std::endl;
1354  #endif
1355 
1356  // Define working arrays
1357  m_wrk_counts = GNdarray(noads, nphibar, neng);
1358  m_wrk_ehacutcorr = GNdarray(noads, nphibar);
1359  m_wrk_vetorate = GNdarray(noads);
1360  m_wrk_activrate = GNdarray(noads, neng);
1361  m_wrk_use_sp = std::vector<bool>(noads);
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 
1368  // Allocate further working arrays
1369  GNdarray geo(npix);
1370  GNdarray eha(npix);
1371 
1372  // Setup node array and rate vector for veto rate interpolation
1373  const GCOMHkd& hdk = obs.hkds()["SCV2M"];
1374  GNodeArray veto_times;
1375  std::vector<double> veto_rates;
1376  veto_times.reserve(hdk.size());
1377  veto_rates.reserve(hdk.size());
1378  for (int i = 0; i < hdk.size(); ++i) {
1379  double rate = hdk.value(i);
1380  if (rate > 0.0) {
1381  veto_times.append(hdk.time(i).secs());
1382  veto_rates.push_back(rate);
1383  }
1384  }
1385 
1386  // Setup sky directions and solid angles for all (Chi, Psi)
1387  std::vector<GSkyDir> skys;
1388  std::vector<double> omegas;
1389  for (int index = 0; index < dri0->m_dri.npix(); ++index) {
1390  GSkyDir sky = dri0->m_dri.inx2dir(index);
1391  double omega = dri0->m_dri.solidangle(index);
1392  skys.push_back(sky);
1393  omegas.push_back(omega);
1394  }
1395 
1396  // Debug
1397  #if defined(G_DEBUG_COMPUTE_DRWS)
1398  std::cout << "Setup node array for veto rate interpolation: ";
1399  std::cout << veto_times.size() << " times, ";
1400  std::cout << veto_rates.size() << " rates" << std::endl;
1401  #endif
1402 
1403  // Get Good Time Intervals. If a pulsar selection is specified then
1404  // reduce the Good Time Intervals to the validity intervals of the
1405  // pulsar emphemerides.
1406  GCOMTim tim = obs.tim();
1407  if (select.has_pulsar()) {
1408  tim.reduce(select.pulsar().validity());
1409  }
1410 
1411  // Initialise event and superpacket counters
1412  int i_evt = 0;
1413  int i_sp = 0;
1414 
1415  // Signal that loop should be terminated
1416  bool terminate = false;
1417 
1418  // Loop over Orbit Aspect Data
1419  for (int i_oad = 0; i_oad < noads; ++i_oad) {
1420 
1421  // Get reference to Orbit Aspect Data of superpacket
1422  const GCOMOad &oad = obs.oads()[i_oad];
1423 
1424  // Check superpacket usage for all DRWs so that their statistics
1425  // get correctly updated
1426  for (int i = 0; i < size(); ++i) {
1427  if (m_dris[i].use_superpacket(oad, tim, select)) {
1428  m_wrk_use_sp[i_oad] = true;
1429  }
1430  }
1431  if (!m_wrk_use_sp[i_oad]) {
1432  continue;
1433  }
1434 
1435  // Get Orbit Aspect Data mid-time in seconds
1436  double time = oad.tstart().secs() + 0.5 * (oad.tstop() - oad.tstart());
1437 
1438  // Prepare Earth horizon angle computation. The celestial system
1439  // is reinterpreted as the COMPTEL coordinate system, where the
1440  // 90 degrees - zenith angle becomes the declination and the azimuth
1441  // angle becomes Right Ascension. This allows us later to use the
1442  // GSkyDir::dist method to compute the distance between the geocentre
1443  // and the telescope Z-axis.
1444  double theta_geocentre = double(oad.gcel());
1445  double phi_geocentre = double(oad.gcaz());
1446  GSkyDir geocentre_comptel;
1447  geocentre_comptel.radec_deg(phi_geocentre, 90.0-theta_geocentre);
1448 
1449  // Compute solid-angle-corrected geometry factors and Earth horizon
1450  // angles for all (Chi,Psi) pixels
1451  double total_geo = 0.0;
1452  for (int index = 0; index < npix; ++index) {
1453 
1454  // Convert sky direction to COMPTEL coordinates
1455  double theta = oad.theta(skys[index]);
1456  double phi = oad.phi(skys[index]);
1457 
1458  // Compute geometric factor summed over all D1, D2 times
1459  // the solid angle of the weighting cube pixel
1460  double geometry = dri0->compute_geometry(oad.tjd(), theta, phi,
1461  select, status) * omegas[index];
1462 
1463  // Store and sum up geometric factor
1464  geo(index) = geometry;
1465  total_geo += geometry;
1466 
1467  // Compute Earth horizon angle as the distance between the Earth
1468  // centre in COMPTEL coordinates and the (Chi, Psi) pixel in
1469  // COMPTEL coordinates minus the radius of the Earth.
1470  GSkyDir chipsi_comptel;
1471  chipsi_comptel.radec_deg(phi, 90.0-theta);
1472  eha(index) = geocentre_comptel.dist_deg(chipsi_comptel) - oad.georad();
1473 
1474  } // endfor: looped over (Chi, Psi)
1475 
1476  // Compute Earth horizon cut correction factor for all Phibar layers
1477  if (total_geo > 0.0) {
1478  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1479  double ehamin = double(iphibar) * dri0->m_phibin + zetamin;
1480  double accepted_geo = 0.0;
1481  for (int index = 0; index < npix; ++index) {
1482  if (eha(index) >= ehamin) {
1483  accepted_geo += geo(index);
1484  }
1485  }
1486  m_wrk_ehacutcorr(i_sp, iphibar) = accepted_geo / total_geo;
1487  }
1488  }
1489 
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.
1493  if (!veto_times.is_empty()) {
1494  double value = veto_times.interpolate(time, veto_rates);
1495  if (value > 0.0) {
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  }
1500  }
1501  }
1502 
1503  // Collect all events within superpacket and store result in 3D array.
1504  // Break if the end of the event list was reached.
1505  for (; i_evt < events->size(); ++i_evt) {
1506 
1507  // Get pointer to event
1508  const GCOMEventAtom* event = (*events)[i_evt];
1509 
1510  // Break loop if the end of the superpacket was reached
1511  if (event->time() > oad.tstop()) {
1512  break;
1513  }
1514 
1515  // Determine energy bin
1516  int ienergy = -1;
1517  for (int i = 0; i < size(); ++i) {
1518  if ((event->energy() >= m_dris[i].m_ebounds.emin()) &&
1519  (event->energy() <= m_dris[i].m_ebounds.emax())) {
1520  ienergy = i;
1521  break;
1522  }
1523  }
1524 
1525  // Skip event if it is not contained in any energy bin
1526  if (ienergy == -1) {
1527  continue;
1528  }
1529 
1530  // Get pointer to appropriate DRW
1531  const GCOMDri* dri = &(m_dris[ienergy]);
1532 
1533  // Check GTIs if the DRW has GTIs
1534  if (dri->gti().size() > 0) {
1535 
1536  // Skip event if it lies before the GTI start
1537  if (event->time() < dri->gti().tstart()) {
1538  continue;
1539  }
1540 
1541  // Break Orbit Aspect Data loop if event lies after the GTI stop
1542  else if (event->time() > dri->gti().tstop()) {
1543  terminate = true;
1544  break;
1545  }
1546 
1547  } // endif: DRW had GTIs
1548 
1549  // Skip event if it lies before the superpacket start
1550  if (event->time() < oad.tstart()) {
1551  continue;
1552  }
1553 
1554  // Apply event selection
1555  if (!dri->m_selection.use_event(*event)) {
1556  continue;
1557  }
1558 
1559  // Compute Compton scatter angle index. Skip if it's invalid.
1560  int iphibar = int((event->phibar() - dri->m_phimin) / dri->m_phibin);
1561  if (iphibar < 0) {
1562  continue;
1563  }
1564  else if (iphibar >= dri->nphibar()) {
1565  continue;
1566  }
1567 
1568  // Check for Earth horizon angle. There is a constant EHA limit
1569  // over a Phibar layer to be compliant with the DRG.
1570  double ehamin = double(iphibar) * dri->m_phibin + zetamin;
1571  if (event->eha() < ehamin) {
1572  continue;
1573  }
1574 
1575  // Now fill the event in the 3D counts array
1576  m_wrk_counts(i_sp, iphibar, ienergy) += 1.0;
1577 
1578  } // endfor: collected events
1579 
1580  // Debug
1581  #if defined(G_DEBUG_COMPUTE_DRWS)
1582  std::cout << "Superpacket " << i_oad;
1583  std::cout << " i_sp=" << i_sp;
1584  std::cout << " time=" << time;
1585  std::cout << " vetorate=" << m_wrk_vetorate(i_oad);
1586  std::cout << " total_geo=" << total_geo;
1587  std::cout << std::endl;
1588  #endif
1589 
1590  // Increment superpacket counter
1591  i_sp++;
1592 
1593  // Break Orbit Aspect Data loop if termination was signalled or if there
1594  // are no more events
1595  if (terminate || i_evt >= events->size()) {
1596  break;
1597  }
1598 
1599  } // endfor: looped over Orbit Aspect Data
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 
1623  // Return
1624  return;
1625 }
1626 
1627 
1628 /***********************************************************************//**
1629  * @brief Fit working arrays for vetorate computation
1630  *
1631  * Determines the f_prompt parameter for each energy bin using a maximum
1632  * log-likelihood fit using the data in the working arrays for each energy
1633  * bin. Based on the fitted f_prompt parameter the method also computes the
1634  * expected background rate time variation for each energy bin.
1635  ***************************************************************************/
1637 {
1638  // Set constants
1639  const double norm = 1.0; // Model normalisation
1640 
1641  // Debug
1642  #if defined(G_DEBUG_COMPUTE_DRWS)
1643  std::cout << "GCOMDris::vetorate_fit" << std::endl;
1644  std::cout << "======================" << std::endl;
1645  #endif
1646 
1647  // Extract dimension from working arrays
1648  int nsp = m_wrk_counts.shape()[0];
1649  int nphibar = m_wrk_counts.shape()[1];
1650  int neng = m_wrk_counts.shape()[2];
1651 
1652  // Debug
1653  #if defined(G_DEBUG_COMPUTE_DRWS)
1654  std::cout << "Number of used superpackets: " << nsp << std::endl;
1655  std::cout << "Number of Phibar layers: " << nphibar << std::endl;
1656  std::cout << "Number of energies: " << neng << std::endl;
1657  #endif
1658 
1659  // Setup rate result array
1660  m_wrk_rate = GNdarray(nsp, neng);
1661 
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);
1667  }
1668  }
1669  if (nvetorate > 0.0) {
1670  for (int isp = 0; isp < nsp; ++isp) {
1671  m_wrk_vetorate(isp) /= nvetorate;
1672  }
1673  }
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  }
1687  }
1688  }
1689 
1690  // Loop over energy bins
1691  for (int ieng = 0; ieng < neng; ++ieng) {
1692 
1693  // Set fprompt parameter
1694  GOptimizerPars pars;
1695  GOptimizerPar par("fprompt", m_dris[ieng].m_drw_fprompt);
1696  par.range(0.0, 1.0);
1697  par.factor_gradient(1.0); // To avoid zero gradient log message
1698  pars.append(par);
1699 
1700  // Set fit function
1701  GCOMDris::likelihood fct(this, ieng, norm);
1702 
1703  // Optimize function and compute errors
1704  #if defined(G_DEBUG_COMPUTE_DRWS)
1705  GLog log;
1706  log.cout(true);
1707  GOptimizerLM opt(&log);
1708  #else
1709  GOptimizerLM opt;
1710  #endif
1711  opt.eps(0.1);
1712  opt.max_iter(500);
1713  opt.optimize(fct, pars);
1714  opt.errors(fct, pars);
1715 
1716  // Retrieve logL
1717  double logL = opt.value();
1718 
1719  // Recover fprompt parameter and errors
1720  double fprompt = pars[0]->value();
1721  double e_fprompt = pars[0]->error();
1722  double factiv = 1.0 - fprompt;
1723 
1724  // Set resulting rate vector for this energy bin
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);
1728  }
1729 
1730  // Set DRW header members
1731  m_dris[ieng].m_drw_status = opt.status_string();
1732  m_dris[ieng].m_drw_fprompt = fprompt;
1733  m_dris[ieng].m_drw_e_fprompt = e_fprompt;
1734  m_dris[ieng].m_drw_iter = opt.iter();
1735 
1736  // Debug: Print fit results
1737  #if defined(G_DEBUG_COMPUTE_DRWS)
1738  std::cout << ieng;
1739  std::cout << " logL=" << logL;
1740  std::cout << " fprompt=" << fprompt << " +/- " << e_fprompt;
1741  std::cout << std::endl;
1742  #endif
1743 
1744  } // endfor: looped over energy bins
1745 
1746  // Return
1747  return;
1748 }
1749 
1750 
1751 /***********************************************************************//**
1752  * @brief Update activation rate
1753  ***************************************************************************/
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 /***********************************************************************//**
1882  * @brief Generate DRWs
1883  *
1884  * @param[in] obs COMPTEL observation.
1885  * @param[in] select Selection set.
1886  * @param[in] zetamin Minimum Earth horizon - Phibar cut (deg).
1887  ***************************************************************************/
1889  const GCOMSelection& select,
1890  const double& zetamin)
1891 {
1892  // Debug
1893  #if defined(G_DEBUG_COMPUTE_DRWS)
1894  std::cout << "GCOMDris::vetorate_generate" << std::endl;
1895  std::cout << "===========================" << std::endl;
1896  #endif
1897 
1898  // Initialise D1 & D2 module status
1899  GCOMStatus status;
1900 
1901  // Get pointer to first DRW (assume their definition is identical)
1902  const GCOMDri* dri0 = &(m_dris[0]);
1903 
1904  // Extract dimensions
1905  int noads = obs.oads().size();
1906  int npix = dri0->m_dri.npix();
1907  int nphibar = dri0->nphibar();
1908  int neng = size();
1909 
1910  // Debug
1911  #if defined(G_DEBUG_COMPUTE_DRWS)
1912  std::cout << "Number of OAD superpackets: " << noads << std::endl;
1913  std::cout << "Number of pixels: " << npix << std::endl;
1914  std::cout << "Number of Phibar layers: " << nphibar << std::endl;
1915  std::cout << "Number of energies: " << neng << std::endl;
1916  #endif
1917 
1918  // Allocate geometry factor and Earth horizon angle working arrays
1919  GNdarray geometry(npix);
1920  GNdarray eha(npix);
1921 
1922  // Setup sky directions and solid angles for all (Chi, Psi)
1923  std::vector<GSkyDir> skys;
1924  std::vector<double> omegas;
1925  for (int index = 0; index < npix; ++index) {
1926  GSkyDir sky = dri0->m_dri.inx2dir(index);
1927  double omega = dri0->m_dri.solidangle(index);
1928  skys.push_back(sky);
1929  omegas.push_back(omega);
1930  }
1931 
1932  // Get Good Time Intervals. If a pulsar selection is specified then
1933  // reduce the Good Time Intervals to the validity intervals of the
1934  // pulsar emphemerides.
1935  GCOMTim tim = obs.tim();
1936  if (select.has_pulsar()) {
1937  tim.reduce(select.pulsar().validity());
1938  }
1939 
1940  // Initialise superpacket counter
1941  int i_sp = 0;
1942 
1943  // Loop over Orbit Aspect Data
1944  for (int i_oad = 0; i_oad < noads; ++i_oad) {
1945 
1946  // Get reference to Orbit Aspect Data of superpacket
1947  const GCOMOad &oad = obs.oads()[i_oad];
1948 
1949  // Skip not-to-be-used superpackets
1950  if (!m_wrk_use_sp[i_oad]) {
1951  continue;
1952  }
1953 
1954  // Prepare Earth horizon angle computation. The celestial system
1955  // is reinterpreted as the COMPTEL coordinate system, where the
1956  // 90 degrees - zenith angle becomes the declination and the azimuth
1957  // angle becomes Right Ascension. This allows us later to use the
1958  // GSkyDir::dist method to compute the distance between the geocentre
1959  // and the telescope Z-axis.
1960  double theta_geocentre = double(oad.gcel());
1961  double phi_geocentre = double(oad.gcaz());
1962  GSkyDir geocentre_comptel;
1963  geocentre_comptel.radec_deg(phi_geocentre, 90.0-theta_geocentre);
1964 
1965  // Compute solid-angle-corrected geometry factors and Earth horizon
1966  // angles for all (Chi,Psi) pixels
1967  for (int index = 0; index < npix; ++index) {
1968 
1969  // Convert sky direction to COMPTEL coordinates
1970  double theta = oad.theta(skys[index]);
1971  double phi = oad.phi(skys[index]);
1972 
1973  // Compute geometric factor summed over all D1, D2 times
1974  // the solid angle of the weighting cube pixel
1975  geometry(index) = dri0->compute_geometry(oad.tjd(), theta, phi,
1976  select, status) * omegas[index];
1977 
1978  // Compute Earth horizon angle as the distance between the Earth
1979  // centre in COMPTEL coordinates and the (Chi, Psi) pixel in
1980  // COMPTEL coordinates minus the radius of the Earth.
1981  GSkyDir chipsi_comptel;
1982  chipsi_comptel.radec_deg(phi, 90.0-theta);
1983  eha(index) = geocentre_comptel.dist_deg(chipsi_comptel) - oad.georad();
1984 
1985  } // endfor: computed solid-angle-corrected geometry factors
1986 
1987  // Loop over all DRWs
1988  for (int i = 0; i < size(); ++i) {
1989 
1990  // Get pointer to appropriate DRW
1991  const GCOMDri* dri = &(m_dris[i]);
1992 
1993  // Loop over all Phibar layers
1994  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
1995 
1996  // Compute minimum Earth horizon angle for Phibar layer
1997  double ehamin = double(iphibar) * dri->m_phibin + zetamin;
1998 
1999  // Loop over all (Chi,Psi) pixels
2000  for (int index = 0; index < npix; ++index) {
2001 
2002  // If Earth horizon angle is equal or larger than the minimum
2003  // requirement then add up the rate weighted geometry factor
2004  if (eha(index) >= ehamin) {
2005 
2006  // Get data space index
2007  int inx = index + iphibar * npix;
2008 
2009  // Store geometry weighted with rate as DRW
2010  m_dris[i][inx] += geometry(index) * m_wrk_rate(i_sp, i);
2011 
2012  } // endif: Earth horizon cut passed
2013 
2014  } // endfor: looped over (Chi, Psi)
2015 
2016  } // endfor: looped over Phibar
2017 
2018  // Set binary table information
2019 
2020  } // endfor: looped over all DRWs
2021 
2022  // Increment superpacket counter
2023  i_sp++;
2024 
2025  } // endfor: looped over Orbit Aspect Data
2026 
2027  // Return
2028  return;
2029 }
2030 
2031 
2032 /***********************************************************************//**
2033  * @brief Finish DRWs
2034  *
2035  * @param[in] obs COMPTEL observation.
2036  *
2037  * Set DRW binary tables
2038  ***************************************************************************/
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 /***********************************************************************//**
2120  * @brief Save working arrays for vetorate computation
2121  *
2122  * @param[in] filename FITS filename.
2123  *
2124  * Save working arrays for vetorate DRW computation in FITS file.
2125  ***************************************************************************/
2126 void GCOMDris::vetorate_save(const GFilename& filename) const
2127 {
2128  // Debug
2129  #if defined(G_DEBUG_COMPUTE_DRWS)
2130  std::cout << "GCOMDris::vetorate_save" << std::endl;
2131  std::cout << "=======================" << std::endl;
2132  #endif
2133 
2134  // Extract dimension from working arrays
2135  int noads = m_wrk_use_sp.size();
2136  int nsp = m_wrk_counts.shape()[0];
2137  int nphibar = m_wrk_counts.shape()[1];
2138  int neng = m_wrk_counts.shape()[2];
2139 
2140  // Allocate FITS images
2141  GFitsImageDouble image_counts(nsp, nphibar, neng);
2142  GFitsImageDouble image_ehacutcorr(nsp, nphibar);
2143  GFitsImageDouble image_vetorate(nsp);
2144  GFitsImageDouble image_activrate(nsp, neng);
2145  GFitsImageShort image_use_sp(noads);
2146 
2147  // Fill FITS images from working arrays
2148  for (int isp = 0; isp < nsp; ++isp) {
2149  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2150  for (int ieng = 0; ieng < neng; ++ieng) {
2151  image_counts(isp, iphibar, ieng) = m_wrk_counts(isp, iphibar, ieng);
2152  }
2153  image_ehacutcorr(isp, iphibar) = m_wrk_ehacutcorr(isp, iphibar);
2154  }
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;
2162  }
2163 
2164  // Set image attributes
2165  image_counts.extname("COUNTS");
2166  image_ehacutcorr.extname("EHACUTCORR");
2167  image_vetorate.extname("VETORATE");
2168  image_activrate.extname("ACTIVRATE");
2169  image_use_sp.extname("SPUSAGE");
2170 
2171  // Create FITS file and append images
2172  GFits fits;
2173  fits.append(image_counts);
2174  fits.append(image_ehacutcorr);
2175  fits.append(image_vetorate);
2176  fits.append(image_activrate);
2177  fits.append(image_use_sp);
2178 
2179  // Save FITS file
2180  fits.saveto(filename, true);
2181 
2182  // Return
2183  return;
2184 }
2185 
2186 
2187 /***********************************************************************//**
2188  * @brief Load working arrays for vetorate computation
2189  *
2190  * @param[in] filename FITS filename.
2191  *
2192  * Load working arrays for vetorate DRW computation from FITS file.
2193  ***************************************************************************/
2194 void GCOMDris::vetorate_load(const GFilename& filename)
2195 {
2196  // Debug
2197  #if defined(G_DEBUG_COMPUTE_DRWS)
2198  std::cout << "GCOMDris::vetorate_load" << std::endl;
2199  std::cout << "=======================" << std::endl;
2200  #endif
2201 
2202  // Open FITS file
2203  GFits fits(filename);
2204 
2205  // Get images
2206  const GFitsImage* image_counts = fits.image("COUNTS");
2207  const GFitsImage* image_ehacutcorr = fits.image("EHACUTCORR");
2208  const GFitsImage* image_vetorate = fits.image("VETORATE");
2209  const GFitsImage* image_activrate = fits.image("ACTIVRATE");
2210  const GFitsImage* image_use_sp = fits.image("SPUSAGE");
2211 
2212  // Extract dimensions
2213  int noads = image_use_sp->naxes(0);
2214  int nsp = image_counts->naxes(0);
2215  int nphibar = image_counts->naxes(1);
2216  int neng = image_counts->naxes(2);
2217 
2218  // Debug
2219  #if defined(G_DEBUG_COMPUTE_DRWS)
2220  std::cout << "Number of OAD superpackets: " << noads << std::endl;
2221  std::cout << "Number of used superpackets: " << nsp << std::endl;
2222  std::cout << "Number of Phibar layers: " << nphibar << std::endl;
2223  std::cout << "Number of energies: " << neng << std::endl;
2224  #endif
2225 
2226  // Allocate working array
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);
2231  m_wrk_use_sp = std::vector<bool>(noads);
2232 
2233  // Extract data from images
2234  for (int isp = 0; isp < nsp; ++isp) {
2235  for (int iphibar = 0; iphibar < nphibar; ++iphibar) {
2236  for (int ieng = 0; ieng < neng; ++ieng) {
2237  m_wrk_counts(isp, iphibar, ieng) = image_counts->pixel(isp, iphibar, ieng);
2238  }
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);
2243  }
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);
2248  }
2249 
2250  // Close FITS file
2251  fits.close();
2252 
2253  // Return
2254  return;
2255 }
2256 
2257 
2258 /***********************************************************************//**
2259  * @brief Log-likelihood function constructor
2260  *
2261  * @param[in] dris Parent calling likelihood function.
2262  * @param[in] ieng DRW energy bin.
2263  * @param[in] norm Normalisation constant.
2264  *
2265  * Constructs the log-likelihood function that is used to determine the
2266  * value of f_prompt.
2267  ***************************************************************************/
2269  const int& ieng,
2270  const double& norm) : GOptimizerFunction()
2271 {
2272  // Store arguments
2273  m_this = dris;
2274  m_ieng = ieng;
2275  m_norm = norm;
2276 
2277  // Set gradient and curvature members
2278  m_gradient = GVector(1);
2279  m_curvature = GMatrixSparse(1,1);
2280 
2281  // Extract dimension from working array
2282  m_nsp = m_this->m_wrk_counts.shape()[0];
2284 
2285  // Multiply veto and constant rate by EHA cut correction. Rates are zero
2286  // in case that the vetorate is zero.
2290  for (int isp = 0; isp < m_nsp; ++isp) {
2291  double vetorate = m_this->m_wrk_vetorate(isp);
2292  if (vetorate > 0.0) {
2293  double activrate = m_this->m_wrk_activrate(isp, ieng);
2294  for (int iphibar = 0; iphibar < m_nphibar; ++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);
2298  }
2299  }
2300  }
2301 
2302  // Compute rate sums
2306  for (int iphibar = 0; iphibar < m_nphibar; ++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);
2310  }
2311  m_diffrate_sum(iphibar) = m_vetorate_sum(iphibar) - m_activrate_sum(iphibar);
2312  }
2313 
2314  // Return
2315  return;
2316 }
2317 
2318 
2319 /***********************************************************************//**
2320  * @brief Log-likelihood function evaluation
2321  *
2322  * @param[in] pars Function parameters.
2323  *
2324  * Computes the log-likelihood function, its gradient and its curvature at
2325  * the specified function parameters.
2326  ***************************************************************************/
2328 {
2329  // Recover parameters
2330  double fprompt = pars[0]->value();
2331  double factiv = 1.0 - fprompt;
2332 
2333  // Allocate phibar normalisation arrays
2334  GNdarray nevents(m_nphibar);
2335  GNdarray nmodel(m_nphibar);
2336  GNdarray norm(m_nphibar);
2337 
2338  // Compute model
2339  GNdarray model = fprompt * m_vetorate + factiv * m_activrate;
2340 
2341  // Compute Phibar normalised model
2342  GNdarray model_norm = model;
2343  for (int iphibar = 0; iphibar < m_nphibar; ++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);
2348  }
2349  }
2350  if (nmodel(iphibar) > 0.0) {
2351  norm(iphibar) = m_norm * nevents(iphibar) / nmodel(iphibar);
2352  for (int isp = 0; isp < m_nsp; ++isp) {
2353  model_norm(isp, iphibar) *= norm(iphibar);
2354  }
2355  }
2356  }
2357 
2358  // Compute LogL
2359  m_value = 0.0;
2360  for (int isp = 0; isp < m_nsp; ++isp) {
2361  for (int iphibar = 0; iphibar < m_nphibar; ++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);
2365  }
2366  }
2367  }
2368 
2369  // Evaluate gradient and curvature
2370  for (int iphibar = 0; iphibar < m_nphibar; ++iphibar) {
2371 
2372  // Precompute normalisation gradient
2373  double nmodel2 = nmodel(iphibar) * nmodel(iphibar);
2374  double g_norm = -m_norm * nevents(iphibar) / nmodel2 * m_diffrate_sum(iphibar);
2375 
2376  // Loop over superpackets
2377  for (int isp = 0; isp < m_nsp; ++isp) {
2378 
2379  // Continue only if model is positive
2380  if (model_norm(isp, iphibar) > 0.0) {
2381 
2382  // Pre computation
2383  double fb = m_this->m_wrk_counts(isp, iphibar, m_ieng) / model_norm(isp, iphibar);
2384  double fc = (1.0 - fb);
2385  double fa = fb / model_norm(isp, iphibar);
2386 
2387  // Compute parameter gradient
2388  double g = norm(iphibar) * m_diffrate(isp, iphibar) + g_norm * model(isp, iphibar);
2389 
2390  // Update gradient
2391  m_gradient[0] += fc * g;
2392 
2393  // Update curvature
2394  m_curvature(0,0) += fa * g * g;
2395 
2396  } // endif: model was positive
2397 
2398  } // endfor: looped over superpackets
2399 
2400  } // endfor: looped over Phibar
2401 
2402  // Return
2403  return;
2404 }
COMPTEL instrument status class.
Definition: GCOMStatus.hpp:49
int size(void) const
Return number of nodes in node array.
Definition: GNodeArray.hpp:192
COMPTEL instrument status class definition.
GCOMDris * m_this
Pointer to GCOMDris object.
Definition: GCOMDris.hpp:115
const double & value(const int &index) const
Return reference to Housekeeping Data value.
Definition: GCOMHkd.cpp:356
GCOMDris & operator=(const GCOMDris &dris)
Assignment operator.
Definition: GCOMDris.cpp:140
void compute_drws(const GCOMObservation &obs, const GCOMSelection &select=GCOMSelection(), const double &zetamin=5.0, const double &timebin=300.0, const std::string &method="phibar")
Compute background weighting cubes.
Definition: GCOMDris.cpp:378
Double precision FITS image class definition.
FITS table double column class interface definition.
Abstract FITS image base class.
Definition: GFitsImage.hpp:43
virtual void eval(const GOptimizerPars &pars)
Log-likelihood function evaluation.
Definition: GCOMDris.cpp:2327
const GCOMOads & oads(void) const
Return Orbit Aspect Data.
Optimizer function abstract base class.
const double & factor_gradient(void) const
Return parameter factor gradient.
double norm(const GVector &vector)
Computes vector norm.
Definition: GVector.cpp:864
Node array class.
Definition: GNodeArray.hpp:60
void max_iter(const int &max_iter)
Set maximum number of iterations.
GTime m_tstart
Selection start time.
Definition: GCOMDri.hpp:165
void clear(void)
Clear array.
Definition: GNdarray.cpp:527
GCOMSelection m_selection
Selection parameters.
Definition: GCOMDri.hpp:181
Sparse matrix class interface definition.
const double & phimin(void) const
Return minimum Compton scatter angle of DRI cube.
Definition: GCOMDri.hpp:371
Definition of COMPTEL tools.
const GCOMHkds & hkds(void) const
Return Housekeeping Data collection.
GNdarray m_diffrate
Vetorate - activation rate array.
Definition: GCOMDris.hpp:108
void reserve(const int &num)
Reserves space for Data space instances in container.
Definition: GCOMDris.hpp:240
virtual double value(void) const
Return function value.
COMPTEL Data Space container class.
Definition: GCOMDris.hpp:56
GSkyMap m_dri
Data cube.
Definition: GCOMDri.hpp:156
COMPTEL Data Space class definition.
COMPTEL event list class definition.
double m_phibin
Phibar binsize (deg)
Definition: GCOMDri.hpp:160
Optimizer parameter container class.
GNdarray m_wrk_counts
3D event cube array
Definition: GCOMDris.hpp:154
COMPTEL observation class interface definition.
COMPTEL event atom class definition.
const float & gcel(void) const
Return Geocentre zenith angle.
Definition: GCOMOad.hpp:283
virtual void optimize(GOptimizerFunction &fct, GOptimizerPars &pars)
Optimize function parameters.
void reserve(const int &num)
Reserves space for nodes in node array.
Definition: GNodeArray.hpp:220
double sum(const GVector &vector)
Computes vector sum.
Definition: GVector.cpp:944
GMatrixSparse m_curvature
Curvature matrix.
Definition: GCOMDris.hpp:114
void compute_drws_phibar(const GCOMObservation &obs, const GCOMEventList *events, const GCOMSelection &select, const double &zetamin, const double &timebin)
Compute background weighting cubes using Phibar dependent rates.
Definition: GCOMDris.cpp:922
GFitsTableCol * append(const GFitsTableCol &column)
Append column to the table.
Definition: GFitsTable.hpp:147
bool is_empty(void) const
Signals if there are no Data space instances in container.
Definition: GCOMDris.hpp:226
double phi(const GSkyDir &sky) const
Return azimuth angle of sky direction in COMPTEL coordinates.
Definition: GCOMOad.hpp:475
GCOMDris(void)
Void constructor.
Definition: GCOMDris.cpp:87
#define G_REMOVE
Definition: GCOMDris.cpp:60
const GTime & tstop(void) const
Return stop time of superpacket.
Definition: GCOMOad.hpp:167
const std::vector< int > & shape(void) const
Return shape of array.
Definition: GNdarray.hpp:308
int size(void) const
Return number of Orbit Aspect Data in container.
Definition: GCOMOads.hpp:141
FITS file class.
Definition: GFits.hpp:63
likelihood(GCOMDris *dris, const int &ieng, const double &norm)
Log-likelihood function constructor.
Definition: GCOMDris.cpp:2268
FITS file class interface definition.
GNdarray m_vetorate
Vetorate array multiplied by EHA cut correction.
Definition: GCOMDris.hpp:106
COMPTEL Data Space container class definition.
COMPTEL selection set class.
COMPTEL Good Time Intervals class definition.
GNdarray backward(void) const
Backward Fast Fourier Transform.
Definition: GFft.cpp:401
void vetorate_save(const GFilename &filename) const
Save working arrays for vetorate computation.
Definition: GCOMDris.cpp:2126
GVector m_gradient
Gradient vector.
Definition: GCOMDris.hpp:113
const float & georad(void) const
Return apparent radius of Earth.
Definition: GCOMOad.hpp:312
int m_nsp
Number of superpackets.
Definition: GCOMDris.hpp:104
COMPTEL Orbit Aspect Data class.
Definition: GCOMOad.hpp:49
void extend(const GCOMDris &dris)
Append Data Space container.
Definition: GCOMDris.cpp:332
void cout(const bool &flag)
Set standard output stream (cout) flag.
Definition: GLog.hpp:275
Implementation of support function used by COMPTEL classes.
int size(void) const
Return number of Good Time Intervals.
Definition: GGti.hpp:154
virtual void clear(void)
Clear binary table.
GCOMDri & at(const int &index)
Return reference to Data Space.
Definition: GCOMDris.cpp:204
bool is_empty(void) const
Signals if there are no nodes in node array.
Definition: GNodeArray.hpp:206
const GTime & tstart(void) const
Return start time of superpacket.
Definition: GCOMOad.hpp:136
COMPTEL selection set class definition.
void saveto(const GFilename &filename, const bool &clobber=false)
Saves to specified FITS file.
Definition: GFits.cpp:1293
void vetorate_fit(void)
Fit working arrays for vetorate computation.
Definition: GCOMDris.cpp:1636
Information logger interface definition.
Definition: GLog.hpp:62
const GCOMTim & tim(void) const
Return COMPTEL Good Time Intervals.
virtual int size(void) const
Return number of events in list.
bool has_pulsar(void) const
Signals that pulsar selection should be performed.
GSkyDir inx2dir(const int &index) const
Returns sky direction of pixel.
Definition: GSkyMap.cpp:1331
Double precision FITS image class.
Filename class.
Definition: GFilename.hpp:62
GNdarray m_vetorate_sum
Time integrated vetorate array.
Definition: GCOMDris.hpp:109
GTime m_tstop
Selection stop time.
Definition: GCOMDri.hpp:166
Fast Fourier Transformation class.
Definition: GFft.hpp:57
void copy_members(const GCOMDris &dris)
Copy class members.
Definition: GCOMDris.cpp:551
virtual ~GCOMDris(void)
Destructor.
Definition: GCOMDris.cpp:118
GNdarray m_wrk_vetorate
1D vetorates array
Definition: GCOMDris.hpp:156
virtual double pixel(const int &ix) const =0
double compute_geometry(const int &tjd, const double &theta, const double &phi, const GCOMSelection &select, const GCOMStatus &status) const
Compute DRG geometry factor.
Definition: GCOMDri.cpp:1506
GVector log(const GVector &vector)
Computes natural logarithm of vector elements.
Definition: GVector.cpp:1274
double interpolate(const double &value, const std::vector< double > &vector) const
Interpolate value.
Definition: GNodeArray.cpp:536
void free_members(void)
Delete class members.
Definition: GCOMDris.cpp:572
GNdarray m_activrate_sum
Time integrated activation rate array.
Definition: GCOMDris.hpp:110
GNdarray m_wrk_rate
2D rate array
Definition: GCOMDris.hpp:158
GChatter
Definition: GTypemaps.hpp:33
GCOMDris * clone(void) const
Clone Data Space container.
Definition: GCOMDris.cpp:188
Optimizer parameters base class definition.
Good Time Interval class.
Definition: GGti.hpp:62
Short integer FITS image class.
std::string print(const GChatter &chatter=NORMAL) const
Print Data Space container.
Definition: GCOMDris.cpp:497
int size(void) const
Return number of Housekeeping Data in container.
Definition: GCOMHkd.hpp:112
void init_members(void)
Initialise class members.
Definition: GCOMDris.cpp:528
GNdarray m_wrk_activrate
2D activation rate array
Definition: GCOMDris.hpp:157
void radec_deg(const double &ra, const double &dec)
Set equatorial sky direction (degrees)
Definition: GSkyDir.cpp:224
N-dimensional array class.
Definition: GNdarray.hpp:44
const GTime & tstop(void) const
Returns latest stop time in Good Time Intervals.
Definition: GGti.hpp:207
Levenberg Marquardt optimizer class interface definition.
const GTime & time(const int &index) const
Return reference to Housekeeping Data time.
Definition: GCOMHkd.cpp:304
const GPulsar & pulsar(void) const
Return pulsar.
const std::string & extname(void) const
Return extension name.
Definition: GFitsHDU.hpp:162
const GTime & tstart(void) const
Returns earliest start time in Good Time Intervals.
Definition: GGti.hpp:194
Short integer FITS image class definition.
void vetorate_finish(const GCOMObservation &obs)
Finish DRWs.
Definition: GCOMDris.cpp:2039
FITS table long integer column.
void vetorate_load(const GFilename &filename)
Load working arrays for vetorate computation.
Definition: GCOMDris.cpp:2194
GNdarray m_activrate
Activation rate array multiplied by EHA cut correction.
Definition: GCOMDris.hpp:107
#define G_INSERT
Definition: GCOMDris.cpp:59
int nphibar(void) const
Return number of Phibar bins.
Definition: GCOMDri.hpp:266
void clear(void)
Clear Data Space container.
Definition: GCOMDris.cpp:170
GOptimizerPar * append(const GOptimizerPar &par)
Append parameter to container.
#define G_COMPUTE_DRWS
Definition: GCOMDris.cpp:61
int naxes(const int &axis) const
Return dimension of an image axis.
Definition: GFitsImage.cpp:344
Fast Fourier transformation class interface definition.
COMPTEL Housekeeping Data container class.
Definition: GCOMHkd.hpp:49
bool use_event(const GCOMEventAtom &event) const
Check if event should be used.
double m_norm
Normalisation value.
Definition: GCOMDris.hpp:103
const GGti & gti(void) const
Return Good Time Intervals of DRI cube.
Definition: GCOMDri.hpp:344
int m_ieng
DRW energy bin.
Definition: GCOMDris.hpp:102
std::vector< bool > m_wrk_use_sp
1D superpacket usage array
Definition: GCOMDris.hpp:159
GFitsImage * image(const int &extno)
Get pointer to image HDU.
Definition: GFits.cpp:368
const double & secs(void) const
Return time in seconds in native reference (TT)
Definition: GTime.hpp:156
std::vector< GCOMDri > m_dris
Data space instances.
Definition: GCOMDris.hpp:151
GGti validity(void) const
Return validity intervals of pulsar ephemerides.
Definition: GPulsar.cpp:286
void compute_drws_vetorate(const GCOMObservation &obs, const GCOMEventList *events, const GCOMSelection &select, const double &zetamin)
Compute background weighting cubes using veto rates.
Definition: GCOMDris.cpp:1250
GFitsBinTable m_drw_table
DRW binary table to append to the FITS file.
Definition: GCOMDri.hpp:173
const int & tjd(void) const
Return Truncated Julian Days of Orbit Aspect Record.
Definition: GCOMOad.hpp:196
void range(const double &min, const double &max)
Set minimum and maximum parameter boundaries.
Interface class for COMPTEL observations.
virtual int iter(void) const
Return number of iterations.
GNdarray m_diffrate_sum
Time integrated difference rate array.
Definition: GCOMDris.hpp:111
virtual void errors(GOptimizerFunction &fct, GOptimizerPars &pars)
Compute parameter uncertainties.
virtual GEvents * events(void)
Return events.
Exception handler interface definition.
FITS table long integer column class interface definition.
void compute_drws_energy(const GCOMObservation &obs, const GCOMEventList *events, const GCOMSelection &select, const double &zetamin, const double &timebin)
Compute background weighting cubes using energy dependent rates.
Definition: GCOMDris.cpp:606
GFitsHDU * append(const GFitsHDU &hdu)
Append HDU to FITS file.
Definition: GFits.cpp:678
COMPTEL event list class.
COMPTEL Data Space class.
Definition: GCOMDri.hpp:62
GVector exp(const GVector &vector)
Computes exponential of vector elements.
Definition: GVector.cpp:1232
GCOMDri & insert(const int &index, const GCOMDri &dri)
Insert Data Space into container.
Definition: GCOMDris.cpp:271
Optimizer parameter class interface definition.
Vector class.
Definition: GVector.hpp:46
COMPTEL Good Time Intervals class.
Definition: GCOMTim.hpp:50
double solidangle(const int &index) const
Returns solid angle of pixel.
Definition: GSkyMap.cpp:1858
void vetorate_setup(const GCOMObservation &obs, const GCOMEventList *events, const GCOMSelection &select, const double &zetamin)
Setup working arrays for vetorate computation.
Definition: GCOMDris.cpp:1325
int size(void) const
Return number of Data space instances in container.
Definition: GCOMDris.hpp:211
const int & tics(void) const
Return tics of Orbit Aspect Record.
Definition: GCOMOad.hpp:225
int m_nphibar
Number of phibar layers.
Definition: GCOMDris.hpp:105
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
void append(const double &node)
Append one node to array.
Definition: GNodeArray.cpp:351
void remove(const int &index)
Remove Data Space from container.
Definition: GCOMDris.cpp:307
const int & npix(void) const
Returns number of pixels.
Definition: GSkyMap.hpp:347
GNdarray m_wrk_ehacutcorr
2D geometry response array
Definition: GCOMDris.hpp:155
const double & phibin(void) const
Return Compton scatter angle bin of DRI cube.
Definition: GCOMDri.hpp:383
Sky direction class.
Definition: GSkyDir.hpp:62
void vetorate_update_activ(void)
Update activation rate.
Definition: GCOMDris.cpp:1754
void reduce(const GGti &gti)
Reduces Good Time Intervals to intersection with intervals.
Definition: GCOMTim.hpp:129
void close(void)
Close FITS file.
Definition: GFits.cpp:1342
void eps(const double &eps)
Set requested absolute convergence precision.
void vetorate_generate(const GCOMObservation &obs, const GCOMSelection &select, const double &zetamin)
Generate DRWs.
Definition: GCOMDris.cpp:1888
Levenberg Marquardt optimizer class.
GCOMDri & append(const GCOMDri &dri)
Append Data Space to container.
Definition: GCOMDris.cpp:249
#define G_AT
Definition: GCOMDris.cpp:58
double m_phimin
Phibar minimum (deg)
Definition: GCOMDri.hpp:159
FITS table double column.
double theta(const GSkyDir &sky) const
Return zenith angle of sky direction in COMPTEL coordinates.
Definition: GCOMOad.hpp:460
COMPTEL Orbit Aspect Data container class definition.
COMPTEL Orbit Aspect Data class definition.
Mathematical function definitions.
const float & gcaz(void) const
Return Geocentre azimuth angle.
Definition: GCOMOad.hpp:254
std::string status_string(void) const
Set fit status string.
COMPTEL event atom class.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
Optimizer parameter class.