#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <iterator>
#include <random>
#include <chrono>

#include "SFramework/TSLikelihoodScanner.h"

#include "TKey.h"
#include "RooNLLVar.h"
#include "RooAbsPdf.h"
#include "RooDataSet.h"
#include "RooFitResult.h"
#include "RooRealVar.h"
#include "Math/ProbFuncMathCore.h"
#include "Math/MinimizerOptions.h"
#include "Math/QuantFuncMathCore.h"
#include "TStopwatch.h"
#include "TGraph.h"
#include "TAxis.h"
#include "TH1F.h"
#include "TCanvas.h"

#include "QFramework/TQIterator.h"
#include "QFramework/TQNamedTaggable.h"

#include "QFramework/TQLibrary.h"

#include "SFramework/TSUtils.h"

ClassImp(TSLikelihoodScanner)

namespace {
  inline bool areEqualAbs(Double_t af, Double_t bf, Double_t epsilon) {
    //return kTRUE if absolute difference between af and bf is less than epsilon
    return TMath::Abs(af-bf) < epsilon;
  }
}

//__________________________________________________________________________________|___________

TSLikelihoodScanner::TSLikelihoodScanner(RooWorkspace * ws, TQFolder* snapshots) : TSStatisticsCalculator("TSLikelihoodScanner",ws,snapshots) {
  // default constructor
}


//__________________________________________________________________________________|___________

TSLikelihoodScanner::~TSLikelihoodScanner() {
  // default destructor
}


//__________________________________________________________________________________|___________

void TSLikelihoodScanner::info(TString message) {
  // print an info message
  std::cout << "SFramework/TSLikelihoodScanner: " << message.Data() << std::endl;
}

//__________________________________________________________________________________|___________

TString TSLikelihoodScanner::stringify(const Point& p){
  // get a string-representation of a point in likelihood space
  std::stringstream ss;
  bool first = true;
  for(const auto& par:p){
    if(!first) ss << ", ";
    first=false;
    ss << par.first;
    ss << "=";
    ss << par.second;
  }
  return TString(ss.str().c_str());
}

//__________________________________________________________________________________|___________

std::map<TString,TQFolder*> TSLikelihoodScanner::collectParameters(TQFolder* options){
  // collect all the parameters to be scanned
  std::map<TString,TQFolder*> params;
  TQFolderIterator itr(options->getListOfFolders("?"));
  while(itr.hasNext()){
    TQFolder* par = itr.readNext();
    if(!par) continue;
    TString parname= par->getTagStringDefault("name",par->GetName());
    params[parname] = par;
    RooRealVar* v = fWorkspace->var(parname);
    if(!v){
      error(TString::Format("unable to retrieve parameter '%s' from workspace!",parname.Data()));
    }
  }
  return params;
}

//__________________________________________________________________________________|___________

TQFolder* TSLikelihoodScanner::runPreFit(TQFolder * options){
  // run a pre-fit, refitting the unconditional minimum
  info("running pre-fit");

  const TString datasetName = options->getTagStringDefault("datasetName", "obsData");
  TString snapshotInitial = options->getTagStringDefault("snapshot.initial",options->getTagStringDefault("snapshot",TString::Format("SnSh_AllVars_Unconditional_%s", datasetName.Data())));
  TString snapshotUnconditional = options->getTagStringDefault("snapshot.unconditional",TString::Format("SnSh_AllVars_Unconditional_%s", datasetName.Data()));

  // setup the fit options

  TQTaggable fitOptions;
  fitOptions.importTagsWithoutPrefix(*options,"fit.");
  fitOptions.setTagBool("reuseMinimizer",false); // this is changed by the "recycle" option
  fitOptions.setTagBool("reuseNll",false); // this we always set to true for consistency
  fitOptions.setTagBool("adjustPOI",false);
  fitOptions.setTagString("datasetName",datasetName);

  // iterate of parameters to scan to collect their names
  std::map<TString,TQFolder*> params = collectParameters(options);

  // load nominal snapshot to start from
  fitOptions.setTagString("snapshot",snapshotInitial);
  if(!this->loadSnapshot(&fitOptions)){
    throw std::runtime_error(TString::Format("unable to load snapshot '%s'",snapshotInitial.Data()).Data());
  } else {
    info(TString::Format("using snapshot '%s'",snapshotInitial.Data()));
  }

  TQFolder* uncondResult = NULL;
  this->setParametersConstFloat(fWorkspace->allVars(),&fitOptions);
  if(options->getTagBoolDefault("refit",true)){
    // refit the unconditional minimum to be extra-safe
    info("refitting unconditional minimum");
    for(auto p:params){
      RooRealVar* v = fWorkspace->var(p.first);
      if(!v) throw std::runtime_error(TString::Format("unable to find parameter '%s'",p.first.Data()).Data());
      v->setConstant(false);
    }
    this->setup(datasetName,&fitOptions);
    uncondResult = this->minimizeNll(&fitOptions);
    int strategy = -1;
    int status = -1;
    if(uncondResult){
      uncondResult->getTagInteger("status", status);
      uncondResult->getTagInteger("strategy", strategy);
    }
    if (!uncondResult || (status != 0 && status != 1)) {
      throw std::runtime_error(TString::Format("runCalculation(...): Unconditional fit failed with status=%d (strategy %d). Stopping!",status,strategy).Data());
    }

  } else {

    // acquire the unconditional point and fit result from the workspace snapshot loaded previously
    uncondResult = new TQFolder("unconditional");
    RooArgSet floatVars(fWorkspace->allVars());
    TSUtils::removeConstantParameters(floatVars);
    TSUtils::convertParameterList(&floatVars,uncondResult->getFolder("floatParsFinal+"));
    RooArgSet constVars(fWorkspace->allVars());
    TSUtils::removeFloatingParameters(floatVars);
    TSUtils::convertParameterList(&constVars,uncondResult->getFolder("constPars+"));

    for(auto par:params){
      TString name(par.first);
      TQFolder * f = uncondResult->getFolder("floatParsFinal+")->getFolder(name+"+");
      double val = fWorkspace->var(name)->getVal();
      f->setTagDouble("val",val);
    }
    double nllval = fNll->getVal();

    uncondResult->setTagBool("dummy",true);
    uncondResult->setTagDouble("minNll",nllval);
    info(TString::Format("re-using unconditional minimum from snapshot '%s' (Nll=%.5f)",snapshotUnconditional.Data(),nllval));
  }
  // unconditional minimal NLL
  Double_t uncondMinNll;
  if(!uncondResult->getTagDouble("minNll",uncondMinNll)){
    throw std::runtime_error("unable to dermine Nll minimum!");
  }

  // if the initial snapshot is not supposed to be the unconditional one, then create it
  if(snapshotInitial != snapshotUnconditional){
    info(TString::Format("runCalculation(...): saving unnconditional snapshot as '%s'!",snapshotUnconditional.Data()));
    fWorkspace->saveSnapshot(snapshotUnconditional.Data(),fWorkspace->allVars());
  }

  this->resetOffset();
  // When an offset is applied the offsetted Nll is not preserved, not able to check for inconsistencies
  if (uncondMinNll != fNll->getVal() && !fitOptions.getTagBoolDefault("offset",true)) {
    warn(TString::Format("inconsistency detected (%.5f vs %.5f), Nll value of unconditional fit not preserved accurately through offsetting!",uncondMinNll,fNll->getVal()).Data());
    uncondMinNll = fNll->getVal();
    uncondResult->setTagDouble("minNll",uncondMinNll);
  }
  uncondResult->setTagBool("unconditional",true);

  Point uncond;
  for(auto p:params){
    TQFolder* floatParsFinal = uncondResult->getFolder("floatParsFinal+");
    TQFolder* par = floatParsFinal->getFolder(p.first);
    if(par){
      uncond[p.first] = par->getTagDoubleDefault("val",0.);
    }
  }
  info(TString::Format("found unconditional minimum (point 0) at %s with %.5f",stringify(uncond).Data(),uncondMinNll));

  return uncondResult;
}

