Commit 784e9fe5cf17dfe651c77c5c748c5041a4be22ca

Authored by knodlseder
1 parent b45c4d28

add remove flag to fix parameters with zero covariance

include/GOptimizerLM.hpp
... ... @@ -114,9 +114,10 @@ protected:
114 114 std::vector<int> m_hit_minimum; //!< Bookkeeping of successive minimum hits
115 115 std::vector<int> m_hit_maximum; //!< Bookkeeping of successive maximum hits
116 116 std::vector<bool> m_par_freeze; //!< Bookkeeping of parameter freeze
  117 + std::vector<bool> m_par_remove; //!< Bookkeeping of parameter removal
117 118 double m_lambda; //!< Actual lambda
118 119 double m_value; //!< Actual function value
119   - double m_diag_load; //!< Value for diagonal loading
  120 + //double m_diag_load; //!< Value for diagonal loading
120 121 int m_status; //!< Fit status
121 122 int m_iter; //!< Iteration
122 123 GLog* m_logger; //!< Pointer to optional logger
... ...
src/opt/GOptimizerLM.cpp
... ... @@ -289,13 +289,14 @@ void GOptimizerLM::init_members(void)
289 289 m_max_stall = 10;
290 290 m_max_hit = 3; //!< Maximum successive boundary hits before freeze
291 291 m_step_adjust = true;
292   - m_diag_load = 1.0e-100;
  292 + //m_diag_load = 1.0e-100;
293 293  
294 294 // Initialise bookkeeping arrays
295 295 m_hit_boundary.clear();
296 296 m_hit_minimum.clear();
297 297 m_hit_maximum.clear();
298 298 m_par_freeze.clear();
  299 + m_par_remove.clear();
299 300  
300 301 // Initialise optimizer values
301 302 m_lambda = m_lambda_start;
... ... @@ -326,11 +327,12 @@ void GOptimizerLM::copy_members(const GOptimizerLM&amp; opt)
326 327 m_max_iter = opt.m_max_iter;
327 328 m_max_stall = opt.m_max_stall;
328 329 m_step_adjust = opt.m_step_adjust;
329   - m_diag_load = opt.m_diag_load;
  330 + //m_diag_load = opt.m_diag_load;
330 331 m_hit_boundary = opt.m_hit_boundary;
331 332 m_hit_minimum = opt.m_hit_minimum;
332 333 m_hit_maximum = opt.m_hit_maximum;
333 334 m_par_freeze = opt.m_par_freeze;
  335 + m_par_remove = opt.m_par_remove;
334 336 m_lambda = opt.m_lambda;
335 337 m_value = opt.m_value;
336 338 m_status = opt.m_status;
... ... @@ -383,33 +385,43 @@ void GOptimizerLM::optimize(GOptimizerFunction* fct, GOptimizerPars* pars)
383 385 m_hit_minimum.clear();
384 386 m_hit_maximum.clear();
385 387 m_par_freeze.clear();
  388 + m_par_remove.clear();
386 389 m_hit_boundary.reserve(m_npars);
387 390 m_hit_minimum.reserve(m_npars);
388 391 m_hit_maximum.reserve(m_npars);
389 392 m_par_freeze.reserve(m_npars);
  393 + m_par_remove.reserve(m_npars);
390 394 for (int i = 0; i < m_npars; ++i) {
391 395 m_hit_boundary.push_back(false);
392 396 m_hit_minimum.push_back(0);
393 397 m_hit_maximum.push_back(0);
394 398 m_par_freeze.push_back(false);
  399 + m_par_remove.push_back(false);
395 400 }
396 401  
397 402 // Initial evaluation
398 403 fct->eval(*pars);
399 404  
400 405 // If a free parameter has a zero diagonal element in the curvature
401   - // matrix then load it with a small value so that it will be fitted.
402   - // This is needed in the LM algorithm as we don't use the full Hessian
403   - // matrix but only the curvature. The problem appears in the unbinned
  406 + // matrix then remove this parameter definitely from the fit as it
  407 + // otherwise will block the fit. The problem appears in the unbinned
