// Code generated by Stan version 2.15.0

#include <stan/model/model_header.hpp>

namespace model20d0584c44a8_FitImplModel_namespace {

using std::istream;
using std::string;
using std::stringstream;
using std::vector;
using stan::io::dump;
using stan::math::lgamma;
using stan::model::prob_grad;
using namespace stan::math;

typedef Eigen::Matrix<double,Eigen::Dynamic,1> vector_d;
typedef Eigen::Matrix<double,1,Eigen::Dynamic> row_vector_d;
typedef Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> matrix_d;

static int current_statement_begin__;

class model20d0584c44a8_FitImplModel : public prob_grad {
private:
    int N;
    vector_d If;
    vector_d Ic;
    double beta0prior;
    double alpha0prior;
    double beta1shape;
    double beta1scale;
    double alpha1shape;
    double alpha1scale;
    double T_f;
public:
    model20d0584c44a8_FitImplModel(stan::io::var_context& context__,
        std::ostream* pstream__ = 0)
        : prob_grad(0) {
        typedef boost::ecuyer1988 rng_t;
        rng_t base_rng(0);  // 0 seed default
        ctor_body(context__, base_rng, pstream__);
    }

    template <class RNG>
    model20d0584c44a8_FitImplModel(stan::io::var_context& context__,
        RNG& base_rng__,
        std::ostream* pstream__ = 0)
        : prob_grad(0) {
        ctor_body(context__, base_rng__, pstream__);
    }

    template <class RNG>
    void ctor_body(stan::io::var_context& context__,
                   RNG& base_rng__,
                   std::ostream* pstream__) {
        current_statement_begin__ = -1;

        static const char* function__ = "model20d0584c44a8_FitImplModel_namespace::model20d0584c44a8_FitImplModel";
        (void) function__;  // dummy to suppress unused var warning
        size_t pos__;
        (void) pos__;  // dummy to suppress unused var warning
        std::vector<int> vals_i__;
        std::vector<double> vals_r__;
        double DUMMY_VAR__(std::numeric_limits<double>::quiet_NaN());
        (void) DUMMY_VAR__;  // suppress unused var warning

        // initialize member variables
        context__.validate_dims("data initialization", "N", "int", context__.to_vec());
        N = int(0);
        vals_i__ = context__.vals_i("N");
        pos__ = 0;
        N = vals_i__[pos__++];
        validate_non_negative_index("If", "N", N);
        context__.validate_dims("data initialization", "If", "vector_d", context__.to_vec(N));
        validate_non_negative_index("If", "N", N);
        If = vector_d(static_cast<Eigen::VectorXd::Index>(N));
        vals_r__ = context__.vals_r("If");
        pos__ = 0;
        size_t If_i_vec_lim__ = N;
        for (size_t i_vec__ = 0; i_vec__ < If_i_vec_lim__; ++i_vec__) {
            If[i_vec__] = vals_r__[pos__++];
        }
        validate_non_negative_index("Ic", "N", N);
        context__.validate_dims("data initialization", "Ic", "vector_d", context__.to_vec(N));
        validate_non_negative_index("Ic", "N", N);
        Ic = vector_d(static_cast<Eigen::VectorXd::Index>(N));
        vals_r__ = context__.vals_r("Ic");
        pos__ = 0;
        size_t Ic_i_vec_lim__ = N;
        for (size_t i_vec__ = 0; i_vec__ < Ic_i_vec_lim__; ++i_vec__) {
            Ic[i_vec__] = vals_r__[pos__++];
        }
        context__.validate_dims("data initialization", "beta0prior", "double", context__.to_vec());
        beta0prior = double(0);
        vals_r__ = context__.vals_r("beta0prior");
        pos__ = 0;
        beta0prior = vals_r__[pos__++];
        context__.validate_dims("data initialization", "alpha0prior", "double", context__.to_vec());
        alpha0prior = double(0);
        vals_r__ = context__.vals_r("alpha0prior");
        pos__ = 0;
        alpha0prior = vals_r__[pos__++];
        context__.validate_dims("data initialization", "beta1shape", "double", context__.to_vec());
        beta1shape = double(0);
        vals_r__ = context__.vals_r("beta1shape");
        pos__ = 0;
        beta1shape = vals_r__[pos__++];
        context__.validate_dims("data initialization", "beta1scale", "double", context__.to_vec());
        beta1scale = double(0);
        vals_r__ = context__.vals_r("beta1scale");
        pos__ = 0;
        beta1scale = vals_r__[pos__++];
        context__.validate_dims("data initialization", "alpha1shape", "double", context__.to_vec());
        alpha1shape = double(0);
        vals_r__ = context__.vals_r("alpha1shape");
        pos__ = 0;
        alpha1shape = vals_r__[pos__++];
        context__.validate_dims("data initialization", "alpha1scale", "double", context__.to_vec());
        alpha1scale = double(0);
        vals_r__ = context__.vals_r("alpha1scale");
        pos__ = 0;
        alpha1scale = vals_r__[pos__++];
        context__.validate_dims("data initialization", "T_f", "double", context__.to_vec());
        T_f = double(0);
        vals_r__ = context__.vals_r("T_f");
        pos__ = 0;
        T_f = vals_r__[pos__++];

        // validate, data variables
        check_greater_or_equal(function__,"N",N,1);
        check_greater_or_equal(function__,"beta0prior",beta0prior,0);
        check_greater_or_equal(function__,"alpha0prior",alpha0prior,0);
        check_greater_or_equal(function__,"beta1shape",beta1shape,0);
        check_greater_or_equal(function__,"beta1scale",beta1scale,0);
        check_greater_or_equal(function__,"alpha1shape",alpha1shape,0);
        check_greater_or_equal(function__,"alpha1scale",alpha1scale,0);
        check_greater_or_equal(function__,"T_f",T_f,0);
        // initialize data variables

        try {
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(e,current_statement_begin__);
            // Next line prevents compiler griping about no return
            throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
        }

        // validate transformed data

        // validate, set parameter ranges
        num_params_r__ = 0U;
        param_ranges_i__.clear();
        ++num_params_r__;
        ++num_params_r__;
        ++num_params_r__;
        ++num_params_r__;
        ++num_params_r__;
    }

