// @(#)root/tmva $Id$
// Author: Tancredi Carli, Dominik Dannheim, Alexander Voigt

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Classes: PDEFoamDiscriminant                                                   *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Implementation.                                                           *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Tancredi Carli   - CERN, Switzerland                                      *
 *      Dominik Dannheim - CERN, Switzerland                                      *
 *      S. Jadach        - Institute of Nuclear Physics, Cracow, Poland           *
 *      Alexander Voigt  - TU Dresden, Germany                                    *
 *      Peter Speckmayer - CERN, Switzerland                                      *
 *                                                                                *
 * Copyright (c) 2008, 2010:                                                      *
 *      CERN, Switzerland                                                         *
 *      MPI-K Heidelberg, Germany                                                 *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://tmva.sourceforge.net/LICENSE)                                          *
 **********************************************************************************/

//_____________________________________________________________________
//
// PDEFoamDiscriminant
//
// This PDEFoam variant stores in every cell the discriminant
//
//    D = #events with given class / total number of events
//
// as well as the statistical error on the discriminant.  It therefore
// acts as a discriminant estimator.  It should be booked together
// with the PDEFoamDiscriminantDensity density estimator, which
// returns the discriminant density at a given phase space point
// during the foam build-up.
//
//_____________________________________________________________________

#include <climits>

#ifndef ROOT_TMath
#include "TMath.h"
#endif

#ifndef ROOT_TMVA_PDEFoamDiscriminant
#include "TMVA/PDEFoamDiscriminant.h"
#endif

ClassImp(TMVA::PDEFoamDiscriminant)

//_____________________________________________________________________
TMVA::PDEFoamDiscriminant::PDEFoamDiscriminant()
   : PDEFoam()
   , fClass(0)
{
   // Default constructor for streamer, user should not use it.
}

//_____________________________________________________________________
TMVA::PDEFoamDiscriminant::PDEFoamDiscriminant(const TString& name, UInt_t cls)
   : PDEFoam(name)
   , fClass(cls)
{}

//_____________________________________________________________________
TMVA::PDEFoamDiscriminant::PDEFoamDiscriminant(const PDEFoamDiscriminant &from)
   : PDEFoam(from)
   , fClass(from.fClass)
{
   // Copy Constructor  NOT IMPLEMENTED (NEVER USED)
   Log() << kFATAL << "COPY CONSTRUCTOR NOT IMPLEMENTED" << Endl;
}

//_____________________________________________________________________
void TMVA::PDEFoamDiscriminant::FillFoamCells(const Event* ev, Float_t wt)
{
   // This function fills an event into the discriminant PDEFoam.  The
   // event weight 'wt' is filled into cell element 0 if the event is
   // of class fClass, and filled into cell element 1 otherwise.

   // find corresponding foam cell
   std::vector<Float_t> values  = ev->GetValues();
   std::vector<Float_t> tvalues = VarTransform(values);
   PDEFoamCell *cell = FindCell(tvalues);

   // 0. Element: Number of signal events (even class == fClass)
   // 1. Element: Number of background events times normalization
   if (ev->GetClass() == fClass)
      SetCellElement(cell, 0, GetCellElement(cell, 0) + wt);
   else
      SetCellElement(cell, 1, GetCellElement(cell, 1) + wt);
}

//_____________________________________________________________________
void TMVA::PDEFoamDiscriminant::Finalize()
{
   // Calc discriminator and its error for every cell and save it to
   // the cell.

   // loop over cells
   for (Long_t iCell = 0; iCell <= fLastCe; iCell++) {
      if (!(fCells[iCell]->GetStat()))
         continue;

      Double_t n_sig = GetCellElement(fCells[iCell], 0); // get number of signal events
      Double_t n_bg  = GetCellElement(fCells[iCell], 1); // get number of bg events

      if (n_sig < 0.) {
         Log() << kWARNING << "Negative number of signal events in cell " << iCell
               << ": " << n_sig << ". Set to 0." << Endl;
         n_sig = 0.;
      }
      if (n_bg < 0.) {
         Log() << kWARNING << "Negative number of background events in cell " << iCell
               << ": " << n_bg << ". Set to 0." << Endl;
         n_bg = 0.;
      }

      // calculate discriminant
      if (n_sig + n_bg > 0) {
         // discriminant
         SetCellElement(fCells[iCell], 0, n_sig / (n_sig + n_bg));
         // discriminant error
         SetCellElement(fCells[iCell], 1, TMath::Sqrt(Sqr(n_sig / Sqr(n_sig + n_bg))*n_sig +
                                                      Sqr(n_bg / Sqr(n_sig + n_bg))*n_bg));

      } else {
         SetCellElement(fCells[iCell], 0, 0.5); // set discriminator
         SetCellElement(fCells[iCell], 1, 1.);  // set discriminator error
      }
   }
}

