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