    ~model20d0584c44a8_FitImplModel() { }


    void transform_inits(const stan::io::var_context& context__,
                         std::vector<int>& params_i__,
                         std::vector<double>& params_r__,
                         std::ostream* pstream__) const {
        stan::io::writer<double> writer__(params_r__,params_i__);
        size_t pos__;
        (void) pos__; // dummy call to supress warning
        std::vector<double> vals_r__;
        std::vector<int> vals_i__;

        if (!(context__.contains_r("sigma_sq")))
            throw std::runtime_error("variable sigma_sq missing");
        vals_r__ = context__.vals_r("sigma_sq");
        pos__ = 0U;
        context__.validate_dims("initialization", "sigma_sq", "double", context__.to_vec());
        // generate_declaration sigma_sq
        double sigma_sq(0);
        sigma_sq = vals_r__[pos__++];
        try {
            writer__.scalar_lb_unconstrain(0,sigma_sq);
        } catch (const std::exception& e) { 
            throw std::runtime_error(std::string("Error transforming variable sigma_sq: ") + e.what());
        }

        if (!(context__.contains_r("beta0")))
            throw std::runtime_error("variable beta0 missing");
        vals_r__ = context__.vals_r("beta0");
        pos__ = 0U;
        context__.validate_dims("initialization", "beta0", "double", context__.to_vec());
        // generate_declaration beta0
        double beta0(0);
        beta0 = vals_r__[pos__++];
        try {
            writer__.scalar_unconstrain(beta0);
        } catch (const std::exception& e) { 
            throw std::runtime_error(std::string("Error transforming variable beta0: ") + e.what());
        }

        if (!(context__.contains_r("beta1")))
            throw std::runtime_error("variable beta1 missing");
        vals_r__ = context__.vals_r("beta1");
        pos__ = 0U;
        context__.validate_dims("initialization", "beta1", "double", context__.to_vec());
        // generate_declaration beta1
        double beta1(0);
        beta1 = vals_r__[pos__++];
        try {
            writer__.scalar_unconstrain(beta1);
        } catch (const std::exception& e) { 
            throw std::runtime_error(std::string("Error transforming variable beta1: ") + e.what());
        }

        if (!(context__.contains_r("alpha0")))
            throw std::runtime_error("variable alpha0 missing");
        vals_r__ = context__.vals_r("alpha0");
        pos__ = 0U;
        context__.validate_dims("initialization", "alpha0", "double", context__.to_vec());
        // generate_declaration alpha0
        double alpha0(0);
        alpha0 = vals_r__[pos__++];
        try {
            writer__.scalar_unconstrain(alpha0);
        } catch (const std::exception& e) { 
            throw std::runtime_error(std::string("Error transforming variable alpha0: ") + e.what());
        }

        if (!(context__.contains_r("alpha1")))
            throw std::runtime_error("variable alpha1 missing");
        vals_r__ = context__.vals_r("alpha1");
        pos__ = 0U;
        context__.validate_dims("initialization", "alpha1", "double", context__.to_vec());
        // generate_declaration alpha1
        double alpha1(0);
        alpha1 = vals_r__[pos__++];
        try {
            writer__.scalar_unconstrain(alpha1);
        } catch (const std::exception& e) { 
            throw std::runtime_error(std::string("Error transforming variable alpha1: ") + e.what());
        }

        params_r__ = writer__.data_r();
        params_i__ = writer__.data_i();
    }

