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

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Classes: PDEFoamKernelLinN                                                     *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Implementation of linear neighbors PDEFoam kernel                         *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      S. Jadach        - Institute of Nuclear Physics, Cracow, Poland           *
 *      Tancredi Carli   - CERN, Switzerland                                      *
 *      Dominik Dannheim - CERN, Switzerland                                      *
 *      Alexander Voigt  - TU Dresden, Germany                                    *
 *                                                                                *
 * 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)                                          *
 **********************************************************************************/

//_____________________________________________________________________
//
// PDEFoamKernelLinN
//
// This PDEFoam kernel estimates a cell value for a given event by
// weighting with cell values of the nearest neighbor cells.
// _____________________________________________________________________

#ifndef ROOT_TMVA_PDEFoamKernelLinN
#include "TMVA/PDEFoamKernelLinN.h"
#endif

ClassImp(TMVA::PDEFoamKernelLinN)

//_____________________________________________________________________
TMVA::PDEFoamKernelLinN::PDEFoamKernelLinN()
   : PDEFoamKernelBase()
{
   // Default constructor for streamer
}

//_____________________________________________________________________
TMVA::PDEFoamKernelLinN::PDEFoamKernelLinN(const PDEFoamKernelLinN &other)
   : PDEFoamKernelBase(other)
{
   // Copy constructor
}

//_____________________________________________________________________
Float_t TMVA::PDEFoamKernelLinN::Estimate(PDEFoam *foam, std::vector<Float_t> &txvec, ECellValue cv)
{
   // Linear neighbors kernel estimator.  It returns the cell value
   // 'cv', corresponding to the event vector 'txvec' (in foam
   // coordinates) linear weighted by the cell values of the neighbor
   // cells.
   //
   // Parameters:
   //
   // - foam - the pdefoam to search in
   //
   // - txvec - event vector in foam coordinates [0,1]
   //
   // - cv - cell value to estimate

   if (foam == NULL)
      Log() << kFATAL << "<PDEFoamKernelLinN::Estimate>: PDEFoam not set!" << Endl;

   return WeightLinNeighbors(foam, txvec, cv, kTRUE);
}

//_____________________________________________________________________
Float_t TMVA::PDEFoamKernelLinN::WeightLinNeighbors(PDEFoam *foam, std::vector<Float_t> &txvec, ECellValue cv, Bool_t treatEmptyCells)
{
   // Returns the cell value, corresponding to 'txvec' (foam
   // coordinates [0,1]), weighted by the neighbor cells via a linear
   // function.
   //
   // Parameters:
   //  - foam - the foam to search in
   //
   //  - txvec - event vector, transformed into foam coordinates [0,1]
   //
   //  - cv - cell value to be weighted
   //
   //  - treatEmptyCells - if this option is set to false (default),
   //    it is not checked, wether the cell value or neighbor cell
   //    values are undefined (using foam->CellValueIsUndefined()).
   //    If this option is set to true, than only non-empty neighbor
   //    cells are taken into account for weighting.  If the cell
   //    value of the cell, which contains txvec, is empty, than its
   //    value is estimated by the average value of the non-empty
   //    neighbor cells (using GetAverageNeighborsValue()).

   Float_t result = 0.;
   UInt_t norm     = 0;
   const Float_t xoffset = 1.e-6;

   if (txvec.size() != UInt_t(foam->GetTotDim()))
      Log() << kFATAL << "Wrong dimension of event variable!" << Endl;

   // find cell, which contains txvec
   PDEFoamCell *cell = foam->FindCell(txvec);
   PDEFoamVect cellSize(foam->GetTotDim());
   PDEFoamVect cellPosi(foam->GetTotDim());
   cell->GetHcub(cellPosi, cellSize);
   // calc value of cell, which contains txvec
   Float_t cellval = 0;
   if (!(treatEmptyCells && foam->CellValueIsUndefined(cell)))
      // cell is not empty -> get cell value
      cellval = foam->GetCellValue(cell, cv);
   else
      // cell is empty -> get average value of non-empty neighbor
      // cells
      cellval = GetAverageNeighborsValue(foam, txvec, cv);

   // loop over all dimensions to find neighbor cells
   for (Int_t dim = 0; dim < foam->GetTotDim(); dim++) {
      std::vector<Float_t> ntxvec(txvec);
      Float_t mindist;
      PDEFoamCell *mindistcell = 0; // cell with minimal distance to txvec
      // calc minimal distance to neighbor cell
      mindist = (txvec[dim] - cellPosi[dim]) / cellSize[dim];
      if (mindist < 0.5) { // left neighbour
         ntxvec[dim] = cellPosi[dim] - xoffset;
         mindistcell = foam->FindCell(ntxvec); // left neighbor cell
      } else { // right neighbour
         mindist = 1 - mindist;
         ntxvec[dim] = cellPosi[dim] + cellSize[dim] + xoffset;
         mindistcell = foam->FindCell(ntxvec); // right neighbor cell
      }
      // get cell value of cell, which contains ntxvec
      Float_t mindistcellval = foam->GetCellValue(mindistcell, cv);
      // if treatment of empty neighbor cells is deactivated, do
      // normal weighting
      if (!(treatEmptyCells && foam->CellValueIsUndefined(mindistcell))) {
         result += cellval        * (0.5 + mindist);
         result += mindistcellval * (0.5 - mindist);
         norm++;
      }
   }
   if (norm == 0) return cellval;   // all nearest neighbors were empty
   else         return result / norm; // normalisation
}

