Commit 8ded0f5f0e46fecf704d04be8b839991b68dfbba

Authored by Florent Forest
1 parent 6577d6a2

cterror implementation

configure.ac
... ... @@ -890,6 +890,7 @@ AC_CONFIG_FILES([Makefile
890 890 src/cttsmap/Makefile
891 891 src/ctbutterfly/Makefile
892 892 src/ctulimit/Makefile
  893 + src/cterror/Makefile
893 894 src/support/Makefile
894 895 src/ctools-setup
895 896 test/Makefile
... ...
pyext/cterror.i 0 → 100644
  1 +/***************************************************************************
  2 + * cterror - Parameter error calculation tool *
  3 + * ----------------------------------------------------------------------- *
  4 + * copyright (C) 2015 by Florent Forest *
  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 cterror.i
  23 + * @brief Parameter error calculation tool interface definition
  24 + * @author Florent Forest
  25 + */
  26 +
  27 +%{
  28 +/* Put headers and other declarations here that are needed for compilation */
  29 +#include "cterror.hpp"
  30 +%}
  31 +
  32 +
  33 +/***********************************************************************//**
  34 + * @class cterror
  35 + *
  36 + * @brief Parameter error calculation tool
  37 + *
  38 + ***************************************************************************/
  39 +class cterror : public ctool {
  40 +
  41 + public:
  42 + // Constructors and destructors
  43 + cterror(void);
  44 + explicit cterror(const GObservations& obs);
  45 + cterror(int argc, char *argv[]);
  46 + cterror(const cterror& app);
  47 + virtual ~cterror(void);
  48 +
  49 + // Methods
  50 + void clear(void);
  51 + void run(void);
  52 + void save(void);
  53 + const GObservations& obs(void) const;
  54 + const GOptimizer* opt(void) const;
  55 +
  56 +};
  57 +
  58 +/***********************************************************************//**
  59 + * @brief Parameter error calculation tool Python extensions
  60 + ***************************************************************************/
  61 +%extend cterror {
  62 + cterror copy() {
  63 + return (*self);
  64 + }
  65 +}
... ...
pyext/ctools/obsutils.py
... ... @@ -158,6 +158,37 @@ def fit(obs, log=False, debug=False, edisp=False):
158 158 # Return observations
159 159 return like
160 160  
  161 +# ================ #
  162 +# Run cterror #
  163 +# ================ #
  164 +def cterror(obs, log=False, debug=False):
  165 + """
  166 + Perform maximum likelihood fitting of observations in the container.
  167 +
  168 + Parameters:
  169 + obs - Observation container
  170 + Keywords:
  171 + log - Create log file(s)
  172 + debug - Create screen dump
  173 + edisp - Apply energy dispersion?
  174 + """
  175 + # Allocate cterror application
  176 + error = ctools.cterror(obs)
  177 +
  178 + # Optionally open the log file
  179 + if log:
  180 + error.logFileOpen()
  181 +
  182 + # Optionally switch-on debugging model
  183 + if debug:
  184 + error["debug"].boolean(True)
  185 +
  186 + # Run cterror application.
  187 + error.run()
  188 +
  189 + # Return observations
  190 + return error
  191 +
161 192  
162 193 # ================= #
163 194 # Create counts map #
... ...
pyext/ctools/tools.i
... ... @@ -59,3 +59,4 @@
59 59 %include "cttsmap.i"
60 60 %include "ctbutterfly.i"
61 61 %include "ctulimit.i"
  62 +%include "cterror.i"
... ...
scripts/cspull.py
... ... @@ -297,8 +297,9 @@ class cspull(ctools.cscript):
297 297 self.log("\n")
298 298  
299 299 # Fit model
300   - like = obsutils.fit(obs, edisp=self.m_edisp, \
301   - log=self.m_log, debug=self.m_debug)
  300 + #like = obsutils.fit(obs, edisp=self.m_edisp, \
  301 + # log=self.m_log, debug=self.m_debug)
  302 + like = obsutils.cterror(obs, log=self.m_log, debug=self.m_debug)
302 303  
303 304 # Store results
304 305 logL = like.opt().value()
... ...
src/Makefile.am
... ... @@ -44,8 +44,8 @@ libctools_la_LIBADD = support/libsupport.la \
44 44 ctcubemask/libctcubemask.la \
45 45 cttsmap/libcttsmap.la \
46 46 ctbutterfly/libctbutterfly.la \
47   - ctulimit/libctulimit.la
48   -
  47 + ctulimit/libctulimit.la \
  48 + cterror/libcterror.la
49 49  
50 50 # Distribute scripts
51 51 EXTRA_DIST = $(scripts)
... ...
src/cterror/Makefile.am
... ... @@ -9,10 +9,15 @@ bin_PROGRAMS = cterror
9 9 # Sources
10 10 sources = cterror.cpp
11 11  
  12 +# Libtool library
  13 +noinst_LTLIBRARIES = libcterror.la
  14 +libcterror_la_SOURCES = $(sources)
  15 +
12 16 # Program definition
13 17 cterror_SOURCES = main.cpp
14 18 cterror_LDFLAGS = $(LIB_LINK_OPTION) @LDFLAGS@
15 19 cterror_CPPFLAGS = @CPPFLAGS@
  20 +cterror_LDADD = libcterror.la $(top_srcdir)/src/support/libsupport.la
16 21  
17 22 # Parameter files
18 23 pfilesdir = $(prefix)/syspfiles
... ...
src/cterror/cterror.cpp
... ... @@ -28,15 +28,16 @@
28 28 #ifdef HAVE_CONFIG_H
29 29 #include <config.h>
30 30 #endif
31   -#include <stdio>
  31 +#include <iostream>
32 32 #include "cterror.hpp"
33 33 #include "GTools.hpp"
34 34 #include "GOptimizer.hpp"
35 35  
36 36 /* __ Method name definitions ____________________________________________ */
37 37 #define G_GET_PARAMETERS "cterror::get_parameters()"
38   -#define G_GET_MODEL_PARAMETER "cterror::get_model_parameter()"
  38 +#define G_ERR_BISECTION "cterror::error_bisection(double&, double&)"
39 39 #define G_EVALUATE "cterror::evaluate(double&)"
  40 +#define G_RUN "cterror::run()"
40 41  
41 42 /* __ Debug definitions __________________________________________________ */
42 43  
... ... @@ -230,92 +231,161 @@ void cterror::run(void)
230 231 // Save original models
231 232 GModels models_orig = m_obs.models();
232 233  
233   - // Save original log-likelihood. If the value is zero it has never been
234   - // computed hence we compute it now.
  234 + // Allocate optimizer
  235 + m_opt = new GOptimizerLM();
  236 + // Optimize and save best log-likelihood
  237 + m_obs.optimize(*m_opt);
  238 + m_obs.errors(*m_opt);
235 239 m_best_logL = m_obs.logL();
236   - if (m_best_logL == 0.0) {
237   -
238   - // Write header
239   - if (logTerse()) {
240   - log << std::endl;
241   - log.header1("Compute best-fit likelihood");
242   - }
243   -
244   - // Reoptimize if likelihood was not given before
245   - GOptimizerLM* opt = new GOptimizerLM();
246   - m_obs.optimize(*opt);
247   - m_obs.errors(*opt);
248   - m_best_logL = m_obs.logL();
249   -
250   - // Write optimised model into logger
251   - if (logTerse()) {
252   - log << m_obs.models() << std::endl;
253   - }
254   -
255   - } // endif: likelihood was zero
256   -
257   - // Compute parameter bracketing
258   - double value = m_model_par->value();
259   - double error = m_model_par->error();
260   - double parmin = value + m_sigma_min * error;
261   - double parmax = value + m_sigma_max * error;
262 240  
263 241 // Write header
264 242 if (logTerse()) {
265 243 log << std::endl;
266   - log.header1("Compute upper limit");
267   - log << gammalib::parformat("Model name");
268   - log << m_skymodel->name() << std::endl;
269   - log << gammalib::parformat("Parameter name");
270   - log << m_model_par->name() << std::endl;
271   - log << gammalib::parformat("Confidence level");
272   - log << m_confidence*100.0 << "%" << std::endl;
273   - log << gammalib::parformat("Log-likelihood difference");
274   - log << m_dlogL << std::endl;
275   - log << gammalib::parformat("Initial parameter range");
276   - log << "[";
277   - log << parmin;
278   - log << ", ";
279   - log << parmax;
280   - log << "]" << std::endl;
  244 + log.header1("Compute best-fit likelihood");
281 245 }
282 246  
283   - // Compute lower boundary
284   - error_bisection(parmin, value);
285   - double value_lo = m_model_par->value();
286   -
  247 + // Write optimised model into logger
287 248 if (logTerse()) {
288   - log << gammalib::parformat("Final lower parameter value");
289   - log << value_lo << std::endl;
  249 + log << m_obs.models() << std::endl;
290 250 }
291 251  
292   - // Reset parameter to previous value
293   - m_model_par->value(value);
294 252  
295   - // Compute upper boundary
296   - error_bisection(value, parmax);
297   - double value_hi = m_model_par->value();
  253 + // Continue only if source model exists
  254 + if (m_obs.models().contains(m_srcname)) {
  255 +
  256 + GModels& models = const_cast<GModels&>(m_obs.models());
  257 + m_skymodel = dynamic_cast<GModelSky*>(models[m_srcname]);
  258 + if (m_skymodel == NULL) {
  259 + std::string msg = "Source \""+m_srcname+"\" is not a sky model. "
  260 + "Please specify the name of a sky model for "
  261 + "parameter error computation.";
  262 + throw GException::invalid_value(G_RUN, msg);
  263 + }
  264 +
  265 + int npars = m_skymodel->spectral()->size();
  266 +
  267 +
  268 + for (int i = 0; i < npars; ++i)
  269 + {
  270 +
  271 + // Re-optimize
  272 + m_obs.optimize(*m_opt);
  273 +
  274 + if(m_skymodel->spectral()->at(i).is_fixed())
  275 + continue;
  276 +
  277 + m_model_par = &(m_skymodel->spectral()->at(i));
  278 +
  279 + // Compute parameter bracketing
  280 + m_value = m_model_par->factor_value();
  281 + double parmin = std::max(m_model_par->factor_min(),
  282 + m_value - 10*m_model_par->factor_error());
  283 + double parmax = std::min(m_model_par->factor_max(),
  284 + m_value + 10*m_model_par->factor_error());
  285 +
  286 + // Write header
  287 + if (logTerse()) {
  288 + log << std::endl;
  289 + log.header1("Compute parameter error");
  290 + log << gammalib::parformat("Model name");
  291 + log << m_skymodel->name() << std::endl;
  292 + log << gammalib::parformat("Parameter name");
  293 + log << m_model_par->name() << std::endl;
  294 + log << gammalib::parformat("Confidence level");
  295 + log << m_confidence*100.0 << "%" << std::endl;
  296 + log << gammalib::parformat("Log-likelihood difference");
  297 + log << m_dlogL << std::endl;
  298 + log << gammalib::parformat("Initial parameter range");
  299 + log << "[";
  300 + log << parmin;
  301 + log << ", ";
  302 + log << parmax;
  303 + log << "]" << std::endl;
  304 + }
  305 +
  306 + // Compute lower boundary
  307 + error_bisection(parmin, m_value);
  308 + double value_lo = m_model_par->factor_value();
  309 +
  310 + if (logTerse()) {
  311 + log << gammalib::parformat("Final lower parameter value");
  312 + log << value_lo << std::endl;
  313 + }
  314 +
  315 + // Reset parameter to original value
  316 + m_model_par->factor_value(m_value);
  317 +
  318 + // Compute upper boundary
  319 + error_bisection(m_value, parmax);
  320 + double value_hi = m_model_par->factor_value();
  321 +
  322 + if (logTerse()) {
  323 + log << gammalib::parformat("Final upper parameter");
  324 + log << value_hi << std::endl;
  325 + }
  326 +
  327 + // Reset parameter to original value
  328 + m_model_par->factor_value(m_value);
  329 +
  330 + // Compute errors
  331 + m_error = 0.5*(value_hi - value_lo);
  332 + double error_max = std::max(value_hi-m_value, m_value-value_lo);
  333 + double error_min = std::min(value_hi-m_value, m_value-value_lo);
  334 +
  335 +
  336 + // Write results to logfile
  337 + if (logTerse()) {
  338 + log << std::endl;
  339 + log.header1("Error results");
  340 + log << gammalib::parformat("Max error");
  341 + log << error_max;
  342 + log << gammalib::parformat("Min error");
  343 + log << error_min;
  344 + log << gammalib::parformat("Mean parameter error");
  345 + log << m_error;
  346 + log << " " << m_model_par->unit();
  347 + log << std::endl;
  348 + log << gammalib::parformat("Parameter scale");
  349 + log << m_model_par->scale();
  350 + log << std::endl;
  351 + }
  352 +
  353 + // Save error result
  354 + m_model_par->factor_error(m_error);
  355 +
  356 + }
298 357  
299   - if (logTerse()) {
300   - log << gammalib::parformat("Final upper parameter");
301   - log << value_hi << std::endl;
302 358 }
303 359  
304   - // Compute error
305   - double error = value_hi - value_lo;
306 360  
307   - // Write results to logfile
  361 + // Return
  362 + return;
  363 +}
  364 +
  365 +/***********************************************************************//**
  366 + * @brief Save maps
  367 + *
  368 + * This method saves the error to an ascii file.
  369 + *
  370 + * @todo No yet implemented as we have no clear use case yet for saving
  371 + * the result.
  372 + ***************************************************************************/
  373 +void cterror::save(void)
  374 +{
  375 + // Write header
308 376 if (logTerse()) {
309 377 log << std::endl;
310   - log.header1("Error results");
311   - log << gammalib::parformat("Parameter error");
312   - log << error;
313   - log << " " << m_model_par->unit();
314   - log << std::endl;
  378 + log.header1("Save results");
315 379 }
316 380  
317   - // Recover original models
318   - m_obs.models(models_orig);
  381 +
  382 + // Get output filename
  383 + std::string outmodel = (*this)["outfile"].filename();
  384 +
  385 + // Write results out as XML model
  386 + if (gammalib::toupper(outmodel) != "NONE") {
  387 + m_obs.models().save(outmodel);
  388 + }
319 389  
320 390 // Return
321 391 return;
... ... @@ -334,11 +404,13 @@ void cterror::init_members(void)
334 404 {
335 405 // Initialise user parameters
336 406 m_srcname.clear();
337   - m_confidence = 0.95;
  407 + m_confidence = 0.68;
338 408 m_sigma_min = 0.0;
339 409 m_sigma_max = 0.0;
340   - m_tol = 1.0e-6;
  410 + m_tol = 1.0e-3;
341 411 m_max_iter = 50;
  412 + m_value = 0.0;
  413 + m_error = 0.0;
342 414  
343 415 // Initialise protected members
344 416 m_obs.clear();
... ... @@ -367,16 +439,11 @@ void cterror::copy_members(const cterror&amp; app)
367 439 m_tol = app.m_tol;
368 440 m_max_iter = app.m_max_iter;
369 441  
370   -
371 442 // Copy protected members
372 443 m_obs = app.m_obs;
373 444 m_dlogL = app.m_dlogL;
374 445 m_best_logL = app.m_best_logL;
375 446  
376   -
377   - // Extract model parameter
378   - get_model_parameter();
379   -
380 447 // Return
381 448 return;
382 449 }
... ... @@ -416,7 +483,7 @@ void cterror::get_parameters(void)
416 483 } // endif: there was no observation in the container
417 484  
418 485  
419   - // If there is are no models associated with the observations then
  486 + // If there are no models associated with the observations then
420 487 // load now the model definition
421 488 if (m_obs.models().size() == 0) {
422 489  
... ... @@ -437,11 +504,9 @@ void cterror::get_parameters(void)
437 504 throw GException::invalid_value(G_GET_PARAMETERS, msg);
438 505 }
439 506  
440   - // Get relevant model and parameter for upper limit computation
441   - get_model_parameter();
442   -
443 507 // Get confidence level and transform into log-likelihood difference
444 508 m_confidence = (*this)["confidence"].real();
  509 +
445 510 double sigma = gammalib::erfinv(m_confidence) * gammalib::sqrt_two;
446 511 m_dlogL = (sigma*sigma) / 2.0;
447 512  
... ... @@ -449,70 +514,10 @@ void cterror::get_parameters(void)
449 514 m_sigma_min = (*this)["sigma_min"].real();
450 515 m_sigma_max = (*this)["sigma_max"].real();
451 516  
452   - // Read energy values
453   - m_eref = (*this)["eref"].real();
454   - m_emin = (*this)["emin"].real();
455   - m_emax = (*this)["emax"].real();
456   -
457 517 // Read precision
458 518 m_tol = (*this)["tol"].real();
459 519 m_max_iter = (*this)["max_iter"].integer();
460 520  
461   - // Return
462   - return;
463   -}
464   -
465   -
466   -/***********************************************************************//**
467   - * @brief Get application parameters
468   - *
469   - * @exception GException::invalid_value
470   - * Did not find a valid model parameter
471   - *
472   - * Extracts a pointer to the sky model (m_skymodel) and a pointer to the
473   - * relevant model parameter (m_model_par) from the model container.
474   - ***************************************************************************/
475   -void cterror::get_model_parameter(void)
476   -{
477   - // Continue only if source model exists
478   - if (m_obs.models().contains(m_srcname)) {
479   -
480   - // Get relevant model and parameter for upper limit computation.
481   - GModels& models = const_cast<GModels&>(m_obs.models());
482   - m_skymodel = dynamic_cast<GModelSky*>(models[m_srcname]);
483   - if (m_skymodel == NULL) {
484   - std::string msg = "Source \""+m_srcname+"\" is not a sky model. "
485   - "Please specify the name of a sky model for "
486   - "upper limit computation.";
487   - throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
488   - }
489   - if (m_skymodel->spectral()->type() == "NodeFunction") {
490   - std::string msg = "\"NodeFunction\" cannot be used as spectral "
491   - "model for an upper limit computation. "
492   - "Please specify another spectral model.";
493   - throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
494   - }
495   - if (m_skymodel->spectral()->has_par("Normalization")) {
496   - m_model_par = &(m_skymodel->spectral()->operator[]("Normalization"));
497   - }
498   - else if (m_skymodel->spectral()->has_par("Prefactor")) {
499   - m_model_par = &(m_skymodel->spectral()->operator[]("Prefactor"));
500   - }
501   - else if (m_skymodel->spectral()->has_par("Integral")) {
502   - m_model_par = &(m_skymodel->spectral()->operator[]("Integral"));
503   - }
504   - else if (m_skymodel->spectral()->has_par("Value")) {
505   - m_model_par = &(m_skymodel->spectral()->operator[]("Value"));
506   - }
507   - else {
508   - std::string msg = "Require spectral parameter \"Normalization\", "
509   - "\"Prefactor\", \"Integral\" or \"Value\" for "
510   - "upper limit computation. The specified source "
511   - "\""+m_srcname+"\" does not have such a parameter.";
512   - throw GException::invalid_value(G_GET_MODEL_PARAMETER, msg);
513   - }
514   -
515   - } // endif: source model existed
516 521  
517 522 // Return
518 523 return;
... ... @@ -551,10 +556,35 @@ void cterror::error_bisection(const double&amp; min, const double&amp; max)
551 556  
552 557 // Throw exception if maximum iterations are reached
553 558 if (iter > m_max_iter) {
554   - std::string msg = "The maximum number of "+gammalib::str(m_max_iter)+
555   - " has been reached. You may consider to increase"
556   - " the \"max_iter\" parameter and re-run cterror.";
557   - throw GException::invalid_value(G_UL_BISECTION, msg);
  559 + if(wrk_min - m_model_par->factor_min() < m_tol)
  560 + {
  561 + std::string msg = "The "+m_model_par->name()+" parameter minimum has been"
  562 + " reached during error calculation. To obtain accurate "
  563 + " errors, consider to set the minimum to a lower value,"
  564 + " and re-run cterror.";
  565 + if (logTerse()) {
  566 + log << msg;
  567 + }
  568 + break;
  569 + }
  570 + else if(m_model_par->factor_max() - wrk_max < m_tol)
  571 + {
  572 + std::string msg = "The "+m_model_par->name()+" parameter maximum has been"
  573 + " reached during error calculation. To obtain accurate "
  574 + " errors, consider to set the maxmimum to a higher value"
  575 + ", and re-run cterror.";
  576 + if (logTerse()) {
  577 + log << msg;
  578 + }
  579 + break;
  580 + }
  581 + else
  582 + {
  583 + std::string msg = "The maximum number of "+gammalib::str(m_max_iter)+
  584 + " has been reached. You may consider to increase"
  585 + " the \"max_iter\" parameter, and re-run cterror.";
  586 + throw GException::invalid_value(G_ERR_BISECTION, msg);
  587 + }
558 588 }
559 589  
560 590 // Compute center of boundary
... ... @@ -568,12 +598,27 @@ void cterror::error_bisection(const double&amp; min, const double&amp; max)
568 598 break;
569 599 }
570 600  
571   - // Change boundaries for further iteration
572   - if (eval_mid > 0.0) {
573   - wrk_max = mid;
  601 + // If we are on the crescent side of the parabola
  602 + if (mid > m_value)
  603 + {
  604 + // Change boundaries for further iteration
  605 + if (eval_mid > 0.0) {
  606 + wrk_max = mid;
  607 + }
  608 + else if (eval_mid < 0.0) {
  609 + wrk_min = mid;
  610 + }
574 611 }
575   - else if (eval_mid < 0.0) {
576   - wrk_min = mid;
  612 + // If we are on the decrescent side of the parabola
  613 + else
  614 + {
  615 + // Change boundaries for further iteration
  616 + if (eval_mid > 0.0) {
  617 + wrk_min = mid;
  618 + }
  619 + else if (eval_mid < 0.0) {
  620 + wrk_max = mid;
  621 + }
577 622 }
578 623  
579 624 // Increment counter
... ... @@ -602,10 +647,16 @@ double cterror::evaluate(const double&amp; value)
602 647 double logL = 0.0;
603 648  
604 649 // Check if given parameter is within boundaries
605   - if (value > m_model_par->min() && value < m_model_par->max()) {
  650 + if (value > m_model_par->factor_min() && value < m_model_par->factor_max()) {
606 651  
607 652 // Change parameter factor
608   - m_model_par->value(value);
  653 + m_model_par->factor_value(value);
  654 +
  655 + //Fix parameter
  656 + m_model_par->fix();
  657 +
  658 + // Re-optimize
  659 + m_obs.optimize(*m_opt);
609 660  
610 661 // Evaluate likelihood for new model container
611 662 m_obs.eval();
... ... @@ -613,6 +664,9 @@ double cterror::evaluate(const double&amp; value)
613 664 // Retrieve likelihood
614 665 logL = m_obs.logL();
615 666  
  667 + // Free parameter
  668 + m_model_par->free();
  669 +
616 670 } // endif: value was inside allowed range
617 671  
618 672 // ... otherwise signal that the parameter went outside the boundaries
... ... @@ -627,6 +681,7 @@ double cterror::evaluate(const double&amp; value)
627 681 // Compute function value
628 682 double logL_difference = logL - m_best_logL - m_dlogL;
629 683  
  684 +
630 685 // Return
631 686 return logL_difference;
632 687 }
... ...
src/cterror/cterror.hpp
... ... @@ -61,7 +61,7 @@ public:
61 61 void run(void);
62 62 void save(void);
63 63 const GObservations& obs(void) const;
64   -
  64 + const GOptimizer* opt(void) const;
65 65  
66 66 protected:
67 67 // Protected methods
... ... @@ -69,7 +69,6 @@ protected:
69 69 void copy_members(const cterror& app);
70 70 void free_members(void);
71 71 void get_parameters(void);
72   - void get_model_parameter(void);
73 72 double evaluate(const double& value);
74 73 void error_bisection(const double& min, const double& max);
75 74  
... ... @@ -80,6 +79,8 @@ protected:
80 79 double m_sigma_max; //!< Starting value maximum (multiple fit errors above fit values)
81 80 double m_tol; //!< Tolerance for limit determination
82 81 int m_max_iter; //!< Maximum number of iterations
  82 + double m_value; //!< Parameter value
  83 + double m_error; //!< Parameter error
83 84  
84 85 // Protected members
85 86 GObservations m_obs; //!< Observation container
... ... @@ -87,6 +88,7 @@ protected:
87 88 GModelSky* m_skymodel; //!< Pointer to sky model
88 89 GModelPar* m_model_par; //!< Pointer to model parameter
89 90 double m_best_logL; //!< Best fit log likelihood of given model
  91 + GOptimizerLM* m_opt;
90 92  
91 93 };
92 94  
... ... @@ -102,5 +104,15 @@ const GObservations&amp; cterror::obs(void) const
102 104 return m_obs;
103 105 }
104 106  
  107 +/***********************************************************************//**
  108 + * @brief Return optimizer
  109 + *
  110 + * @return Pointer to optimizer
  111 + ***************************************************************************/
  112 +inline
  113 +const GOptimizer* cterror::opt(void) const
  114 +{
  115 + return m_opt;
  116 +}
105 117  
106 118 #endif /* CTERROR_HPP */
... ...
src/cterror/cterror.par
... ... @@ -19,6 +19,7 @@
19 19 #===================
20 20 inobs, f, a, "events.fits",,, "Input event list, counts cube or observation definition file"
21 21 inmodel, f, a, "$CTOOLS/share/models/crab.xml",,, "Source model"
  22 +outfile, f, a, "results.xml",,, "Save results"
22 23 srcname, s, a, "Crab",,, "Source of interest"
23 24 expcube, f, a, "NONE",,, "Exposure cube file (only needed for stacked analysis)"
24 25 psfcube, f, a, "NONE",,, "PSF cube file (only needed for stacked analysis)"
... ... @@ -32,10 +33,7 @@ irf, s, a, &quot;cta_dummy_irf&quot;,,, &quot;Instrument response function&quot;
32 33 confidence, r, h, 0.68,0.0,1.0, "Confidence level"
33 34 sigma_min, r, h, 0.0,,, "Start minimum value (multiple sigmas above fit value)"
34 35 sigma_max, r, h, 10.0,,, "Start maximum value (multiple sigmas above fit value)"
35   -eref, r, h, 1.0,,, "Reference energy for differential limits (TeV)"
36   -emin, r, h, 1.0,,, "Minimum energy for flux limits (TeV)"
37   -emax, r, h, 100.0,,, "Maximum energy for flux limits (TeV)"
38   -tol, r, h, 1e-5,,, "Computation tolerance"
  36 +tol, r, h, 1e-3,,, "Computation tolerance"
39 37 max_iter, i, h, 50,,, "Maximum number of iterations"
40 38  
41 39 #
... ...
src/cterror/main.cpp
... ... @@ -28,7 +28,7 @@
28 28 #ifdef HAVE_CONFIG_H
29 29 #include <config.h>
30 30 #endif
31   -#include <cstdio>
  31 +#include <iostream>
32 32 #include "cterror.hpp"
33 33  
34 34  
... ...