//__________________________________________________________________________________|___________

TQFolder * TSLikelihoodScanner::runCalculation(TQFolder * options){
  // perform the entire calculation chain, including the pre-fit as well as the actual scan

  if (!fWorkspace || !fModelConfig || !options){
    // expect valid inputs
    return NULL;
  }

  TQFolder* uncondResult = NULL;
  const TString datasetName = options->getTagStringDefault("datasetName", "obsData");
  bool refitUnconditional = options->getTagBoolDefault("refitUnconditional", true);
  TString snapshotUnconditional = options->getTagStringDefault("snapshot.unconditional",options->getTagStringDefault("snapshot",TString::Format("SnSh_AllVars_Unconditional_%s", datasetName.Data())));
  if(!fWorkspace->loadSnapshot(snapshotUnconditional) || refitUnconditional){
    uncondResult = runPreFit(options);
  }

  std::map<Point,TQFolder*> result = runScan(options,uncondResult);

  TQFolder* scan = finalizeScan(options,result);
  scan->setTagString("content","points");

  const TString snapshotNominal = options->getTagStringDefault("snapshot.nominal","SnSh_AllVars_Nominal");
  fWorkspace->loadSnapshot(snapshotNominal);

  return scan;
}

//__________________________________________________________________________________|___________

std::map<TSLikelihoodScanner::Point,TQFolder*> TSLikelihoodScanner::runScan(TQFolder * options, TQFolder* uncondResult){
  // run scan of the conditional points
  TString logfile;
  bool redirect = options->getTagString("fit.logToFile",logfile);
  // read the options
  bool recycle = options->getTagBoolDefault("recycle",false);
  bool shufflePoints = options->getTagBoolDefault("shufflePoints",false);
  bool startFromLastPoint = options->getTagBoolDefault("startFromLastPoint",false);
  const TString datasetName = options->getTagStringDefault("datasetName", "obsData");
  const TString snapshotUnconditional = options->getTagStringDefault("snapshot.unconditional",TString::Format("SnSh_AllVars_Unconditional_%s", datasetName.Data()));
  const TString snapshotInitial =  options->getTagStringDefault("snapshot.initial",snapshotUnconditional);

  // setup the fit options
  TQTaggable fitOptions;
  fitOptions.importTagsWithoutPrefix(*options,"fit.");
  // bool hesse = fitOptions.getTagBoolDefault("runHesse",false); // BW: hashed (unused variable)
  fitOptions.setTagBool("reuseNll",true); // this we always set to true for consistency
  fitOptions.setTagBool("adjustPOI",false);
  fitOptions.setTagString("datasetName",datasetName);

  int constOpt = fitOptions.getTagIntegerDefault("constOptimize",1);

  // iterate of parameters to scan to collect their names
  std::map<TString,TQFolder*> params = collectParameters(options);
  fitOptions.setTagBool("runMinos",false);
  fitOptions.setTagBool("runHesse",false);
  fitOptions.setTagBool("loadSnapshot",false);

  for(const auto& par:params){
    fitOptions.removeTag(TString("initParam.")+par.first);
    fitOptions.removeTag(TString("presetParam.")+par.first);
  }

  // create the list of scheduled points
  std::vector<Point> points;
  Point emptypoint;
  std::vector<TQFolder*> folders;
  for(auto p:params){
    folders.push_back(p.second);
  }
  generatePoints(folders,points,emptypoint,0);

  // iterate over all scheduled points
  const size_t npoints = points.size();
  info(TString::Format("running scan over %d points",(int)npoints));

  size_t lastPoint  = std::min(options->getTagIntegerDefault("onlyPoints.last",npoints-1),(int)(npoints-1));
  size_t firstPoint = options->getTagIntegerDefault("onlyPoints.first",0);
  if(shufflePoints){
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    std::shuffle ( points.begin()+firstPoint, points.begin()+lastPoint, std::default_random_engine(seed));
  }

  Point uncond;
  std::map<TSLikelihoodScanner::Point,TQFolder*> result;
  bool isFirstPoint = true;
  RooArgSet* allVars = NULL;
  for(size_t ipoint = firstPoint; ipoint<=lastPoint; ++ipoint){
    const Point& point(points[ipoint]);

    // if this is the first point, take care that we don't need to recreate the minimizer everytime
    if(isFirstPoint){

      // create the nll
      fWorkspace->loadSnapshot(snapshotUnconditional);
      this->setParametersConstFloat(fWorkspace->allVars(),&fitOptions);
      for(const auto& par:point){
        RooRealVar* var = fWorkspace->var(par.first);
        var->setConstant(true);
      }
      fitOptions.setTagBool("reuseMinimizer",true);
      if(redirect) TQLibrary::redirect(logfile,true);
      this->setup(datasetName,&fitOptions);
      if(redirect) TQLibrary::restore();
      allVars = fNll->getVariables();

      // check for the unconditional result
      if(uncondResult){

        if(!uncondResult->getTagBoolDefault("unconditional",false)) throw std::runtime_error("internal error: unconditional result is missing the 'unconditional' tag!");

        // prepare the uncondtional point from the fit result
        for(auto par:params){
          TString name(par.first);
          TQFolder * f = uncondResult->getFolder("floatParsFinal")->getFolder(name);
          if(!f){
            throw std::runtime_error(TString::Format("unable to find parameter '%s' in fit result!",name.Data()).Data());
          }
          double val = f->getTagDoubleDefault("val");
          uncond[name] = val;
        }
      } else {
        // acquire the unconditional point and fit result from the workspace snapshot loaded previously

        uncondResult = new TQFolder("unconditionalDummy");
        RooArgSet floatVars(fWorkspace->allVars());
        floatVars.remove(*(fModelConfig->GetObservables()));
        floatVars.remove(*(fModelConfig->GetGlobalObservables()));
        TSUtils::removeConstantParameters(floatVars);
        TSUtils::convertParameterList(&floatVars,uncondResult->getFolder("floatParsFinal+"));
        RooArgSet constVars(fWorkspace->allVars());
        constVars.remove(*(fModelConfig->GetObservables()));
        constVars.remove(*(fModelConfig->GetGlobalObservables()));
        TSUtils::removeFloatingParameters(floatVars);
        TSUtils::convertParameterList(&constVars,uncondResult->getFolder("constPars+"));

        for(auto par:params){
          TString name(par.first);
          TQFolder * f = uncondResult->getFolder("floatParsFinal+")->getFolder(name+"+");
          double val = fWorkspace->var(name)->getVal();
          f->setTagDouble("val",val);
          uncond[name] = val;
        }
        TSUtils::setParameterValues(allVars,fWorkspace->allVars());
        double nllval = fNll->getVal();
        this->resetOffset();
        if(nllval != fNll->getVal()){
          throw std::runtime_error("Nll offset broken!");
        }
        uncondResult->setTagBool("unconditional",true);
        uncondResult->setTagBool("dummy",true);
        uncondResult->setTagDouble("minNll",nllval);
        info(TString::Format("re-using unconditional minimum (point 0) from snapshot '%s' at %s (Nll=%.5f)",snapshotUnconditional.Data(),stringify(uncond).Data(),nllval));
      }
      result[uncond] = uncondResult;
    }

    // acquire the starting values
    if(isFirstPoint || !startFromLastPoint){
      fWorkspace->loadSnapshot(snapshotInitial);
      // set the the const/float attributes so the parameter counting doesn't get confused later
      this->setParametersConstFloat(fWorkspace->allVars(),&fitOptions);
      for(const auto& par:point){
        RooRealVar* var = fWorkspace->var(par.first);
        var->setConstant(true);
      }
    }

    // set the POI values to the point
    bool isuncond = true;
    for(const auto& par:point){
      RooRealVar* var = fWorkspace->var(par.first);
      const double val(par.second);
      var->setVal(val);
      var->setConstant(true);
      if(var->getVal() != par.second){
        throw std::runtime_error(TString::Format("inconsistency detected, scanned parameter '%s' [%g,%g] from workspace has value %g after setting it to %g!",var->GetName(),var->getMin(),var->getMax(),var->getVal(),val).Data());
      }
      if(uncond[par.first] != par.second){
        isuncond=false;
      }
    }

    isFirstPoint = false;

    // print an info message
    // check if the point is identical to the unconditional minimum
    if(isuncond){
      info(TString::Format(" point %s is identical to unconditional minimum",stringify(point).Data()));
      continue;
    } else {
      info(TString::Format(" fitting point %d/%d at %s",int(ipoint+1),int(npoints),stringify(point).Data()));
    }

    if(!recycle){
      // create the Nll
      if(redirect){
        info(TString::Format(" writing log of Nll creation to '%s'",logfile.Data()));
        TQLibrary::redirect(logfile,true);
      }
      this->setup(datasetName,&fitOptions);
      allVars = fNll->getVariables();
      if(redirect) TQLibrary::restore();
    }

    // set the POI values to the point
    TSUtils::setParameterValues(allVars,fWorkspace->allVars());
    for(const auto& par:point){
      RooRealVar* nllvar = (RooRealVar*)(allVars->find(par.first));
      const double val(par.second);
      nllvar->setVal(val);
      nllvar->setConstant(true);
      if(nllvar->getVal() != par.second){
        throw std::runtime_error(TString::Format("inconsistency detected, scanned parameter '%s' [%g,%g] from Nll has value %g after setting it to %g!",nllvar->GetName(),nllvar->getMin(),nllvar->getMax(),nllvar->getVal(),val).Data());
      }
    }

    // perform a consistency check for const'ness
    for(const auto& par:point){
      RooRealVar* var = dynamic_cast<RooRealVar*>(allVars->find(par.first));
      if(!var->isConstant()){
        this->error(TString::Format("inconsistency detected, scanned parameter '%s' is floating before the fit (should be constant)!",var->GetName()).Data());
      }
      if(var->getVal() != par.second){
        this->error(TString::Format("inconsistency detected, scanned parameter '%s' has value %g before the fit (should be %g)!",var->GetName(),var->getVal(),par.second).Data());
      }
    }

    // run the minimizer
    fNll->constOptimizeTestStatistic(RooAbsArg::ValueChange,constOpt>1);
    if(redirect) TQLibrary::redirect(logfile,true);
    TQFolder* fitResult = this->minimizeNll(&fitOptions);
    if(redirect) TQLibrary::restore();

    // perform a consistency check for const'ness
    for(const auto& par:point){
      RooRealVar* var = dynamic_cast<RooRealVar*>(allVars->find(par.first));
      if(!var){
        this->error(TString::Format("unable to find parameter '%s'!",par.first.Data()).Data());
        continue;
      }

      if(!var->isConstant()){
        this->error(TString::Format("inconsistency detected, scanned parameter '%s' is floating after the fit (should be constant)!",var->GetName()).Data());
      }

      if(var->getVal() != par.second){
        this->error(TString::Format("inconsistency detected, scanned parameter '%s' has value %g after the fit (should be %g)!",var->GetName(),var->getVal(),par.second).Data());
      }
    }

    // extract and store the results
    double minnll = fitResult->getTagDoubleDefault("minNll",std::numeric_limits<double>::infinity());
    fNll->constOptimizeTestStatistic(RooAbsArg::ValueChange,constOpt>1);
  // When an offset is applied the offsetted Nll is not preserved, not able to check for inconsistencies
    if(minnll != fNll->getVal() && !fitOptions.getTagBoolDefault("offset",true)) {
      this->error(TString::Format("inconsistency detected (%.5f vs %.5f), Nll value not preserved accurately!",minnll, fNll->getVal()).Data());
      continue;
    }

    info(TString::Format(" -> found minNll=%g at %s",minnll,stringify(point).Data()));

    result[point]=fitResult;
    if(!recycle){
      delete allVars;
      allVars = NULL;
    }
  }


  // check back the unconditional point
  double uncondMinNll;
  if(!uncondResult->getTagDouble("minNll",uncondMinNll)){
    throw std::runtime_error("unable to determine Nll minimum!");
  }

  // acquire and propagate the values properly
  if(!allVars) allVars = fNll->getVariables();
  fWorkspace->loadSnapshot(snapshotUnconditional);
  TSUtils::setParameterValues(allVars,fWorkspace->allVars());
  this->setParametersConstFloat(allVars,&fitOptions);

  // perform the check
  double minNll = fNll->getVal();
  // When an offset is applied the offsetted Nll is not preserved, not able to check for inconsistencies
  if(!::areEqualAbs(uncondMinNll,minNll,1e-5) && !fitOptions.getTagBoolDefault("offset",true) ){
    warn(TString::Format("inconsistency detected (%.5f vs %.5f), Nll value of unconditional fit (%s) not preserved accurately - will be refitted later!",uncondMinNll,minNll,stringify(uncond).Data()).Data());
  } else {
    info(TString::Format("absolute minimum of Nll is at %.5f",uncondMinNll).Data());
  }
  delete allVars;

  return result;
}

