/* 
    Autogenerated using:
    - Template: 'src/ext/models/model.cpp.mako'
    - Model definition: 'codegen/recipes/wc.yaml'
    Do not modify this autogenerated code. Instead modify template
    or model definition.
*/
#include "cubnm/models/wc.hpp"

// Static constants instance
WCModel::Constants WCModel::mc;

// Initialize constants based on dt
void WCModel::init_constants(double dt) {
    mc.dt = dt; // integration step
    mc.sqrt_dt = sqrt(mc.dt); // square root of integration step
    mc.tau_E = 2.5; // excitatory time constant (ms)
    mc.tau_I = 3.75; // inhibitory time constant (ms)
    mc.itau_E = 1.0/mc.tau_E; // inverse of tau_E
    mc.itau_I = 1.0/mc.tau_I; // inverse of tau_I
    mc.a_E = 1.5; // excitatory gain
    mc.a_I = 1.5; // inhibitory gain
    mc.mu_E = 3.0; // excitatory firing threshold
    mc.mu_I = 3.0; // inhibitory firing threshold
}

void WCModel::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
) {
    // E = 0.001
    _state_vars[0] = 0.001;
    // I = 0.001
    _state_vars[1] = 0.001;
}

void WCModel::_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
) {
    // E = 0.001
    _state_vars[0] = 0.001;
    // I = 0.001
    _state_vars[1] = 0.001;
}

void WCModel::h_step(
        double* _state_vars, double* _intermediate_vars,
        double* _global_params, double* _regional_params,
        double& tmp_globalinput,
        double* noise, long& noise_idx
        ) {
    // Calculate sigmoid activations
    // S_E = 1.0 / (1.0 + exp(-a_E * (c_EE * E - c_IE * I + G * globalinput + P_E - mu_E)))
    _intermediate_vars[0] = 1.0 / (1.0 + exp(-WCModel::mc.a_E * (_regional_params[0] * _state_vars[0] - _regional_params[1] * _state_vars[1] + _global_params[0] * tmp_globalinput + _regional_params[4] - WCModel::mc.mu_E)));
    // S_I = 1.0 / (1.0 + exp(-a_I * (c_EI * E - c_II * I + P_I - mu_I)))
    _intermediate_vars[1] = 1.0 / (1.0 + exp(-WCModel::mc.a_I * (_regional_params[2] * _state_vars[0] - _regional_params[3] * _state_vars[1] + _regional_params[5] - WCModel::mc.mu_I)));

    // Calculate derivatives
    // E_dot = (-E + (1.0 - E) * S_E) * itau_E
    _intermediate_vars[2] = (-_state_vars[0] + (1.0 - _state_vars[0]) * _intermediate_vars[0]) * WCModel::mc.itau_E;
    // I_dot = (-I + (1.0 - I) * S_I) * itau_I
    _intermediate_vars[3] = (-_state_vars[1] + (1.0 - _state_vars[1]) * _intermediate_vars[1]) * WCModel::mc.itau_I;

    // Update state variables with noise
    // E += dt * E_dot + sqrt_dt * noise_E * sigma_E
    _state_vars[0] += WCModel::mc.dt * _intermediate_vars[2] + WCModel::mc.sqrt_dt * noise[noise_idx] * _regional_params[6];
    // I += dt * I_dot + sqrt_dt * noise_I * sigma_I
    _state_vars[1] += WCModel::mc.dt * _intermediate_vars[3] + WCModel::mc.sqrt_dt * noise[noise_idx + 1] * _regional_params[7];

    // Clip to valid range [0, 1]
    // E = max(0.0, min(1.0, E))
    _state_vars[0] = max(0.0, min(1.0, _state_vars[0]));
    // I = max(0.0, min(1.0, I))
    _state_vars[1] = max(0.0, min(1.0, _state_vars[1]));
}
