// CelerisLab – step/init_flow.cu
// Channel-flow initialization kernels (double-buffer and EsoPull).
// Included by kernel_v2.cu after all headers.  No standalone compilation.
// ============================================================================

#ifndef CELERIS_STEP_INIT_FLOW_CU
#define CELERIS_STEP_INIT_FLOW_CU

// ---- Helper: write equilibrium for a given velocity ----
__device__ __forceinline__ void write_equilibrium(
    fpxx* fi, unsigned long k, float u_init)
{
    for (int i = 0; i < NQ; i++) {
        float cu = (float)d_cx[i] * u_init;
        float val = d_w[i] * RHO * (1.0f + 3.0f*cu + 4.5f*cu*cu
                                      - 1.5f*u_init*u_init);
#if USE_DDF_SHIFTING
        val -= d_w[i];
#endif
        store_ddf(fi, index_f(k, (unsigned int)i), val);
    }
}

__device__ __forceinline__ void write_rest_equilibrium(
    fpxx* fi, unsigned long k)
{
    for (int i = 0; i < NQ; i++) {
        float val = d_w[i] * RHO;
#if USE_DDF_SHIFTING
        val -= d_w[i];
#endif
        store_ddf(fi, index_f(k, (unsigned int)i), val);
    }
}

__device__ __forceinline__ uint16_t channel_flag_from_coords(
    unsigned int x, unsigned int y)
{
    if (y == 0u || y == (unsigned int)(NY - 1))
        return (uint16_t)(FLAG_SOLID | FLAG_BC_WALL);
    if (x == 0u)
        return (uint16_t)(FLAG_SOLID | FLAG_BC_INLET);
    if (x == (unsigned int)(NX - 1))
        return (uint16_t)(FLAG_SOLID | FLAG_BC_OUTLET);
    return FLAG_FLUID;
}

__device__ __forceinline__ uint16_t finalize_domain_flag(
    uint16_t fl, unsigned int x, unsigned int y)
{
    if (is_obstacle(fl))
        return fl;

    const uint16_t base = channel_flag_from_coords(x, y);
    if (is_sensor(fl) && base == FLAG_FLUID)
        return (uint16_t)(base | FLAG_SENSOR);
    if (is_force_region(fl) && base == FLAG_FLUID)
        return (uint16_t)(base | FLAG_FRC_REGION);
    return base;
}

// ============================================================================
// InitTubeFlow_v2 — double-buffer channel initialization
// ============================================================================
__global__ void InitTubeFlow_v2(uint16_t* flag, fpxx* fi)
{
#if DIM == 2
    unsigned int x, y; unsigned long k;
    index_from_thread(x, y, k);
    if (x >= (unsigned int)NX || y >= (unsigned int)NY) return;

    const uint16_t fl = finalize_domain_flag(flag[k], x, y);
    flag[k] = fl;
    if (is_solid(fl)) {
        write_rest_equilibrium(fi, k);
    } else {
        write_equilibrium(fi, k, inlet_target_u((float)y));
    }
#elif DIM == 3
    unsigned int x, y, z; unsigned long k;
    index_from_thread(x, y, z, k);
    if (x >= (unsigned int)NX || y >= (unsigned int)NY || z >= (unsigned int)NZ) return;

    const uint16_t fl = finalize_domain_flag(flag[k], x, y);
    flag[k] = fl;
    if (is_solid(fl)) {
        write_rest_equilibrium(fi, k);
    } else {
        write_equilibrium(fi, k, inlet_target_u((float)y));
    }
#endif
}

// ============================================================================
// InitEsoPull — EsoPull single-buffer channel initialization
// ============================================================================
__global__ void InitEsoPull(uint16_t* flag, fpxx* fi)
{
#if DIM == 2
    unsigned int x, y; unsigned long k;
    index_from_thread(x, y, k);
    if (x >= (unsigned int)NX || y >= (unsigned int)NY) return;

    const uint16_t fl = finalize_domain_flag(flag[k], x, y);
    flag[k] = fl;
    if (is_solid(fl)) {
        write_rest_equilibrium(fi, k);
    } else {
        write_equilibrium(fi, k, inlet_target_u((float)y));
    }
#elif DIM == 3
    unsigned int x, y, z; unsigned long k;
    index_from_thread(x, y, z, k);
    if (x >= (unsigned int)NX || y >= (unsigned int)NY || z >= (unsigned int)NZ) return;

    const uint16_t fl = finalize_domain_flag(flag[k], x, y);
    flag[k] = fl;
    if (is_solid(fl)) {
        write_rest_equilibrium(fi, k);
    } else {
        write_equilibrium(fi, k, inlet_target_u((float)y));
    }
#endif
}

#endif // CELERIS_STEP_INIT_FLOW_CU