/*
 * TofNucleiZCut.h
 *
 *  Created on: 21-apr-2009
 *      Author: Nicola Mori
 */

/*! @file TofNucleiZCut.h The TofNucleiZCut class definition file */

#ifndef NO_TOFNUCLEI

#ifndef TOFNUCLEIZCUT_H_
#define TOFNUCLEIZCUT_H_

#include "../../PamCutBase/PamCutBase.h"
#include <ToFNuclei.h>

#ifdef DEBUGPAMCUT
#include <TH2F.h>
#endif

/*! @enum TofNucleiZ_Return Return values for rejected events. */
enum TofNucleiZ_Return {
  TOFNUCLEIZ_OUTOFBOUNDS, ///< Discarded because charge is out of bounds in a layer.
  TOFNUCLEIZ_TOOFEWLAYERS, ///< Discarded because charge can be measured in too few layers.
  TOFNUCLEIZ_ILLEGALZ
///< Discarded because charge is not between 1 and 8
};

/*! @brief The TofNuclei charge cut.
 *
 * This cut uses the TofNuclei library to cut events depending on particle's charge value.
 *
 */

class TofNucleiZCut: public PamCut {

public:
  /*! @brief Constructor.
   *
   * The charge to look for is passed to the TofNucleiZCut object as Z. For each charge, there is an associated distribution of
   * events, with mean Zmean and standard deviation sigmaZ. These values will be used to check the events.
   *
   * @param cutName The cut's name.
   * @param Z The charge value.
   * @param lowerLimit The lower bound (in units of sigmaZ) of the desired charge range, defined as Zmean - lowerBound*sigmaZ.
   * @param upperLimit The upper bound (in units of sigmaZ) of the desired charge range, defined as Zmean + upperBound*sigmaZ.
   * @param minLayers The minimum number of layers for which Z must have been measured.
   * @param layersMask The masked layers (see #TOFLAYERS). These will be ignored throughout all the TofNucleiZCut analysis.
   * @see Check
   */
  TofNucleiZCut(const char *cutName, unsigned int Z, float lowerLimit, float upperLimit, unsigned int minLayers = 6,
      unsigned int layersMask = 0);

  /*! @brief Destructor. */
  ~TofNucleiZCut() {
    delete _tofNuclei;

#ifdef DEBUGPAMCUT

    for (UInt_t j = 0; j < 12; j++) {
      h_tof_z_beta[j]->Write();
    }

#endif

  }

  /*! @brief The TofNucleiZ check.
   *
   * The routine selects events whose value of Zmean obtained from the ToF is in the range [Zmean - sigma*lowerBound, Zmean + sigma*upperBound].
   * Zmean and sigma are defined respectively as the mean and the standard deviation of the charge distributions obtained using ToFNuclei.
   * The calibration values used in this routine (for all energies) are:
   *
   *   Z=1 |   Zmean     sigma
   *   ------------------------
   *   S11 |  0.987      0.11
   *   S12 |  0.988      0.12
   *   S21 |  0.961      0.083
   *   S22 |  0.966      0.10
   *   S31 |  0.981      0.092
   *   S32 |  0.979      0.095
   *
   *   Z=2 |   Zmean     sigma
   *   ------------------------
   *   S11 |  1.96       0.12
   *   S12 |  1.95       0.14
   *   S21 |  1.95       0.13
   *   S22 |  1.96       0.14
   *   S31 |  1.99       0.14
   *   S32 |  2.00       0.15
   *
   * In current implementation, heavier nuclei up to oxygen are partially calibrated; means are taken equal to the particle's charge (Zmean = Z)
   * and a single sigma is used for all ToF layers:
   *
   *   Z |  sigma
   *   -----------
   *   3 |  0.20
   *   4 |  0.25
   *   5 |  0.32
   *   6 |  0.40
   *   7 |  0.45
   *   8 |  0.50
   *
   * The charge of the particle is detrmined by calling ToFNuclei::Get_Charge_ToF_std_layer().
   * First of all, the number of non-masked layers giving a valid charge information is checked to be greater than minLayers; then the bound
   * on the charge value is checked for all valid planes. If at least one of the valid, non-masked planes gives a charge outside the bounds
   * the routine will return #TOFNUCLEIZ_OUTOFBOUNDS. Note that this happens even if more than minLayers give a charge inside boundaries;
   * for example, if minLayers = 5 and we have 6 good charge measurement of which only 5 are inside the boundaries, the check will fail.
   * Notice that masking a layer has the net effect of reducing the number of layers: asking minLayers = 5 and masking two planes
   * will result in return value of #TOFNUCLEIZ_TOOFEWLAYERS for all events, since the "effective ToF" has only 4 layers.
   *
   * @param event The event to analyze.
   * @return #CUTOK if the charge obtained from TofNuclei is in the range [Z - sigma*lowerBound, Z + sigma*upperBound] in at least minLayers
   *          (apart from eventual masked layers).
   * @return #TOFNUCLEIZ_OUTOFBOUNDS if charge is out of bounds in at least one non-masked layer.
   * @return #TOFNUCLEIZ_TOOFEWLAYERS if charge information is available for a number of layers lesser than minLayers.
   * @return #TRKNUCLEIZ_OUTOFBOUNDS if Z < 1 or Z > 8.
   */
  int Check(PamLevel2 *event);

private:

#ifdef DEBUGPAMCUT

  TH2F* h_tof_z_beta[12];

#endif

  unsigned int _Z;
  SimpleMatrix<float> _mean; // Index structure: [Z-1][layer]
  SimpleMatrix<float> _sigma; // Index structure: [Z-1][layer]
  static const float _sigmaZdefault[8];

  float _lowerLimit;
  float _upperLimit;
  unsigned int _minLayers;
  unsigned int _layersMask;

  ToFNuclei *_tofNuclei;
  static const unsigned int _maskArray[6];

};

#endif /* TOFNUCLEIZCUT_H_ */

#endif /* NO_TOFNUCLEI */