    void transform_inits(const stan::io::var_context& context,
                         Eigen::Matrix<double,Eigen::Dynamic,1>& params_r,
                         std::ostream* pstream__) const {
      std::vector<double> params_r_vec;
      std::vector<int> params_i_vec;
      transform_inits(context, params_i_vec, params_r_vec, pstream__);
      params_r.resize(params_r_vec.size());
      for (int i = 0; i < params_r.size(); ++i)
        params_r(i) = params_r_vec[i];
    }


    template <bool propto__, bool jacobian__, typename T__>
    T__ log_prob(vector<T__>& params_r__,
                 vector<int>& params_i__,
                 std::ostream* pstream__ = 0) const {

        T__ DUMMY_VAR__(std::numeric_limits<double>::quiet_NaN());
        (void) DUMMY_VAR__;  // suppress unused var warning

        T__ lp__(0.0);
        stan::math::accumulator<T__> lp_accum__;

        // model parameters
        stan::io::reader<T__> in__(params_r__,params_i__);

        T__ sigma_sq;
        (void) sigma_sq;  // dummy to suppress unused var warning
        if (jacobian__)
            sigma_sq = in__.scalar_lb_constrain(0,lp__);
        else
            sigma_sq = in__.scalar_lb_constrain(0);

        T__ beta0;
        (void) beta0;  // dummy to suppress unused var warning
        if (jacobian__)
            beta0 = in__.scalar_constrain(lp__);
        else
            beta0 = in__.scalar_constrain();

        T__ beta1;
        (void) beta1;  // dummy to suppress unused var warning
        if (jacobian__)
            beta1 = in__.scalar_constrain(lp__);
        else
            beta1 = in__.scalar_constrain();

        T__ alpha0;
        (void) alpha0;  // dummy to suppress unused var warning
        if (jacobian__)
            alpha0 = in__.scalar_constrain(lp__);
        else
            alpha0 = in__.scalar_constrain();

        T__ alpha1;
        (void) alpha1;  // dummy to suppress unused var warning
        if (jacobian__)
            alpha1 = in__.scalar_constrain(lp__);
        else
            alpha1 = in__.scalar_constrain();


        // transformed parameters
        validate_non_negative_index("Mu", "N", N);
        Eigen::Matrix<T__,Eigen::Dynamic,1>  Mu(static_cast<Eigen::VectorXd::Index>(N));
        (void) Mu;  // dummy to suppress unused var warning

        stan::math::initialize(Mu, DUMMY_VAR__);
        stan::math::fill(Mu,DUMMY_VAR__);
        validate_non_negative_index("Sigma", "N", N);
        Eigen::Matrix<T__,Eigen::Dynamic,1>  Sigma(static_cast<Eigen::VectorXd::Index>(N));
        (void) Sigma;  // dummy to suppress unused var warning

        stan::math::initialize(Sigma, DUMMY_VAR__);
        stan::math::fill(Sigma,DUMMY_VAR__);


        try {
            current_statement_begin__ = 23;
            stan::math::assign(Mu, add(beta0,multiply(beta1,If)));
            current_statement_begin__ = 24;
            for (int i = 1; i <= N; ++i) {
                current_statement_begin__ = 24;
                stan::math::assign(get_base1_lhs(Sigma,i,"Sigma",1), (sigma_sq / exp((alpha0 + (alpha1 * log(get_base1(If,i,"If",1)))))));
            }
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(e,current_statement_begin__);
            // Next line prevents compiler griping about no return
            throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
        }

        // validate transformed parameters
        for (int i0__ = 0; i0__ < N; ++i0__) {
            if (stan::math::is_uninitialized(Mu(i0__))) {
                std::stringstream msg__;
                msg__ << "Undefined transformed parameter: Mu" << '[' << i0__ << ']';
                throw std::runtime_error(msg__.str());
            }
        }
        for (int i0__ = 0; i0__ < N; ++i0__) {
            if (stan::math::is_uninitialized(Sigma(i0__))) {
                std::stringstream msg__;
                msg__ << "Undefined transformed parameter: Sigma" << '[' << i0__ << ']';
                throw std::runtime_error(msg__.str());
            }
        }

        const char* function__ = "validate transformed params";
        (void) function__;  // dummy to suppress unused var warning

        // model body
        try {

            current_statement_begin__ = 28;
            lp_accum__.add(gamma_log<propto__>(sigma_sq, 1, 1));
            current_statement_begin__ = 29;
            lp_accum__.add(normal_log<propto__>(beta0, 0, beta0prior));
            current_statement_begin__ = 30;
            lp_accum__.add(normal_log<propto__>(alpha0, 0, alpha0prior));
            current_statement_begin__ = 31;
            lp_accum__.add(gamma_log<propto__>(beta1, beta1shape, beta1scale));
            current_statement_begin__ = 32;
            lp_accum__.add(gamma_log<propto__>(-(alpha1), alpha1shape, alpha1scale));
            current_statement_begin__ = 33;
            lp_accum__.add(normal_log<propto__>(Ic, Mu, Sigma));
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(e,current_statement_begin__);
            // Next line prevents compiler griping about no return
            throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
        }

        lp_accum__.add(lp__);
        return lp_accum__.sum();

    } // log_prob()