//_____________________________________________________________________
Float_t TMVA::PDEFoamKernelLinN::GetAverageNeighborsValue(PDEFoam *foam,
                                                          std::vector<Float_t> &txvec,
                                                          ECellValue cv)
{
   // This function returns the average value 'cv' of only nearest
   // neighbor cells.  It is used in cases when a cell value is
   // undefined and the cell value shall be estimated by the
   // (well-defined) cell values of the neighbor cells.
   //
   // Parameters:
   // - foam - the foam to search in
   // - txvec - event vector, transformed into foam coordinates [0, 1]
   // - cv - cell value, see definition of ECellValue

   const Float_t xoffset = 1.e-6;
   Float_t norm   = 0; // normalisation
   Float_t result = 0; // return value

   PDEFoamCell *cell = foam->FindCell(txvec); // find cooresponding cell
   PDEFoamVect cellSize(foam->GetTotDim());
   PDEFoamVect cellPosi(foam->GetTotDim());
   cell->GetHcub(cellPosi, cellSize); // get cell coordinates

   // loop over all dimensions and find neighbor cells
   for (Int_t dim = 0; dim < foam->GetTotDim(); dim++) {
      std::vector<Float_t> ntxvec(txvec);
      PDEFoamCell* left_cell  = 0; // left cell
      PDEFoamCell* right_cell = 0; // right cell

      // get left cell
      ntxvec[dim] = cellPosi[dim] - xoffset;
      left_cell   = foam->FindCell(ntxvec);
      if (!foam->CellValueIsUndefined(left_cell)) {
         // if left cell is not empty, take its value
         result += foam->GetCellValue(left_cell, cv);
         norm++;
      }
      // get right cell
      ntxvec[dim] = cellPosi[dim] + cellSize[dim] + xoffset;
      right_cell  = foam->FindCell(ntxvec);
      if (!foam->CellValueIsUndefined(right_cell)) {
         // if right cell is not empty, take its value
         result += foam->GetCellValue(right_cell, cv);
         norm++;
      }
   }
   if (norm > 0)  result /= norm; // calc average target
   else         result = 0;     // return null if all neighbors are empty

   return result;
}
 PDEFoamKernelLinN.cxx:1
 PDEFoamKernelLinN.cxx:2
 PDEFoamKernelLinN.cxx:3
 PDEFoamKernelLinN.cxx:4
 PDEFoamKernelLinN.cxx:5
 PDEFoamKernelLinN.cxx:6
 PDEFoamKernelLinN.cxx:7
 PDEFoamKernelLinN.cxx:8
 PDEFoamKernelLinN.cxx:9
 PDEFoamKernelLinN.cxx:10
 PDEFoamKernelLinN.cxx:11
 PDEFoamKernelLinN.cxx:12
 PDEFoamKernelLinN.cxx:13
 PDEFoamKernelLinN.cxx:14
 PDEFoamKernelLinN.cxx:15
 PDEFoamKernelLinN.cxx:16
 PDEFoamKernelLinN.cxx:17
 PDEFoamKernelLinN.cxx:18
 PDEFoamKernelLinN.cxx:19
 PDEFoamKernelLinN.cxx:20
 PDEFoamKernelLinN.cxx:21
 PDEFoamKernelLinN.cxx:22
 PDEFoamKernelLinN.cxx:23
 PDEFoamKernelLinN.cxx:24
 PDEFoamKernelLinN.cxx:25
 PDEFoamKernelLinN.cxx:26
 PDEFoamKernelLinN.cxx:27
 PDEFoamKernelLinN.cxx:28
 PDEFoamKernelLinN.cxx:29
 PDEFoamKernelLinN.cxx:30
 PDEFoamKernelLinN.cxx:31
 PDEFoamKernelLinN.cxx:32
 PDEFoamKernelLinN.cxx:33
 PDEFoamKernelLinN.cxx:34
 PDEFoamKernelLinN.cxx:35
 PDEFoamKernelLinN.cxx:36
 PDEFoamKernelLinN.cxx:37
 PDEFoamKernelLinN.cxx:38
 PDEFoamKernelLinN.cxx:39
 PDEFoamKernelLinN.cxx:40
 PDEFoamKernelLinN.cxx:41
 PDEFoamKernelLinN.cxx:42
 PDEFoamKernelLinN.cxx:43
 PDEFoamKernelLinN.cxx:44
 PDEFoamKernelLinN.cxx:45
 PDEFoamKernelLinN.cxx:46
 PDEFoamKernelLinN.cxx:47
 PDEFoamKernelLinN.cxx:48
 PDEFoamKernelLinN.cxx:49
 PDEFoamKernelLinN.cxx:50
 PDEFoamKernelLinN.cxx:51
 PDEFoamKernelLinN.cxx:52
 PDEFoamKernelLinN.cxx:53
 PDEFoamKernelLinN.cxx:54
 PDEFoamKernelLinN.cxx:55
 PDEFoamKernelLinN.cxx:56
 PDEFoamKernelLinN.cxx:57
 PDEFoamKernelLinN.cxx:58
 PDEFoamKernelLinN.cxx:59
 PDEFoamKernelLinN.cxx:60
 PDEFoamKernelLinN.cxx:61
 PDEFoamKernelLinN.cxx:62
 PDEFoamKernelLinN.cxx:63
 PDEFoamKernelLinN.cxx:64
 PDEFoamKernelLinN.cxx:65
 PDEFoamKernelLinN.cxx:66
 PDEFoamKernelLinN.cxx:67
 PDEFoamKernelLinN.cxx:68
 PDEFoamKernelLinN.cxx:69
 PDEFoamKernelLinN.cxx:70
 PDEFoamKernelLinN.cxx:71
 PDEFoamKernelLinN.cxx:72
 PDEFoamKernelLinN.cxx:73
 PDEFoamKernelLinN.cxx:74
 PDEFoamKernelLinN.cxx:75
 PDEFoamKernelLinN.cxx:76
 PDEFoamKernelLinN.cxx:77
 PDEFoamKernelLinN.cxx:78
 PDEFoamKernelLinN.cxx:79
 PDEFoamKernelLinN.cxx:80
 PDEFoamKernelLinN.cxx:81
 PDEFoamKernelLinN.cxx:82
 PDEFoamKernelLinN.cxx:83
 PDEFoamKernelLinN.cxx:84
 PDEFoamKernelLinN.cxx:85
 PDEFoamKernelLinN.cxx:86
 PDEFoamKernelLinN.cxx:87
 PDEFoamKernelLinN.cxx:88
 PDEFoamKernelLinN.cxx:89
 PDEFoamKernelLinN.cxx:90
 PDEFoamKernelLinN.cxx:91
 PDEFoamKernelLinN.cxx:92
 PDEFoamKernelLinN.cxx:93
 PDEFoamKernelLinN.cxx:94
 PDEFoamKernelLinN.cxx:95
 PDEFoamKernelLinN.cxx:96
 PDEFoamKernelLinN.cxx:97
 PDEFoamKernelLinN.cxx:98
 PDEFoamKernelLinN.cxx:99
 PDEFoamKernelLinN.cxx:100
 PDEFoamKernelLinN.cxx:101
 PDEFoamKernelLinN.cxx:102
 PDEFoamKernelLinN.cxx:103
 PDEFoamKernelLinN.cxx:104
 PDEFoamKernelLinN.cxx:105
 PDEFoamKernelLinN.cxx:106
 PDEFoamKernelLinN.cxx:107
 PDEFoamKernelLinN.cxx:108
 PDEFoamKernelLinN.cxx:109
 PDEFoamKernelLinN.cxx:110
 PDEFoamKernelLinN.cxx:111
 PDEFoamKernelLinN.cxx:112
 PDEFoamKernelLinN.cxx:113
 PDEFoamKernelLinN.cxx:114
 PDEFoamKernelLinN.cxx:115
 PDEFoamKernelLinN.cxx:116
 PDEFoamKernelLinN.cxx:117
 PDEFoamKernelLinN.cxx:118
 PDEFoamKernelLinN.cxx:119
 PDEFoamKernelLinN.cxx:120
 PDEFoamKernelLinN.cxx:121
 PDEFoamKernelLinN.cxx:122
 PDEFoamKernelLinN.cxx:123
 PDEFoamKernelLinN.cxx:124
 PDEFoamKernelLinN.cxx:125
 PDEFoamKernelLinN.cxx:126
 PDEFoamKernelLinN.cxx:127
 PDEFoamKernelLinN.cxx:128
 PDEFoamKernelLinN.cxx:129
 PDEFoamKernelLinN.cxx:130
 PDEFoamKernelLinN.cxx:131
 PDEFoamKernelLinN.cxx:132
 PDEFoamKernelLinN.cxx:133
 PDEFoamKernelLinN.cxx:134
 PDEFoamKernelLinN.cxx:135
 PDEFoamKernelLinN.cxx:136
 PDEFoamKernelLinN.cxx:137
 PDEFoamKernelLinN.cxx:138
 PDEFoamKernelLinN.cxx:139
 PDEFoamKernelLinN.cxx:140
 PDEFoamKernelLinN.cxx:141
 PDEFoamKernelLinN.cxx:142
 PDEFoamKernelLinN.cxx:143
 PDEFoamKernelLinN.cxx:144
 PDEFoamKernelLinN.cxx:145
 PDEFoamKernelLinN.cxx:146
 PDEFoamKernelLinN.cxx:147
 PDEFoamKernelLinN.cxx:148
 PDEFoamKernelLinN.cxx:149
 PDEFoamKernelLinN.cxx:150
 PDEFoamKernelLinN.cxx:151
 PDEFoamKernelLinN.cxx:152
 PDEFoamKernelLinN.cxx:153
 PDEFoamKernelLinN.cxx:154
 PDEFoamKernelLinN.cxx:155
 PDEFoamKernelLinN.cxx:156
 PDEFoamKernelLinN.cxx:157
 PDEFoamKernelLinN.cxx:158
 PDEFoamKernelLinN.cxx:159
 PDEFoamKernelLinN.cxx:160
 PDEFoamKernelLinN.cxx:161
 PDEFoamKernelLinN.cxx:162
 PDEFoamKernelLinN.cxx:163
 PDEFoamKernelLinN.cxx:164
 PDEFoamKernelLinN.cxx:165
 PDEFoamKernelLinN.cxx:166
 PDEFoamKernelLinN.cxx:167
 PDEFoamKernelLinN.cxx:168
 PDEFoamKernelLinN.cxx:169
 PDEFoamKernelLinN.cxx:170
 PDEFoamKernelLinN.cxx:171
 PDEFoamKernelLinN.cxx:172
 PDEFoamKernelLinN.cxx:173
 PDEFoamKernelLinN.cxx:174
 PDEFoamKernelLinN.cxx:175
 PDEFoamKernelLinN.cxx:176
 PDEFoamKernelLinN.cxx:177
 PDEFoamKernelLinN.cxx:178
 PDEFoamKernelLinN.cxx:179
 PDEFoamKernelLinN.cxx:180
 PDEFoamKernelLinN.cxx:181
 PDEFoamKernelLinN.cxx:182
 PDEFoamKernelLinN.cxx:183
 PDEFoamKernelLinN.cxx:184
 PDEFoamKernelLinN.cxx:185
 PDEFoamKernelLinN.cxx:186
 PDEFoamKernelLinN.cxx:187
 PDEFoamKernelLinN.cxx:188
 PDEFoamKernelLinN.cxx:189
 PDEFoamKernelLinN.cxx:190
 PDEFoamKernelLinN.cxx:191
 PDEFoamKernelLinN.cxx:192
 PDEFoamKernelLinN.cxx:193
 PDEFoamKernelLinN.cxx:194
 PDEFoamKernelLinN.cxx:195
 PDEFoamKernelLinN.cxx:196
 PDEFoamKernelLinN.cxx:197
 PDEFoamKernelLinN.cxx:198
 PDEFoamKernelLinN.cxx:199
 PDEFoamKernelLinN.cxx:200
 PDEFoamKernelLinN.cxx:201
 PDEFoamKernelLinN.cxx:202
 PDEFoamKernelLinN.cxx:203