/***************************************************************************** 
 * Project: RooFit                                                           * 
 * author: Max Baak (mbaak@cern.ch)                                          *
 *****************************************************************************/ 

// Written by Max Baak (mbaak@cern.ch)
// 1-dimensional morph function between a list of input functions (varlist) as a function of one input parameter (m).
// The vector mrefpoints assigns an m-number to each function in the function list.
// For example: varlist can contain MC histograms (or single numbers) of a reconstructed mass, for certain 
// true Higgs masses indicated in mrefpoints. the input parameter m is the true (continous) Higgs mass.
// Morphing can be set to be linear or non-linear, or mixture of the two.

#include "Riostream.h" 

#include "Roo1DMomentMorphFunction.h" 
#include "RooAbsCategory.h" 
#include "RooRealIntegral.h"
#include "RooRealConstant.h"
#include "RooRealVar.h"
#include "RooFormulaVar.h"
#include "RooCustomizer.h"
#include "RooAddPdf.h"
#include "RooAddition.h"
#include "RooMoment.h"
#include "RooLinearVar.h"
#include "RooChangeTracker.h"

#include "TMath.h"

using namespace std;

ClassImp(Roo1DMomentMorphFunction) 


//_____________________________________________________________________________
  Roo1DMomentMorphFunction::Roo1DMomentMorphFunction() : _mref(0), _frac(0), _M(0), _setting(Linear)
{
  _varItr    = _varList.createIterator() ;
}



//_____________________________________________________________________________
Roo1DMomentMorphFunction::Roo1DMomentMorphFunction(const char *name, const char *title, 
						   RooAbsReal& _m,
						   const RooArgList& varList,
						   const TVectorD& mrefpoints,
						   const Setting& setting) :
  RooAbsReal(name,title), 
  m("m","m",this,_m),
  _varList("varList","List of variables",this),
  _setting(setting)
{ 
  // CTOR

  // observables
  TIterator* varItr = varList.createIterator() ;
  RooAbsArg* var ;
  for (Int_t i=0; (var = (RooAbsArg*)varItr->Next()); ++i) {
    if (!dynamic_cast<RooAbsReal*>(var)) {
      coutE(InputArguments) << "Roo1DMomentMorphFunction::ctor(" << GetName() << ") ERROR: variable " << var->GetName() << " is not of type RooAbsReal" << endl ;
      throw string("RooPolyMorh::ctor() ERROR variable is not of type RooAbsReal") ;
    }
    _varList.add(*var) ;
  }
  delete varItr ;

  _mref      = new TVectorD(mrefpoints);
  _frac      = 0 ;
  _varItr    = _varList.createIterator() ;

  // initialization
  initialize();
} 



//_____________________________________________________________________________
Roo1DMomentMorphFunction::Roo1DMomentMorphFunction(const Roo1DMomentMorphFunction& other, const char* name) :  
  RooAbsReal(other,name), 
  m("m",this,other.m),
  _varList("varList",this,other._varList),
  _setting(other._setting)
{ 
  _mref = new TVectorD(*other._mref) ;
  _frac = 0 ;
  _varItr    = _varList.createIterator() ;

  // initialization
  initialize();
} 

//_____________________________________________________________________________
Roo1DMomentMorphFunction::~Roo1DMomentMorphFunction() 
{
  if (_mref)   delete _mref;
  if (_frac)   delete _frac;
  if (_varItr) delete _varItr;
  if (_M)      delete _M;
}



//_____________________________________________________________________________
void Roo1DMomentMorphFunction::initialize() 
{
  Int_t nVar = _varList.getSize();

  // other quantities needed
  if (nVar!=_mref->GetNrows()) {
    coutE(InputArguments) << "Roo1DMomentMorphFunction::initialize(" << GetName() << ") ERROR: nVar != nRefPoints" << endl ;
    assert(0) ;
  }

  _frac = new TVectorD(nVar);

  TVectorD* dm = new TVectorD(nVar);
  _M = new TMatrixD(nVar,nVar);

  // transformation matrix for non-linear extrapolation, needed in evaluate()
  TMatrixD M(nVar,nVar);
  for (Int_t i=0; i<_mref->GetNrows(); ++i) {
    (*dm)[i] = (*_mref)[i]-(*_mref)[0];
    M(i,0) = 1.;
    if (i>0) M(0,i) = 0.;
  }
  for (Int_t i=1; i<_mref->GetNrows(); ++i) {
    for (Int_t j=1; j<_mref->GetNrows(); ++j) {
      M(i,j) = TMath::Power((*dm)[i],(double)j);
    }
  }
  (*_M) = M.Invert();

  delete dm ;
}