    template <bool propto, bool jacobian, typename T_>
    T_ log_prob(Eigen::Matrix<T_,Eigen::Dynamic,1>& params_r,
               std::ostream* pstream = 0) const {
      std::vector<T_> vec_params_r;
      vec_params_r.reserve(params_r.size());
      for (int i = 0; i < params_r.size(); ++i)
        vec_params_r.push_back(params_r(i));
      std::vector<int> vec_params_i;
      return log_prob<propto,jacobian,T_>(vec_params_r, vec_params_i, pstream);
    }


    void get_param_names(std::vector<std::string>& names__) const {
        names__.resize(0);
        names__.push_back("sigma_sq");
        names__.push_back("beta0");
        names__.push_back("beta1");
        names__.push_back("alpha0");
        names__.push_back("alpha1");
        names__.push_back("Mu");
        names__.push_back("Sigma");
        names__.push_back("T_c");
    }


    void get_dims(std::vector<std::vector<size_t> >& dimss__) const {
        dimss__.resize(0);
        std::vector<size_t> dims__;
        dims__.resize(0);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dims__.push_back(N);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dims__.push_back(N);
        dimss__.push_back(dims__);
        dims__.resize(0);
        dimss__.push_back(dims__);
    }

    template <typename RNG>
    void write_array(RNG& base_rng__,
                     std::vector<double>& params_r__,
                     std::vector<int>& params_i__,
                     std::vector<double>& vars__,
                     bool include_tparams__ = true,
                     bool include_gqs__ = true,
                     std::ostream* pstream__ = 0) const {
        vars__.resize(0);
        stan::io::reader<double> in__(params_r__,params_i__);
        static const char* function__ = "model20d0584c44a8_FitImplModel_namespace::write_array";
        (void) function__;  // dummy to suppress unused var warning
        // read-transform, write parameters
        double sigma_sq = in__.scalar_lb_constrain(0);
        double beta0 = in__.scalar_constrain();
        double beta1 = in__.scalar_constrain();
        double alpha0 = in__.scalar_constrain();
        double alpha1 = in__.scalar_constrain();
        vars__.push_back(sigma_sq);
        vars__.push_back(beta0);
        vars__.push_back(beta1);
        vars__.push_back(alpha0);
        vars__.push_back(alpha1);

        if (!include_tparams__) return;
        // declare and define transformed parameters
        double lp__ = 0.0;
        (void) lp__;  // dummy to suppress unused var warning
        stan::math::accumulator<double> lp_accum__;

        double DUMMY_VAR__(std::numeric_limits<double>::quiet_NaN());
        (void) DUMMY_VAR__;  // suppress unused var warning

        validate_non_negative_index("Mu", "N", N);
        vector_d Mu(static_cast<Eigen::VectorXd::Index>(N));
        (void) Mu;  // dummy to suppress unused var warning

        stan::math::initialize(Mu, std::numeric_limits<double>::quiet_NaN());
        stan::math::fill(Mu,DUMMY_VAR__);
        validate_non_negative_index("Sigma", "N", N);
        vector_d Sigma(static_cast<Eigen::VectorXd::Index>(N));
        (void) Sigma;  // dummy to suppress unused var warning

        stan::math::initialize(Sigma, std::numeric_limits<double>::quiet_NaN());
        stan::math::fill(Sigma,DUMMY_VAR__);


        try {
            current_statement_begin__ = 23;
            stan::math::assign(Mu, add(beta0,multiply(beta1,If)));
            current_statement_begin__ = 24;
            for (int i = 1; i <= N; ++i) {
                current_statement_begin__ = 24;
                stan::math::assign(get_base1_lhs(Sigma,i,"Sigma",1), (sigma_sq / exp((alpha0 + (alpha1 * log(get_base1(If,i,"If",1)))))));
            }
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(e,current_statement_begin__);
            // Next line prevents compiler griping about no return
            throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
        }

        // validate transformed parameters

        // write transformed parameters
        for (int k_0__ = 0; k_0__ < N; ++k_0__) {
            vars__.push_back(Mu[k_0__]);
        }
        for (int k_0__ = 0; k_0__ < N; ++k_0__) {
            vars__.push_back(Sigma[k_0__]);
        }

        if (!include_gqs__) return;
        // declare and define generated quantities
        double T_c(0.0);
        (void) T_c;  // dummy to suppress unused var warning

        stan::math::initialize(T_c, std::numeric_limits<double>::quiet_NaN());
        stan::math::fill(T_c,DUMMY_VAR__);


        try {
            current_statement_begin__ = 37;
            stan::math::assign(T_c, (beta0 + (beta1 * T_f)));
        } catch (const std::exception& e) {
            stan::lang::rethrow_located(e,current_statement_begin__);
            // Next line prevents compiler griping about no return
            throw std::runtime_error("*** IF YOU SEE THIS, PLEASE REPORT A BUG ***");
        }

        // validate generated quantities

        // write generated quantities
        vars__.push_back(T_c);

    }