404 408 // fitting where parameter gradients may be zero (due to the truncation
405   - // of the PSF), but the Npred gradient is not zero. As the Npred
406   - // curvature is by definition zero, we would never move the
407   - // corresponding fit parameter, and thus block the fit. This is
408   - // prevented by this kluge.
  409 + // of the PSF), but the Npred gradient is not zero. In principle we
  410 + // could use the Npred gradient for fitting (I guess), but I still
  411 + // have to figure out how ... (the diagonal loading was not so
  412 + // successful as it faked early convergence)
409 413 for (int ipar = 0; ipar < m_npars; ++ipar) {
410 414 if (pars->par(ipar).isfree()) {
411   - if ((*fct->covar())(ipar,ipar) == 0.0)
412   - (*fct->covar())(ipar,ipar) = m_diag_load;
  415 + if ((*fct->covar())(ipar,ipar) == 0.0) {
  416 + //(*fct->covar())(ipar,ipar) = m_diag_load;
  417 + if (m_logger != NULL) {
  418 + *m_logger << " Parameter \"" << pars->par(ipar).name();
  419 + *m_logger << "\" has zero covariance.";
  420 + *m_logger << " Fix parameter." << std::endl;
  421 + }
  422 + m_par_remove[ipar] = true;
  423 + pars->par(ipar).fix();
  424 + }
413 425 }
414 426 }
415 427  
... ... @@ -560,7 +572,7 @@ void GOptimizerLM::optimize(GOptimizerFunction* fct, GOptimizerPars* pars)
560 572 // Free now all temporarily frozen parameters so that the resulting
561 573 // model has the same attributes as the initial model
562 574 for (int ipar = 0; ipar < m_npars; ++ipar) {
563   - if (m_par_freeze[ipar]) {
  575 + if (m_par_freeze[ipar] || m_par_remove[ipar]) {
564 576 pars->par(ipar).free();
565 577 if (m_logger != NULL) {
566 578 *m_logger << " Free parameter \""
... ... @@ -748,18 +760,25 @@ void GOptimizerLM::iteration(GOptimizerFunction* fct, GOptimizerPars* pars)
748 760 fct->eval(*pars);
749 761  
750 762 // If a free parameter has a zero diagonal element in the curvature
751   - // matrix then load it with a small value so that it will be fitted.
752   - // This is needed in the LM algorithm as we don't use the full Hessian
753   - // matrix but only the curvature. The problem appears in the unbinned
  763 + // matrix then remove this parameter definitely from the fit as it
  764 + // otherwise will block the fit. The problem appears in the unbinned
754 765 // fitting where parameter gradients may be zero (due to the truncation
755   - // of the PSF), but the Npred gradient is not zero. As the Npred
756   - // curvature is by definition zero, we would never move the
757   - // corresponding fit parameter, and thus block the fit. This is
758   - // prevented by this kluge.
  766 + // of the PSF), but the Npred gradient is not zero. In principle we
  767 + // could use the Npred gradient for fitting (I guess), but I still
  768 + // have to figure out how ... (the diagonal loading was not so
  769 + // successful as it faked early convergence)
759 770 for (int ipar = 0; ipar < m_npars; ++ipar) {
760 771 if (pars->par(ipar).isfree()) {
761   - if ((*fct->covar())(ipar,ipar) == 0.0)
762   - (*fct->covar())(ipar,ipar) = m_diag_load;
  772 + if ((*fct->covar())(ipar,ipar) == 0.0) {
  773 + //(*fct->covar())(ipar,ipar) = m_diag_load;
  774 + if (m_logger != NULL) {
  775 + *m_logger << " Parameter \"" << pars->par(ipar).name();
  776 + *m_logger << "\" has zero covariance.";
  777 + *m_logger << " Fix parameter." << std::endl;
  778 + }
  779 + m_par_remove[ipar] = true;
  780 + pars->par(ipar).fix();
  781 + }
763 782 }
764 783 }
765 784  
... ...