//_____________________________________________________________________________
Double_t Roo1DMomentMorphFunction::evaluate() const 
{ 
  calculateFractions(); // this sets _frac vector, based on function of m

  _varItr->Reset() ;

  Double_t ret(0);
  RooAbsReal* var(0) ;
  for (Int_t i=0; (var = (RooAbsReal*)_varItr->Next()); ++i) {
    ret += (*_frac)(i) * var->getVal();
  }

  return ret ;
} 


//_____________________________________________________________________________
void Roo1DMomentMorphFunction::calculateFractions() const
{
  Int_t nVar = _varList.getSize();

  Double_t dm = m - (*_mref)[0];

  // fully non-linear
  double sumposfrac=0.;
  for (Int_t i=0; i<nVar; ++i) {
    double ffrac=0.;
    for (Int_t j=0; j<nVar; ++j) { ffrac += (*_M)(j,i) * (j==0?1.:TMath::Power(dm,(double)j)); }
    if (ffrac>=0) sumposfrac+=ffrac;
    (*_frac)(i) = ffrac;
  }

  // various mode settings
  int imin = idxmin(m);
  int imax = idxmax(m);
  double mfrac = (m-(*_mref)[imin])/((*_mref)[imax]-(*_mref)[imin]);
  switch (_setting) {
    case NonLinear:
      // default already set above
    break;
    case Linear: 
      for (Int_t i=0; i<nVar; ++i)
        (*_frac)(i) = 0.;      
      if (imax>imin) { // m in between mmin and mmax
        (*_frac)(imin) = (1.-mfrac); 
        (*_frac)(imax) = (mfrac);
      } else if (imax==imin) { // m outside mmin and mmax
        (*_frac)(imin) = (1.);
      }
    break;
    case NonLinearLinFractions:
      for (Int_t i=0; i<nVar; ++i)
        (*_frac)(i) = (0.);
      if (imax>imin) { // m in between mmin and mmax
        (*_frac)(imin) = (1.-mfrac);
        (*_frac)(imax) = (mfrac);
      } else if (imax==imin) { // m outside mmin and mmax
        (*_frac)(imin) = (1.);
      }
    break;
    case NonLinearPosFractions:
      for (Int_t i=0; i<nVar; ++i) {
        if ((*_frac)(i)<0) (*_frac)(i)=(0.);
        (*_frac)(i) = (*_frac)(i)/sumposfrac;
      }
    break;
  } 
}

//_____________________________________________________________________________
int Roo1DMomentMorphFunction::idxmin(const double& mval) const
{
  int imin(0);
  Int_t nVar = _varList.getSize();
  double mmin=-DBL_MAX;
  for (Int_t i=0; i<nVar; ++i) 
    if ( (*_mref)[i]>mmin && (*_mref)[i]<=mval ) { mmin=(*_mref)[i]; imin=i; }
  return imin;
}


