/* 
    Autogenerated using:
    - Template: 'include/cubnm/models/model.hpp.mako'
    - Model definition: 'codegen/recipes/rwwex.yaml'
    Do not modify this autogenerated code. Instead modify template
    or model definition.
*/
#ifndef RWWEX_HPP
#define RWWEX_HPP
#include "cubnm/models/base.hpp"

class rWWExModel : public BaseModel {
public:
    // Constants struct - must always be defined even if empty
    struct Constants {
        double dt; // integration step
        double sqrt_dt; // square root of integration step
        double J_N; // synaptic coupling
        double a; // input-output function parameter a
        double b; // input-output function parameter b
        double d; // input-output function parameter d
        double gamma; // kinetic parameter
        double tau; // synaptic time constant
        double itau; // inverse of tau (1/tau)
        double dt_itau;
        double dt_gamma;
    };

    // Config struct - must always be defined even if empty
    struct Config {
    };

    using BaseModel::BaseModel;
    
    ~rWWExModel() {
        if (cpu_initialized) {
            this->free_cpu();
            if (cpu_noise_initialized) {
                this->free_cpu_noise();
            }
        }
        if (gpu_initialized) {
            this->free_gpu();
            if (gpu_noise_initialized) {
                this->free_gpu_noise();
            }
        }
    }

    // Static model properties
    static constexpr char* name = "rWWEx";
    static constexpr int n_state_vars = 3;
    static constexpr int n_intermediate_vars = 2;
    static constexpr int n_noise = 1;
    static constexpr int n_global_params = 1;
    static constexpr int n_regional_params = 3;
    static constexpr int conn_state_var_idx = 2;
    static constexpr int bold_state_var_idx = 2;
    static constexpr int n_ext_int = 0;
    static constexpr int n_ext_bool = 0;
    static constexpr int n_ext_int_shared = 0;
    static constexpr int n_ext_bool_shared = 0;
    static constexpr int n_global_out_int = 0;
    static constexpr int n_global_out_bool = 0;
    static constexpr int n_global_out_double = 0;
    static constexpr int n_regional_out_int = 0;
    static constexpr int n_regional_out_bool = 0;
    static constexpr int n_regional_out_double = 0;
    static constexpr bool has_post_bw_step = false;
    static constexpr bool has_post_integration = false;
    static constexpr bool is_osc = false;

    // Static members
    static Constants mc;
    Config conf;

    // Static initialization method
    static void init_constants(double dt = 0.1);
    // Device-callable methods (GPU)
    CUDA_CALLABLE_MEMBER void init(
        double* _state_vars, double* _intermediate_vars, 
        double* _global_params, double* _regional_params,
        int* _ext_int, bool* _ext_bool,
        int* _ext_int_shared, bool* _ext_bool_shared);

    CUDA_CALLABLE_MEMBER void step(
        double* _state_vars, double* _intermediate_vars,
        double* _global_params, double* _regional_params,
        double& tmp_globalinput,
        double* noise, long& noise_idx);

    CUDA_CALLABLE_MEMBER void post_bw_step(
        double* _state_vars, double* _intermediate_vars,
        int* _ext_int, bool* _ext_bool, 
        int* _ext_int_shared, bool* _ext_bool_shared,
        bool& restart,
        double* _global_params, double* _regional_params,
        int& ts_bold);

    CUDA_CALLABLE_MEMBER void restart(
        double* _state_vars, double* _intermediate_vars, 
        double* _global_params, double* _regional_params,
        int* _ext_int, bool* _ext_bool,
        int* _ext_int_shared, bool* _ext_bool_shared);

    CUDA_CALLABLE_MEMBER void post_integration(
        double ***state_vars_out, 
        int **global_out_int, bool **global_out_bool,
        double* _state_vars, double* _intermediate_vars, 
        int* _ext_int, bool* _ext_bool, 
        int* _ext_int_shared, bool* _ext_bool_shared,
        double** global_params, double** regional_params,
        double* _global_params, double* _regional_params,
        int& sim_idx, const int& nodes, int& j);

    // GPU interface methods
    void init_gpu(BWConstants bwc, bool force_reinit) override final {
        _init_gpu<rWWExModel>(this, bwc, force_reinit);
    }

    void run_simulations_gpu(
        double * BOLD_ex_out, double * fc_trils_out, double * fcd_trils_out,
        double ** global_params, double ** regional_params, double * v_list,
        double ** SC, int * SC_indices, double * SC_dist) override final {
        _run_simulations_gpu<rWWExModel>(
            BOLD_ex_out, fc_trils_out, fcd_trils_out, 
            global_params, regional_params, v_list,
            SC, SC_indices, SC_dist, this);
    }

    // CPU host methods (always required)
    void h_init(
        double* _state_vars, double* _intermediate_vars, 
        double* _global_params, double* _regional_params,
        int* _ext_int, bool* _ext_bool,
        int* _ext_int_shared, bool* _ext_bool_shared) override final;

    void h_step(
        double* _state_vars, double* _intermediate_vars,
        double* _global_params, double* _regional_params,
        double& tmp_globalinput,
        double* noise, long& noise_idx) override final;

    void _j_restart(
        double* _state_vars, double* _intermediate_vars, 
        double* _global_params, double* _regional_params,
        int* _ext_int, bool* _ext_bool,
        int* _ext_int_shared, bool* _ext_bool_shared) override final;



    // CPU interface methods
    void init_cpu(bool force_reinit) override final {
        _init_cpu<rWWExModel>(this, force_reinit);
    }

    void run_simulations_cpu(
        double * BOLD_ex_out, double * fc_trils_out, double * fcd_trils_out,
        double ** global_params, double ** regional_params, double * v_list,
        double ** SC, int * SC_indices, double * SC_dist) override final {
        _run_simulations_cpu<rWWExModel>(
            BOLD_ex_out, fc_trils_out, fcd_trils_out, 
            global_params, regional_params, v_list,
            SC, SC_indices, SC_dist, this);
    }

    // Getter methods
    int get_n_state_vars() override final {
        return n_state_vars;
    }

    int get_n_global_out_bool() override final {
        return n_global_out_bool;
    }

    int get_n_global_out_int() override final {
        return n_global_out_int;
    }

    int get_n_global_params() override final {
        return n_global_params;
    }

    int get_n_regional_params() override final {
        return n_regional_params;
    }

    char * get_name() override final {
        return name;
    }
};

#endif