/* Parameters.h - A class to contain the model parameters and precision tuning
 *   (originally in parameters.c and precision.c)
 *
 * Copyright (C) 2006  Jochen Voss, Andreas Voss.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */

#ifndef PARAMETERS_H
#define PARAMETERS_H

#include <RcppArmadillo.h> // for std, cmath and many other supports via Rcpp

// Note: Parameters class now includes precision constants
// Indices for packed parameters array

// #define PARAM_a   0
// #define PARAM_v   1
// #define PARAM_t0  2
// #define PARAM_d   3
// #define PARAM_szr 4
// #define PARAM_sv  5
// #define PARAM_st0 6
// #define PARAM_zr  7

#define PARAM_a   0
#define PARAM_v   1
#define PARAM_zr  2
#define PARAM_d   3
#define PARAM_szr 4
#define PARAM_sv  5
#define PARAM_t0  6
#define PARAM_st0 7

#define BOUNDARY_LOWER 0
#define BOUNDARY_UPPER 1

const double EPSILON = 1e-6; // used in ddiffusion
const unsigned int MAX_INPUT_VALUES = 1e+6; // max simulation number

class Parameters
{
public:
  double a;     // Boundary separation
  double v;     // Mean of the drift
  double t0;    // Non-decision time
  double d;     // Difference between boundaries of non-decision time
  double szr;   // width of zr distribution
  double sv;    // standard deviation of v distribution
  double st0;   // width of t0 distribution
  double zr;    // Mean of diffusion starting point relative to boundaries

  // Precision constants set by SetPrecision()
  double  TUNE_DZ;
  double  TUNE_DV;
  double  TUNE_DT0;

  double  TUNE_PDE_DT_MIN;   // If std=c++11 we can use C++ defaults to set as = 1e-6;
  double  TUNE_PDE_DT_MAX;   // ... we can default to = 1e-6;
  double  TUNE_PDE_DT_SCALE; // ... we can default to = 0.0;

  double  TUNE_INT_T0;
  double  TUNE_INT_Z;

  double  TUNE_SV_EPSILON; // CONVERSION NOTE: See below in SetPrecision()
  double  TUNE_SZ_EPSILON; // CONVERSION NOTE: See below in SetPrecision()
  double  TUNE_ST0_EPSILON; // CONVERSION NOTE: See below in SetPrecision()

  // Specialized constructor
  Parameters(std::vector<double> params, double precision);
  Parameters(double * params, double precision);
  bool ValidateParams (bool print);
  void Show(std::string str) const;

private:
  void  SetPrecision (double p)
  {
    // Try to achieve an accuracy of approximately 10^{-p} for the CDF.
    TUNE_PDE_DT_MIN   = std::pow(10, -0.400825*p-1.422813);
    TUNE_PDE_DT_MAX   = std::pow(10, -0.627224*p+0.492689);
    TUNE_PDE_DT_SCALE = std::pow(10, -1.012677*p+2.261668);

    TUNE_DZ  = std::pow(10, -0.5*p-0.033403); // CDF
    TUNE_DV  = std::pow(10, -1.0*p+1.4);
    TUNE_DT0 = std::pow(10, -0.5*p-0.323859);

    TUNE_INT_T0 = 0.089045 * std::exp(-1.037580*p); // PDF
    TUNE_INT_Z  = 0.508061 * std::exp(-1.022373*p);

    // CONVERSION NOTE:
    //     These have been added to optimise code paths by treating very small variances as 0
    //     e.g. with precision = 3, sv or sz values < 10^-5 are considered 0
    TUNE_SV_EPSILON  = std::pow (10, -(p+2.0));     // Used by pdiffusion
    TUNE_SZ_EPSILON  = std::pow (10, -(p+2.0));     // Used by ddiffusion and pdiffusion
    TUNE_ST0_EPSILON = std::pow (10, -(p+2.0));   // Used by ddiffusion
  }

};

///////////////////// Density.h  //////////////////////
double g_minus(double t, Parameters *params);
double g_plus(double t, Parameters *params);

#endif // PARAMETERS_H
