// CelerisLab – boundary/inlet/channel_stabilized.cuh
// Donor-based west velocity inlet closures designed for robust ghost-source use.
// ============================================================================

#ifndef CELERIS_BOUNDARY_INLET_CHANNEL_STABILIZED_CUH
#define CELERIS_BOUNDARY_INLET_CHANNEL_STABILIZED_CUH

#if LATTICE_MODEL == LATTICE_D2Q9
__device__ inline void apply_channel_stabilized_inlet_d2q9(
    float* __restrict__ f,
    const float* __restrict__ f_neb,
    float y_coord)
{
    float rho_neb, u_neb, v_neb;
    compute_rho_u(f_neb, rho_neb, u_neb, v_neb);

    const float u_target = inlet_target_u(y_coord);
    const float v_target = 0.0f;
    const float rho_in = west_velocity_rho_closure_d2q9(f, u_target);

    float feq_tar[9], feq_neb[9];
    compute_feq(rho_in, u_target, v_target, feq_tar);
    compute_feq(rho_neb, u_neb, v_neb, feq_neb);

#if COLLISION_MODEL == 1
    const float beta_n = INLET_TRT_NEQ_DAMP;
#else
    const float beta_n = 1.0f;
#endif

    const float f1_try = feq_tar[1] + beta_n * (f_neb[1] - feq_neb[1]);
    const float known_sum = f[0] + f[2] + f[3] + f[4] + f[6] + f[8];
    float pair_diff = rho_in * v_target + (f[4] - f[3]) + (f[6] - f[8]);
    const float f1_hi = fmaxf(0.0f, rho_in - known_sum - fabsf(pair_diff));
    const float f1 = fminf(fmaxf(f1_try, 0.0f), f1_hi);
    float pair_sum = rho_in - known_sum - f1;

    if (fabsf(pair_diff) > pair_sum) {
        pair_diff = copysignf(pair_sum, pair_diff);
    }

    f[1] = f1;
    f[5] = 0.5f * (pair_sum + pair_diff);
    f[7] = 0.5f * (pair_sum - pair_diff);
}
#endif

#if LATTICE_MODEL == LATTICE_D3Q19
__device__ inline void apply_channel_stabilized_inlet_d3q19(
    float* __restrict__ f,
    const float* __restrict__ f_neb,
    float y_coord)
{
    float rho_neb, un, vn, wn;
    compute_rho_u(f_neb, rho_neb, un, vn, wn);

    const float u_tar = inlet_target_u(y_coord);
    const float v_tar = 0.0f;
    const float w_tar = 0.0f;
    const float rho_in = west_velocity_rho_closure_d3q19(f, u_tar);

    float feq_tar[19], feq_neb[19];
    compute_feq(rho_in, u_tar, v_tar, w_tar, feq_tar);
    compute_feq(rho_neb, un, vn, wn, feq_neb);

#if COLLISION_MODEL == 1
    const float beta_n = INLET_TRT_NEQ_DAMP;
#else
    const float beta_n = 1.0f;
#endif

    const float f1_try = feq_tar[1] + beta_n * (f_neb[1] - feq_neb[1]);
    const float zsum_try = (feq_tar[9] + feq_tar[15])
                         + beta_n * ((f_neb[9] - feq_neb[9])
                                   + (f_neb[15] - feq_neb[15]));

    const float known_sum = f[0] + f[2] + f[3] + f[4] + f[5] + f[6]
                          + f[8] + f[10] + f[11] + f[12] + f[14]
                          + f[16] + f[17] + f[18];
    const float rem_total = rho_in - known_sum;

    float y_diff = rho_in * v_tar
                 - (f[3] - f[4] - f[8] + f[11] - f[12] + f[14] + f[17] - f[18]);
    float z_diff = rho_in * w_tar
                 - (f[5] - f[6] - f[10] + f[11] - f[12] + f[16] + f[18] - f[17]);

    const float f1_hi = fmaxf(0.0f, rem_total - fabsf(y_diff));
    const float f1 = fminf(fmaxf(f1_try, 0.0f), f1_hi);

    const float zsum_hi = fmaxf(0.0f, rem_total - f1 - fabsf(y_diff));
    const float z_sum = fminf(fmaxf(zsum_try, 0.0f), zsum_hi);
    if (fabsf(z_diff) > z_sum) {
        z_diff = copysignf(z_sum, z_diff);
    }

    float y_sum = rem_total - f1 - z_sum;
    y_sum = fmaxf(y_sum, 0.0f);
    if (fabsf(y_diff) > y_sum) {
        y_diff = copysignf(y_sum, y_diff);
    }

    f[1]  = f1;
    f[9]  = 0.5f * (z_sum + z_diff);
    f[15] = 0.5f * (z_sum - z_diff);
    f[7]  = 0.5f * (y_sum + y_diff);
    f[13] = 0.5f * (y_sum - y_diff);
}
#endif

#endif // CELERIS_BOUNDARY_INLET_CHANNEL_STABILIZED_CUH
