Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
PiecewiseInterpolation.cxx
Go to the documentation of this file.
1 /*****************************************************************************
2 
3  *****************************************************************************/
4 
5 //////////////////////////////////////////////////////////////////////////////
6 /** \class PiecewiseInterpolation
7  * \ingroup HistFactory
8  */
9 
11 
12 #include "RooFit.h"
13 
14 #include "Riostream.h"
15 #include "TBuffer.h"
16 
17 #include "RooAbsReal.h"
18 #include "RooAbsPdf.h"
19 #include "RooErrorHandler.h"
20 #include "RooArgSet.h"
21 #include "RooNLLVar.h"
22 #include "RooChi2Var.h"
23 #include "RooRealVar.h"
24 #include "RooMsgService.h"
25 #include "RooNumIntConfig.h"
26 #include "RooTrace.h"
27 
28 #include <exception>
29 #include <math.h>
30 
31 using namespace std;
32 
33 ClassImp(PiecewiseInterpolation);
34 ;
35 
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 
39 PiecewiseInterpolation::PiecewiseInterpolation()
40 {
41  _positiveDefinite=false;
42  TRACE_CREATE
43 }
44 
45 
46 
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 PiecewiseInterpolation::PiecewiseInterpolation(const char* name, const char* title, const RooAbsReal& nominal,
50  const RooArgList& lowSet,
51  const RooArgList& highSet,
52  const RooArgList& paramSet,
53  Bool_t takeOwnership) :
54  RooAbsReal(name, title),
55  _nominal("!nominal","nominal value", this, (RooAbsReal&)nominal),
56  _lowSet("!lowSet","low-side variation",this),
57  _highSet("!highSet","high-side variation",this),
58  _paramSet("!paramSet","high-side variation",this),
59  _positiveDefinite(false)
60 
61 {
62  // Constructor with two set of RooAbsReals. The value of the function will be
63  //
64  // A = sum_i lowSet(i)*highSet(i)
65  //
66  // If takeOwnership is true the PiecewiseInterpolation object will take ownership of the arguments in sumSet
67 
68  // KC: check both sizes
69  if (lowSet.getSize() != highSet.getSize()) {
70  coutE(InputArguments) << "PiecewiseInterpolation::ctor(" << GetName() << ") ERROR: input lists should be of equal length" << endl ;
71  RooErrorHandler::softAbort() ;
72  }
73 
74  RooFIter inputIter1 = lowSet.fwdIterator() ;
75  RooAbsArg* comp ;
76  while((comp = inputIter1.next())) {
77  if (!dynamic_cast<RooAbsReal*>(comp)) {
78  coutE(InputArguments) << "PiecewiseInterpolation::ctor(" << GetName() << ") ERROR: component " << comp->GetName()
79  << " in first list is not of type RooAbsReal" << endl ;
80  RooErrorHandler::softAbort() ;
81  }
82  _lowSet.add(*comp) ;
83  if (takeOwnership) {
84  _ownedList.addOwned(*comp) ;
85  }
86  }
87 
88 
89  RooFIter inputIter2 = highSet.fwdIterator() ;
90  while((comp = inputIter2.next())) {
91  if (!dynamic_cast<RooAbsReal*>(comp)) {
92  coutE(InputArguments) << "PiecewiseInterpolation::ctor(" << GetName() << ") ERROR: component " << comp->GetName()
93  << " in first list is not of type RooAbsReal" << endl ;
94  RooErrorHandler::softAbort() ;
95  }
96  _highSet.add(*comp) ;
97  if (takeOwnership) {
98  _ownedList.addOwned(*comp) ;
99  }
100  }
101 
102 
103  RooFIter inputIter3 = paramSet.fwdIterator() ;
104  while((comp = inputIter3.next())) {
105  if (!dynamic_cast<RooAbsReal*>(comp)) {
106  coutE(InputArguments) << "PiecewiseInterpolation::ctor(" << GetName() << ") ERROR: component " << comp->GetName()
107  << " in first list is not of type RooAbsReal" << endl ;
108  RooErrorHandler::softAbort() ;
109  }
110  _paramSet.add(*comp) ;
111  if (takeOwnership) {
112  _ownedList.addOwned(*comp) ;
113  }
114  _interpCode.push_back(0); // default code: linear interpolation
115  }
116 
117 
118  // Choose special integrator by default
119  specialIntegratorConfig(kTRUE)->method1D().setLabel("RooBinIntegrator") ;
120  TRACE_CREATE
121 }
122 
123 
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// Copy constructor
127 
128 PiecewiseInterpolation::PiecewiseInterpolation(const PiecewiseInterpolation& other, const char* name) :
129  RooAbsReal(other, name),
130  _nominal("!nominal",this,other._nominal),
131  _lowSet("!lowSet",this,other._lowSet),
132  _highSet("!highSet",this,other._highSet),
133  _paramSet("!paramSet",this,other._paramSet),
134  _positiveDefinite(other._positiveDefinite),
135  _interpCode(other._interpCode)
136 {
137  // Member _ownedList is intentionally not copy-constructed -- ownership is not transferred
138  TRACE_CREATE
139 }
140 
141 
142 
143 ////////////////////////////////////////////////////////////////////////////////
144 /// Destructor
145 
146 PiecewiseInterpolation::~PiecewiseInterpolation()
147 {
148  TRACE_DESTROY
149 }
150 
151 
152 
153 
154 ////////////////////////////////////////////////////////////////////////////////
155 /// Calculate and return current value of self
156 
157 Double_t PiecewiseInterpolation::evaluate() const
158 {
159  ///////////////////
160  Double_t nominal = _nominal;
161  Double_t sum(nominal) ;
162 
163  for (unsigned int i=0; i < _paramSet.size(); ++i) {
164  auto param = static_cast<RooAbsReal*>(_paramSet.at(i));
165  auto low = static_cast<RooAbsReal*>(_lowSet.at(i));
166  auto high = static_cast<RooAbsReal*>(_highSet.at(i));
167  Int_t icode = _interpCode[i] ;
168 
169  switch(icode) {
170  case 0: {
171  // piece-wise linear
172  if(param->getVal()>0)
173  sum += param->getVal()*(high->getVal() - nominal );
174  else
175  sum += param->getVal()*(nominal - low->getVal());
176  break ;
177  }
178  case 1: {
179  // pice-wise log
180  if(param->getVal()>=0)
181  sum *= pow(high->getVal()/nominal, +param->getVal());
182  else
183  sum *= pow(low->getVal()/nominal, -param->getVal());
184  break ;
185  }
186  case 2: {
187  // parabolic with linear
188  double a = 0.5*(high->getVal()+low->getVal())-nominal;
189  double b = 0.5*(high->getVal()-low->getVal());
190  double c = 0;
191  if(param->getVal()>1 ){
192  sum += (2*a+b)*(param->getVal()-1)+high->getVal()-nominal;
193  } else if(param->getVal()<-1 ) {
194  sum += -1*(2*a-b)*(param->getVal()+1)+low->getVal()-nominal;
195  } else {
196  sum += a*pow(param->getVal(),2) + b*param->getVal()+c;
197  }
198  break ;
199  }
200  case 3: {
201  //parabolic version of log-normal
202  double a = 0.5*(high->getVal()+low->getVal())-nominal;
203  double b = 0.5*(high->getVal()-low->getVal());
204  double c = 0;
205  if(param->getVal()>1 ){
206  sum += (2*a+b)*(param->getVal()-1)+high->getVal()-nominal;
207  } else if(param->getVal()<-1 ) {
208  sum += -1*(2*a-b)*(param->getVal()+1)+low->getVal()-nominal;
209  } else {
210  sum += a*pow(param->getVal(),2) + b*param->getVal()+c;
211  }
212  break ;
213  }
214  case 4: {
215 
216  // WVE ****************************************************************
217  // WVE *** THIS CODE IS CRITICAL TO HISTFACTORY FIT CPU PERFORMANCE ***
218  // WVE *** Do not modify unless you know what you are doing... ***
219  // WVE ****************************************************************
220 
221  double x = param->getVal();
222  if (x>1) {
223  sum += x*(high->getVal() - nominal );
224  } else if (x<-1) {
225  sum += x*(nominal - low->getVal());
226  } else {
227  double eps_plus = high->getVal() - nominal;
228  double eps_minus = nominal - low->getVal();
229  double S = 0.5 * (eps_plus + eps_minus);
230  double A = 0.0625 * (eps_plus - eps_minus);
231 
232  //fcns+der+2nd_der are eq at bd
233 
234  double val = nominal + x * (S + x * A * ( 15 + x * x * (-10 + x * x * 3 ) ) );
235 
236 
237  if (val < 0) val = 0;
238  sum += val-nominal;
239  }
240  break ;
241 
242  // WVE ****************************************************************
243  }
244  case 5: {
245 
246  double x0 = 1.0;//boundary;
247  double x = param->getVal();
248 
249  if (x > x0 || x < -x0)
250  {
251  if(x>0)
252  sum += x*(high->getVal() - nominal );
253  else
254  sum += x*(nominal - low->getVal());
255  }
256  else if (nominal != 0)
257  {
258  double eps_plus = high->getVal() - nominal;
259  double eps_minus = nominal - low->getVal();
260  double S = (eps_plus + eps_minus)/2;
261  double A = (eps_plus - eps_minus)/2;
262 
263  //fcns+der are eq at bd
264  double a = S;
265  double b = 3*A/(2*x0);
266  //double c = 0;
267  double d = -A/(2*x0*x0*x0);
268 
269  double val = nominal + a*x + b*pow(x, 2) + 0/*c*pow(x, 3)*/ + d*pow(x, 4);
270  if (val < 0) val = 0;
271 
272  //cout << "Using interp code 5, val = " << val << endl;
273 
274  sum += val-nominal;
275  }
276  break ;
277  }
278  default: {
279  coutE(InputArguments) << "PiecewiseInterpolation::evaluate ERROR: " << param->GetName()
280  << " with unknown interpolation code" << icode << endl ;
281  break ;
282  }
283  }
284  }
285 
286  if(_positiveDefinite && (sum<0)){
287  sum = 1e-6;
288  sum = 0;
289  // cout <<"sum < 0 forcing positive definite"<<endl;
290  // int code = 1;
291  // RooArgSet* myset = new RooArgSet();
292  // cout << "integral = " << analyticalIntegralWN(code, myset) << endl;
293  } else if(sum<0){
294  cxcoutD(Tracing) <<"PiecewiseInterpolation::evaluate - sum < 0, not forcing positive definite"<<endl;
295  }
296  return sum;
297 
298 }
299 
300 ////////////////////////////////////////////////////////////////////////////////
301 
302 Bool_t PiecewiseInterpolation::setBinIntegrator(RooArgSet& allVars)
303 {
304  if(allVars.getSize()==1){
305  RooAbsReal* temp = const_cast<PiecewiseInterpolation*>(this);
306  temp->specialIntegratorConfig(kTRUE)->method1D().setLabel("RooBinIntegrator") ;
307  int nbins = ((RooRealVar*) allVars.first())->numBins();
308  temp->specialIntegratorConfig(kTRUE)->getConfigSection("RooBinIntegrator").setRealValue("numBins",nbins);
309  return true;
310  }else{
311  cout << "Currently BinIntegrator only knows how to deal with 1-d "<<endl;
312  return false;
313  }
314  return false;
315 }
316 
317 ////////////////////////////////////////////////////////////////////////////////
318 /// Advertise that all integrals can be handled internally.
319 
320 Int_t PiecewiseInterpolation::getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars,
321  const RooArgSet* normSet, const char* /*rangeName*/) const
322 {
323  /*
324  cout << "---------------------------\nin PiecewiseInterpolation get analytic integral " <<endl;
325  cout << "all vars = "<<endl;
326  allVars.Print("v");
327  cout << "anal vars = "<<endl;
328  analVars.Print("v");
329  cout << "normset vars = "<<endl;
330  if(normSet2)
331  normSet2->Print("v");
332  */
333 
334 
335  // Handle trivial no-integration scenario
336  if (allVars.getSize()==0) return 0 ;
337  if (_forceNumInt) return 0 ;
338 
339 
340  // Force using numeric integration
341  // use special numeric integrator
342  return 0;
343 
344 
345  // KC: check if interCode=0 for all
346  RooFIter paramIterExtra(_paramSet.fwdIterator()) ;
347  int i=0;
348  while( paramIterExtra.next() ) {
349  if(!_interpCode.empty() && _interpCode[i]!=0){
350  // can't factorize integral
351  cout <<"can't factorize integral"<<endl;
352  return 0;
353  }
354  ++i;
355  }
356 
357  // Select subset of allVars that are actual dependents
358  analVars.add(allVars) ;
359  // RooArgSet* normSet = normSet2 ? getObservables(normSet2) : 0 ;
360  // RooArgSet* normSet = getObservables();
361  // RooArgSet* normSet = 0;
362 
363 
364  // Check if this configuration was created before
365  Int_t sterileIdx(-1) ;
366  CacheElem* cache = (CacheElem*) _normIntMgr.getObj(normSet,&analVars,&sterileIdx) ;
367  if (cache) {
368  return _normIntMgr.lastIndex()+1 ;
369  }
370 
371  // Create new cache element
372  cache = new CacheElem ;
373 
374  // Make list of function projection and normalization integrals
375  RooAbsReal *func ;
376  // const RooArgSet* nset = _paramList.nset() ;
377 
378  // do nominal
379  func = (RooAbsReal*)(&_nominal.arg()) ;
380  RooAbsReal* funcInt = func->createIntegral(analVars) ;
381  cache->_funcIntList.addOwned(*funcInt) ;
382 
383  // do variations
384  RooFIter lowIter(_lowSet.fwdIterator()) ;
385  RooFIter highIter(_highSet.fwdIterator()) ;
386  RooFIter paramIter(_paramSet.fwdIterator()) ;
387 
388  // int i=0;
389  i=0;
390  while(paramIter.next() ) {
391  func = (RooAbsReal*)lowIter.next() ;
392  funcInt = func->createIntegral(analVars) ;
393  cache->_lowIntList.addOwned(*funcInt) ;
394 
395  func = (RooAbsReal*)highIter.next() ;
396  funcInt = func->createIntegral(analVars) ;
397  cache->_highIntList.addOwned(*funcInt) ;
398  ++i;
399  }
400 
401  // Store cache element
402  Int_t code = _normIntMgr.setObj(normSet,&analVars,(RooAbsCacheElement*)cache,0) ;
403 
404  return code+1 ;
405 }
406 
407 
408 
409 
410 ////////////////////////////////////////////////////////////////////////////////
411 /// Implement analytical integrations by doing appropriate weighting from component integrals
412 /// functions to integrators of components
413 
414 Double_t PiecewiseInterpolation::analyticalIntegralWN(Int_t code, const RooArgSet* /*normSet2*/,const char* /*rangeName*/) const
415 {
416  /*
417  cout <<"Enter analytic Integral"<<endl;
418  printDirty(true);
419  // _nominal.arg().setDirtyInhibit(kTRUE) ;
420  _nominal.arg().setShapeDirty() ;
421  RooAbsReal* temp ;
422  RooFIter lowIter(_lowSet.fwdIterator()) ;
423  while((temp=(RooAbsReal*)lowIter.next())) {
424  // temp->setDirtyInhibit(kTRUE) ;
425  temp->setShapeDirty() ;
426  }
427  RooFIter highIter(_highSet.fwdIterator()) ;
428  while((temp=(RooAbsReal*)highIter.next())) {
429  // temp->setDirtyInhibit(kTRUE) ;
430  temp->setShapeDirty() ;
431  }
432  */
433 
434  /*
435  RooAbsArg::setDirtyInhibit(kTRUE);
436  printDirty(true);
437  cout <<"done setting dirty inhibit = true"<<endl;
438 
439  // old integral, only works for linear and not positive definite
440  CacheElem* cache = (CacheElem*) _normIntMgr.getObjByIndex(code-1) ;
441 
442 
443  std::unique_ptr<RooArgSet> vars2( getParameters(RooArgSet()) );
444  std::unique_ptr<RooArgSet> iset( _normIntMgr.nameSet2ByIndex(code-1)->select(*vars2) );
445  cout <<"iset = "<<endl;
446  iset->Print("v");
447 
448  double sum = 0;
449  RooArgSet* vars = getVariables();
450  vars->remove(_paramSet);
451  _paramSet.Print("v");
452  vars->Print("v");
453  if(vars->getSize()==1){
454  RooRealVar* obs = (RooRealVar*) vars->first();
455  for(int i=0; i<obs->numBins(); ++i){
456  obs->setVal( obs->getMin() + (.5+i)*(obs->getMax()-obs->getMin())/obs->numBins());
457  sum+=evaluate()*(obs->getMax()-obs->getMin())/obs->numBins();
458  cout << "obs = " << obs->getVal() << " sum = " << sum << endl;
459  }
460  } else{
461  cout <<"only know how to deal with 1 observable right now"<<endl;
462  }
463  */
464 
465  /*
466  _nominal.arg().setDirtyInhibit(kFALSE) ;
467  RooFIter lowIter2(_lowSet.fwdIterator()) ;
468  while((temp=(RooAbsReal*)lowIter2.next())) {
469  temp->setDirtyInhibit(kFALSE) ;
470  }
471  RooFIter highIter2(_highSet.fwdIterator()) ;
472  while((temp=(RooAbsReal*)highIter2.next())) {
473  temp->setDirtyInhibit(kFALSE) ;
474  }
475  */
476 
477  /*
478  RooAbsArg::setDirtyInhibit(kFALSE);
479  printDirty(true);
480  cout <<"done"<<endl;
481  cout << "sum = " <<sum<<endl;
482  //return sum;
483  */
484 
485  // old integral, only works for linear and not positive definite
486  CacheElem* cache = (CacheElem*) _normIntMgr.getObjByIndex(code-1) ;
487  if( cache==NULL ) {
488  std::cout << "Error: Cache Element is NULL" << std::endl;
489  throw std::exception();
490  }
491 
492  // old integral, only works for linear and not positive definite
493  RooFIter funcIntIter = cache->_funcIntList.fwdIterator() ;
494  RooFIter lowIntIter = cache->_lowIntList.fwdIterator() ;
495  RooFIter highIntIter = cache->_highIntList.fwdIterator() ;
496  RooAbsReal *funcInt(0), *low(0), *high(0), *param(0) ;
497  Double_t value(0) ;
498  Double_t nominal(0);
499 
500  // get nominal
501  int i=0;
502  while(( funcInt = (RooAbsReal*)funcIntIter.next())) {
503  value += funcInt->getVal() ;
504  nominal = value;
505  i++;
506  }
507  if(i==0 || i>1) { cout << "problem, wrong number of nominal functions"<<endl; }
508 
509  // now get low/high variations
510  i = 0;
511  RooFIter paramIter(_paramSet.fwdIterator()) ;
512 
513  // KC: old interp code with new iterator
514  while( (param=(RooAbsReal*)paramIter.next()) ) {
515  low = (RooAbsReal*)lowIntIter.next() ;
516  high = (RooAbsReal*)highIntIter.next() ;
517 
518  if(param->getVal()>0) {
519  value += param->getVal()*(high->getVal() - nominal );
520  } else {
521  value += param->getVal()*(nominal - low->getVal());
522  }
523  ++i;
524  }
525 
526  /* // MB : old bit of interpolation code
527  while( (param=(RooAbsReal*)_paramIter->Next()) ) {
528  low = (RooAbsReal*)lowIntIter->Next() ;
529  high = (RooAbsReal*)highIntIter->Next() ;
530 
531  if(param->getVal()>0) {
532  value += param->getVal()*(high->getVal() - nominal );
533  } else {
534  value += param->getVal()*(nominal - low->getVal());
535  }
536  ++i;
537  }
538  */
539 
540  /* KC: the code below is wrong. Can't pull out a constant change to a non-linear shape deformation.
541  while( (param=(RooAbsReal*)paramIter.next()) ) {
542  low = (RooAbsReal*)lowIntIter.next() ;
543  high = (RooAbsReal*)highIntIter.next() ;
544 
545  if(_interpCode.empty() || _interpCode.at(i)==0){
546  // piece-wise linear
547  if(param->getVal()>0)
548  value += param->getVal()*(high->getVal() - nominal );
549  else
550  value += param->getVal()*(nominal - low->getVal());
551  } else if(_interpCode.at(i)==1){
552  // pice-wise log
553  if(param->getVal()>=0)
554  value *= pow(high->getVal()/nominal, +param->getVal());
555  else
556  value *= pow(low->getVal()/nominal, -param->getVal());
557  } else if(_interpCode.at(i)==2){
558  // parabolic with linear
559  double a = 0.5*(high->getVal()+low->getVal())-nominal;
560  double b = 0.5*(high->getVal()-low->getVal());
561  double c = 0;
562  if(param->getVal()>1 ){
563  value += (2*a+b)*(param->getVal()-1)+high->getVal()-nominal;
564  } else if(param->getVal()<-1 ) {
565  value += -1*(2*a-b)*(param->getVal()+1)+low->getVal()-nominal;
566  } else {
567  value += a*pow(param->getVal(),2) + b*param->getVal()+c;
568  }
569  } else if(_interpCode.at(i)==3){
570  //parabolic version of log-normal
571  double a = 0.5*(high->getVal()+low->getVal())-nominal;
572  double b = 0.5*(high->getVal()-low->getVal());
573  double c = 0;
574  if(param->getVal()>1 ){
575  value += (2*a+b)*(param->getVal()-1)+high->getVal()-nominal;
576  } else if(param->getVal()<-1 ) {
577  value += -1*(2*a-b)*(param->getVal()+1)+low->getVal()-nominal;
578  } else {
579  value += a*pow(param->getVal(),2) + b*param->getVal()+c;
580  }
581 
582  } else {
583  coutE(InputArguments) << "PiecewiseInterpolation::analyticalIntegralWN ERROR: " << param->GetName()
584  << " with unknown interpolation code" << endl ;
585  }
586  ++i;
587  }
588  */
589 
590  // cout << "value = " << value <<endl;
591  return value;
592 }
593 
594 
595 ////////////////////////////////////////////////////////////////////////////////
596 
597 void PiecewiseInterpolation::setInterpCode(RooAbsReal& param, int code){
598  int index = _paramSet.index(&param);
599  if(index<0){
600  coutE(InputArguments) << "PiecewiseInterpolation::setInterpCode ERROR: " << param.GetName()
601  << " is not in list" << endl ;
602  } else {
603  coutW(InputArguments) << "PiecewiseInterpolation::setInterpCode : " << param.GetName()
604  << " is now " << code << endl ;
605  _interpCode.at(index) = code;
606  }
607 }
608 
609 
610 ////////////////////////////////////////////////////////////////////////////////
611 
612 void PiecewiseInterpolation::setAllInterpCodes(int code){
613  for(unsigned int i=0; i<_interpCode.size(); ++i){
614  _interpCode.at(i) = code;
615  }
616 }
617 
618 
619 ////////////////////////////////////////////////////////////////////////////////
620 
621 void PiecewiseInterpolation::printAllInterpCodes(){
622  for(unsigned int i=0; i<_interpCode.size(); ++i){
623  coutI(InputArguments) <<"interp code for " << _paramSet.at(i)->GetName() << " = " << _interpCode.at(i) <<endl;
624  }
625 }
626 
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 /// WVE note: assumes nominal and alternates have identical structure, must add explicit check
630 
631 std::list<Double_t>* PiecewiseInterpolation::binBoundaries(RooAbsRealLValue& obs, Double_t xlo, Double_t xhi) const
632 {
633  return _nominal.arg().binBoundaries(obs,xlo,xhi) ;
634 }
635 
636 
637 ////////////////////////////////////////////////////////////////////////////////
638 /// WVE note: assumes nominal and alternates have identical structure, must add explicit check
639 
640 Bool_t PiecewiseInterpolation::isBinnedDistribution(const RooArgSet& obs) const
641 {
642  return _nominal.arg().isBinnedDistribution(obs) ;
643 }
644 
645 
646 
647 ////////////////////////////////////////////////////////////////////////////////
648 
649 std::list<Double_t>* PiecewiseInterpolation::plotSamplingHint(RooAbsRealLValue& obs, Double_t xlo, Double_t xhi) const
650 {
651  return _nominal.arg().plotSamplingHint(obs,xlo,xhi) ;
652 }
653 
654 ////////////////////////////////////////////////////////////////////////////////
655 /// Stream an object of class PiecewiseInterpolation.
656 
657 void PiecewiseInterpolation::Streamer(TBuffer &R__b)
658 {
659  if (R__b.IsReading()) {
660  R__b.ReadClassBuffer(PiecewiseInterpolation::Class(),this);
661  specialIntegratorConfig(kTRUE)->method1D().setLabel("RooBinIntegrator") ;
662  if (_interpCode.empty()) _interpCode.resize(_paramSet.getSize());
663  } else {
664  R__b.WriteClassBuffer(PiecewiseInterpolation::Class(),this);
665  }
666 }
667 
668 
669 /*
670 ////////////////////////////////////////////////////////////////////////////////
671 /// Customized printing of arguments of a PiecewiseInterpolation to more intuitively reflect the contents of the
672 /// product operator construction
673 
674 void PiecewiseInterpolation::printMetaArgs(ostream& os) const
675 {
676  _lowIter->Reset() ;
677  if (_highIter) {
678  _highIter->Reset() ;
679  }
680 
681  Bool_t first(kTRUE) ;
682 
683  RooAbsArg* arg1, *arg2 ;
684  if (_highSet.getSize()!=0) {
685 
686  while((arg1=(RooAbsArg*)_lowIter->Next())) {
687  if (!first) {
688  os << " + " ;
689  } else {
690  first = kFALSE ;
691  }
692  arg2=(RooAbsArg*)_highIter->Next() ;
693  os << arg1->GetName() << " * " << arg2->GetName() ;
694  }
695 
696  } else {
697 
698  while((arg1=(RooAbsArg*)_lowIter->Next())) {
699  if (!first) {
700  os << " + " ;
701  } else {
702  first = kFALSE ;
703  }
704  os << arg1->GetName() ;
705  }
706 
707  }
708 
709  os << " " ;
710 }
711 
712 */