//_____________________________________________________________________________
int Roo1DMomentMorphFunction::idxmax(const double& mval) const
{
  int imax(0);
  Int_t nVar = _varList.getSize();
  double mmax=DBL_MAX;
  for (Int_t i=0; i<nVar; ++i) 
    if ( (*_mref)[i]<mmax && (*_mref)[i]>=mval ) { mmax=(*_mref)[i]; imax=i; }
  return imax;
}
 Roo1DMomentMorphFunction.cxx:1
 Roo1DMomentMorphFunction.cxx:2
 Roo1DMomentMorphFunction.cxx:3
 Roo1DMomentMorphFunction.cxx:4
 Roo1DMomentMorphFunction.cxx:5
 Roo1DMomentMorphFunction.cxx:6
 Roo1DMomentMorphFunction.cxx:7
 Roo1DMomentMorphFunction.cxx:8
 Roo1DMomentMorphFunction.cxx:9
 Roo1DMomentMorphFunction.cxx:10
 Roo1DMomentMorphFunction.cxx:11
 Roo1DMomentMorphFunction.cxx:12
 Roo1DMomentMorphFunction.cxx:13
 Roo1DMomentMorphFunction.cxx:14
 Roo1DMomentMorphFunction.cxx:15
 Roo1DMomentMorphFunction.cxx:16
 Roo1DMomentMorphFunction.cxx:17
 Roo1DMomentMorphFunction.cxx:18
 Roo1DMomentMorphFunction.cxx:19
 Roo1DMomentMorphFunction.cxx:20
 Roo1DMomentMorphFunction.cxx:21
 Roo1DMomentMorphFunction.cxx:22
 Roo1DMomentMorphFunction.cxx:23
 Roo1DMomentMorphFunction.cxx:24
 Roo1DMomentMorphFunction.cxx:25
 Roo1DMomentMorphFunction.cxx:26
 Roo1DMomentMorphFunction.cxx:27
 Roo1DMomentMorphFunction.cxx:28
 Roo1DMomentMorphFunction.cxx:29
 Roo1DMomentMorphFunction.cxx:30
 Roo1DMomentMorphFunction.cxx:31
 Roo1DMomentMorphFunction.cxx:32
 Roo1DMomentMorphFunction.cxx:33
 Roo1DMomentMorphFunction.cxx:34
 Roo1DMomentMorphFunction.cxx:35
 Roo1DMomentMorphFunction.cxx:36
 Roo1DMomentMorphFunction.cxx:37
 Roo1DMomentMorphFunction.cxx:38
 Roo1DMomentMorphFunction.cxx:39
 Roo1DMomentMorphFunction.cxx:40
 Roo1DMomentMorphFunction.cxx:41
 Roo1DMomentMorphFunction.cxx:42
 Roo1DMomentMorphFunction.cxx:43
 Roo1DMomentMorphFunction.cxx:44
 Roo1DMomentMorphFunction.cxx:45
 Roo1DMomentMorphFunction.cxx:46
 Roo1DMomentMorphFunction.cxx:47
 Roo1DMomentMorphFunction.cxx:48
 Roo1DMomentMorphFunction.cxx:49
 Roo1DMomentMorphFunction.cxx:50
 Roo1DMomentMorphFunction.cxx:51
 Roo1DMomentMorphFunction.cxx:52
 Roo1DMomentMorphFunction.cxx:53
 Roo1DMomentMorphFunction.cxx:54
 Roo1DMomentMorphFunction.cxx:55
 Roo1DMomentMorphFunction.cxx:56
 Roo1DMomentMorphFunction.cxx:57
 Roo1DMomentMorphFunction.cxx:58
 Roo1DMomentMorphFunction.cxx:59
 Roo1DMomentMorphFunction.cxx:60
 Roo1DMomentMorphFunction.cxx:61
 Roo1DMomentMorphFunction.cxx:62
 Roo1DMomentMorphFunction.cxx:63
 Roo1DMomentMorphFunction.cxx:64
 Roo1DMomentMorphFunction.cxx:65
 Roo1DMomentMorphFunction.cxx:66
 Roo1DMomentMorphFunction.cxx:67
 Roo1DMomentMorphFunction.cxx:68
 Roo1DMomentMorphFunction.cxx:69
 Roo1DMomentMorphFunction.cxx:70
 Roo1DMomentMorphFunction.cxx:71
 Roo1DMomentMorphFunction.cxx:72
 Roo1DMomentMorphFunction.cxx:73
 Roo1DMomentMorphFunction.cxx:74
 Roo1DMomentMorphFunction.cxx:75
 Roo1DMomentMorphFunction.cxx:76
 Roo1DMomentMorphFunction.cxx:77
 Roo1DMomentMorphFunction.cxx:78
 Roo1DMomentMorphFunction.cxx:79
 Roo1DMomentMorphFunction.cxx:80
 Roo1DMomentMorphFunction.cxx:81
 Roo1DMomentMorphFunction.cxx:82
 Roo1DMomentMorphFunction.cxx:83
 Roo1DMomentMorphFunction.cxx:84
 Roo1DMomentMorphFunction.cxx:85
 Roo1DMomentMorphFunction.cxx:86
 Roo1DMomentMorphFunction.cxx:87
 Roo1DMomentMorphFunction.cxx:88
 Roo1DMomentMorphFunction.cxx:89
 Roo1DMomentMorphFunction.cxx:90
 Roo1DMomentMorphFunction.cxx:91
 Roo1DMomentMorphFunction.cxx:92
 Roo1DMomentMorphFunction.cxx:93
 Roo1DMomentMorphFunction.cxx:94
 Roo1DMomentMorphFunction.cxx:95
 Roo1DMomentMorphFunction.cxx:96
 Roo1DMomentMorphFunction.cxx:97
 Roo1DMomentMorphFunction.cxx:98
 Roo1DMomentMorphFunction.cxx:99
 Roo1DMomentMorphFunction.cxx:100
 Roo1DMomentMorphFunction.cxx:101
 Roo1DMomentMorphFunction.cxx:102
 Roo1DMomentMorphFunction.cxx:103
 Roo1DMomentMorphFunction.cxx:104
 Roo1DMomentMorphFunction.cxx:105
 Roo1DMomentMorphFunction.cxx:106
 Roo1DMomentMorphFunction.cxx:107
 Roo1DMomentMorphFunction.cxx:108
 Roo1DMomentMorphFunction.cxx:109
 Roo1DMomentMorphFunction.cxx:110
 Roo1DMomentMorphFunction.cxx:111
 Roo1DMomentMorphFunction.cxx:112
 Roo1DMomentMorphFunction.cxx:113
 Roo1DMomentMorphFunction.cxx:114
 Roo1DMomentMorphFunction.cxx:115
 Roo1DMomentMorphFunction.cxx:116
 Roo1DMomentMorphFunction.cxx:117
 Roo1DMomentMorphFunction.cxx:118
 Roo1DMomentMorphFunction.cxx:119
 Roo1DMomentMorphFunction.cxx:120
 Roo1DMomentMorphFunction.cxx:121
 Roo1DMomentMorphFunction.cxx:122
 Roo1DMomentMorphFunction.cxx:123
 Roo1DMomentMorphFunction.cxx:124
 Roo1DMomentMorphFunction.cxx:125
 Roo1DMomentMorphFunction.cxx:126
 Roo1DMomentMorphFunction.cxx:127
 Roo1DMomentMorphFunction.cxx:128
 Roo1DMomentMorphFunction.cxx:129
 Roo1DMomentMorphFunction.cxx:130
 Roo1DMomentMorphFunction.cxx:131
 Roo1DMomentMorphFunction.cxx:132
 Roo1DMomentMorphFunction.cxx:133
 Roo1DMomentMorphFunction.cxx:134
 Roo1DMomentMorphFunction.cxx:135
 Roo1DMomentMorphFunction.cxx:136
 Roo1DMomentMorphFunction.cxx:137
 Roo1DMomentMorphFunction.cxx:138
 Roo1DMomentMorphFunction.cxx:139
 Roo1DMomentMorphFunction.cxx:140
 Roo1DMomentMorphFunction.cxx:141
 Roo1DMomentMorphFunction.cxx:142
 Roo1DMomentMorphFunction.cxx:143
 Roo1DMomentMorphFunction.cxx:144
 Roo1DMomentMorphFunction.cxx:145
 Roo1DMomentMorphFunction.cxx:146
 Roo1DMomentMorphFunction.cxx:147
 Roo1DMomentMorphFunction.cxx:148
 Roo1DMomentMorphFunction.cxx:149
 Roo1DMomentMorphFunction.cxx:150
 Roo1DMomentMorphFunction.cxx:151
 Roo1DMomentMorphFunction.cxx:152
 Roo1DMomentMorphFunction.cxx:153
 Roo1DMomentMorphFunction.cxx:154
 Roo1DMomentMorphFunction.cxx:155
 Roo1DMomentMorphFunction.cxx:156
 Roo1DMomentMorphFunction.cxx:157
 Roo1DMomentMorphFunction.cxx:158
 Roo1DMomentMorphFunction.cxx:159
 Roo1DMomentMorphFunction.cxx:160
 Roo1DMomentMorphFunction.cxx:161
 Roo1DMomentMorphFunction.cxx:162
 Roo1DMomentMorphFunction.cxx:163
 Roo1DMomentMorphFunction.cxx:164
 Roo1DMomentMorphFunction.cxx:165
 Roo1DMomentMorphFunction.cxx:166
 Roo1DMomentMorphFunction.cxx:167
 Roo1DMomentMorphFunction.cxx:168
 Roo1DMomentMorphFunction.cxx:169
 Roo1DMomentMorphFunction.cxx:170
 Roo1DMomentMorphFunction.cxx:171
 Roo1DMomentMorphFunction.cxx:172
 Roo1DMomentMorphFunction.cxx:173
 Roo1DMomentMorphFunction.cxx:174
 Roo1DMomentMorphFunction.cxx:175
 Roo1DMomentMorphFunction.cxx:176
 Roo1DMomentMorphFunction.cxx:177
 Roo1DMomentMorphFunction.cxx:178
 Roo1DMomentMorphFunction.cxx:179
 Roo1DMomentMorphFunction.cxx:180
 Roo1DMomentMorphFunction.cxx:181
 Roo1DMomentMorphFunction.cxx:182
 Roo1DMomentMorphFunction.cxx:183
 Roo1DMomentMorphFunction.cxx:184
 Roo1DMomentMorphFunction.cxx:185
 Roo1DMomentMorphFunction.cxx:186
 Roo1DMomentMorphFunction.cxx:187
 Roo1DMomentMorphFunction.cxx:188
 Roo1DMomentMorphFunction.cxx:189
 Roo1DMomentMorphFunction.cxx:190
 Roo1DMomentMorphFunction.cxx:191
 Roo1DMomentMorphFunction.cxx:192
 Roo1DMomentMorphFunction.cxx:193
 Roo1DMomentMorphFunction.cxx:194
 Roo1DMomentMorphFunction.cxx:195
 Roo1DMomentMorphFunction.cxx:196
 Roo1DMomentMorphFunction.cxx:197
 Roo1DMomentMorphFunction.cxx:198
 Roo1DMomentMorphFunction.cxx:199
 Roo1DMomentMorphFunction.cxx:200
 Roo1DMomentMorphFunction.cxx:201
 Roo1DMomentMorphFunction.cxx:202
 Roo1DMomentMorphFunction.cxx:203
 Roo1DMomentMorphFunction.cxx:204
 Roo1DMomentMorphFunction.cxx:205
 Roo1DMomentMorphFunction.cxx:206
 Roo1DMomentMorphFunction.cxx:207
 Roo1DMomentMorphFunction.cxx:208
 Roo1DMomentMorphFunction.cxx:209
 Roo1DMomentMorphFunction.cxx:210
 Roo1DMomentMorphFunction.cxx:211
 Roo1DMomentMorphFunction.cxx:212
 Roo1DMomentMorphFunction.cxx:213
 Roo1DMomentMorphFunction.cxx:214
 Roo1DMomentMorphFunction.cxx:215
 Roo1DMomentMorphFunction.cxx:216
 Roo1DMomentMorphFunction.cxx:217
 Roo1DMomentMorphFunction.cxx:218
 Roo1DMomentMorphFunction.cxx:219
 Roo1DMomentMorphFunction.cxx:220
 Roo1DMomentMorphFunction.cxx:221
 Roo1DMomentMorphFunction.cxx:222
 Roo1DMomentMorphFunction.cxx:223
 Roo1DMomentMorphFunction.cxx:224
 Roo1DMomentMorphFunction.cxx:225
 Roo1DMomentMorphFunction.cxx:226
 Roo1DMomentMorphFunction.cxx:227
 Roo1DMomentMorphFunction.cxx:228
 Roo1DMomentMorphFunction.cxx:229