    template <typename RNG>
    void write_array(RNG& base_rng,
                     Eigen::Matrix<double,Eigen::Dynamic,1>& params_r,
                     Eigen::Matrix<double,Eigen::Dynamic,1>& vars,
                     bool include_tparams = true,
                     bool include_gqs = true,
                     std::ostream* pstream = 0) const {
      std::vector<double> params_r_vec(params_r.size());
      for (int i = 0; i < params_r.size(); ++i)
        params_r_vec[i] = params_r(i);
      std::vector<double> vars_vec;
      std::vector<int> params_i_vec;
      write_array(base_rng,params_r_vec,params_i_vec,vars_vec,include_tparams,include_gqs,pstream);
      vars.resize(vars_vec.size());
      for (int i = 0; i < vars.size(); ++i)
        vars(i) = vars_vec[i];
    }

    static std::string model_name() {
        return "model20d0584c44a8_FitImplModel";
    }


    void constrained_param_names(std::vector<std::string>& param_names__,
                                 bool include_tparams__ = true,
                                 bool include_gqs__ = true) const {
        std::stringstream param_name_stream__;
        param_name_stream__.str(std::string());
        param_name_stream__ << "sigma_sq";
        param_names__.push_back(param_name_stream__.str());
        param_name_stream__.str(std::string());
        param_name_stream__ << "beta0";
        param_names__.push_back(param_name_stream__.str());
        param_name_stream__.str(std::string());
        param_name_stream__ << "beta1";
        param_names__.push_back(param_name_stream__.str());
        param_name_stream__.str(std::string());
        param_name_stream__ << "alpha0";
        param_names__.push_back(param_name_stream__.str());
        param_name_stream__.str(std::string());
        param_name_stream__ << "alpha1";
        param_names__.push_back(param_name_stream__.str());

        if (!include_gqs__ && !include_tparams__) return;
        for (int k_0__ = 1; k_0__ <= N; ++k_0__) {
            param_name_stream__.str(std::string());
            param_name_stream__ << "Mu" << '.' << k_0__;
            param_names__.push_back(param_name_stream__.str());
        }
        for (int k_0__ = 1; k_0__ <= N; ++k_0__) {
            param_name_stream__.str(std::string());
            param_name_stream__ << "Sigma" << '.' << k_0__;
            param_names__.push_back(param_name_stream__.str());
        }

        if (!include_gqs__) return;
        param_name_stream__.str(std::string());
        param_name_stream__ << "T_c";
        param_names__.push_back(param_name_stream__.str());
    }


