ctools 2.1.0.dev
Loading...
Searching...
No Matches
ctulimit.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * ctulimit - Upper limit calculation tool *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2015-2022 by Michael Mayer *
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 ctulimit.hpp
23 * @brief Upper limit calculation tool interface implementation
24 * @author Michael Mayer
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <cstdio>
32#include "ctulimit.hpp"
33#include "GTools.hpp"
34#include "GOptimizer.hpp"
35
36/* __ Method name definitions ____________________________________________ */
37#define G_GET_MODEL_PARAMETER "ctulimit::get_model_parameter()"
38#define G_GET_PARAMETER_BRACKETS "ctulimit::get_parameter_brackets(double&, "\
39 "double&)"
40#define G_UL_BISECTION "ctulimit::ul_bisection(double&, double&)"
41
42/* __ Debug definitions __________________________________________________ */
43
44/* __ Coding definitions _________________________________________________ */
45
46
47/*==========================================================================
48 = =
49 = Constructors/destructors =
50 = =
51 ==========================================================================*/
52
53/***********************************************************************//**
54 * @brief Void constructor
55 *
56 * Constructs an empty ctulimit tool.
57 ***************************************************************************/
59{
60 // Initialise members
62
63 // Return
64 return;
65}
66
67
68/***********************************************************************//**
69 * @brief Observations constructor
70 *
71 * param[in] obs Observation container.
72 *
73 * Constructs ctulimit tool from an observations container.
74 ***************************************************************************/
75ctulimit::ctulimit(const GObservations& obs) :
76 ctlikelihood(CTULIMIT_NAME, VERSION, obs)
77{
78 // Initialise members
80
81 // Return
82 return;
83}
84
85
86
87/***********************************************************************//**
88 * @brief Command line constructor
89 *
90 * @param[in] argc Number of arguments in command line.
91 * @param[in] argv Array of command line arguments.
92 *
93 * Constructs an instance of the ctulimit tool that will parse user
94 * parameters that are provided as command line arguments.
95 ***************************************************************************/
96ctulimit::ctulimit(int argc, char *argv[]) :
97 ctlikelihood(CTULIMIT_NAME, VERSION, argc, argv)
98{
99 // Initialise members
100 init_members();
101
102 // Return
103 return;
104}
105
106
107/***********************************************************************//**
108 * @brief Copy constructor
109 *
110 * @param[in] app Application.
111 *
112 * Constructs an instance of the ctulimit tool by copying information from
113 * another ctulimit tool.
114 ***************************************************************************/
116{
117 // Initialise members
118 init_members();
119
120 // Copy members
121 copy_members(app);
122
123 // Return
124 return;
125}
126
127
128/***********************************************************************//**
129 * @brief Destructor
130 *
131 * Destructs the ctulimit tool.
132 ***************************************************************************/
134{
135 // Free members
136 free_members();
137
138 // Return
139 return;
140}
141
142
143/*==========================================================================
144 = =
145 = Operators =
146 = =
147 ==========================================================================*/
148
149/***********************************************************************//**
150 * @brief Assignment operator
151 *
152 * @param[in] app Application.
153 * @return Application.
154 *
155 * Assigns a ctulimit tool.
156 ***************************************************************************/
158{
159 // Execute only if object is not identical
160 if (this != &app) {
161
162 // Copy base class members
163 this->ctlikelihood::operator=(app);
164
165 // Free members
166 free_members();
167
168 // Initialise members
169 init_members();
170
171 // Copy members
172 copy_members(app);
173
174 } // endif: object was not identical
175
176 // Return this object
177 return *this;
178}
179
180
181/*==========================================================================
182 = =
183 = Public methods =
184 = =
185 ==========================================================================*/
186
187/***********************************************************************//**
188 * @brief Clear ctulimit tool
189 *
190 * Resets the ctulimit tool to a clean initial state.
191 ***************************************************************************/
193{
194 // Free members
195 free_members();
198 this->ctool::free_members();
199
200 // Clear base class (needed to conserve tool name and version)
201 this->GApplication::clear();
202
203 // Initialise members
204 this->ctool::init_members();
207 init_members();
208
209 // Write header into logger
210 log_header();
211
212 // Return
213 return;
214}
215
216
217/***********************************************************************//**
218 * @brief Compute upper limit
219 *
220 * Computes the upper limit depending on the given algorithm
221 ***************************************************************************/
223{
224 // Get task parameters
226
227 // Set energy dispersion flags of all CTA observations and save old
228 // values in save_edisp vector
229 std::vector<bool> save_edisp = set_edisp(m_obs, m_apply_edisp);
230
231 // Write input observation container into logger
232 log_observations(NORMAL, m_obs, "Input observation");
233
234 // Save original models
235 GModels models_orig = m_obs.models();
236
237 // Initialise best fit optimizer
238 GOptimizerLM best_opt;
239
240 // Save original log-likelihood. If the value is zero it has never been
241 // computed hence we compute it now.
242 m_best_logL = m_obs.logL();
243 if (m_best_logL == 0.0) {
244
245 // Write header into logger
246 log_header1(TERSE, "Compute best-fit likelihood");
247
248 // Make sure that requested model parameter is free
249 m_model_par->free();
250
251 // Optimize and save best log-likelihood
252 m_obs.optimize(m_opt);
253 m_obs.errors(m_opt);
254 m_best_logL = m_obs.logL();
255
256 // Store optimizer for later recovery
257 best_opt = m_opt;
258
259 // Write optimised model into logger
260 log_string(NORMAL, m_opt.print(m_chatter));
261 log_value(NORMAL,"Maximum log likelihood",gammalib::str(m_best_logL,3));
262 log_string(NORMAL, m_obs.models().print(m_chatter));
263
264 } // endif: likelihood was zero
265
266 // ... otherwise use original log-likelihood
267 else {
268
269 // Write header into logger
270 log_header1(TERSE, "Extract best-fit likelihood");
271
272 // Write optimised model into logger
273 log_value(NORMAL,"Maximum log likelihood",gammalib::str(m_best_logL,3));
274 log_string(NORMAL, m_obs.models().print(m_chatter));
275
276 }
277
278 // Get parameter brackets
279 double parmin;
280 double parmax;
281 get_parameter_brackets(parmin, parmax);
282
283 // Write header into logger
284 log_header1(TERSE, "Compute upper limit");
285
286 // Write some parameters into logger
287 log_value(NORMAL, "Model name", m_skymodel->name());
288 log_value(NORMAL, "Parameter name", m_model_par->name());
289 log_value(NORMAL, "Best factor value", m_best_value);
290 log_value(NORMAL, "Confidence level", gammalib::str(m_confidence*100.0)+"%");
291 log_value(NORMAL, "Maximum log likelihood",gammalib::str(m_best_logL,3));
292 log_value(NORMAL, "Log-likelihood difference", m_dlogL);
293 log_value(NORMAL, "Initial factor value range",
294 "["+gammalib::str(parmin)+", "+gammalib::str(parmax)+"]");
295
296 // Compute upper limit
297 ulimit_bisection(parmin, parmax);
298
299 // Write final parameter into logger
300 log_value(NORMAL, "Upper limit factor value", m_model_par->factor_value());
301 log_value(NORMAL, "Upper limit param. value", m_model_par->value());
302
303 // Compute upper limit intensity and fluxes
305
306 // Write header into logger
307 log_header1(TERSE, "Upper limit results");
308
309 // Write result into logger
310 log_value(TERSE, "Differential flux limit",
311 gammalib::str(m_diff_ulimit)+" ph/cm2/s/MeV at "+
312 gammalib::str(m_eref)+" TeV");
313 log_value(TERSE, "Integral flux limit",
314 gammalib::str(m_flux_ulimit)+" ph/cm2/s within ["+
315 gammalib::str(m_emin)+"-"+
316 gammalib::str(m_emax)+"] TeV");
317 log_value(TERSE, "Energy flux limit",
318 gammalib::str(m_eflux_ulimit)+" erg/cm2/s within ["+
319 gammalib::str(m_emin)+"-"+
320 gammalib::str(m_emax)+"] TeV");
321
322 // Recover original models
323 m_obs.models(models_orig);
324
325 // Recover optimizer
326 m_opt = best_opt;
327
328 // Restore energy dispersion flags of all CTA observations
329 restore_edisp(m_obs, save_edisp);
330
331 // Return
332 return;
333}
334
335
336/***********************************************************************//**
337 * @brief Save upper limits
338 *
339 * Saves the upper limit to an ASCII file in comma-separated value format.
340 *
341 * @todo No yet implemented as we have no clear use case yet for saving
342 * the result.
343 ***************************************************************************/
345{
346 // Return
347 return;
348}
349
350
351/*==========================================================================
352 = =
353 = Private methods =
354 = =
355 ==========================================================================*/
356
357/***********************************************************************//**
358 * @brief Initialise class members
359 ***************************************************************************/
361{
362 // Initialise user parameters
363 m_srcname.clear();
364 m_parname.clear();
365 m_confidence = 0.95;
366 m_sigma_min = 0.0;
367 m_sigma_max = 0.0;
368 m_eref = 0.0;
369 m_emin = 0.0;
370 m_emax = 0.0;
371 m_tol = 1.0e-6;
372 m_max_iter = 50;
373 m_apply_edisp = false;
374 m_chatter = static_cast<GChatter>(2);
375
376 // Initialise protected members
377 m_dlogL = 0.0;
378 m_best_logL = 0.0;
379 m_best_value = 0.0;
380 m_best_error = 0.0;
381 m_flux_ulimit = 0.0;
382 m_diff_ulimit = 0.0;
383 m_eflux_ulimit = 0.0;
384 m_skymodel = NULL;
385 m_model_par = NULL;
386 m_is_spatial = false;
387
388 // Return
389 return;
390}
391
392
393/***********************************************************************//**
394 * @brief Copy class members
395 *
396 * @param[in] app Application.
397 ***************************************************************************/
399{
400 // Copy user parameters
401 m_srcname = app.m_srcname;
402 m_parname = app.m_parname;
403 m_confidence = app.m_confidence;
404 m_sigma_min = app.m_sigma_min;
405 m_sigma_max = app.m_sigma_max;
406 m_eref = app.m_eref;
407 m_emin = app.m_emin;
408 m_emax = app.m_emax;
409 m_tol = app.m_tol;
410 m_max_iter = app.m_max_iter;
411 m_apply_edisp = app.m_apply_edisp;
412 m_chatter = app.m_chatter;
413
414 // Copy protected members
415 m_dlogL = app.m_dlogL;
416 m_best_logL = app.m_best_logL;
417 m_best_value = app.m_best_value;
418 m_best_error = app.m_best_error;
419 m_diff_ulimit = app.m_diff_ulimit;
420 m_flux_ulimit = app.m_flux_ulimit;
421 m_eflux_ulimit = app.m_eflux_ulimit;
422
423 // Extract model parameter
425
426 // Return
427 return;
428}
429
430
431/***********************************************************************//**
432 * @brief Delete class members
433 ***************************************************************************/
435{
436 // Return
437 return;
438}
439
440
441/***********************************************************************//**
442 * @brief Get application parameters
443 *
444 * Get all task parameters from parameter file.
445 ***************************************************************************/
447{
448 // Setup observations from "inobs" parameter
450
451 // Set observation statistic
452 set_obs_statistic(gammalib::toupper((*this)["statistic"].string()));
453
454 // Setup models from "inmodel" parameter
455 setup_models(m_obs, (*this)["srcname"].string());
456
457 // Get name of test source and optional parameter
458 m_srcname = (*this)["srcname"].string();
459 m_parname = (*this)["parname"].string();
460
461 // Get relevant model and parameter for upper limit computation
463
464 // Read energy dispersion flag
465 m_apply_edisp = (*this)["edisp"].boolean();
466
467 // Get confidence level and transform into log-likelihood difference
468 m_confidence = (*this)["confidence"].real();
469 double sigma = gammalib::erfinv(m_confidence) * gammalib::sqrt_two;
470 m_dlogL = (sigma*sigma) / 2.0;
471
472 // Read starting boundaries for bisection
473 m_sigma_min = (*this)["sigma_min"].real();
474 m_sigma_max = (*this)["sigma_max"].real();
475
476 // Read energy values
477 m_eref = (*this)["eref"].real();
478 m_emin = (*this)["emin"].real();
479 m_emax = (*this)["emax"].real();
480
481 // Set optimizer characteristics from user parameters
482 m_opt.eps((*this)["like_accuracy"].real());
483 m_opt.max_iter((*this)["max_iter"].integer());
484
485 // Read precision
486 m_tol = (*this)["tol"].real();
487 m_max_iter = (*this)["max_iter"].integer();
488
489 // Get remaining parameters
490 m_chatter = static_cast<GChatter>((*this)["chatter"].integer());
491
492 // Write parameters into logger
493 log_parameters(TERSE);
494
495 // Return
496 return;
497}
498
499
500/***********************************************************************//**
501 * @brief Get model parameter
502 *
503 * @exception GException::invalid_value
504 * Did not find a valid model or model parameter
505 *
506 * Extracts a pointer to the sky model (m_skymodel) and a pointer to the
507 * model parameter (m_model_par) that should be varied for the upper limit
508 * determination from the model container.
509 ***************************************************************************/
511{
512 // Define list of valid spectral model parameters, terminated with a
513 // NULL pointer to signal the end of the list
514 const char* pars[] = {"Normalization", "Value", "Prefactor",
515 "Integral", "PhotonFlux", "EnergyFlux",
516 NULL};
517
518 // Initialises sky model and model parameters pointers
519 m_skymodel = NULL;
520 m_model_par = NULL;
521 m_is_spatial = false;
522
523 // If the model container does not container the specified source then
524 // throw an exception
525 if (!m_obs.models().contains(m_srcname)) {
526 std::string msg = "Source \""+m_srcname+"\" not found in model "
527 "container. Please add a source with that name "
528 "or check for possible typos.";
529 throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
530 }
531
532 // Get relevant sky model for upper limit computation. If the model is not
533 // a sky model or if the model has a "NodeFunction" as spectral component
534 // then throw an exception.
535 GModels& models = const_cast<GModels&>(m_obs.models());
536 m_skymodel = dynamic_cast<GModelSky*>(models[m_srcname]);
537 if (m_skymodel == NULL) {
538 std::string msg = "Source \""+m_srcname+"\" is not a sky model. Please "
539 "specify the name of a sky model for upper limit "
540 "computation.";
541 throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
542 }
543
544 // If a parameter name was specified then use that parameter
545 if (!m_parname.empty()) {
546 if (m_skymodel->spatial()->has_par(m_parname)) {
547 m_model_par = &(m_skymodel->spatial()->operator[](m_parname));
548 m_is_spatial = true;
549 }
550 else if (m_skymodel->spectral()->has_par(m_parname)) {
551 m_model_par = &(m_skymodel->spectral()->operator[](m_parname));
552 }
553 else {
554 std::string msg = "Spatial or spectral model of source \""+
555 m_srcname+"\" has no parameter \""+m_parname+
556 "\". Please specify a valid parameter name "
557 "or leave the parameter name blank for "
558 "autodetermination of an intensity- or "
559 "flux-like parameter.";
560 throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
561 }
562 }
563
564 // ... otherwise find the appropriate model parameter
565 else {
566
567 // If a node function was specified then a valid parameter name is
568 // needed
569 if (m_skymodel->spectral()->type() == "NodeFunction") {
570 std::string msg = "Spectral model of source \""+m_srcname+"\" is "
571 "a \"NodeFunction\" but no parameter name was "
572 "specified. Please use the \"parname\" parameter "
573 "to specify the parameter that should be used "
574 "for the upper limit computation.";
575 throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
576 }
577
578 // Find appropriate model parameter and store its pointer in the
579 // m_model_par member
580 for (const char** par = pars; *par != NULL; ++par) {
581 if (m_skymodel->spectral()->has_par(*par)) {
582 m_model_par = &(m_skymodel->spectral()->operator[](*par));
583 break;
584 }
585 }
586
587 } // endelse: searched for parameter
588
589 // If no model parameter was found then throw an exception
590 if (m_model_par == NULL) {
591 std::string msg = "Require one of the following spectral "
592 "parameters for upper limit computation: ";
593 for (const char** par = pars; *par != NULL; ++par) {
594 if (par != pars) {
595 msg.append(", ");
596 }
597 msg.append("\""+std::string(*par)+"\"");
598 }
599 msg.append(". The specified source \""+m_srcname+"\" does not "
600 "have such a parameter.");
601 throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
602 }
603
604 // Return
605 return;
606}
607
608
609/***********************************************************************//**
610 * @brief Determine parameter brackets
611 *
612 * @param[out] parmin Minimum parameter value.
613 * @param[out] parmax Maximum parameter value.
614 *
615 * @exception GException::invalid_value
616 * Exceeded maximum number of iterations in the bracket search.
617 *
618 * Determines the brackets for the parameter of interest.
619 ***************************************************************************/
620void ctulimit::get_parameter_brackets(double& parmin, double& parmax)
621{
622 // Write header into logger
623 log_header1(TERSE, "Find parameter brackets");
624
625 // Extract current value and error
626 m_best_value = m_model_par->factor_value();
627 m_best_error = m_model_par->factor_error();
628
629 // If parameter error is zero then take parameter value as error
630 if (m_best_error == 0.0) {
632 }
633
634 // Compute parameter bracketing
637 if (m_model_par->has_min() && m_model_par->factor_min() > parmin) {
638 parmin = m_model_par->factor_min();
639 }
640 if (m_model_par->has_max() && m_model_par->factor_max() < parmax) {
641 parmax = m_model_par->factor_max();
642 }
643
644 // Initialise iteration counter
645 int iter = 0;
646
647 // Make sure that upper limit is bracketed
648 while (true) {
649
650 // Throw exception if maximum iterations are reached
651 if (iter > m_max_iter) {
652 std::string msg = "The maximum number of "+gammalib::str(m_max_iter)+
653 " has been reached. You may consider to increase"
654 " the \"max_iter\" parameter and re-run ctulimit.";
655 throw GException::invalid_value(G_GET_PARAMETER_BRACKETS, msg);
656 }
657
658 // If model parameter is spatial parameter then make sure that no
659 // values are cached for source
660 if (m_is_spatial) {
661 m_obs.remove_response_cache(m_srcname);
662 }
663
664 // Evaluate logL at upper boundary
665 double logL = evaluate(*m_model_par, parmax);
666 double eval_mid = logL - (m_best_logL + m_dlogL);
667
668 // Write current parameter range into logger
669 log_value(NORMAL, "Parameter range",
670 "["+gammalib::str(parmin)+", "+gammalib::str(parmax)+"] "
671 "logL("+gammalib::str(parmax)+")="+gammalib::str(logL));
672
673 // If the logL increase is not enough, increase maximum parameter
674 // value, otherwise break
675 if (eval_mid < 0.0) {
676 parmax *= 10.0;
677 }
678 else {
679 break;
680 }
681
682 // Increase number of iterations
683 iter++;
684
685 } // endwhile
686
687 // Return
688 return;
689}
690
691
692/***********************************************************************//**
693 * @brief Calculate upper limit using a bisection method
694 *
695 * @param[in] parmin Minimum parameter value
696 * @param[in] parmax Maximum parameter value
697 *
698 * @exception GException::invalid_value
699 * Exceeded maximum number of iterations in the upper limit
700 * search.
701 *
702 * Calculates the upper limit using a bisection method. The bisection is
703 * stopped if the log-likelihood value is within the tolerance of the target
704 * value. The bisection is also stopped putting a warning in the log file if
705 * the parameter interval becomes smaller than a tolerance of 1.0e-6. The
706 * method stops with an exception if the maximum number of iterations is
707 * exhausted.
708 ***************************************************************************/
709void ctulimit::ulimit_bisection(const double& parmin, const double& parmax)
710{
711 // Copy values to working values
712 double wrk_min = parmin;
713 double wrk_max = parmax;
714
715 // Initialise iteration counter and restart flag
716 int iter = 0;
717 bool restart = false;
718
719 // Loop until breaking condition is reached
720 while (true) {
721
722 // Throw exception if maximum iterations are reached
723 if (iter > m_max_iter) {
724 std::string msg = "The maximum number of "+gammalib::str(m_max_iter)+
725 " has been reached. You may consider to increase"
726 " the \"max_iter\" parameter and re-run ctulimit.";
727 throw GException::invalid_value(G_UL_BISECTION, msg);
728 }
729
730 // If model parameter is spatial parameter then make sure that no
731 // values are cached for source
732 if (m_is_spatial) {
733 m_obs.remove_response_cache(m_srcname);
734 }
735
736 // Compute center of boundary
737 double mid = (wrk_min + wrk_max) / 2.0;
738
739 // Calculate function value
740 double logL = evaluate(*m_model_par, mid);
741 double eval_mid = logL - (m_best_logL + m_dlogL);
742
743 // Log information
744 log_value(NORMAL, "Iteration "+gammalib::str(iter),
745 "["+gammalib::str(wrk_min)+", "+gammalib::str(wrk_max)+"] "
746 "logL("+gammalib::str(mid)+")="+gammalib::str(logL)+" "
747 "dlogL="+gammalib::str(eval_mid));
748
749 // Check for convergence inside tolerance
750 if (std::abs(eval_mid) < m_tol) {
751 break;
752 }
753
754 // Assess status
755 int status = 0;
756
757 // Check whether mid-point is close to best parameter value
758 double eps = (mid != 0.0) ? (mid - m_best_value)/mid : mid - m_best_value;
759 if (std::abs(eps) < 1.0e-6) {
760 std::string msg =
761 " *** WARNING: Parameter range mid-point "+gammalib::str(mid)+" is "
762 "close to best factor\n"
763 " value "+gammalib::str(m_best_value)+" yet the "
764 "log-likelihood value "+gammalib::str(logL)+"\n"
765 " at the mid-point differs significantly from the "
766 "log-likelihood value\n"
767 " "+gammalib::str(m_best_logL)+" for the best factor "
768 "value.";
769 log_string(TERSE, msg);
770 status = 1;
771 }
772
773 // Check for vanishing parameter range
774 eps = (mid != 0.0) ? (wrk_min - wrk_max)/mid : wrk_min - wrk_max;
775 if (std::abs(eps) < 1.0e-6) {
776 std::string msg =
777 " *** WARNING: Parameter range ["+gammalib::str(wrk_min)+", "+
778 gammalib::str(wrk_max)+"] has reduced\n"
779 " to a narrow interval without reaching convergence! "
780 "The best\n"
781 " log-likelihood value is probably not an absolute "
782 "but only a local\n"
783 " minimum.";
784 log_string(TERSE, msg);
785 status = 2;
786 }
787
788 // Restart bisection if a restart is required
789 if (!restart && status != 0) {
790
791 // Adopt current logL as best log-likelihood
792 restart = true;
793 iter = 0;
794 wrk_min = parmin;
795 wrk_max = parmax;
796 m_best_logL = logL;
797
798 // Signal restart
799 std::string msg =
800 " Adopt "+gammalib::str(logL)+" as best log-likelihood and restart "
801 "bisection";
802 log_string(TERSE, msg);
803
804 // Restart
805 continue;
806
807 } // endif: restart bisection if required
808
809 // Change boundaries for further iteration
810 if (eval_mid > 0.0) {
811 wrk_max = mid; // logL too large, new range = [wrk_min, mid]
812 }
813 else {
814 wrk_min = mid; // logL too small, new range = [mid, wrk_max]
815 }
816
817 // Increment counter
818 iter++;
819
820 } // endwhile
821
822 // Return
823 return;
824
825}
826
827
828/***********************************************************************//**
829 * @brief Compute upper limit intensity and fluxes
830 *
831 * Compute upper limit intensity and fluxes, including a correct computation
832 * for the diffuse map cube models.
833 ***************************************************************************/
835{
836 // Initialise upper limit intensity and fluxes
837 m_diff_ulimit = 0.0;
838 m_flux_ulimit = 0.0;
839 m_eflux_ulimit = 0.0;
840
841 // Get reference energy for differential upper limit
842 GEnergy eref = GEnergy(m_eref, "TeV");
843
844 // Create energy range for flux limits
845 GEnergy emin = GEnergy(m_emin, "TeV");
846 GEnergy emax = GEnergy(m_emax, "TeV");
847
848 // Set pointer to spectral model and initialise spectral nodes model
849 // pointer
850 GModelSpectral* spectral = m_skymodel->spectral();
851 GModelSpectralNodes* nodes = NULL;
852
853 // If the spectral model is a diffuse cube then create a node function
854 // spectral model that is the product of the diffuse cube node function
855 // and the spectral model evaluated at the energies of the node function
856 GModelSpatialDiffuseCube* cube =
857 dynamic_cast<GModelSpatialDiffuseCube*>(m_skymodel->spatial());
858 if (cube != NULL) {
859
860 // Set MC cone to the entire sky. This method call is needed to
861 // set-up the cube spectrum
862 cube->mc_cone(GSkyRegionCircle(0.0, 0.0, 180.0));
863
864 // Allocate node function to replace the spectral component
865 nodes = new GModelSpectralNodes(cube->spectrum());
866 for (int i = 0; i < nodes->nodes(); ++i) {
867 GEnergy energy = nodes->energy(i);
868 double intensity = nodes->intensity(i);
869 double value = spectral->eval(energy);
870 nodes->intensity(i, value*intensity);
871 }
872
873 // Set the spectral model pointer to the node function. If there are
874 // no nodes the spectral pointer is set to NULL since in this case the
875 // spectral->flux method will throw an exception
876 if (nodes->nodes() > 0) {
877 spectral = nodes;
878 }
879 else {
880 spectral = NULL;
881 }
882
883 } // endif: spatial model was a diffuse cube
884
885 // Compute upper limit intensity and fluxes
886 if (spectral != NULL) {
887 m_diff_ulimit = spectral->eval(eref);
888 m_flux_ulimit = spectral->flux(emin, emax);
889 m_eflux_ulimit = spectral->eflux(emin, emax);
890 }
891
892 // Free spectral nodes if they have been allocated
893 if (nodes != NULL) {
894 delete nodes;
895 }
896
897 // Return
898 return;
899}
Base class for likelihood tools.
GOptimizerLM m_opt
Optimizer.
ctlikelihood & operator=(const ctlikelihood &app)
Assignment operator.
double evaluate(GModelPar &par, const double &value)
Evaluates the log-likelihood function.
void free_members(void)
Delete class members.
void init_members(void)
Initialise class members.
void free_members(void)
Delete class members.
GObservations m_obs
Observation container.
void init_members(void)
Initialise class members.
void set_obs_statistic(const std::string &statistic)
Set fit statistic for CTA observations.
void restore_edisp(GObservations &obs, const std::vector< bool > &edisp) const
Restore energy dispersion flags of CTA observations.
Definition ctool.cpp:1689
void setup_models(GObservations &obs, const std::string &name="")
Setup model container.
Definition ctool.cpp:545
void free_members(void)
Delete class members.
Definition ctool.cpp:357
void log_observations(const GChatter &chatter, const GObservations &obs, const std::string &what="Observation")
Log observation container.
Definition ctool.cpp:1251
std::vector< bool > set_edisp(GObservations &obs, const bool &edisp) const
Set energy dispersion to CTA observations.
Definition ctool.cpp:1649
void log_parameters(const GChatter &chatter)
Log application parameters.
Definition ctool.cpp:1208
void init_members(void)
Initialise class members.
Definition ctool.cpp:321
void setup_observations(GObservations &obs, const bool &response=true, const bool &list=true, const bool &cube=true)
Setup observation container.
Definition ctool.cpp:431
Upper limit calculation tool.
Definition ctulimit.hpp:50
ctulimit & operator=(const ctulimit &app)
Assignment operator.
Definition ctulimit.cpp:157
double m_sigma_min
Starting value minimum (multiple fit errors above fit values)
Definition ctulimit.hpp:86
bool m_apply_edisp
Apply energy dispersion?
Definition ctulimit.hpp:93
void save(void)
Save upper limits.
Definition ctulimit.cpp:344
double m_flux_ulimit
Flux upper limit value.
Definition ctulimit.hpp:102
double m_best_value
Best parameter value factor.
Definition ctulimit.hpp:99
void get_parameters(void)
Get application parameters.
Definition ctulimit.cpp:446
virtual ~ctulimit(void)
Destructor.
Definition ctulimit.cpp:133
GModelPar * m_model_par
Pointer to model parameter.
Definition ctulimit.hpp:105
double m_eflux_ulimit
Energy flux upper limits.
Definition ctulimit.hpp:103
void process(void)
Compute upper limit.
Definition ctulimit.cpp:222
void ulimit_bisection(const double &parmin, const double &parmax)
Calculate upper limit using a bisection method.
Definition ctulimit.cpp:709
double m_eref
Reference energy for flux limits (TeV)
Definition ctulimit.hpp:88
void free_members(void)
Delete class members.
Definition ctulimit.cpp:434
ctulimit(void)
Void constructor.
Definition ctulimit.cpp:58
void get_model_parameter(void)
Get model parameter.
Definition ctulimit.cpp:510
double m_confidence
Confidence level.
Definition ctulimit.hpp:85
std::string m_srcname
Name of source for upper limit computation.
Definition ctulimit.hpp:83
void compute_ulimit(void)
Compute upper limit intensity and fluxes.
Definition ctulimit.cpp:834
double m_diff_ulimit
Differential upper limit value.
Definition ctulimit.hpp:101
GModelSky * m_skymodel
Pointer to sky model.
Definition ctulimit.hpp:104
void copy_members(const ctulimit &app)
Copy class members.
Definition ctulimit.cpp:398
int m_max_iter
Maximum number of iterations.
Definition ctulimit.hpp:92
double m_emax
Maximum energy for flux limits (TeV)
Definition ctulimit.hpp:90
void clear(void)
Clear ctulimit tool.
Definition ctulimit.cpp:192
std::string m_parname
Name of parameter for upper limit computation.
Definition ctulimit.hpp:84
double m_dlogL
Likelihood difference for upper limit computation.
Definition ctulimit.hpp:97
double m_best_logL
Best fit log likelihood of given model.
Definition ctulimit.hpp:98
double m_best_error
Best parameter value error.
Definition ctulimit.hpp:100
double m_sigma_max
Starting value maximum (multiple fit errors above fit values)
Definition ctulimit.hpp:87
double m_tol
Tolerance for limit determination.
Definition ctulimit.hpp:91
double m_emin
Minimum energy for flux limits (TeV)
Definition ctulimit.hpp:89
bool m_is_spatial
Signal that model parameter is spatial parameter.
Definition ctulimit.hpp:106
void init_members(void)
Initialise class members.
Definition ctulimit.cpp:360
void get_parameter_brackets(double &parmin, double &parmax)
Determine parameter brackets.
Definition ctulimit.cpp:620
GChatter m_chatter
Chattiness.
Definition ctulimit.hpp:94
#define G_UL_BISECTION
Definition ctulimit.cpp:40
#define G_GET_PARAMETER_BRACKETS
Definition ctulimit.cpp:38
#define G_GET_MODEL_PARAMETER
Definition ctulimit.cpp:37
Upper limit calculation tool interface implementation.
#define CTULIMIT_NAME
Definition ctulimit.hpp:34