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

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Classes: PDEFoamKernelGauss                                                    *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Implementation of gauss 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)                                          *
 **********************************************************************************/

//_____________________________________________________________________
//
// PDEFoamKernelGauss
//
// This PDEFoam kernel estimates a cell value for a given event by
// weighting all cell values with a gauss function.
// _____________________________________________________________________

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

#ifndef ROOT_TMVA_PDEFoamKernelGauss
#include "TMVA/PDEFoamKernelGauss.h"
#endif

ClassImp(TMVA::PDEFoamKernelGauss)

//_____________________________________________________________________
TMVA::PDEFoamKernelGauss::PDEFoamKernelGauss(Float_t sigma)
   : PDEFoamKernelBase()
   , fSigma(sigma)
{
   // Default constructor for streamer
}

//_____________________________________________________________________
TMVA::PDEFoamKernelGauss::PDEFoamKernelGauss(const PDEFoamKernelGauss &other)
   : PDEFoamKernelBase(other)
   , fSigma(other.fSigma)
{
   // Copy constructor
}

//_____________________________________________________________________
Float_t TMVA::PDEFoamKernelGauss::Estimate(PDEFoam *foam, std::vector<Float_t> &txvec, ECellValue cv)
{
   // Gaussian kernel estimator.  It returns the cell value 'cv',
   // corresponding to the event vector 'txvec' (in foam coordinates)
   // weighted by the cell values of all other cells, where the weight
   // is a gaussian function.
   //
   // 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 << "<PDEFoamKernelGauss::Estimate>: PDEFoam not set!" << Endl;

   Float_t result = 0, norm = 0;

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

      // calc cell density
      Float_t cell_val = 0;
      if (!foam->CellValueIsUndefined(foam->fCells[iCell]))
         // cell is not empty
         cell_val = foam->GetCellValue(foam->fCells[iCell], cv);
      else
         // cell is empty -> calc average target of neighbor cells
         cell_val = GetAverageNeighborsValue(foam, txvec, cv);

      // calculate gaussian weight between txvec and fCells[iCell]
      Float_t gau = WeightGaus(foam, foam->fCells[iCell], txvec);

      result += gau * cell_val;
      norm   += gau;
   }

   return (norm != 0 ? result / norm : 0);
}

//_____________________________________________________________________
Float_t TMVA::PDEFoamKernelGauss::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;
}

//_____________________________________________________________________
Float_t TMVA::PDEFoamKernelGauss::WeightGaus(PDEFoam *foam, PDEFoamCell* cell,
                                             std::vector<Float_t> &txvec)
{
   // Returns the gauss weight between the 'cell' and a given coordinate 'txvec'.
   //
   // Parameters:
   // - cell - the cell
   //
   // - txvec - the transformed event variables (in [0,1]) (coordinates <0 are
   //   set to 0, >1 are set to 1)
   //
   // Returns:
   // exp(-(d/sigma)^2/2), where
   //  - d - is the euclidean distance between 'txvec' and the point of the 'cell'
   //    which is most close to 'txvec' (in order to avoid artefacts because of the
   //    form of the cells).
   //  - sigma = 1/VolFrac

   // get cell coordinates
   PDEFoamVect cellSize(foam->GetTotDim());
   PDEFoamVect cellPosi(foam->GetTotDim());
   cell->GetHcub(cellPosi, cellSize);

   // calc position of nearest edge of cell
   std::vector<Float_t> cell_center;
   cell_center.reserve(foam->GetTotDim());
   for (Int_t i = 0; i < foam->GetTotDim(); ++i) {
      if (txvec[i] < 0.) txvec[i] = 0.;
      if (txvec[i] > 1.) txvec[i] = 1.;
      //cell_center.push_back(cellPosi[i] + (0.5*cellSize[i]));
      if (cellPosi[i] > txvec.at(i))
         cell_center.push_back(cellPosi[i]);
      else if (cellPosi[i] + cellSize[i] < txvec.at(i))
         cell_center.push_back(cellPosi[i] + cellSize[i]);
      else
         cell_center.push_back(txvec.at(i));
   }

   Float_t distance = 0; // euclidean distance for weighting
   for (Int_t i = 0; i < foam->GetTotDim(); ++i)
      distance += Sqr(txvec.at(i) - cell_center.at(i));
   distance = TMath::Sqrt(distance);

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