//__________________________________________________________________________________|___________

TQFolder* TSLikelihoodScanner::finalizeScan(TQFolder* options, std::map<Point,TQFolder*>& result){
  // finalize the scan, cross-checking the minima if requested
  TString logfile;
  bool redirect = options->getTagString("fit.logToFile",logfile);
  // read the options
  bool storeFullResults = options->getTagBoolDefault("storeFullResults",false);
  bool saveFullSnapshots = options->getTagBoolDefault("saveFullSnapshots",false);
  const TString datasetName = options->getTagStringDefault("datasetName", "obsData");
  TString snapshotInitial = options->getTagStringDefault("snapshot.initial",options->getTagStringDefault("snapshot",TString::Format("SnSh_AllVars_Unconditional_%s", datasetName.Data())));
  TString snapshotUnconditional = options->getTagStringDefault("snapshot.unconditional",options->getTagStringDefault("snapshot",TString::Format("SnSh_AllVars_Unconditional_%s", datasetName.Data())));

  // setup the fit options
  TQTaggable fitOptions;
  fitOptions.importTagsWithoutPrefix(*options,"fit.");
  fitOptions.setTagBool("reuseMinimizer",false); // this is changed by the "recycle" option
  fitOptions.setTagBool("reuseNll",true); // this we always set to true for consistency
  fitOptions.setTagBool("adjustPOI",false);
  fitOptions.setTagString("datasetName",datasetName);

  bool crossCheckMinima = options->getTagBoolDefault("crossCheckMinima",false);
  RooArgSet* allVars = fNll->getVariables();

  std::map<Point,TQFolder*> final;
  for(const auto& r:result){
    bool consistent = true;
    bool correct = true;
    bool isuncond = r.second->getTagBoolDefault("unconditional",false);
    double minnll = r.second->getTagDoubleDefault("minNll",std::numeric_limits<double>::infinity());
    if(crossCheckMinima){
      TSUtils::setParameterValues(*allVars,r.second->getFolder("floatParsFinal"));
      TSUtils::setParameterValues(*allVars,r.second->getFolder("constPars"));
      fNll->constOptimizeTestStatistic(RooAbsArg::ValueChange,false);
      double nllval = fNll->getVal();
      correct = ::areEqualAbs(nllval,minnll,1e-5);
      if(!correct){
        if(isuncond) warn(TString::Format("inconsistency detected: unconditional minimum at %s changes Nll value from %.5f to %.5f when loading snapshot, refitting!",stringify(r.first).Data(),minnll,nllval).Data());
        else warn(TString::Format("inconsistency detected: minimum from %s changes Nll value from %.5f to %.5f when loading snapshot, refitting!",stringify(r.first).Data(),nllval,minnll).Data());
      }
    }
    Point startpoint=r.first;
    if(correct && crossCheckMinima){
      double minval = minnll;
      for(const auto& r2:result){
        TSUtils::setParameterValues(*allVars,r2.second->getFolder("floatParsFinal"));
        TSUtils::setParameterValues(*allVars,r.second->getFolder("constPars"));
        for(const auto& par:r.first){
          RooRealVar* var = (RooRealVar*)(allVars->find(par.first));
          var->setVal(par.second);
        }
        fNll->constOptimizeTestStatistic(RooAbsArg::ValueChange,false);
        double othermin = fNll->getVal();
        if(othermin < minval){
          startpoint = r2.first;
          minval = othermin;
        }
      }
      consistent = !(minnll < minval);
      if(!consistent) warn(TString::Format("inconsistency detected: minimum from %s provides improvement for %s, refitting!",stringify(startpoint).Data(),stringify(r.first).Data()));
    }
    if(!consistent || !correct){
      TSUtils::setParameterValues(*allVars,result[startpoint]->getFolder("floatParsFinal"));
      for(const auto& par:r.first){
        RooRealVar* var = (RooRealVar*)(fWorkspace->var(par.first));
        var->setVal(par.second);
        if(!isuncond){
          var->setConstant(true);
        } else{
          var->setConstant(false);
        }
      }

      // run the minimizer
      if(redirect) TQLibrary::redirect(logfile,true);
      fNll->constOptimizeTestStatistic(RooAbsArg::ValueChange,false);
      TQFolder* fitResult = this->minimizeNll(&fitOptions);
      if(redirect) TQLibrary::restore();

      // extract and store the results
      double minnll = fitResult->getTagDoubleDefault("minNll",std::numeric_limits<double>::infinity());
      if(minnll != fNll->getVal()){
        throw std::runtime_error("inconsistency detected, Nll value not preserved accurately!");
      }
      final[r.first]=fitResult;
    } else {
      //      info(TString::Format("minimum from %s is consistent, no improvement found!",stringify(r.first).Data()));
      final[r.first]=r.second;
    }

    if(saveFullSnapshots){
      TString k(stringify(r.first));
      k.ReplaceAll("=","_");
      k.ReplaceAll(",","_");
      k.ReplaceAll(" ","");
      TSUtils::setParameterValues(fWorkspace->allVars(),allVars);
      TSUtils::setParametersConstFloat(fWorkspace->allVars(),allVars);
      this->fWorkspace->saveSnapshot(TString::Format("Scan_%s_%s",options->GetName(),k.Data()).Data(),*allVars);
    }

  }
  double ymin = std::numeric_limits<double>::infinity();
  for(const auto& r:final){
    double minnll = r.second->getTagDoubleDefault("minNll",std::numeric_limits<double>::infinity());
    ymin = std::min(ymin,minnll);
  }

  delete allVars;

  // create the result folder
  std::map<TString,TQFolder*> params = collectParameters(options);
  const size_t npar(params.size());
  TQFolder * resultfolder = TQFolder::newFolder("Scan");
  TQFolder* graph = resultfolder->getFolder("Scan+");
  graph->setTagInteger("nDim",npar);
  int ipar=0;
  for(const auto& par:params){
    TString lbl(TString::Format("x%d",ipar));
    graph->setTagString(lbl,par.first);
    ++ipar;
  }

  size_t ipoint = options->getTagIntegerDefault("onlyPoints.first",0);;
  for(const auto& r:final){
    double minnll = r.second->getTagDoubleDefault("minNll",std::numeric_limits<double>::infinity());
    double y = 2 * ( minnll - ymin );
    // put them together nicely
    bool isuncond = r.second->getTagBoolDefault("unconditional",false);
    TQFolder* p = graph->getFolder(TString::Format("p.%d+",isuncond ? 0 : int(ipoint+1)));
    if(isuncond || storeFullResults){
      r.second->setName(".fit");
      p->addFolder(r.second);
    } else {
      delete r.second;
    }
    size_t ipar=0;
    for(auto par:params){
      const double val = r.first.at(par.first);
      p->setTagDouble(TString::Format("x%d",(int)(ipar)),val);
      ++ipar;
    }
    p->setTagDouble("y",y);
    p->setTagDouble("minNll",minnll);
    info(TString::Format("result at %s is %f (%.15g)",stringify(r.first).Data(),y,minnll));
    ipoint++;
  }
  fWorkspace->loadSnapshot(snapshotUnconditional);

  return resultfolder;
}

