GammaLib 2.1.0.dev
Loading...
Searching...
No Matches
GSPIModelDataSpace.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GSPIModelDataSpace.cpp - INTEGRAL/SPI data space model *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2020-2025 by Juergen Knoedlseder *
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 GSPIModelDataSpace.cpp
23 * @brief INTEGRAL/SPI data space model implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <typeinfo>
32#include "GException.hpp"
33#include "GTools.hpp"
34#include "GTimes.hpp"
35#include "GVector.hpp"
36#include "GMatrixSparse.hpp"
37#include "GModelPar.hpp"
38#include "GModelRegistry.hpp"
40#include "GSPIObservation.hpp"
41#include "GSPIEventBin.hpp"
42#include "GSPITools.hpp"
43
44/* __ Constants __________________________________________________________ */
45
46/* __ Globals ____________________________________________________________ */
48const GModelRegistry g_spi_data_space_registry(&g_spi_data_space_seed);
49
50/* __ Method name definitions ____________________________________________ */
51#define G_CONSTRUCTOR "GSPIModelDataSpace::GSPIModelDataSpace("\
52 "GSPIObservation&, std::string&, std::string&, int&)"
53#define G_EVAL1 "GSPIModelDataSpace::eval(GEvent&, GObservation&, bool&)"
54#define G_EVAL2 "GSPIModelDataSpace::eval(GObservation&, GMatrixSparse*)"
55#define G_SETUP "GSPIModelDataSpace::setup(Observation&)"
56#define G_READ "GSPIModelDataSpace::read(GXmlElement&)"
57#define G_WRITE "GSPIModelDataSpace::write(GXmlElement&)"
58#define G_GET_DATE_TIME "GSPIModelDataSpace::get_date_time(std::string&)"
59
60/* __ Macros _____________________________________________________________ */
61
62/* __ Coding definitions _________________________________________________ */
63
64/* __ Debug definitions __________________________________________________ */
65//#define G_DUMP_MC //!< Dump MC information
66//#define G_DEBUG_SETUP //!< Debug setup method
67//#define G_DEBUG_SETUP_MODEL //!< Debug setup of model
68//#define G_DEBUG_SETUP_MODEL_MAP //!< Debug setup of parameter map
69//#define G_DEBUG_SETUP_MODEL_FIX //!< Debug fixing of parameters
70//#define G_DEBUG_SPLIT_POINTING //!< Debug splitting of pointing
71
72/*==========================================================================
73 = =
74 = Constructors/destructors =
75 = =
76 ==========================================================================*/
77
78/***********************************************************************//**
79 * @brief Void constructor
80 *
81 * Constructs an empty INTEGRAL/SPI data space model.
82 ***************************************************************************/
84{
85 // Initialise members
87
88 // Return
89 return;
90}
91
92
93/***********************************************************************//**
94 * @brief Model and method constructor
95 *
96 * @param[in] obs INTEGRAL/SPI observation.
97 * @param[in] name Model name.
98 * @param[in] method Fit method.
99 * @param[in] index Model index.
100 *
101 * @exception GException::out_of_range
102 * Model index out of range.
103 *
104 * Constructs an INTEGRAL/SPI data space model by setting the fit method
105 * and the model index.
106 *
107 * The constructor uses the INTEGRAL/SPI observation to setup the model
108 * parameters and the mapping of parameters to the data space.
109 ***************************************************************************/
111 const std::string& name,
112 const std::string& method,
113 const int& index) :
114 GModelData()
115{
116 // Initialise members
117 init_members();
118
119 // Set members
120 m_name = name;
121 m_method = method;
122 m_index = index;
123
124 // Setup model
125 setup(obs);
126
127 // Check whether the index is valid. We can only do this if the
128 // observation contains an event cube
129 GSPIEventCube* cube = dynamic_cast<GSPIEventCube*>(m_obs->events());
130 if (cube != NULL) {
131 int num_models = cube->models();
132 if (index < 0 || index >= num_models) {
133 throw GException::out_of_range(G_CONSTRUCTOR, "Invalid model index",
134 index, num_models);
135 }
136 }
137
138 // Return
139 return;
140}
141
142
143/***********************************************************************//**
144 * @brief XML constructor
145 *
146 * @param[in] xml XML element.
147 *
148 * Constructs an INTEGRAL/SPI data space model from the information that is
149 * found in an XML element. Please refer to the read() method to learn more
150 * about the information that is expected in the XML element.
151 ***************************************************************************/
153 GModelData(xml)
154{
155 // Initialise members
156 init_members();
157
158 // Read XML
159 read(xml);
160
161 // Return
162 return;
163}
164
165
166/***********************************************************************//**
167 * @brief Copy constructor
168 *
169 * @param[in] model INTEGRAL/SPI data space model.
170 *
171 * Constructs an INTEGRAL/SPI data space model by copying information from an
172 * existing model. Note that the copy is a deep copy, so the original object
173 * can be destroyed after the copy without any loss of information.
174 ***************************************************************************/
176 GModelData(model)
177{
178 // Initialise private members for clean destruction
179 init_members();
180
181 // Copy members
182 copy_members(model);
183
184 // Return
185 return;
186}
187
188
189/***********************************************************************//**
190 * @brief Destructor
191 *
192 * Destroys an INTEGRAL/SPI data space model.
193 ***************************************************************************/
195{
196 // Free members
197 free_members();
198
199 // Return
200 return;
201}
202
203
204/*==========================================================================
205 = =
206 = Operators =
207 = =
208 ==========================================================================*/
209
210/***********************************************************************//**
211 * @brief Assignment operator
212 *
213 * @param[in] model INTEGRAL/SPI data space model.
214 * @return INTEGRAL/SPI data space model
215 *
216 * Assigns the information from an INTEGRAL/SPI data space model to the
217 * class instance. Note that a deep copy of the information is performed, so
218 * the @p model instance can be destroyed after the assignment without any
219 * loss of information.
220 ***************************************************************************/
222{
223 // Execute only if object is not identical
224 if (this != &model) {
225
226 // Copy base class members
227 this->GModelData::operator=(model);
228
229 // Free members
230 free_members();
231
232 // Initialise members
233 init_members();
234
235 // Copy members
236 copy_members(model);
237
238 } // endif: object was not identical
239
240 // Return
241 return *this;
242}
243
244
245/*==========================================================================
246 = =
247 = Public methods =
248 = =
249 ==========================================================================*/
250
251/***********************************************************************//**
252 * @brief Clear instance
253 *
254 * Resets the object to a clean initial state. All information that resided
255 * in the object will be lost.
256 ***************************************************************************/
258{
259 // Free class members (base and derived classes, derived class first)
260 free_members();
262 this->GModel::free_members();
263
264 // Initialise members
265 this->GModel::init_members();
267 init_members();
268
269 // Return
270 return;
271}
272
273
274/***********************************************************************//**
275 * @brief Clone instance
276 *
277 * @return Pointer to deep copy of INTEGRAL/SPI data space model.
278 *
279 * Clone an INTEGRAL/SPI data space model. Cloning performs a deep copy of
280 * the information, so the original object can be destroyed after cloning
281 * without any loss of information.
282 ***************************************************************************/
284{
285 return new GSPIModelDataSpace(*this);
286}
287
288
289/***********************************************************************//**
290 * @brief Evaluate function
291 *
292 * @param[in] event Observed event.
293 * @param[in] obs Observation.
294 * @param[in] gradients Compute gradients?
295 * @return Model value.
296 *
297 * @exception GException::invalid_argument
298 * Observation is not an INTEGRAL/SPI observation.
299 * Event is not an INTEGRAL/SPI event bin.
300 *
301 * Evaluates the value of the INTEGRAL/SPI data space model for a given
302 * event and a given observation.
303 ***************************************************************************/
305 const GObservation& obs,
306 const bool& gradients) const
307{
308 // Reset parameter indices
309 m_has_eval_inx = false;
310 m_eval_inx.clear();
311
312 // Extract INTEGRAL/SPI event bin
313 const GSPIEventBin* bin = dynamic_cast<const GSPIEventBin*>(&event);
314 if (bin == NULL) {
315 std::string cls = std::string(typeid(&event).name());
316 std::string msg = "Event of type \""+cls+"\" is not an INTEGRAL/SPI "
317 "event bin. Please specify an INTEGRAL/SPI event "
318 "bin as argument.";
320 }
321
322 // Setup model
323 setup(obs);
324
325 // Initialise value
326 double value = 0.0;
327
328 // Continue only if model was initialised
329 if (m_index >= 0 && m_parameters.size() > 0) {
330
331 // Get bin size
332 double size = bin->size();
333
334 // Continue only if bin size is positive
335 if (size > 0.0) {
336
337 // Get bin index in data space
338 int index = bin->index();
339
340 // Get parameter index
341 int ipar = m_map[index];
342
343 // Get relevant model parameter
344 const GModelPar* par = &(m_parameters[ipar]);
345
346 // Get model value divided by size (note that the size will be
347 // multiplied-in later, hence here we need the model value divided
348 // by size)
349 value = bin->model(m_index) / size;
350
351 // Get model scale factor
352 double scale = par->value();
353
354 // Optionally compute gradients
355 if (gradients) {
356
357 // Compute partial derivative
358 double grad = (par->is_free()) ? value * par->scale() : 0.0;
359
360 // Set gradient
361 par->factor_gradient(grad);
362
363 // Signal that gradient for this parameter was set
364 m_has_eval_inx = true;
365 m_eval_inx.push_back(ipar);
366
367 } // endif: gradient computation was requested
368
369 // Compute scaled model value
370 value *= scale;
371
372 // Compile option: Check for NaN/Inf
373 #if defined(G_NAN_CHECK)
374 if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
375 std::cout << "*** ERROR: GSPIModelDataSpace::eval";
376 std::cout << "(index=" << index << "):";
377 std::cout << " NaN/Inf encountered";
378 std::cout << " (value=" << value;
379 std::cout << ", scale=" << scale;
380 std::cout << ")" << std::endl;
381 }
382 #endif
383
384 } // endif: binsize was positive
385
386 } // endif: model was initialised
387
388 // Return
389 return value;
390}
391
392
393/***********************************************************************//**
394 * @brief Return model values and gradients
395 *
396 * @param[in] obs Observation.
397 * @param[out] gradients Pointer to matrix of gradients.
398 * @param[in] offset Column index of first matrix gradient.
399 * @return Model values.
400 *
401 * @exception GException::invalid_argument
402 * Observation does not contain a SPI event cube
403 *
404 * Evaluates the model values and parameter gradients for all events in an
405 * observation. Gradients are only returned if the @p gradients pointer is
406 * not NULL.
407 *
408 * The matrix of gradients is a sparse matrix where the number of rows
409 * corresponds to the number of events and the number of columns corresponds
410 * to the number of model parameters (see GObservation::model() method).
411 *
412 * An exception is thrown if the dimension of the @p gradients matrix is not
413 * compatible with the model and the observations.
414 ***************************************************************************/
416 GMatrixSparse* gradients,
417 const int& offset) const
418{
419 // Setup model
420 setup(obs);
421
422 // Get pointer to event cube
423 const GSPIEventCube* cube = dynamic_cast<const GSPIEventCube*>(obs.events());
424 if (cube == NULL) {
425 std::string cls = std::string(typeid(obs.events()).name());
426 std::string msg = "Events of type \""+cls+"\" are not an INTEGRAL/SPI "
427 "event cube. Please specify an INTEGRAL/SPI observation "
428 "with an event cube as argument.";
430 }
431
432 // Get number of model parameters and number of events
433 int npars = size(); // Number of model parameters
434 int nevents = cube->size(); // Number of events in cube
435 int nmodels = cube->models(); // Number of models in cube (sky + background)
436
437 // Initialise gradients flag
438 bool grad = ((gradients != NULL) && (npars > 0));
439
440 // If gradients were requested then check matrix consistency
441 if (grad) {
442 if (gradients->columns() < npars+offset) {
443 std::string msg = "Number of "+gammalib::str(gradients->columns())+
444 " columns in gradient matrix is smaller than "
445 "the number of "+gammalib::str(npars)+" parameters "
446 "in model plus the offset "+gammalib::str(offset)+
447 ". Please provide a compatible gradient matrix.";
449 }
450 if (gradients->rows() != nevents) {
451 std::string msg = "Number of "+gammalib::str(gradients->rows())+
452 " rows in gradient matrix differs from number "
453 "of "+gammalib::str(nevents)+" events in "
454 "observation. Please provide a compatible "
455 "gradient matrix.";
457 }
458 }
459
460 // Initialise temporary memory pointers for gradient computation
461 double** tmp_values = NULL;
462 int** tmp_rows = NULL;
463 int* tmp_number = NULL;
464 int* tmp_inx = NULL;
465
466 // If gradient computation is requested then allocate temporary memory
467 // for quick column-wise matrix filling. Filling the matrix element by
468 // element is very slow, hence we store the gradient information in
469 // temporary memory that can then be filled column-wise in the sparse
470 // gradient matrix.
471 if (grad) {
472
473 // Allocate temporary memory for each column that will store the
474 // gradient information in compressed vectors.
475 tmp_values = new double*[npars]; // Compressed values for all columns
476 tmp_rows = new int*[npars]; // Row indices of values for all columns
477 tmp_number = new int[npars]; // Number of elements for all columns
478 tmp_inx = new int[npars]; // Number of current element indices for all columns
479
480 // Initialise temporary memory
481 for (int i = 0; i < npars; ++i) {
482 tmp_values[i] = NULL;
483 tmp_rows[i] = NULL;
484 tmp_number[i] = 0;
485 tmp_inx[i] = 0;
486 }
487
488 // Determine the number of compressed values for all columns
489 for (int k = 0; k < nevents; ++k) {
490 if (cube->event_size(k) > 0.0) {
491 int ipar = m_map[k]; // Parameter index for event
492 tmp_number[ipar]++; // Increment number of times the index is used
493 }
494 }
495
496 // Allocate memory for compressed column arrays
497 for (int i = 0; i < npars; ++i) {
498 if (tmp_number[i] > 0) {
499 tmp_values[i] = new double[tmp_number[i]];
500 tmp_rows[i] = new int[tmp_number[i]];
501 }
502 }
503
504 } // endif: gradient computation was requested
505
506 // Initialise values
507 GVector values(nevents);
508
509 // Continue only if model was initialised
510 if (m_index >= 0 && m_parameters.size() > 0) {
511
512 // Signal all parameters that will have analytical gradients. These
513 // are all parameters that are free and for which the model provides
514 // analytical gradients.
515 if (grad) {
516 for (int i = 0; i < npars; ++i) {
517 const GModelPar& par = (*this)[i];
518 if (par.is_free() && par.has_grad()) {
519 obs.computed_gradient(*this, par);
520 }
521 }
522 } // endif: gradients were requested
523
524 // Loop over events
525 for (int k = 0; k < nevents; ++k) {
526
527 // Get event bin size
528 double size = cube->event_size(k);
529
530 // Continue only if event bin size is positive
531 if (size > 0.0) {
532
533 // Get parameter index that corresponds to event bin
534 int ipar = m_map[k];
535
536 // Get relevant model parameter
537 const GModelPar* par = &(m_parameters[ipar]);
538
539 // Get model value divided by size (note that the size will be
540 // multiplied-in later, hence here we need the model value divided
541 // by size)
542 double value = cube->event_model(k, m_index) / size;
543
544 // Store scaled model value
545 values[k] = value * par->value();
546
547 // Optionally compute gradients
548 if (grad) {
549
550 // Compute partial derivative
551 double gradient = (par->is_free()) ? value * par->scale() : 0.0;
552
553 // Store gradient in temporary memory
554 //(*gradients)(k, ipar) = gradient;
555 tmp_values[ipar][tmp_inx[ipar]] = gradient; // Value
556 tmp_rows[ipar][tmp_inx[ipar]] = k; // Row index
557 tmp_inx[ipar]++; // Increment index
558
559 } // endif: gradient computation was requested
560
561 } // endif: binsize was positive
562
563 } // endfor: looped over events
564
565 } // endif: model was initialised
566
567 // If gradient was requested then fill temporary memory in sparse
568 // matrix and free temporary memory for quick filling
569 if (grad) {
570
571 // Fill temporary memory in sparse matrix
572 for (int i = 0; i < npars; ++i) {
573 if (tmp_number[i] > 0) {
574 gradients->column(i+offset, tmp_values[i], tmp_rows[i], tmp_number[i]);
575 }
576 }
577
578 // Free values
579 if (tmp_values != NULL) {
580 for (int i = 0; i < npars; ++i) {
581 if (tmp_values[i] != NULL) delete [] tmp_values[i];
582 }
583 delete [] tmp_values;
584 }
585
586 // Free row indices
587 if (tmp_rows != NULL) {
588 for (int i = 0; i < npars; ++i) {
589 if (tmp_rows[i] != NULL) delete [] tmp_rows[i];
590 }
591 delete [] tmp_rows;
592 }
593
594 // Free number of elements and current index
595 if (tmp_number != NULL) delete [] tmp_number;
596 if (tmp_inx != NULL) delete [] tmp_inx;
597
598 } // endif: gradient computation was requested
599
600 // Return values
601 return values;
602}
603
604
605/***********************************************************************//**
606 * @brief Model setup hook
607 *
608 * @param[in] obs Observation.
609 *
610 * Setup the model for a given observation.
611 ***************************************************************************/
613{
614 // Continue only if observation pointer differs
615 if (&obs != m_obs) {
616
617 // Debug: signal that pointer differs
618 #if defined(G_DEBUG_SETUP)
619 std::cout << "GSPIModelDataSpace::setup_model: ";
620 std::cout << "observation pointer differs";
621 std::cout << std::endl;
622 #endif
623
624 // Extract INTEGRAL/SPI observation
625 const GSPIObservation* spi_obs = dynamic_cast<const GSPIObservation*>(&obs);
626 if (spi_obs == NULL) {
627 std::string cls = std::string(typeid(&obs).name());
628 std::string msg = "Observation of type \""+cls+"\" is not an "
629 "INTEGRAL/SPI observation. Please specify an "
630 "INTEGRAL/SPI observation as argument.";
632 }
633
634 // Store observation pointer
635 m_obs = const_cast<GSPIObservation*>(spi_obs);
636
637 // Extract INTEGRAL/SPI event cube. Continue only if the cube is
638 // valid
639 GSPIEventCube* cube = dynamic_cast<GSPIEventCube*>(m_obs->events());
640 if (cube != NULL) {
641
642 // Continue only if the model index is valid
643 if (m_index >= 0 && m_index < cube->models()) {
644
645 // Continue only if there is a method
646 if (!m_method.empty()) {
647 const_cast<GSPIModelDataSpace*>(this)->setup_pars(cube);
648 }
649
650 // Debug: signal that index is not valid
651 #if defined(G_DEBUG_SETUP)
652 else {
653 std::cout << "GSPIModelDataSpace::setup: ";
654 std::cout << "no method defined.";
655 std::cout << std::endl;
656 }
657 #endif
658
659 } // endif: model index was valid
660
661 // Debug: signal that index is not valid
662 #if defined(G_DEBUG_SETUP)
663 else {
664 std::cout << "GSPIModelDataSpace::setup: ";
665 std::cout << "model index " << m_index << " is not in valid ";
666 std::cout << "range.";
667 std::cout << std::endl;
668 }
669 #endif
670
671 } // endif: cube was valid
672
673 // Debug: signal that event cube was invalid
674 #if defined(G_DEBUG_SETUP)
675 else {
676 std::cout << "GSPIModelDataSpace::setup: ";
677 std::cout << "no valid event cube found in observation";
678 std::cout << std::endl;
679 }
680 #endif
681
682 } // endif: observation pointer differed
683
684 // Return
685 return;
686}
687
688
689
690
691/***********************************************************************//**
692 * @brief Return spatially integrated data model
693 *
694 * @param[in] obsEng Measured event energy.
695 * @param[in] obsTime Measured event time.
696 * @param[in] obs Observation.
697 *
698 * Spatially integrates the data model for a given measured event energy and
699 * event time.
700 *
701 * @todo Implement method.
702 ***************************************************************************/
704 const GTime& obsTime,
705 const GObservation& obs) const
706{
707 // Initialise result
708 double npred = 0.0;
709
710 // Return
711 return npred;
712}
713
714
715/***********************************************************************//**
716 * @brief Return simulated list of events
717 *
718 * @param[in] obs Observation.
719 * @param[in] ran Random number generator.
720 *
721 * Draws a sample of events from the INTEGRAL/SPI data space model using a
722 * Monte Carlo simulation.
723 *
724 * @todo Implement method.
725 ***************************************************************************/
727 GRan& ran) const
728{
729 // Initialise new event cube
730 GSPIEventCube* cube = new GSPIEventCube;
731
732 // Return
733 return cube;
734}
735
736
737/***********************************************************************//**
738 * @brief Read model from XML element
739 *
740 * @param[in] xml XML element.
741 *
742 * Read the INTEGRAL/SPI data space model from an XML element.
743 *
744 * The model is composed of a list of scale parameters. The following XML
745 * file format is expected:
746 *
747 * <source name="Background" type="DataSpace" method="orbit,dete" index="0" instrument="SPI">
748 * <parameter name="REV0019_DETID00" .../>
749 * <parameter name="REV0019_DETID01" .../>
750 * ...
751 * </source>
752 ***************************************************************************/
754{
755 // Clear instance
756 clear();
757
758 // Set model method and index
759 m_method = xml.attribute("method");
760 m_index = gammalib::toint(xml.attribute("index"));
761
762 // Get number of parameters from XML file
763 int npars = xml.elements("parameter");
764
765 // Loop over all parameters
766 for (int i = 0; i < npars; ++i) {
767
768 // Allocate parameter
769 GModelPar parameter;
770
771 // Get XML element
772 const GXmlElement* par = xml.element("parameter", i);
773
774 // Read parameter from XML element
775 parameter.read(*par);
776
777 // Signal that parameter has gradient
778 parameter.has_grad(true);
779
780 // Push parameter on list
781 m_parameters.push_back(parameter);
782
783 } // endfor: looped over parameters
784
785 // Read model attributes
786 read_attributes(xml);
787
788 // Set pointers
789 set_pointers();
790
791 // Return
792 return;
793}
794
795
796/***********************************************************************//**
797 * @brief Write model into XML element
798 *
799 * @param[in] xml XML element.
800 *
801 * @exception GException::invalid_value
802 * Existing XML element is not of required type
803 * Invalid number of model parameters or nodes found in XML element.
804 *
805 * Write the INTEGRAL/SPI data space model into an XML element.
806 *
807 * The model is composed of a list of scale parameters. The following XML
808 * file structure will be written:
809 *
810 * <source name="Background" type="DataSpace" method="orbit,dete" index="0" instrument="SPI">
811 * <parameter name="REV0019_DETID00" .../>
812 * <parameter name="REV0019_DETID01" .../>
813 * ...
814 * </source>
815 ***************************************************************************/
817{
818 // Initialise pointer on source
819 GXmlElement* src = NULL;
820
821 // Search corresponding source
822 int n = xml.elements("source");
823 for (int k = 0; k < n; ++k) {
824 GXmlElement* element = xml.element("source", k);
825 if (element->attribute("name") == name()) {
826 src = element;
827 break;
828 }
829 }
830
831 // If no source with corresponding name was found then append one.
832 // Set also the type and the instrument.
833 if (src == NULL) {
834 src = xml.append("source");
835 src->attribute("name", name());
836 src->attribute("type", type());
837 if (instruments().length() > 0) {
838 src->attribute("instrument", instruments());
839 }
840 }
841
842 // Verify model type
843 if (src->attribute("type") != type()) {
844 std::string msg = "Invalid model type \""+src->attribute("type")+"\" "
845 "found in XML file. Model type \""+type()+"\" "
846 "expected.";
848 }
849
850 // Determine number of parameters
851 int npars = m_parameters.size();
852
853 // If XML element has 0 parameters then append parameters
854 if (src->elements() == 0) {
855 for (int i = 0; i < npars; ++i) {
856 src->append(GXmlElement("parameter"));
857 }
858 }
859
860 // Verify that XML element has the required number of nodes
861 if (src->elements() != npars || src->elements("parameter") != npars) {
862 std::string msg = "Invalid number of parameters "+
863 gammalib::str(src->elements("parameter"))+
864 " found in XML file, but model requires exactly "+
865 gammalib::str(npars)+" parameters.";
867 }
868
869 // Loop over all parameters
870 for (int i = 0; i < npars; ++i) {
871
872 // Get XML element
873 GXmlElement* par = src->element("parameter", i);
874
875 // Write parameter into XML element
876 m_parameters[i].write(*par);
877
878 } // endfor: looped over parameters
879
880 // Write model attributes
881 write_attributes(*src);
882
883 // Write method and index
884 src->attribute("method", m_method);
885 src->attribute("index", gammalib::str(m_index));
886
887 // Return
888 return;
889}
890
891
892/***********************************************************************//**
893 * @brief Print model information
894 *
895 * @param[in] chatter Chattiness.
896 * @return String containing model information.
897 ***************************************************************************/
898std::string GSPIModelDataSpace::print(const GChatter& chatter) const
899{
900 // Initialise result string
901 std::string result;
902
903 // Continue only if chatter is not silent
904 if (chatter != SILENT) {
905
906 // Append header
907 result.append("=== GSPIModelDataSpace ===");
908
909 // Append attributes
910 result.append("\n"+print_attributes());
911
912 // Append parameter summary
913 result.append("\n"+gammalib::parformat("Method"));
914 result.append(m_method);
915 result.append("\n"+gammalib::parformat("Number of parameters"));
916 result.append(gammalib::str(size()));
917 for (int i = 0; i < size(); ++i) {
918 result.append("\n"+m_pars[i]->print(chatter));
919 }
920
921 } // endif: chatter was not silent
922
923 // Return result
924 return result;
925}
926
927
928/*==========================================================================
929 = =
930 = Private methods =
931 = =
932 ==========================================================================*/
933
934/***********************************************************************//**
935 * @brief Initialise class members
936 ***************************************************************************/
938{
939 // Initialise base class members
940 m_instruments.clear();
941 m_instruments.push_back("SPI");
942
943 // Initialise members
944 m_obs = NULL;
945 m_method.clear();
946 m_index = -1;
947 m_map_size = 0;
948 m_map = NULL;
949 m_parameters.clear();
950
951 // Return
952 return;
953}
954
955
956/***********************************************************************//**
957 * @brief Copy class members
958 *
959 * @param[in] model Model.
960 ***************************************************************************/
962{
963 // Copy members
964 m_obs = model.m_obs; // Copy pointer
965 m_method = model.m_method;
966 m_index = model.m_index;
967 m_map_size = model.m_map_size;
969
970 // Copy parameter map
971 if (m_map_size > 0) {
972 m_map = new int[m_map_size];
973 for (int i = 0; i < m_map_size; ++i) {
974 m_map[i] = model.m_map[i];
975 }
976 }
977
978 // Set parameter pointers
979 set_pointers();
980
981 // Return
982 return;
983}
984
985
986/***********************************************************************//**
987 * @brief Delete class members
988 ***************************************************************************/
990{
991 // Delete memory
992 if (m_map != NULL) delete [] m_map;
993
994 // Set pointers to free
995 m_map = NULL;
996
997 // Return
998 return;
999}
1000
1001
1002/***********************************************************************//**
1003 * @brief Set pointers
1004 *
1005 * Set pointers to all model parameters. The pointers are stored in a vector
1006 * that is member of the GModel base class.
1007 ***************************************************************************/
1009{
1010 // Clear parameter pointer(s)
1011 m_pars.clear();
1012
1013 // Get number of parameters
1014 int npars = m_parameters.size();
1015
1016 // Set pointers for all parameters
1017 for (int i = 0; i < npars; ++i) {
1018 m_pars.push_back(&(m_parameters[i]));
1019 }
1020
1021 // Return
1022 return;
1023}
1024
1025
1026/***********************************************************************//**
1027 * @brief Setup parameters
1028 *
1029 * @param[in] cube INTEGRAL/SPI event cube
1030 *
1031 * Setup the parameters for a given model.
1032 *
1033 * We assume that the model index is within the valid range of possible
1034 * indices and that a method was specified.
1035 ***************************************************************************/
1037{
1038 // Free parameter map
1039 free_members();
1040
1041 // Get cube dimensions
1042 int n_events = cube->size();
1043 int n_pt = cube->naxis(0);
1044 int n_det = cube->naxis(1);
1045 int n_eng = cube->naxis(2);
1046
1047 // Initialise index vectors for all three dimensions
1048 std::vector<int> pt_indices(n_pt, 0);
1049 std::vector<int> det_indices(n_det, 0);
1050 std::vector<int> eng_indices(n_eng, 0);
1051
1052 // Initialise name vectors for all three dimensions
1053 std::vector<std::string> pt_names;
1054 std::vector<std::string> det_names;
1055 std::vector<std::string> eng_names;
1056
1057 // Determine pointing indices
1058 setup_pointing_indices(cube, &pt_indices, &pt_names);
1059
1060 // Determine detector indices
1061 setup_detector_indices(cube, &det_indices, &det_names);
1062
1063 // Determine energy indices
1064 setup_energy_indices(cube, &eng_indices, &eng_names);
1065
1066 // Determine number of parameters in each dimension. The number of
1067 // parameters is given by the last index in the vector + 1. The check
1068 // for a non-zero index vector size if just for security, if the event
1069 // cube is set it should always be positive, yet for an empty event cube
1070 // it may be zero, and in this case the method will just do nothing.
1071 int npt = (pt_indices.size() > 0) ? pt_indices[pt_indices.size()-1] + 1 : 0;
1072 int ndet = (det_indices.size() > 0) ? det_indices[det_indices.size()-1] + 1 : 0;
1073 int neng = (eng_indices.size() > 0) ? eng_indices[eng_indices.size()-1] + 1 : 0;
1074 int npars = npt * ndet * neng;
1075
1076 // Debug: print number of parameters in each dimension
1077 #if defined(G_DEBUG_SETUP_MODEL)
1078 std::cout << "GSPIModelDataSpace::setup_pars: ";
1079 std::cout << "determined pointing, detector and energy indices:" << std::endl;
1080 std::cout << "- npt = " << npt << std::endl;
1081 std::cout << "- ndet = " << ndet << std::endl;
1082 std::cout << "- neng = " << neng << std::endl;
1083 std::cout << "- npars = " << npars << std::endl;
1084 #endif
1085
1086 // Continue only if there are parameters in the model
1087 if (npars > 0) {
1088
1089 // Allocate parameters vector
1090 std::vector<GModelPar> parameters;
1091 parameters.reserve(npars);
1092
1093 // Allocate parameters. Energy parameter indices vary the most fastest
1094 // followed by detector parameter indices, follwed by pointing parameter
1095 // indices.
1096 for (int ipt = 0; ipt < npt; ++ipt) {
1097 for (int idet = 0; idet < ndet; ++idet) {
1098 for (int ieng = 0; ieng < neng; ++ieng) {
1099
1100 // Build parameter name
1101 std::string par_name;
1102 if (m_name.empty()) {
1103 par_name = "Scale";
1104 }
1105 else {
1106 par_name = m_name;
1107 }
1108 if (eng_names.size() > 0) {
1109 par_name += " " + eng_names[ieng];
1110 }
1111 if (det_names.size() > 0) {
1112 par_name += " " + det_names[idet];
1113 }
1114 if (pt_names.size() > 0) {
1115 par_name += " " + pt_names[ipt];
1116 }
1117
1118 // If parameter name exists already in this class instance
1119 // (because they were read using the read() method) then
1120 // recover the parameter and push it into the vector of
1121 // parameters
1122 bool has_par = false;
1123 for (int i = 0; i < m_parameters.size(); ++i) {
1124 if (m_parameters[i].name() == par_name) {
1125 parameters.push_back(m_parameters[i]);
1126 has_par = true;
1127 #if defined(G_DEBUG_SETUP_MODEL)
1128 std::cout << "GSPIModelDataSpace::setup_pars: ";
1129 std::cout << "copy old parameter \"";
1130 std::cout << m_parameters[i].name() << "\"" << std::endl;
1131 #endif
1132 break;
1133 }
1134 }
1135
1136 // ... otherwise allocate new model parameter
1137 if (!has_par) {
1138 GModelPar par;
1139 par.clear();
1140 par.name(par_name);
1141 par.free();
1142 par.value(1.0);
1143 par.scale(1.0);
1144 par.gradient(0.0);
1145 par.has_grad(true);
1146 parameters.push_back(par);
1147 #if defined(G_DEBUG_SETUP_MODEL)
1148 std::cout << "GSPIModelDataSpace::setup_pars: ";
1149 std::cout << "allocate new parameter \"";
1150 std::cout << par_name << "\"" << std::endl;
1151 #endif
1152 }
1153
1154 } // endfor: looped over energy parameters
1155 } // endfor: looped over detector parameters
1156 } // endfor: looped over pointing parameters
1157
1158 // Allocate parameter map
1159 m_map_size = n_pt * n_det * n_eng;
1160 if (m_map_size > 0) {
1161 m_map = new int[m_map_size];
1162 }
1163
1164 // Debug: print size of parameter map in each dimension
1165 #if defined(G_DEBUG_SETUP_MODEL)
1166 std::cout << "GSPIModelDataSpace::setup_pars: ";
1167 std::cout << "allocated parameter map:" << std::endl;
1168 std::cout << "- n_pt = " << n_pt << std::endl;
1169 std::cout << "- n_det = " << n_det << std::endl;
1170 std::cout << "- n_eng = " << n_eng << std::endl;
1171 std::cout << "- m_map_size = " << m_map_size << std::endl;
1172 #endif
1173
1174 // Compute parameter map
1175 for (int i_pt = 0; i_pt < n_pt; ++i_pt) {
1176 for (int i_det = 0; i_det < n_det; ++i_det) {
1177 for (int i_eng = 0; i_eng < n_eng; ++i_eng) {
1178
1179 // Compute parameter index, respecting the scheme defined
1180 // earlier: energy parameter indices vary the most fastest,
1181 // followed by detector parameter indices, followed by
1182 // pointing parameter indices
1183 int index = pt_indices[i_pt] * ndet * neng +
1184 det_indices[i_det] * neng +
1185 eng_indices[i_eng];
1186
1187 // Compute map index (same as in GSPIEventCube::read_dsp)
1188 int i_map = (i_pt * n_det + i_det) * n_eng + i_eng;
1189
1190 // Set map value
1191 m_map[i_map] = index;
1192
1193 // Debug: print mapping
1194 #if defined(G_DEBUG_SETUP_MODEL_MAP)
1195 std::cout << "- [" << i_pt << "," << i_det << "," << i_eng << "]";
1196 std::cout << " = " << index << std::endl;
1197 #endif
1198
1199 } // endfor: looped over energies
1200 } // endfor: looped over detectors
1201 } // endfor: looped over pointings
1202
1203 // Replace model parameters
1204 m_parameters = parameters;
1205
1206 // Set pointers
1207 set_pointers();
1208
1209 // Get number of parameters
1210 int n_pars = m_parameters.size();
1211
1212 // Determine number of events that use each parameter
1213 std::vector<int> n_uses(n_pars, 0);
1214 for (int i = 0; i < n_events; ++i) {
1215 if (cube->event_size(i) > 0.0) {
1216 int ipar = m_map[i]; // Parameter index for event bin
1217 n_uses[ipar]++; // Increment usage of parameter
1218 }
1219 }
1220
1221 // Fix all parameters that are not used
1222 for (int i = 0; i < n_pars; ++i) {
1223 if (n_uses[i] == 0) {
1224 m_parameters[i].fix();
1225 #if defined(G_DEBUG_SETUP_MODEL_FIX)
1226 std::cout << "GSPIModelDataSpace::setup_pars: ";
1227 std::cout << "parameter \"" << m_parameters[i].name() << "\" ";
1228 std::cout << "not used, fix parameter." << std::endl;
1229 #endif
1230 }
1231 }
1232
1233 } // endif: the model has parameters
1234
1235 // Return
1236 return;
1237}
1238
1239
1240/***********************************************************************//**
1241 * @brief Setup pointing indices
1242 *
1243 * @param[in] cube Event cube.
1244 * @param[in,out] indices Vector of pointing indices.
1245 * @param[in,out] names Vector of pointing names.
1246 *
1247 * Setup vectors of pointing indices and pointing names. The length of the
1248 * vectors correspond to the number of pointings in the observation.
1249 ***************************************************************************/
1251 std::vector<int>* indices,
1252 std::vector<std::string>* names)
1253{
1254 // Convert method to lower case
1255 std::string method = gammalib::tolower(m_method);
1256
1257 // Search for "point"
1258 if (gammalib::contains(method, "point")) {
1259 setup_point(cube, indices, names);
1260 }
1261
1262 // Search for "orbit"
1263 else if (gammalib::contains(method, "orbit")) {
1264 setup_orbit(cube, indices, names);
1265 }
1266
1267 // Search for "date"
1268 else if (gammalib::contains(method, "date")) {
1269 double time = get_date_time(method);
1270 setup_date(cube, indices, names, time);
1271 }
1272
1273 // Handle "gedfail"
1274 if (gammalib::contains(method, "gedfail")) {
1275 add_gedfail(cube, indices, names);
1276 }
1277
1278 // Handle "gedanneal"
1279 if (gammalib::contains(method, "gedanneal")) {
1280 add_gedanneal(cube, indices, names);
1281 }
1282
1283 // Return
1284 return;
1285}
1286
1287
1288/***********************************************************************//**
1289 * @brief Setup detector indices
1290 *
1291 * @param[in] cube Event cube.
1292 * @param[in,out] indices Vector of detector indices.
1293 * @param[in,out] names Vector of detector names.
1294 *
1295 * Setup vectors of detector indices and detector names. The length of the
1296 * vectors correspond to the number of detectors in the observation.
1297 ***************************************************************************/
1299 std::vector<int>* indices,
1300 std::vector<std::string>* names)
1301{
1302 // Convert method to lower case
1303 std::string method = gammalib::tolower(m_method);
1304
1305 // Search for "dete"
1306 if (gammalib::contains(method, "dete")) {
1307 setup_dete(cube, indices, names);
1308 }
1309
1310 // Search for "evtclass"
1311 else if (gammalib::contains(method, "evtclass")) {
1312 setup_evtclass(cube, indices, names);
1313 }
1314
1315 // Return
1316 return;
1317}
1318
1319
1320/***********************************************************************//**
1321 * @brief Setup energy indices
1322 *
1323 * @param[in] cube Event cube.
1324 * @param[in,out] indices Vector of energy indices.
1325 * @param[in,out] names Vector of energy names.
1326 *
1327 * Setup vectors of energy indices and energy names. The length of the
1328 * vectors correspond to the number of energies in the observation.
1329 ***************************************************************************/
1331 std::vector<int>* indices,
1332 std::vector<std::string>* names)
1333{
1334 // Convert method to lower case
1335 std::string method = gammalib::tolower(m_method);
1336
1337 // Search for "ebin"
1338 if (gammalib::contains(method, "ebin")) {
1339 setup_ebin(cube, indices, names);
1340 }
1341
1342 // Return
1343 return;
1344}
1345
1346
1347/***********************************************************************//**
1348 * @brief Setup pointing indices and names for "point" method
1349 *
1350 * @param[in] cube Event cube.
1351 * @param[in,out] indices Vector of pointing indices.
1352 * @param[in,out] names Vector of pointing names.
1353 *
1354 * Setup vectors of pointing indices and names for "point" method.
1355 ***************************************************************************/
1357 std::vector<int>* indices,
1358 std::vector<std::string>* names)
1359{
1360 // Get number of detectors
1361 int npt = indices->size();
1362
1363 // Setup index vector
1364 for (int ipt = 0; ipt < npt; ++ipt) {
1365 (*indices)[ipt] = ipt;
1366 names->push_back("P" + gammalib::str(ipt, "%6.6d"));
1367 }
1368
1369 // Return
1370 return;
1371}
1372
1373
1374/***********************************************************************//**
1375 * @brief Setup pointing indices and names for "orbit" method
1376 *
1377 * @param[in] cube Event cube.
1378 * @param[in,out] indices Vector of pointing indices.
1379 * @param[in,out] names Vector of pointing names.
1380 *
1381 * Setup vectors of pointing indices and names for "orbit" method.
1382 ***************************************************************************/
1384 std::vector<int>* indices,
1385 std::vector<std::string>* names)
1386{
1387 // Allocate orbit strings
1388 std::vector<std::string> orbits;
1389
1390 // Get number of pointings
1391 int npt = indices->size();
1392
1393 // Loop over all pointings
1394 for (int ipt = 0; ipt < npt; ++ipt) {
1395
1396 // Initialise index
1397 int index = -1;
1398
1399 // Get orbit
1400 std::string orbit = cube->ptid(ipt).substr(0,4);
1401
1402 // If orbit is in orbits then store the location of the string
1403 // in the vector as parameter index.
1404 for (int i = 0; i < orbits.size(); ++i) {
1405 if (orbit == orbits[i]) {
1406 index = i;
1407 break;
1408 }
1409 }
1410
1411 // If orbit is not yet in vector then
1412 if (index == -1) {
1413 index = orbits.size();
1414 orbits.push_back(orbit);
1415 names->push_back("O" + orbit);
1416 }
1417
1418 // Store index
1419 (*indices)[ipt] = index;
1420
1421 } // endfor: looped over pointings
1422
1423 // Return
1424 return;
1425}
1426
1427
1428/***********************************************************************//**
1429 * @brief Setup pointing indices and names for "date" method
1430 *
1431 * @param[in] cube Event cube.
1432 * @param[in,out] indices Vector of pointing indices.
1433 * @param[in,out] names Vector of pointing names.
1434 * @param[in] time Time scale in seconds.
1435 *
1436 * Setup vectors of pointing indices and names for "date" method.
1437 ***************************************************************************/
1439 std::vector<int>* indices,
1440 std::vector<std::string>* names,
1441 const double& time)
1442{
1443 // Compute start time, number of time bins and length of time bin in
1444 // seconds
1445 double tstart = cube->gti().tstart().secs();
1446 double tbin = cube->gti().telapse();
1447 int nbins = int(tbin / time + 0.5);
1448 if (nbins < 1) {
1449 nbins = 1;
1450 }
1451 tbin /= double(nbins);
1452
1453 // Get number of pointings
1454 int npt = indices->size();
1455
1456 // Loop over all pointings
1457 for (int ipt = 0; ipt < npt; ++ipt) {
1458
1459 // Get time of pointing in seconds
1460 double t = 0.5 * (cube->gti().tstart(ipt).secs() +
1461 cube->gti().tstop(ipt).secs());
1462
1463 // Compute grouping index. Make sure that it is in valid range.
1464 int index = int((t - tstart) / tbin);
1465 if (index < 0) {
1466 index = 0;
1467 }
1468 else if (index >= nbins) {
1469 index = nbins - 1;
1470 }
1471
1472 // Store index
1473 (*indices)[ipt] = index;
1474
1475 } // endfor: looped over indices
1476
1477 // Remove unused indices
1478 for (int index = 0, used_index = 0; index < nbins; ++index) {
1479
1480 // Replace all indices "index" by "used_index"
1481 int nindex = 0;
1482 for (int ipt = 0; ipt < npt; ++ipt) {
1483 if ((*indices)[ipt] == index) {
1484 (*indices)[ipt] = used_index;
1485 nindex++;
1486 }
1487 }
1488
1489 // If we found indices to replace then add an index name and
1490 // increase "used_index"
1491 if (nindex > 0) {
1492
1493 // Add date to names
1494 names->push_back("T" + gammalib::str(used_index, "%6.6d"));
1495
1496 // Increment used index
1497 used_index++;
1498
1499 } // endif: index was used
1500
1501 } // endfor: looped over all pointings
1502
1503 // Return
1504 return;
1505}
1506
1507
1508/***********************************************************************//**
1509 * @brief Modify pointing indices and names for "gedfail" method
1510 *
1511 * @param[in] cube Event cube.
1512 * @param[in,out] indices Vector of pointing indices.
1513 * @param[in,out] names Vector of pointing names.
1514 *
1515 * Inserts additional model parameters for each pointing where a detector
1516 * failure occured.
1517 ***************************************************************************/
1519 std::vector<int>* indices,
1520 std::vector<std::string>* names)
1521{
1522 // Set detector failure times
1524
1525 // Split pointings for all detector failures
1526 for (int i = 0; i < times.size(); ++i) {
1527 split_pointing_indices(cube, indices, names, times[i], "F"+gammalib::str(i));
1528 }
1529
1530 // Return
1531 return;
1532}
1533
1534
1535/***********************************************************************//**
1536 * @brief Modify pointing indices and names for "gedanneal" method
1537 *
1538 * @param[in] cube Event cube.
1539 * @param[in,out] indices Vector of pointing indices.
1540 * @param[in,out] names Vector of pointing names.
1541 *
1542 * Inserts additional model parameters for each pointing where a detector
1543 * annealing occured.
1544 ***************************************************************************/
1546 std::vector<int>* indices,
1547 std::vector<std::string>* names)
1548{
1549 // Set detector annealing start times
1551
1552 // Split pointings for all detector annealings
1553 for (int i = 0; i < times.size(); ++i) {
1554 split_pointing_indices(cube, indices, names, times[i], "A"+gammalib::str(i, "%2.2d"));
1555 }
1556
1557 // Return
1558 return;
1559}
1560
1561
1562/***********************************************************************//**
1563 * @brief Setup detector indices and names for "dete" method
1564 *
1565 * @param[in] cube Event cube.
1566 * @param[in,out] indices Vector of detector indices.
1567 * @param[in,out] names Vector of detector names.
1568 *
1569 * Setup vectors of detector indices and names for "dete" method.
1570 ***************************************************************************/
1572 std::vector<int>* indices,
1573 std::vector<std::string>* names)
1574{
1575 // Get number of detectors
1576 int ndet = indices->size();
1577
1578 // Setup index vector
1579 for (int idet = 0; idet < ndet; ++idet) {
1580 (*indices)[idet] = idet;
1581 names->push_back("D" + gammalib::str(idet, "%3.3d"));
1582 }
1583
1584 // Return
1585 return;
1586}
1587
1588
1589/***********************************************************************//**
1590 * @brief Setup detector indices and names for "evtclass" method
1591 *
1592 * @param[in] cube Event cube.
1593 * @param[in,out] indices Vector of detector indices.
1594 * @param[in,out] names Vector of detector names.
1595 *
1596 * Setup vectors of detector indices and names for "evtclass" method.
1597 ***************************************************************************/
1599 std::vector<int>* indices,
1600 std::vector<std::string>* names)
1601{
1602 // Get number of detectors
1603 int ndet = indices->size();
1604
1605 // Flag which event classes occur in the actual dataset
1606 for (int idet = 0; idet < ndet; ++idet) {
1607
1608 // Get detector ID for first pointing
1609 int detid = cube->dir(0, idet).detid();
1610
1611 // Set the corresponding event class flag
1612 if (detid >=0 && detid < 19) {
1613 (*indices)[idet] = 0; // SE
1614 }
1615 else if (detid >= 19 && detid < 61) {
1616 (*indices)[idet] = 1; // ME2
1617 }
1618 else if (detid >= 61 && detid < 85) {
1619 (*indices)[idet] = 2; // ME3
1620 }
1621 else if (detid >= 85 && detid < 104) {
1622 (*indices)[idet] = 3; // PEE
1623 }
1624 else if (detid >= 104 && detid < 123) {
1625 (*indices)[idet] = 4; // PES
1626 }
1627 else if (detid >= 123 && detid < 142) {
1628 (*indices)[idet] = 5; // PEM
1629 }
1630
1631 } // endfor: looped over all detectors
1632
1633 // Remove unused indices
1634 for (int index = 0, used_index = 0; index < 6; ++index) {
1635
1636 // Replace all indices "index" by "used_index"
1637 int nindex = 0;
1638 for (int idet = 0; idet < ndet; ++idet) {
1639 if ((*indices)[idet] == index) {
1640 (*indices)[idet] = used_index;
1641 nindex++;
1642 }
1643 }
1644
1645 // If we found indices to replace then add an index name and
1646 // increase "used_index"
1647 if (nindex > 0) {
1648
1649 // Add date to names
1650 names->push_back("C" + gammalib::str(used_index, "%1.1d"));
1651
1652 // Increment used index
1653 used_index++;
1654
1655 } // endif: index was used
1656
1657 } // endfor: looped over all pointings
1658
1659 // Return
1660 return;
1661}
1662
1663
1664/***********************************************************************//**
1665 * @brief Setup energy indices and names for "ebin" method
1666 *
1667 * @param[in] cube Event cube.
1668 * @param[in,out] indices Vector of energy indices.
1669 * @param[in,out] names Vector of energy names.
1670 *
1671 * Setup vectors of energy indices and names for "ebin" method.
1672 ***************************************************************************/
1674 std::vector<int>* indices,
1675 std::vector<std::string>* names)
1676{
1677 // Get number of detectors
1678 int neng = indices->size();
1679
1680 // Setup index vector
1681 for (int ieng = 0; ieng < neng; ++ieng) {
1682 (*indices)[ieng] = ieng;
1683 names->push_back("E" + gammalib::str(ieng, "%3.3d"));
1684 }
1685
1686 // Return
1687 return;
1688}
1689
1690
1691/***********************************************************************//**
1692 * @brief Get time scale from method string
1693 *
1694 * @param[in] method Method string.
1695 * @return Time scale (seconds).
1696 *
1697 * Get the time scale for the "DATE" method from the method string. The
1698 * following time units are supported: min, hour, day, week, month or year.
1699 ***************************************************************************/
1700double GSPIModelDataSpace::get_date_time(const std::string& method) const
1701{
1702 // Get position of "date" method in string
1703 size_t start = method.find("date") + 4;
1704
1705 // Get scale of time
1706 double scale = 0.0;
1707 size_t stop = std::string::npos;
1708 if ((stop = method.find("min", start)) != std::string::npos) {
1709 scale = 60.0;
1710 }
1711 else if ((stop = method.find("hour", start)) != std::string::npos) {
1712 scale = 3600.0;
1713 }
1714 else if ((stop = method.find("day", start)) != std::string::npos) {
1715 scale = 86400.0;
1716 }
1717 else if ((stop = method.find("week", start)) != std::string::npos) {
1718 scale = 604800.0;
1719 }
1720 else if ((stop = method.find("month", start)) != std::string::npos) {
1721 scale = 2628000.0;
1722 }
1723 else if ((stop = method.find("year", start)) != std::string::npos) {
1724 scale = 31536000.0;
1725 }
1726
1727 // Throw an exception if no time scale was found
1728 if (stop == std::string::npos) {
1729 std::string msg = "Method string \""+method+"\" does not contain "
1730 "time units for \"DATE\" method. Please specify one "
1731 "of the following units: min, hour, day, week, "
1732 "month or year.";
1734 }
1735
1736 // Get time in seconds
1737 double time = gammalib::todouble(method.substr(start, stop-start)) * scale;
1738
1739 // Return time
1740 return time;
1741}
1742
1743
1744/***********************************************************************//**
1745 * @brief Split pointing indices and names at given time
1746 *
1747 * @param[in] cube Event cube.
1748 * @param[in,out] indices Vector of pointing indices.
1749 * @param[in,out] names Vector of pointing names.
1750 * @param[in] time Time of split.
1751 * @param[in] reason Reason for split.
1752 *
1753 * Split the pointing indices at a given time.
1754 ***************************************************************************/
1756 std::vector<int>* indices,
1757 std::vector<std::string>* names,
1758 const GTime& time,
1759 const std::string& reason) const
1760{
1761 // Debug option: notify entry of method
1762 #if defined(G_DEBUG_SPLIT_POINTING)
1763 std::cout << "GSPIModelDataSpace::split_pointing_indices: ";
1764 std::cout << time.utc() << " " << reason << std::endl;
1765 #endif
1766
1767 // Get number of pointings
1768 int npt = indices->size();
1769
1770 // Continue only if there are pointings
1771 if (npt > 0) {
1772
1773 // Get index of largest pointing group plus one
1774 int igrp_last = 0;
1775 for (int ipt = 0; ipt < npt; ++ipt) {
1776 if ((*indices)[ipt] > igrp_last) {
1777 igrp_last = (*indices)[ipt];
1778 }
1779 }
1780 igrp_last++;
1781
1782 // Initialise time span of pointing group
1783 int ipt_start = 0;
1784 int ipt_stop = 0;
1785 int igrp_current = (*indices)[ipt_start];
1786 GTime tstart = cube->gti().tstart(ipt_start);
1787 GTime tstop = cube->gti().tstop(ipt_start);
1788
1789 // Loop over all pointings
1790 for (int ipt = 0; ipt < npt; ++ipt) {
1791
1792 // If pointing is in same pointing group then update stop
1793 // time
1794 if ((*indices)[ipt] == igrp_current) {
1795 tstop = cube->gti().tstop(ipt);
1796 ipt_stop = ipt;
1797 }
1798
1799 // If pointing is in different pointing group or the end of
1800 // the pointings has been reached then check whether specified
1801 // time is comprised in the time interval of the pointing
1802 // group. If this is the case an attempt is made to split
1803 // the pointing group into two.
1804 if (((*indices)[ipt] != igrp_current) || (ipt == npt-1)) {
1805
1806 // If time is comprised within pointing group then split
1807 // pointing group
1808 if ((time > tstart) && (time < tstop)) {
1809
1810 // Assign a new pointing group index to all pointings
1811 // that have a start time not earlier than the
1812 // specified time
1813 int nnew = 0;
1814 for (int kpt = ipt_start; kpt <= ipt_stop; ++kpt) {
1815 if (cube->gti().tstart(kpt) > time) {
1816 (*indices)[kpt] = igrp_last;
1817 nnew++;
1818 }
1819 }
1820
1821 // If a new pointing group was assigned then add a
1822 // name to the vector and increment the new pointing
1823 // group index. If no name exists so far then add an
1824 // empty name since we split one pointing group into
1825 // two.
1826 if (nnew > 0) {
1827 igrp_last++;
1828 if (names->size() == 0) {
1829 names->push_back("");
1830 }
1831 names->push_back(reason);
1832 }
1833
1834 } // endif: pointing group splitted
1835
1836 // Update time span of next pointing group
1837 ipt_start = ipt;
1838 ipt_stop = ipt;
1839 igrp_current = (*indices)[ipt];
1840 tstart = cube->gti().tstart(ipt);
1841 tstop = cube->gti().tstop(ipt);
1842
1843 } // endif: next pointing group or end encountered
1844
1845 } // endfor: looped over pointings
1846
1847 } // endif: there were pointings
1848
1849 // Return
1850 return;
1851}
#define G_WRITE
Exception handler interface definition.
Sparse matrix class definition.
#define G_CONSTRUCTOR
Definition GMatrix.cpp:41
Model parameter class interface definition.
Model registry class definition.
INTEGRAL/SPI event bin class definition.
#define G_EVAL1
const GSPIModelDataSpace g_spi_data_space_seed
#define G_GET_DATE_TIME
#define G_EVAL2
#define G_SETUP
INTEGRAL/SPI data space model interface definition.
INTEGRAL/SPI observation class definition.
Definition of INTEGRAL/SPI tools.
Time container class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Vector class interface definition.
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
Abstract interface for the event classes.
Definition GEvent.hpp:71
void gti(const GGti &gti)
Set Good Time Intervals.
Definition GEvents.cpp:154
const int & rows(void) const
Return number of matrix rows.
const int & columns(void) const
Return number of matrix columns.
Sparse matrix class interface definition.
virtual GVector column(const int &column) const
Extract column as vector from matrix.
Abstract data model class.
void init_members(void)
Initialise class members.
void free_members(void)
Delete class members.
virtual GModelData & operator=(const GModelData &model)
Assignment operator.
Model parameter class.
Definition GModelPar.hpp:87
void read(const GXmlElement &xml)
Extract parameter attributes from XML element.
Interface definition for the model registry class.
GModelPar & scale(const int &index)
Returns reference to scale parameter by index.
Definition GModel.cpp:384
std::vector< std::string > m_instruments
Instruments to which model applies.
Definition GModel.hpp:179
std::vector< GModelPar * > m_pars
Pointers to all model parameters.
Definition GModel.hpp:182
void write_attributes(GXmlElement &xml) const
Write model attributes.
Definition GModel.cpp:738
std::string m_name
Model name.
Definition GModel.hpp:178
void free_members(void)
Delete class members.
Definition GModel.cpp:687
void init_members(void)
Initialise class members.
Definition GModel.cpp:637
std::string print_attributes(void) const
Print model attributes.
Definition GModel.cpp:785
std::vector< int > m_eval_inx
Definition GModel.hpp:192
int size(void) const
Return number of parameters in model.
Definition GModel.hpp:237
bool has_par(const std::string &name) const
Checks if parameter name exists.
Definition GModel.cpp:299
std::string instruments(void) const
Returns instruments to which model applies.
Definition GModel.cpp:325
bool m_has_eval_inx
Definition GModel.hpp:190
void read_attributes(const GXmlElement &xml)
Read model attributes.
Definition GModel.cpp:699
const std::string & name(void) const
Return parameter name.
Definition GModel.hpp:265
Abstract observation base class.
virtual GEvents * events(void)
Return events.
void computed_gradient(const GModel &model, const GModelPar &par) const
Signals that an analytical gradient was computed for a model parameter.
bool is_free(void) const
Signal if parameter is free.
void free(void)
Free a parameter.
const double & scale(void) const
Return parameter scale.
bool has_grad(void) const
Signal if parameter gradient is computed analytically.
const double & factor_gradient(void) const
Return parameter factor gradient.
double gradient(void) const
Return parameter gradient.
void clear(void)
Clear parameter.
double value(void) const
Return parameter value.
const std::string & name(void) const
Return parameter name.
Random number generator class.
Definition GRan.hpp:44
INTEGRAL/SPI event bin class.
const double & model(const int &index) const
Return model value.
virtual double size(void) const
Return size of event bin.
const int & index(void) const
Return event bin index.
INTEGRAL/SPI event bin container class.
const GSPIInstDir & dir(const int &ipt, const int &idet) const
Return instrument direction.
const double & event_model(const int &ievent, const int &imodel) const
Return value of model for event bin.
const double & event_size(const int &ievent) const
Return size of event bin.
int models(void) const
Return number of models.
virtual int naxis(const int &axis) const
Return number of bins in axis.
virtual int size(void) const
Return event cube size.
const std::string & ptid(const int &ipt) const
Return pointing identifier.
void detid(const int &detid)
Set detector identifier.
INTEGRAL/SPI data space model.
void setup_evtclass(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Setup detector indices and names for "evtclass" method.
virtual void setup(const GObservation &obs) const
Model setup hook.
int * m_map
Parameter map.
void split_pointing_indices(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names, const GTime &time, const std::string &reason) const
Split pointing indices and names at given time.
double get_date_time(const std::string &method) const
Get time scale from method string.
std::string m_method
Fitting method.
void setup_date(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names, const double &time)
Setup pointing indices and names for "date" method.
void init_members(void)
Initialise class members.
void copy_members(const GSPIModelDataSpace &model)
Copy class members.
void add_gedfail(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Modify pointing indices and names for "gedfail" method.
int m_index
Index of model in event bins.
virtual GSPIModelDataSpace & operator=(const GSPIModelDataSpace &model)
Assignment operator.
void setup_detector_indices(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Setup detector indices.
void setup_energy_indices(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Setup energy indices.
int m_map_size
Size of parameter map.
virtual GSPIModelDataSpace * clone(void) const
Clone instance.
void add_gedanneal(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Modify pointing indices and names for "gedanneal" method.
void setup_dete(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Setup detector indices and names for "dete" method.
void free_members(void)
Delete class members.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print model information.
GSPIModelDataSpace(void)
Void constructor.
void setup_pointing_indices(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Setup pointing indices.
void set_pointers(void)
Set pointers.
virtual double eval(const GEvent &event, const GObservation &obs, const bool &gradients=false) const
Evaluate function.
GSPIObservation * m_obs
SPI observation.
virtual void read(const GXmlElement &xml)
Read model from XML element.
virtual double npred(const GEnergy &obsEng, const GTime &obsTime, const GObservation &obs) const
Return spatially integrated data model.
virtual std::string type(void) const
Return model type.
virtual void clear(void)
Clear instance.
void setup_ebin(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Setup energy indices and names for "ebin" method.
std::vector< GModelPar > m_parameters
Model parameters.
virtual void write(GXmlElement &xml) const
Write model into XML element.
virtual GSPIEventCube * mc(const GObservation &obs, GRan &ran) const
Return simulated list of events.
void setup_orbit(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Setup pointing indices and names for "orbit" method.
void setup_point(GSPIEventCube *cube, std::vector< int > *indices, std::vector< std::string > *names)
Setup pointing indices and names for "point" method.
void setup_pars(GSPIEventCube *cube)
Setup parameters.
virtual ~GSPIModelDataSpace(void)
Destructor.
INTEGRAL/SPI observation class.
Time class.
Definition GTime.hpp:55
std::string utc(const int &precision=0) const
Return time as string in UTC time system.
Definition GTime.cpp:465
Time container class.
Definition GTimes.hpp:45
int size(void) const
Return number of times.
Definition GTimes.hpp:100
Vector class.
Definition GVector.hpp:46
XML element node class.
const GXmlAttribute * attribute(const int &index) const
Return attribute.
virtual GXmlNode * append(const GXmlNode &node)
Append XML child node.
Definition GXmlNode.cpp:287
virtual GXmlElement * element(const int &index)
Return pointer to GXMLElement child.
Definition GXmlNode.cpp:640
virtual int elements(void) const
Return number of GXMLElement children of node.
Definition GXmlNode.cpp:586
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1162
bool is_infinite(const double &x)
Signal if argument is infinite.
Definition GTools.hpp:186
bool is_notanumber(const double &x)
Signal if argument is not a number.
Definition GTools.hpp:203
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:508
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:945
std::string tolower(const std::string &s)
Convert string to lower case.
Definition GTools.cpp:974
int toint(const std::string &arg)
Convert string into integer value.
Definition GTools.cpp:840
bool contains(const std::string &str, const std::string &substring)
Checks if a substring is in a string.
Definition GTools.cpp:1361
GTimes spi_annealing_start_times(void)
Return start time of annealing operations.
GTimes spi_gedfail_times(void)
Return times of detector failures.