lengths.clΒΆ

///
/// @file lengths.cl
///
/// Kernel to measure distances from midslope to thin channel pixels aka hillslope length.
///
/// @author CPS
/// @bug No known bugs
///

///
/// @defgroup lengths Hillslope lengths
/// Measure hillslope lengths
///


#ifdef KERNEL_HILLSLOPE_LENGTHS
///
/// TBD
///
/// Compiled if KERNEL_HILLSLOPE_LENGTHS is defined.
///
/// @param[in]     seed_point_array: list of initial streamline point vectors,
///                                  one allotted to each kernel instance
/// @param[in]     mask_array: grid pixel mask (padded),
///                            with @p true = masked, @p false = good
/// @param[in]     uv_array: flow unit velocity vector grid (padded)
/// @param[in,out] mapping_array: flag grid recording status of each pixel (padded)
/// @param[in,out] label_array: label grid giving the ID of the subsegment to which
///                             this pixel belongs (padded); the MSB is set if left flank
/// @param[out] traj_length_array: list of lengths of each trajectory;
///                                one per @p seed_point_array vector
///
/// @returns void
///
/// @ingroup lengths
///
__kernel void hillslope_lengths(
        __global const float2 *seed_point_array,
        __global const bool   *mask_array,
        __global const float2 *uv_array,
        __global const uint   *mapping_array,
        __global const uint   *label_array,
        __global       float  *traj_length_array
   )
{
    // For every mid-slope /or/ ridge pixel

    const uint global_id = get_global_id(0u)+get_global_id(1u)*get_global_size(0u);
#ifdef DO_MEASURE_HSL_FROM_RIDGES
    const uint from_flag = IS_RIDGE;
#else
    const uint from_flag = IS_MIDSLOPE;
#endif
#ifdef VERBOSE
    // Report how kernel instances are distributed
    if (global_id==0 || global_id==get_global_offset(0u)) {
        printf("\n  >>> on GPU/OpenCL device: id=%d offset=%d ",
                get_global_id(0u),
                get_global_offset(0u));
        printf("#workitems=%d x #workgroups=%d = %d=%d\n",
                get_local_size(0u), get_num_groups(0u),
                get_local_size(0u)*get_num_groups(0u),
                get_global_size(0u));
    }
#endif
    if (global_id>=N_SEED_POINTS) {
        // This is a "padding" seed, so let's bail
        return;
    }
    __private uint idx, n_steps=0u;
    __private float dl=0.0f, dt=DT_MAX, l_trajectory=0.0f;
    __private float2 uv1_vec, uv2_vec, dxy1_vec, dxy2_vec,
                     vec = seed_point_array[global_id], prev_vec, next_vec;
    __private bool moved_off = false;

//    printf("len=%g (p=%g) vec=%g,%g\n",traj_length_array[global_id],PIXEL_SIZE,
//    vec[0]*PIXEL_SIZE+2800.0f,vec[1]*PIXEL_SIZE+2800.0f);

    // Remember here
    idx = get_array_idx(vec);
    // Integrate downstream until a channel pixel (or masked pixel) is reached
    while (((~mapping_array[idx])&IS_THINCHANNEL) && n_steps<MAX_N_STEPS) {
        compute_step_vec(dt, uv_array, &dxy1_vec, &dxy2_vec, &uv1_vec, &uv2_vec,
                         vec, &next_vec, &idx);
        if (mask_array[idx]) return;
        if (!moved_off && ((~mapping_array[idx])&from_flag)) {
            // Flag when we've moved off the initial band of mid-slope/ridge pixels
            moved_off = true;
        } else if (moved_off && ((mapping_array[idx])&from_flag)) {
            // Bail if we cross another mid-slope pixel, meaning that mid-slope/ridge
            //   mapping isn't working for this streamline
            return;
        }
        if (lengths_runge_kutta_step(&dt, &dl, &l_trajectory, &dxy1_vec, &dxy2_vec,
                                     &vec, &prev_vec,  &next_vec, &n_steps, &idx)) {
#ifdef DEBUG
            printf("Lengths: R-K breaking\n");
#endif
            return;
//            break;
        }
    }
    if (mapping_array[idx]&IS_THINCHANNEL) {
        // We've reached a (thin) channel, so save this trajectory length
        // No need for atomic here since we're writing to the source pixel
        traj_length_array[global_id] = l_trajectory*PIXEL_SIZE;
//#ifdef DEBUG
//        vec = seed_point_array[global_id];
//        vec *= PIXEL_SIZE;
//        vec += (float2)(550.0f,400.0f);
//        if (vec[0]>600.0f && vec[0]<700.0f && vec[1]>400.0f && vec[1]<500.0f)
//            printf("vec=%g,%g   len=%g\n",vec[0],vec[1],traj_length_array[global_id]);
//#endif
    }
    return;
}
#endif