int TSLikelihoodScanner::nPoints(TQFolder* config){
  TQFolderIterator itr(config->getListOfFolders("?"),true);
  int n = 1;
  while(itr.hasNext()){
    TQFolder* par = itr.readNext();
    int nbins;
    if(!par->getTagInteger("nbins",nbins)){
      throw std::runtime_error(TString::Format("unable to estimate number of points without <nbins> tag in %s/%s",config->getRoot()->GetName(),config->getPath().Data()).Data());
    }
    n *= (nbins+1);
  }
  return n;
}

void TSLikelihoodScanner::generatePoints(const std::vector<TQFolder*>& params, std::vector<Point>& points, const Point& thispoint, size_t idx){
  TQFolder* par = params[idx];
  TString parname= par->getTagStringDefault("name",par->GetName());

  int nbins;
  RooRealVar* var = fWorkspace->var(parname);
  double low,high;

  double lo,hi;
  bool rel = par->getTagBoolDefault("rel",false);
  TSUtils::getPlotRange(var,lo,hi,nbins);
  par->getTagDouble("min",lo);
  par->getTagDouble("max",hi);
  par->getTagInteger("nbins",nbins);
  if(rel){
    double absmin = par->getTagDoubleDefault("absmin",var->getMin());
    double absmax = par->getTagDoubleDefault("absmax",var->getMax());
    double val = var->getVal();
    low  = std::max(absmin,val - fabs(lo * var->getErrorLo()));
    high = std::min(absmax,val + fabs(hi * var->getErrorHi()));
  } else {
    low = lo;
    high = hi;
  }

  // Perform the scan
  double delta_x = (high - low) / nbins;

  for (int i = 0; i <= nbins; ++i) {
    double val = low + i * delta_x;
    Point point(thispoint);
    point[parname] = val;
    if(idx+1 < params.size()){
      generatePoints(params,points,point,idx+1);
    } else {
      points.push_back(point);
    }
  }
}
 TSLikelihoodScanner.cxx:1
 TSLikelihoodScanner.cxx:2
 TSLikelihoodScanner.cxx:3
 TSLikelihoodScanner.cxx:4
 TSLikelihoodScanner.cxx:5
 TSLikelihoodScanner.cxx:6
 TSLikelihoodScanner.cxx:7
 TSLikelihoodScanner.cxx:8
 TSLikelihoodScanner.cxx:9
 TSLikelihoodScanner.cxx:10
 TSLikelihoodScanner.cxx:11
 TSLikelihoodScanner.cxx:12
 TSLikelihoodScanner.cxx:13
 TSLikelihoodScanner.cxx:14
 TSLikelihoodScanner.cxx:15
 TSLikelihoodScanner.cxx:16
 TSLikelihoodScanner.cxx:17
 TSLikelihoodScanner.cxx:18
 TSLikelihoodScanner.cxx:19
 TSLikelihoodScanner.cxx:20
 TSLikelihoodScanner.cxx:21
 TSLikelihoodScanner.cxx:22
 TSLikelihoodScanner.cxx:23
 TSLikelihoodScanner.cxx:24
 TSLikelihoodScanner.cxx:25
 TSLikelihoodScanner.cxx:26
 TSLikelihoodScanner.cxx:27
 TSLikelihoodScanner.cxx:28
 TSLikelihoodScanner.cxx:29
 TSLikelihoodScanner.cxx:30
 TSLikelihoodScanner.cxx:31
 TSLikelihoodScanner.cxx:32
 TSLikelihoodScanner.cxx:33
 TSLikelihoodScanner.cxx:34
 TSLikelihoodScanner.cxx:35
 TSLikelihoodScanner.cxx:36
 TSLikelihoodScanner.cxx:37
 TSLikelihoodScanner.cxx:38
 TSLikelihoodScanner.cxx:39
 TSLikelihoodScanner.cxx:40
 TSLikelihoodScanner.cxx:41
 TSLikelihoodScanner.cxx:42
 TSLikelihoodScanner.cxx:43
 TSLikelihoodScanner.cxx:44
 TSLikelihoodScanner.cxx:45
 TSLikelihoodScanner.cxx:46
 TSLikelihoodScanner.cxx:47
 TSLikelihoodScanner.cxx:48
 TSLikelihoodScanner.cxx:49
 TSLikelihoodScanner.cxx:50
 TSLikelihoodScanner.cxx:51
 TSLikelihoodScanner.cxx:52
 TSLikelihoodScanner.cxx:53
 TSLikelihoodScanner.cxx:54
 TSLikelihoodScanner.cxx:55
 TSLikelihoodScanner.cxx:56
 TSLikelihoodScanner.cxx:57
 TSLikelihoodScanner.cxx:58
 TSLikelihoodScanner.cxx:59
 TSLikelihoodScanner.cxx:60
 TSLikelihoodScanner.cxx:61
 TSLikelihoodScanner.cxx:62
 TSLikelihoodScanner.cxx:63
 TSLikelihoodScanner.cxx:64
 TSLikelihoodScanner.cxx:65
 TSLikelihoodScanner.cxx:66
 TSLikelihoodScanner.cxx:67
 TSLikelihoodScanner.cxx:68
 TSLikelihoodScanner.cxx:69
 TSLikelihoodScanner.cxx:70
 TSLikelihoodScanner.cxx:71
 TSLikelihoodScanner.cxx:72
 TSLikelihoodScanner.cxx:73
 TSLikelihoodScanner.cxx:74
 TSLikelihoodScanner.cxx:75
 TSLikelihoodScanner.cxx:76
 TSLikelihoodScanner.cxx:77
 TSLikelihoodScanner.cxx:78
 TSLikelihoodScanner.cxx:79
 TSLikelihoodScanner.cxx:80
 TSLikelihoodScanner.cxx:81
 TSLikelihoodScanner.cxx:82
 TSLikelihoodScanner.cxx:83
 TSLikelihoodScanner.cxx:84
 TSLikelihoodScanner.cxx:85
 TSLikelihoodScanner.cxx:86
 TSLikelihoodScanner.cxx:87
 TSLikelihoodScanner.cxx:88
 TSLikelihoodScanner.cxx:89
 TSLikelihoodScanner.cxx:90
 TSLikelihoodScanner.cxx:91
 TSLikelihoodScanner.cxx:92
 TSLikelihoodScanner.cxx:93
 TSLikelihoodScanner.cxx:94
 TSLikelihoodScanner.cxx:95
 TSLikelihoodScanner.cxx:96
 TSLikelihoodScanner.cxx:97
 TSLikelihoodScanner.cxx:98
 TSLikelihoodScanner.cxx:99
 TSLikelihoodScanner.cxx:100
 TSLikelihoodScanner.cxx:101
 TSLikelihoodScanner.cxx:102
 TSLikelihoodScanner.cxx:103
 TSLikelihoodScanner.cxx:104
 TSLikelihoodScanner.cxx:105
 TSLikelihoodScanner.cxx:106
 TSLikelihoodScanner.cxx:107
 TSLikelihoodScanner.cxx:108
 TSLikelihoodScanner.cxx:109
 TSLikelihoodScanner.cxx:110
 TSLikelihoodScanner.cxx:111
 TSLikelihoodScanner.cxx:112
 TSLikelihoodScanner.cxx:113
 TSLikelihoodScanner.cxx:114
 TSLikelihoodScanner.cxx:115
 TSLikelihoodScanner.cxx:116
 TSLikelihoodScanner.cxx:117
 TSLikelihoodScanner.cxx:118
 TSLikelihoodScanner.cxx:119
 TSLikelihoodScanner.cxx:120
 TSLikelihoodScanner.cxx:121
 TSLikelihoodScanner.cxx:122
 TSLikelihoodScanner.cxx:123
 TSLikelihoodScanner.cxx:124
 TSLikelihoodScanner.cxx:125
 TSLikelihoodScanner.cxx:126
 TSLikelihoodScanner.cxx:127
 TSLikelihoodScanner.cxx:128
 TSLikelihoodScanner.cxx:129
 TSLikelihoodScanner.cxx:130
 TSLikelihoodScanner.cxx:131
 TSLikelihoodScanner.cxx:132
 TSLikelihoodScanner.cxx:133
 TSLikelihoodScanner.cxx:134
 TSLikelihoodScanner.cxx:135
 TSLikelihoodScanner.cxx:136
 TSLikelihoodScanner.cxx:137
 TSLikelihoodScanner.cxx:138
 TSLikelihoodScanner.cxx:139
 TSLikelihoodScanner.cxx:140
 TSLikelihoodScanner.cxx:141
 TSLikelihoodScanner.cxx:142
 TSLikelihoodScanner.cxx:143
 TSLikelihoodScanner.cxx:144
 TSLikelihoodScanner.cxx:145
 TSLikelihoodScanner.cxx:146
 TSLikelihoodScanner.cxx:147
 TSLikelihoodScanner.cxx:148
 TSLikelihoodScanner.cxx:149
 TSLikelihoodScanner.cxx:150
 TSLikelihoodScanner.cxx:151
 TSLikelihoodScanner.cxx:152
 TSLikelihoodScanner.cxx:153
 TSLikelihoodScanner.cxx:154
 TSLikelihoodScanner.cxx:155
 TSLikelihoodScanner.cxx:156
 TSLikelihoodScanner.cxx:157
 TSLikelihoodScanner.cxx:158
 TSLikelihoodScanner.cxx:159
 TSLikelihoodScanner.cxx:160
 TSLikelihoodScanner.cxx:161
 TSLikelihoodScanner.cxx:162
 TSLikelihoodScanner.cxx:163
 TSLikelihoodScanner.cxx:164
 TSLikelihoodScanner.cxx:165
 TSLikelihoodScanner.cxx:166
 TSLikelihoodScanner.cxx:167
 TSLikelihoodScanner.cxx:168
 TSLikelihoodScanner.cxx:169
 TSLikelihoodScanner.cxx:170
 TSLikelihoodScanner.cxx:171
 TSLikelihoodScanner.cxx:172
 TSLikelihoodScanner.cxx:173
 TSLikelihoodScanner.cxx:174
 TSLikelihoodScanner.cxx:175
 TSLikelihoodScanner.cxx:176
 TSLikelihoodScanner.cxx:177
 TSLikelihoodScanner.cxx:178
 TSLikelihoodScanner.cxx:179
 TSLikelihoodScanner.cxx:180
 TSLikelihoodScanner.cxx:181
 TSLikelihoodScanner.cxx:182
 TSLikelihoodScanner.cxx:183
 TSLikelihoodScanner.cxx:184
 TSLikelihoodScanner.cxx:185
 TSLikelihoodScanner.cxx:186
 TSLikelihoodScanner.cxx:187
 TSLikelihoodScanner.cxx:188
 TSLikelihoodScanner.cxx:189
 TSLikelihoodScanner.cxx:190
 TSLikelihoodScanner.cxx:191
 TSLikelihoodScanner.cxx:192
 TSLikelihoodScanner.cxx:193
 TSLikelihoodScanner.cxx:194
 TSLikelihoodScanner.cxx:195
 TSLikelihoodScanner.cxx:196
 TSLikelihoodScanner.cxx:197
 TSLikelihoodScanner.cxx:198
 TSLikelihoodScanner.cxx:199
 TSLikelihoodScanner.cxx:200
 TSLikelihoodScanner.cxx:201
 TSLikelihoodScanner.cxx:202
 TSLikelihoodScanner.cxx:203
 TSLikelihoodScanner.cxx:204
 TSLikelihoodScanner.cxx:205
 TSLikelihoodScanner.cxx:206
 TSLikelihoodScanner.cxx:207
 TSLikelihoodScanner.cxx:208
 TSLikelihoodScanner.cxx:209
 TSLikelihoodScanner.cxx:210
 TSLikelihoodScanner.cxx:211
 TSLikelihoodScanner.cxx:212
 TSLikelihoodScanner.cxx:213
 TSLikelihoodScanner.cxx:214
 TSLikelihoodScanner.cxx:215
 TSLikelihoodScanner.cxx:216
 TSLikelihoodScanner.cxx:217
 TSLikelihoodScanner.cxx:218
 TSLikelihoodScanner.cxx:219
 TSLikelihoodScanner.cxx:220
 TSLikelihoodScanner.cxx:221
 TSLikelihoodScanner.cxx:222
 TSLikelihoodScanner.cxx:223
 TSLikelihoodScanner.cxx:224
 TSLikelihoodScanner.cxx:225
 TSLikelihoodScanner.cxx:226
 TSLikelihoodScanner.cxx:227
 TSLikelihoodScanner.cxx:228
 TSLikelihoodScanner.cxx:229
 TSLikelihoodScanner.cxx:230
 TSLikelihoodScanner.cxx:231
 TSLikelihoodScanner.cxx:232
 TSLikelihoodScanner.cxx:233
 TSLikelihoodScanner.cxx:234
 TSLikelihoodScanner.cxx:235
 TSLikelihoodScanner.cxx:236
 TSLikelihoodScanner.cxx:237
 TSLikelihoodScanner.cxx:238
 TSLikelihoodScanner.cxx:239
 TSLikelihoodScanner.cxx:240
 TSLikelihoodScanner.cxx:241
 TSLikelihoodScanner.cxx:242
 TSLikelihoodScanner.cxx:243
 TSLikelihoodScanner.cxx:244
 TSLikelihoodScanner.cxx:245
 TSLikelihoodScanner.cxx:246
 TSLikelihoodScanner.cxx:247
 TSLikelihoodScanner.cxx:248
 TSLikelihoodScanner.cxx:249
 TSLikelihoodScanner.cxx:250
 TSLikelihoodScanner.cxx:251
 TSLikelihoodScanner.cxx:252
 TSLikelihoodScanner.cxx:253
 TSLikelihoodScanner.cxx:254
 TSLikelihoodScanner.cxx:255
 TSLikelihoodScanner.cxx:256
 TSLikelihoodScanner.cxx:257
 TSLikelihoodScanner.cxx:258
 TSLikelihoodScanner.cxx:259
 TSLikelihoodScanner.cxx:260
 TSLikelihoodScanner.cxx:261
 TSLikelihoodScanner.cxx:262
 TSLikelihoodScanner.cxx:263
 TSLikelihoodScanner.cxx:264
 TSLikelihoodScanner.cxx:265
 TSLikelihoodScanner.cxx:266
 TSLikelihoodScanner.cxx:267
 TSLikelihoodScanner.cxx:268
 TSLikelihoodScanner.cxx:269
 TSLikelihoodScanner.cxx:270
 TSLikelihoodScanner.cxx:271
 TSLikelihoodScanner.cxx:272
 TSLikelihoodScanner.cxx:273
 TSLikelihoodScanner.cxx:274
 TSLikelihoodScanner.cxx:275
 TSLikelihoodScanner.cxx:276
 TSLikelihoodScanner.cxx:277
 TSLikelihoodScanner.cxx:278
 TSLikelihoodScanner.cxx:279
 TSLikelihoodScanner.cxx:280
 TSLikelihoodScanner.cxx:281
 TSLikelihoodScanner.cxx:282
 TSLikelihoodScanner.cxx:283
 TSLikelihoodScanner.cxx:284
 TSLikelihoodScanner.cxx:285
 TSLikelihoodScanner.cxx:286
 TSLikelihoodScanner.cxx:287
 TSLikelihoodScanner.cxx:288
 TSLikelihoodScanner.cxx:289
 TSLikelihoodScanner.cxx:290
 TSLikelihoodScanner.cxx:291
 TSLikelihoodScanner.cxx:292
 TSLikelihoodScanner.cxx:293
 TSLikelihoodScanner.cxx:294
 TSLikelihoodScanner.cxx:295
 TSLikelihoodScanner.cxx:296
 TSLikelihoodScanner.cxx:297
 TSLikelihoodScanner.cxx:298
 TSLikelihoodScanner.cxx:299
 TSLikelihoodScanner.cxx:300
 TSLikelihoodScanner.cxx:301
 TSLikelihoodScanner.cxx:302
 TSLikelihoodScanner.cxx:303
 TSLikelihoodScanner.cxx:304
 TSLikelihoodScanner.cxx:305
 TSLikelihoodScanner.cxx:306
 TSLikelihoodScanner.cxx:307
 TSLikelihoodScanner.cxx:308
 TSLikelihoodScanner.cxx:309
 TSLikelihoodScanner.cxx:310
 TSLikelihoodScanner.cxx:311
 TSLikelihoodScanner.cxx:312
 TSLikelihoodScanner.cxx:313
 TSLikelihoodScanner.cxx:314
 TSLikelihoodScanner.cxx:315
 TSLikelihoodScanner.cxx:316
 TSLikelihoodScanner.cxx:317
 TSLikelihoodScanner.cxx:318
 TSLikelihoodScanner.cxx:319
 TSLikelihoodScanner.cxx:320
 TSLikelihoodScanner.cxx:321
 TSLikelihoodScanner.cxx:322
 TSLikelihoodScanner.cxx:323
 TSLikelihoodScanner.cxx:324
 TSLikelihoodScanner.cxx:325
 TSLikelihoodScanner.cxx:326
 TSLikelihoodScanner.cxx:327
 TSLikelihoodScanner.cxx:328
 TSLikelihoodScanner.cxx:329
 TSLikelihoodScanner.cxx:330
 TSLikelihoodScanner.cxx:331
 TSLikelihoodScanner.cxx:332
 TSLikelihoodScanner.cxx:333
 TSLikelihoodScanner.cxx:334
 TSLikelihoodScanner.cxx:335
 TSLikelihoodScanner.cxx:336
 TSLikelihoodScanner.cxx:337
 TSLikelihoodScanner.cxx:338
 TSLikelihoodScanner.cxx:339
 TSLikelihoodScanner.cxx:340
 TSLikelihoodScanner.cxx:341
 TSLikelihoodScanner.cxx:342
 TSLikelihoodScanner.cxx:343
 TSLikelihoodScanner.cxx:344
 TSLikelihoodScanner.cxx:345
 TSLikelihoodScanner.cxx:346
 TSLikelihoodScanner.cxx:347
 TSLikelihoodScanner.cxx:348
 TSLikelihoodScanner.cxx:349
 TSLikelihoodScanner.cxx:350
 TSLikelihoodScanner.cxx:351
 TSLikelihoodScanner.cxx:352
 TSLikelihoodScanner.cxx:353
 TSLikelihoodScanner.cxx:354
 TSLikelihoodScanner.cxx:355
 TSLikelihoodScanner.cxx:356
 TSLikelihoodScanner.cxx:357
 TSLikelihoodScanner.cxx:358
 TSLikelihoodScanner.cxx:359
 TSLikelihoodScanner.cxx:360
 TSLikelihoodScanner.cxx:361
 TSLikelihoodScanner.cxx:362
 TSLikelihoodScanner.cxx:363
 TSLikelihoodScanner.cxx:364
 TSLikelihoodScanner.cxx:365
 TSLikelihoodScanner.cxx:366
 TSLikelihoodScanner.cxx:367
 TSLikelihoodScanner.cxx:368
 TSLikelihoodScanner.cxx:369
 TSLikelihoodScanner.cxx:370
 TSLikelihoodScanner.cxx:371
 TSLikelihoodScanner.cxx:372
 TSLikelihoodScanner.cxx:373
 TSLikelihoodScanner.cxx:374
 TSLikelihoodScanner.cxx:375
 TSLikelihoodScanner.cxx:376
 TSLikelihoodScanner.cxx:377
 TSLikelihoodScanner.cxx:378
 TSLikelihoodScanner.cxx:379
 TSLikelihoodScanner.cxx:380
 TSLikelihoodScanner.cxx:381
 TSLikelihoodScanner.cxx:382
 TSLikelihoodScanner.cxx:383
 TSLikelihoodScanner.cxx:384
 TSLikelihoodScanner.cxx:385
 TSLikelihoodScanner.cxx:386
 TSLikelihoodScanner.cxx:387
 TSLikelihoodScanner.cxx:388
 TSLikelihoodScanner.cxx:389
 TSLikelihoodScanner.cxx:390
 TSLikelihoodScanner.cxx:391
 TSLikelihoodScanner.cxx:392
 TSLikelihoodScanner.cxx:393
 TSLikelihoodScanner.cxx:394
 TSLikelihoodScanner.cxx:395
 TSLikelihoodScanner.cxx:396
 TSLikelihoodScanner.cxx:397
 TSLikelihoodScanner.cxx:398
 TSLikelihoodScanner.cxx:399
 TSLikelihoodScanner.cxx:400
 TSLikelihoodScanner.cxx:401
 TSLikelihoodScanner.cxx:402
 TSLikelihoodScanner.cxx:403
 TSLikelihoodScanner.cxx:404
 TSLikelihoodScanner.cxx:405
 TSLikelihoodScanner.cxx:406
 TSLikelihoodScanner.cxx:407
 TSLikelihoodScanner.cxx:408
 TSLikelihoodScanner.cxx:409
 TSLikelihoodScanner.cxx:410
 TSLikelihoodScanner.cxx:411
 TSLikelihoodScanner.cxx:412
 TSLikelihoodScanner.cxx:413
 TSLikelihoodScanner.cxx:414
 TSLikelihoodScanner.cxx:415
 TSLikelihoodScanner.cxx:416
 TSLikelihoodScanner.cxx:417
 TSLikelihoodScanner.cxx:418
 TSLikelihoodScanner.cxx:419
 TSLikelihoodScanner.cxx:420
 TSLikelihoodScanner.cxx:421
 TSLikelihoodScanner.cxx:422
 TSLikelihoodScanner.cxx:423
 TSLikelihoodScanner.cxx:424
 TSLikelihoodScanner.cxx:425
 TSLikelihoodScanner.cxx:426
 TSLikelihoodScanner.cxx:427
 TSLikelihoodScanner.cxx:428
 TSLikelihoodScanner.cxx:429
 TSLikelihoodScanner.cxx:430
 TSLikelihoodScanner.cxx:431
 TSLikelihoodScanner.cxx:432
 TSLikelihoodScanner.cxx:433
 TSLikelihoodScanner.cxx:434
 TSLikelihoodScanner.cxx:435
 TSLikelihoodScanner.cxx:436
 TSLikelihoodScanner.cxx:437
 TSLikelihoodScanner.cxx:438
 TSLikelihoodScanner.cxx:439
 TSLikelihoodScanner.cxx:440
 TSLikelihoodScanner.cxx:441
 TSLikelihoodScanner.cxx:442
 TSLikelihoodScanner.cxx:443
 TSLikelihoodScanner.cxx:444
 TSLikelihoodScanner.cxx:445
 TSLikelihoodScanner.cxx:446
 TSLikelihoodScanner.cxx:447
 TSLikelihoodScanner.cxx:448
 TSLikelihoodScanner.cxx:449
 TSLikelihoodScanner.cxx:450
 TSLikelihoodScanner.cxx:451
 TSLikelihoodScanner.cxx:452
 TSLikelihoodScanner.cxx:453
 TSLikelihoodScanner.cxx:454
 TSLikelihoodScanner.cxx:455
 TSLikelihoodScanner.cxx:456
 TSLikelihoodScanner.cxx:457
 TSLikelihoodScanner.cxx:458
 TSLikelihoodScanner.cxx:459
 TSLikelihoodScanner.cxx:460
 TSLikelihoodScanner.cxx:461
 TSLikelihoodScanner.cxx:462
 TSLikelihoodScanner.cxx:463
 TSLikelihoodScanner.cxx:464
 TSLikelihoodScanner.cxx:465
 TSLikelihoodScanner.cxx:466
 TSLikelihoodScanner.cxx:467
 TSLikelihoodScanner.cxx:468
 TSLikelihoodScanner.cxx:469
 TSLikelihoodScanner.cxx:470
 TSLikelihoodScanner.cxx:471
 TSLikelihoodScanner.cxx:472
 TSLikelihoodScanner.cxx:473
 TSLikelihoodScanner.cxx:474
 TSLikelihoodScanner.cxx:475
 TSLikelihoodScanner.cxx:476
 TSLikelihoodScanner.cxx:477
 TSLikelihoodScanner.cxx:478
 TSLikelihoodScanner.cxx:479
 TSLikelihoodScanner.cxx:480
 TSLikelihoodScanner.cxx:481
 TSLikelihoodScanner.cxx:482
 TSLikelihoodScanner.cxx:483
 TSLikelihoodScanner.cxx:484
 TSLikelihoodScanner.cxx:485
 TSLikelihoodScanner.cxx:486
 TSLikelihoodScanner.cxx:487
 TSLikelihoodScanner.cxx:488
 TSLikelihoodScanner.cxx:489
 TSLikelihoodScanner.cxx:490
 TSLikelihoodScanner.cxx:491
 TSLikelihoodScanner.cxx:492
 TSLikelihoodScanner.cxx:493
 TSLikelihoodScanner.cxx:494
 TSLikelihoodScanner.cxx:495
 TSLikelihoodScanner.cxx:496
 TSLikelihoodScanner.cxx:497
 TSLikelihoodScanner.cxx:498
 TSLikelihoodScanner.cxx:499
 TSLikelihoodScanner.cxx:500
 TSLikelihoodScanner.cxx:501
 TSLikelihoodScanner.cxx:502
 TSLikelihoodScanner.cxx:503
 TSLikelihoodScanner.cxx:504
 TSLikelihoodScanner.cxx:505
 TSLikelihoodScanner.cxx:506
 TSLikelihoodScanner.cxx:507
 TSLikelihoodScanner.cxx:508
 TSLikelihoodScanner.cxx:509
 TSLikelihoodScanner.cxx:510
 TSLikelihoodScanner.cxx:511
 TSLikelihoodScanner.cxx:512
 TSLikelihoodScanner.cxx:513
 TSLikelihoodScanner.cxx:514
 TSLikelihoodScanner.cxx:515
 TSLikelihoodScanner.cxx:516
 TSLikelihoodScanner.cxx:517
 TSLikelihoodScanner.cxx:518
 TSLikelihoodScanner.cxx:519
 TSLikelihoodScanner.cxx:520
 TSLikelihoodScanner.cxx:521
 TSLikelihoodScanner.cxx:522
 TSLikelihoodScanner.cxx:523
 TSLikelihoodScanner.cxx:524
 TSLikelihoodScanner.cxx:525
 TSLikelihoodScanner.cxx:526
 TSLikelihoodScanner.cxx:527
 TSLikelihoodScanner.cxx:528
 TSLikelihoodScanner.cxx:529
 TSLikelihoodScanner.cxx:530
 TSLikelihoodScanner.cxx:531
 TSLikelihoodScanner.cxx:532
 TSLikelihoodScanner.cxx:533
 TSLikelihoodScanner.cxx:534
 TSLikelihoodScanner.cxx:535
 TSLikelihoodScanner.cxx:536
 TSLikelihoodScanner.cxx:537
 TSLikelihoodScanner.cxx:538
 TSLikelihoodScanner.cxx:539
 TSLikelihoodScanner.cxx:540
 TSLikelihoodScanner.cxx:541
 TSLikelihoodScanner.cxx:542
 TSLikelihoodScanner.cxx:543
 TSLikelihoodScanner.cxx:544
 TSLikelihoodScanner.cxx:545
 TSLikelihoodScanner.cxx:546
 TSLikelihoodScanner.cxx:547
 TSLikelihoodScanner.cxx:548
 TSLikelihoodScanner.cxx:549
 TSLikelihoodScanner.cxx:550
 TSLikelihoodScanner.cxx:551
 TSLikelihoodScanner.cxx:552
 TSLikelihoodScanner.cxx:553
 TSLikelihoodScanner.cxx:554
 TSLikelihoodScanner.cxx:555
 TSLikelihoodScanner.cxx:556
 TSLikelihoodScanner.cxx:557
 TSLikelihoodScanner.cxx:558
 TSLikelihoodScanner.cxx:559
 TSLikelihoodScanner.cxx:560
 TSLikelihoodScanner.cxx:561
 TSLikelihoodScanner.cxx:562
 TSLikelihoodScanner.cxx:563
 TSLikelihoodScanner.cxx:564
 TSLikelihoodScanner.cxx:565
 TSLikelihoodScanner.cxx:566
 TSLikelihoodScanner.cxx:567
 TSLikelihoodScanner.cxx:568
 TSLikelihoodScanner.cxx:569
 TSLikelihoodScanner.cxx:570
 TSLikelihoodScanner.cxx:571
 TSLikelihoodScanner.cxx:572
 TSLikelihoodScanner.cxx:573
 TSLikelihoodScanner.cxx:574
 TSLikelihoodScanner.cxx:575
 TSLikelihoodScanner.cxx:576
 TSLikelihoodScanner.cxx:577
 TSLikelihoodScanner.cxx:578
 TSLikelihoodScanner.cxx:579
 TSLikelihoodScanner.cxx:580
 TSLikelihoodScanner.cxx:581
 TSLikelihoodScanner.cxx:582
 TSLikelihoodScanner.cxx:583
 TSLikelihoodScanner.cxx:584
 TSLikelihoodScanner.cxx:585
 TSLikelihoodScanner.cxx:586
 TSLikelihoodScanner.cxx:587
 TSLikelihoodScanner.cxx:588
 TSLikelihoodScanner.cxx:589
 TSLikelihoodScanner.cxx:590
 TSLikelihoodScanner.cxx:591
 TSLikelihoodScanner.cxx:592
 TSLikelihoodScanner.cxx:593
 TSLikelihoodScanner.cxx:594
 TSLikelihoodScanner.cxx:595
 TSLikelihoodScanner.cxx:596
 TSLikelihoodScanner.cxx:597
 TSLikelihoodScanner.cxx:598
 TSLikelihoodScanner.cxx:599
 TSLikelihoodScanner.cxx:600
 TSLikelihoodScanner.cxx:601
 TSLikelihoodScanner.cxx:602
 TSLikelihoodScanner.cxx:603
 TSLikelihoodScanner.cxx:604
 TSLikelihoodScanner.cxx:605
 TSLikelihoodScanner.cxx:606
 TSLikelihoodScanner.cxx:607
 TSLikelihoodScanner.cxx:608
 TSLikelihoodScanner.cxx:609
 TSLikelihoodScanner.cxx:610
 TSLikelihoodScanner.cxx:611
 TSLikelihoodScanner.cxx:612
 TSLikelihoodScanner.cxx:613
 TSLikelihoodScanner.cxx:614
 TSLikelihoodScanner.cxx:615
 TSLikelihoodScanner.cxx:616
 TSLikelihoodScanner.cxx:617
 TSLikelihoodScanner.cxx:618
 TSLikelihoodScanner.cxx:619
 TSLikelihoodScanner.cxx:620
 TSLikelihoodScanner.cxx:621
 TSLikelihoodScanner.cxx:622
 TSLikelihoodScanner.cxx:623
 TSLikelihoodScanner.cxx:624
 TSLikelihoodScanner.cxx:625
 TSLikelihoodScanner.cxx:626
 TSLikelihoodScanner.cxx:627
 TSLikelihoodScanner.cxx:628
 TSLikelihoodScanner.cxx:629
 TSLikelihoodScanner.cxx:630
 TSLikelihoodScanner.cxx:631
 TSLikelihoodScanner.cxx:632
 TSLikelihoodScanner.cxx:633
 TSLikelihoodScanner.cxx:634
 TSLikelihoodScanner.cxx:635
 TSLikelihoodScanner.cxx:636
 TSLikelihoodScanner.cxx:637
 TSLikelihoodScanner.cxx:638
 TSLikelihoodScanner.cxx:639
 TSLikelihoodScanner.cxx:640
 TSLikelihoodScanner.cxx:641
 TSLikelihoodScanner.cxx:642
 TSLikelihoodScanner.cxx:643
 TSLikelihoodScanner.cxx:644
 TSLikelihoodScanner.cxx:645
 TSLikelihoodScanner.cxx:646
 TSLikelihoodScanner.cxx:647
 TSLikelihoodScanner.cxx:648
 TSLikelihoodScanner.cxx:649
 TSLikelihoodScanner.cxx:650
 TSLikelihoodScanner.cxx:651
 TSLikelihoodScanner.cxx:652
 TSLikelihoodScanner.cxx:653
 TSLikelihoodScanner.cxx:654
 TSLikelihoodScanner.cxx:655
 TSLikelihoodScanner.cxx:656
 TSLikelihoodScanner.cxx:657
 TSLikelihoodScanner.cxx:658
 TSLikelihoodScanner.cxx:659
 TSLikelihoodScanner.cxx:660
 TSLikelihoodScanner.cxx:661
 TSLikelihoodScanner.cxx:662
 TSLikelihoodScanner.cxx:663
 TSLikelihoodScanner.cxx:664
 TSLikelihoodScanner.cxx:665
 TSLikelihoodScanner.cxx:666
 TSLikelihoodScanner.cxx:667
 TSLikelihoodScanner.cxx:668
 TSLikelihoodScanner.cxx:669
 TSLikelihoodScanner.cxx:670
 TSLikelihoodScanner.cxx:671
 TSLikelihoodScanner.cxx:672
 TSLikelihoodScanner.cxx:673
 TSLikelihoodScanner.cxx:674
 TSLikelihoodScanner.cxx:675
 TSLikelihoodScanner.cxx:676
 TSLikelihoodScanner.cxx:677
 TSLikelihoodScanner.cxx:678
 TSLikelihoodScanner.cxx:679
 TSLikelihoodScanner.cxx:680
 TSLikelihoodScanner.cxx:681
 TSLikelihoodScanner.cxx:682
 TSLikelihoodScanner.cxx:683
 TSLikelihoodScanner.cxx:684
 TSLikelihoodScanner.cxx:685
 TSLikelihoodScanner.cxx:686
 TSLikelihoodScanner.cxx:687
 TSLikelihoodScanner.cxx:688
 TSLikelihoodScanner.cxx:689
 TSLikelihoodScanner.cxx:690
 TSLikelihoodScanner.cxx:691
 TSLikelihoodScanner.cxx:692
 TSLikelihoodScanner.cxx:693
 TSLikelihoodScanner.cxx:694
 TSLikelihoodScanner.cxx:695
 TSLikelihoodScanner.cxx:696
 TSLikelihoodScanner.cxx:697
 TSLikelihoodScanner.cxx:698
 TSLikelihoodScanner.cxx:699
 TSLikelihoodScanner.cxx:700
 TSLikelihoodScanner.cxx:701
 TSLikelihoodScanner.cxx:702
 TSLikelihoodScanner.cxx:703
 TSLikelihoodScanner.cxx:704
 TSLikelihoodScanner.cxx:705
 TSLikelihoodScanner.cxx:706
 TSLikelihoodScanner.cxx:707
 TSLikelihoodScanner.cxx:708