    void unconstrained_param_names(std::vector<std::string>& param_names__,
                                   bool include_tparams__ = true,
                                   bool include_gqs__ = true) const {
        std::stringstream param_name_stream__;
        param_name_stream__.str(std::string());
        param_name_stream__ << "sigma_sq";
        param_names__.push_back(param_name_stream__.str());
        param_name_stream__.str(std::string());
        param_name_stream__ << "beta0";
        param_names__.push_back(param_name_stream__.str());
        param_name_stream__.str(std::string());
        param_name_stream__ << "beta1";
        param_names__.push_back(param_name_stream__.str());
        param_name_stream__.str(std::string());
        param_name_stream__ << "alpha0";
        param_names__.push_back(param_name_stream__.str());
        param_name_stream__.str(std::string());
        param_name_stream__ << "alpha1";
        param_names__.push_back(param_name_stream__.str());

        if (!include_gqs__ && !include_tparams__) return;
        for (int k_0__ = 1; k_0__ <= N; ++k_0__) {
            param_name_stream__.str(std::string());
            param_name_stream__ << "Mu" << '.' << k_0__;
            param_names__.push_back(param_name_stream__.str());
        }
        for (int k_0__ = 1; k_0__ <= N; ++k_0__) {
            param_name_stream__.str(std::string());
            param_name_stream__ << "Sigma" << '.' << k_0__;
            param_names__.push_back(param_name_stream__.str());
        }

        if (!include_gqs__) return;
        param_name_stream__.str(std::string());
        param_name_stream__ << "T_c";
        param_names__.push_back(param_name_stream__.str());
    }

}; // model

}

typedef model20d0584c44a8_FitImplModel_namespace::model20d0584c44a8_FitImplModel stan_model;