//_____________________________________________________________________
TH2D* TMVA::PDEFoamDiscriminant::Project2(Int_t idim1, Int_t idim2, ECellValue cell_value, PDEFoamKernelBase *kernel, UInt_t nbin)
{
   // Project foam variable idim1 and variable idim2 to histogram.
   // The projection algorithm is modified such that the z axis range
   // of the returned histogram is [0, 1], as necessary for the
   // interpretation as a discriminator.  This is done by weighting
   // the cell values (in case of cell_value = kValue) by the cell
   // volume in all dimensions, excluding 'idim1' and 'idim2'.
   //
   // Parameters:
   //
   // - idim1, idim2 - dimensions to project to
   //
   // - cell_value - the cell value to draw
   //
   // - kernel - a PDEFoam kernel (optional).  If NULL is given, the
   //            kernel is ignored and the pure cell values are
   //            plotted.
   //
   // - nbin - number of bins in x and y direction of result histogram
   //          (optional, default is 50).
   //
   // Returns:
   // a 2-dimensional histogram

   // avoid plotting of wrong dimensions
   if ((idim1 >= GetTotDim()) || (idim1 < 0) ||
       (idim2 >= GetTotDim()) || (idim2 < 0) ||
       (idim1 == idim2))
      Log() << kFATAL << "<Project2>: wrong dimensions given: "
            << idim1 << ", " << idim2 << Endl;

   // root can not handle too many bins in one histogram --> catch this
   // Furthermore, to have more than 1000 bins in the histogram doesn't make
   // sense.
   if (nbin > 1000) {
      Log() << kWARNING << "Warning: number of bins too big: " << nbin
            << " Using 1000 bins for each dimension instead." << Endl;
      nbin = 1000;
   } else if (nbin < 1) {
      Log() << kWARNING << "Wrong bin number: " << nbin
            << "; set nbin=50" << Endl;
      nbin = 50;
   }

   // create result histogram
   TString hname(Form("h_%d_vs_%d", idim1, idim2));

   // if histogram with this name already exists, delete it
   TH2D* h1 = (TH2D*)gDirectory->Get(hname.Data());
   if (h1) delete h1;
   h1 = new TH2D(hname.Data(), Form("var%d vs var%d", idim1, idim2), nbin, fXmin[idim1], fXmax[idim1], nbin, fXmin[idim2], fXmax[idim2]);

   if (!h1) Log() << kFATAL << "ERROR: Can not create histo" << hname << Endl;
   if (cell_value == kValue)
      h1->GetZaxis()->SetRangeUser(-std::numeric_limits<float>::epsilon(),
                                   1. + std::numeric_limits<float>::epsilon());

   // ============== start projection algorithm ================
   // loop over all histogram bins (2-dim)
   for (Int_t xbin = 1; xbin <= h1->GetNbinsX(); ++xbin) {
      for (Int_t ybin = 1; ybin <= h1->GetNbinsY(); ++ybin) {
         // calculate the phase space point, which corresponds to this
         // bin combination
         std::map<Int_t, Float_t> txvec;
         txvec[idim1] = VarTransform(idim1, h1->GetXaxis()->GetBinCenter(xbin));
         txvec[idim2] = VarTransform(idim2, h1->GetYaxis()->GetBinCenter(ybin));

         // find the cells, which corresponds to this phase space
         // point
         std::vector<TMVA::PDEFoamCell*> cells = FindCells(txvec);

         // loop over cells and fill the histogram with the cell
         // values
         Float_t sum_cv = 0; // sum of the cell values
         for (std::vector<TMVA::PDEFoamCell*>::const_iterator it = cells.begin();
              it != cells.end(); ++it) {
            // get cell position and size
            PDEFoamVect cellPosi(GetTotDim()), cellSize(GetTotDim());
            (*it)->GetHcub(cellPosi, cellSize);
            // Create complete event vector from txvec.  The missing
            // coordinates of txvec are set to the cell center.
            std::vector<Float_t> tvec;
            for (Int_t i = 0; i < GetTotDim(); ++i) {
               if (i != idim1 && i != idim2)
                  tvec.push_back(cellPosi[i] + 0.5 * cellSize[i]);
               else
                  tvec.push_back(txvec[i]);
            }
            // get the cell value using the kernel
            Float_t cv = 0;
            if (kernel != NULL) {
               cv = kernel->Estimate(this, tvec, cell_value);
            } else {
               cv = GetCellValue(FindCell(tvec), cell_value);
            }
            if (cell_value == kValue) {
               // calculate cell volume in other dimensions (not
               // including idim1 and idim2)
               Float_t area_cell = 1.;
               for (Int_t d1 = 0; d1 < GetTotDim(); ++d1) {
                  if ((d1 != idim1) && (d1 != idim2))
                     area_cell *= cellSize[d1];
               }
               // calc discriminator * (cell area times foam area)
               // foam is normalized -> length of foam = 1.0
               cv *= area_cell;
            }
            sum_cv += cv;
         }

         // fill the bin content
         h1->SetBinContent(xbin, ybin, sum_cv + h1->GetBinContent(xbin, ybin));
      }
   }

   return h1;
}
 PDEFoamDiscriminant.cxx:1
 PDEFoamDiscriminant.cxx:2
 PDEFoamDiscriminant.cxx:3
 PDEFoamDiscriminant.cxx:4
 PDEFoamDiscriminant.cxx:5
 PDEFoamDiscriminant.cxx:6
 PDEFoamDiscriminant.cxx:7
 PDEFoamDiscriminant.cxx:8
 PDEFoamDiscriminant.cxx:9
 PDEFoamDiscriminant.cxx:10
 PDEFoamDiscriminant.cxx:11
 PDEFoamDiscriminant.cxx:12
 PDEFoamDiscriminant.cxx:13
 PDEFoamDiscriminant.cxx:14
 PDEFoamDiscriminant.cxx:15
 PDEFoamDiscriminant.cxx:16
 PDEFoamDiscriminant.cxx:17
 PDEFoamDiscriminant.cxx:18
 PDEFoamDiscriminant.cxx:19
 PDEFoamDiscriminant.cxx:20
 PDEFoamDiscriminant.cxx:21
 PDEFoamDiscriminant.cxx:22
 PDEFoamDiscriminant.cxx:23
 PDEFoamDiscriminant.cxx:24
 PDEFoamDiscriminant.cxx:25
 PDEFoamDiscriminant.cxx:26
 PDEFoamDiscriminant.cxx:27
 PDEFoamDiscriminant.cxx:28
 PDEFoamDiscriminant.cxx:29
 PDEFoamDiscriminant.cxx:30
 PDEFoamDiscriminant.cxx:31
 PDEFoamDiscriminant.cxx:32
 PDEFoamDiscriminant.cxx:33
 PDEFoamDiscriminant.cxx:34
 PDEFoamDiscriminant.cxx:35
 PDEFoamDiscriminant.cxx:36
 PDEFoamDiscriminant.cxx:37
 PDEFoamDiscriminant.cxx:38
 PDEFoamDiscriminant.cxx:39
 PDEFoamDiscriminant.cxx:40
 PDEFoamDiscriminant.cxx:41
 PDEFoamDiscriminant.cxx:42
 PDEFoamDiscriminant.cxx:43
 PDEFoamDiscriminant.cxx:44
 PDEFoamDiscriminant.cxx:45
 PDEFoamDiscriminant.cxx:46
 PDEFoamDiscriminant.cxx:47
 PDEFoamDiscriminant.cxx:48
 PDEFoamDiscriminant.cxx:49
 PDEFoamDiscriminant.cxx:50
 PDEFoamDiscriminant.cxx:51
 PDEFoamDiscriminant.cxx:52
 PDEFoamDiscriminant.cxx:53
 PDEFoamDiscriminant.cxx:54
 PDEFoamDiscriminant.cxx:55
 PDEFoamDiscriminant.cxx:56
 PDEFoamDiscriminant.cxx:57
 PDEFoamDiscriminant.cxx:58
 PDEFoamDiscriminant.cxx:59
 PDEFoamDiscriminant.cxx:60
 PDEFoamDiscriminant.cxx:61
 PDEFoamDiscriminant.cxx:62
 PDEFoamDiscriminant.cxx:63
 PDEFoamDiscriminant.cxx:64
 PDEFoamDiscriminant.cxx:65
 PDEFoamDiscriminant.cxx:66
 PDEFoamDiscriminant.cxx:67
 PDEFoamDiscriminant.cxx:68
 PDEFoamDiscriminant.cxx:69
 PDEFoamDiscriminant.cxx:70
 PDEFoamDiscriminant.cxx:71
 PDEFoamDiscriminant.cxx:72
 PDEFoamDiscriminant.cxx:73
 PDEFoamDiscriminant.cxx:74
 PDEFoamDiscriminant.cxx:75
 PDEFoamDiscriminant.cxx:76
 PDEFoamDiscriminant.cxx:77
 PDEFoamDiscriminant.cxx:78
 PDEFoamDiscriminant.cxx:79
 PDEFoamDiscriminant.cxx:80
 PDEFoamDiscriminant.cxx:81
 PDEFoamDiscriminant.cxx:82
 PDEFoamDiscriminant.cxx:83
 PDEFoamDiscriminant.cxx:84
 PDEFoamDiscriminant.cxx:85
 PDEFoamDiscriminant.cxx:86
 PDEFoamDiscriminant.cxx:87
 PDEFoamDiscriminant.cxx:88
 PDEFoamDiscriminant.cxx:89
 PDEFoamDiscriminant.cxx:90
 PDEFoamDiscriminant.cxx:91
 PDEFoamDiscriminant.cxx:92
 PDEFoamDiscriminant.cxx:93
 PDEFoamDiscriminant.cxx:94
 PDEFoamDiscriminant.cxx:95
 PDEFoamDiscriminant.cxx:96
 PDEFoamDiscriminant.cxx:97
 PDEFoamDiscriminant.cxx:98
 PDEFoamDiscriminant.cxx:99
 PDEFoamDiscriminant.cxx:100
 PDEFoamDiscriminant.cxx:101
 PDEFoamDiscriminant.cxx:102
 PDEFoamDiscriminant.cxx:103
 PDEFoamDiscriminant.cxx:104
 PDEFoamDiscriminant.cxx:105
 PDEFoamDiscriminant.cxx:106
 PDEFoamDiscriminant.cxx:107
 PDEFoamDiscriminant.cxx:108
 PDEFoamDiscriminant.cxx:109
 PDEFoamDiscriminant.cxx:110
 PDEFoamDiscriminant.cxx:111
 PDEFoamDiscriminant.cxx:112
 PDEFoamDiscriminant.cxx:113
 PDEFoamDiscriminant.cxx:114
 PDEFoamDiscriminant.cxx:115
 PDEFoamDiscriminant.cxx:116
 PDEFoamDiscriminant.cxx:117
 PDEFoamDiscriminant.cxx:118
 PDEFoamDiscriminant.cxx:119
 PDEFoamDiscriminant.cxx:120
 PDEFoamDiscriminant.cxx:121
 PDEFoamDiscriminant.cxx:122
 PDEFoamDiscriminant.cxx:123
 PDEFoamDiscriminant.cxx:124
 PDEFoamDiscriminant.cxx:125
 PDEFoamDiscriminant.cxx:126
 PDEFoamDiscriminant.cxx:127
 PDEFoamDiscriminant.cxx:128
 PDEFoamDiscriminant.cxx:129
 PDEFoamDiscriminant.cxx:130
 PDEFoamDiscriminant.cxx:131
 PDEFoamDiscriminant.cxx:132
 PDEFoamDiscriminant.cxx:133
 PDEFoamDiscriminant.cxx:134
 PDEFoamDiscriminant.cxx:135
 PDEFoamDiscriminant.cxx:136
 PDEFoamDiscriminant.cxx:137
 PDEFoamDiscriminant.cxx:138
 PDEFoamDiscriminant.cxx:139
 PDEFoamDiscriminant.cxx:140
 PDEFoamDiscriminant.cxx:141
 PDEFoamDiscriminant.cxx:142
 PDEFoamDiscriminant.cxx:143
 PDEFoamDiscriminant.cxx:144
 PDEFoamDiscriminant.cxx:145
 PDEFoamDiscriminant.cxx:146
 PDEFoamDiscriminant.cxx:147
 PDEFoamDiscriminant.cxx:148
 PDEFoamDiscriminant.cxx:149
 PDEFoamDiscriminant.cxx:150
 PDEFoamDiscriminant.cxx:151
 PDEFoamDiscriminant.cxx:152
 PDEFoamDiscriminant.cxx:153
 PDEFoamDiscriminant.cxx:154
 PDEFoamDiscriminant.cxx:155
 PDEFoamDiscriminant.cxx:156
 PDEFoamDiscriminant.cxx:157
 PDEFoamDiscriminant.cxx:158
 PDEFoamDiscriminant.cxx:159
 PDEFoamDiscriminant.cxx:160
 PDEFoamDiscriminant.cxx:161
 PDEFoamDiscriminant.cxx:162
 PDEFoamDiscriminant.cxx:163
 PDEFoamDiscriminant.cxx:164
 PDEFoamDiscriminant.cxx:165
 PDEFoamDiscriminant.cxx:166
 PDEFoamDiscriminant.cxx:167
 PDEFoamDiscriminant.cxx:168
 PDEFoamDiscriminant.cxx:169
 PDEFoamDiscriminant.cxx:170
 PDEFoamDiscriminant.cxx:171
 PDEFoamDiscriminant.cxx:172
 PDEFoamDiscriminant.cxx:173
 PDEFoamDiscriminant.cxx:174
 PDEFoamDiscriminant.cxx:175
 PDEFoamDiscriminant.cxx:176
 PDEFoamDiscriminant.cxx:177
 PDEFoamDiscriminant.cxx:178
 PDEFoamDiscriminant.cxx:179
 PDEFoamDiscriminant.cxx:180
 PDEFoamDiscriminant.cxx:181
 PDEFoamDiscriminant.cxx:182
 PDEFoamDiscriminant.cxx:183
 PDEFoamDiscriminant.cxx:184
 PDEFoamDiscriminant.cxx:185
 PDEFoamDiscriminant.cxx:186
 PDEFoamDiscriminant.cxx:187
 PDEFoamDiscriminant.cxx:188
 PDEFoamDiscriminant.cxx:189
 PDEFoamDiscriminant.cxx:190
 PDEFoamDiscriminant.cxx:191
 PDEFoamDiscriminant.cxx:192
 PDEFoamDiscriminant.cxx:193
 PDEFoamDiscriminant.cxx:194
 PDEFoamDiscriminant.cxx:195
 PDEFoamDiscriminant.cxx:196
 PDEFoamDiscriminant.cxx:197
 PDEFoamDiscriminant.cxx:198
 PDEFoamDiscriminant.cxx:199
 PDEFoamDiscriminant.cxx:200
 PDEFoamDiscriminant.cxx:201
 PDEFoamDiscriminant.cxx:202
 PDEFoamDiscriminant.cxx:203
 PDEFoamDiscriminant.cxx:204
 PDEFoamDiscriminant.cxx:205
 PDEFoamDiscriminant.cxx:206
 PDEFoamDiscriminant.cxx:207
 PDEFoamDiscriminant.cxx:208
 PDEFoamDiscriminant.cxx:209
 PDEFoamDiscriminant.cxx:210
 PDEFoamDiscriminant.cxx:211
 PDEFoamDiscriminant.cxx:212
 PDEFoamDiscriminant.cxx:213
 PDEFoamDiscriminant.cxx:214
 PDEFoamDiscriminant.cxx:215
 PDEFoamDiscriminant.cxx:216
 PDEFoamDiscriminant.cxx:217
 PDEFoamDiscriminant.cxx:218
 PDEFoamDiscriminant.cxx:219
 PDEFoamDiscriminant.cxx:220
 PDEFoamDiscriminant.cxx:221
 PDEFoamDiscriminant.cxx:222
 PDEFoamDiscriminant.cxx:223
 PDEFoamDiscriminant.cxx:224
 PDEFoamDiscriminant.cxx:225
 PDEFoamDiscriminant.cxx:226
 PDEFoamDiscriminant.cxx:227
 PDEFoamDiscriminant.cxx:228
 PDEFoamDiscriminant.cxx:229
 PDEFoamDiscriminant.cxx:230
 PDEFoamDiscriminant.cxx:231
 PDEFoamDiscriminant.cxx:232
 PDEFoamDiscriminant.cxx:233
 PDEFoamDiscriminant.cxx:234
 PDEFoamDiscriminant.cxx:235
 PDEFoamDiscriminant.cxx:236
 PDEFoamDiscriminant.cxx:237
 PDEFoamDiscriminant.cxx:238
 PDEFoamDiscriminant.cxx:239
 PDEFoamDiscriminant.cxx:240
 PDEFoamDiscriminant.cxx:241
 PDEFoamDiscriminant.cxx:242
 PDEFoamDiscriminant.cxx:243
 PDEFoamDiscriminant.cxx:244
 PDEFoamDiscriminant.cxx:245
 PDEFoamDiscriminant.cxx:246
 PDEFoamDiscriminant.cxx:247
 PDEFoamDiscriminant.cxx:248
 PDEFoamDiscriminant.cxx:249
 PDEFoamDiscriminant.cxx:250
 PDEFoamDiscriminant.cxx:251
 PDEFoamDiscriminant.cxx:252
 PDEFoamDiscriminant.cxx:253
 PDEFoamDiscriminant.cxx:254
 PDEFoamDiscriminant.cxx:255
 PDEFoamDiscriminant.cxx:256
 PDEFoamDiscriminant.cxx:257
 PDEFoamDiscriminant.cxx:258