countlink.clΒΆ

///
/// @file countlink.cl
///
/// Kernels to (re)map thin channels, branching structure, and single outflow directions.
///
/// @author CPS
/// @bug No known bugs
///

#ifdef KERNEL_COUNT_DOWNCHANNELS
///
/// REVISE? Integrate downstream from all channel heads until either a masked boundary
/// pixel is reached or until a channel pixel with a non-zero count is reached.
/// At each new pixel step, link the previous pixel to the current pixel.
/// (Re)designate traversed pixels as 'thin channel' along the way.
///
/// Compiled if KERNEL_COUNT_DOWNCHANNELS 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] count_array: counter grid recording number of pixel steps
///                             downstream from dominant channel head (padded)
/// @param[in,out] link_array: link grid providing the grid array index of the next
///                             downstream pixel (padded)
///
/// @returns void
///
/// @ingroup structure
///
__kernel void count_downchannels(
        __global const float2 *seed_point_array,
        __global const bool   *mask_array,
        __global const float2 *uv_array,
        __global       uint  *mapping_array,
        __global       uint  *count_array,
        __global       uint  *link_array
   )
{
    // For every channel head pixel...

    const uint global_id = get_global_id(0u)+get_global_id(1u)*get_global_size(0u);
    if (global_id>=N_SEED_POINTS) {
        // This is a "padding" seed, so let's bail
//#ifdef DEBUG
//        printf("Bailing @ %d !in [%d-%d]\n",
//                global_id,get_global_offset(0u),N_SEED_POINTS-1);
//#endif
        return;
    }

#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
    __private uint idx, prev_idx, n_steps=0u, counter=1u;
    __private float dl=0.0f, dt=DT_MAX;
    __private float2 uv1_vec, uv2_vec, dxy1_vec, dxy2_vec,
                     vec = seed_point_array[global_id], next_vec;

    // Remember here
    idx = get_array_idx(vec);
    prev_idx = idx;
    // Initialize the TEMPORARY downstream counter - used here to terminate
    //   tracing if we land onto a "superior channel" pixel already traced
    //   in another kernel instance
    atomic_xchg(&count_array[idx],counter++);
    // Integrate downstream until the masked boundary is reached or n_steps too big
    //   OR (where counter++<count_array[idx]) we step onto a more important channel
    // HACK: factor 1000x
    while (!mask_array[idx] && n_steps<1000*(MAX_N_STEPS)) {
        compute_step_vec(dt, uv_array, &dxy1_vec, &dxy2_vec, &uv1_vec, &uv2_vec,
                         vec, &next_vec, &idx);
        if (countlink_runge_kutta_step(&dt, &dl, &dxy1_vec, &dxy2_vec,
                                       &vec, &next_vec, &idx, mapping_array)) {
            break;
        }
        n_steps++;
        // If at a new pixel
        if (prev_idx!=idx) {
            atomic_and(&mapping_array[idx],~IS_CHANNELHEAD);
            // Redesignate as a thin channel pixel
            atomic_or(&mapping_array[idx],IS_THINCHANNEL);
            // Link to here from the last pixel,
            // i.e., point the previous pixel to this its downstream neighbor
            // Hack
            atomic_xchg(&link_array[prev_idx],idx);
//            if (!mask_array[prev_idx]) atomic_xchg(&link_array[prev_idx],idx);
            // If we've landed on a pixel whose channel length count
            //    exceeds our counter, we must have stepped off a minor onto a major
            //    channel, and thus need to stop
            if (++counter<count_array[idx]) {
                break;
            }
            atomic_xchg(&count_array[idx],counter);
            prev_idx = idx;
        }
    }
    // Hack
    atomic_xchg(&link_array[prev_idx],idx);
//    if (!mask_array[prev_idx]) atomic_xchg(&link_array[prev_idx],idx);
    return;
}
#endif

#ifdef KERNEL_FLAG_DOWNCHANNELS
///
/// TBD.
///
/// Compiled if KERNEL_FLAG_DOWNCHANNELS is defined.
///
/// @param[in]      seed_point_array   (float2 *, RO):
/// @param[in]      mask_array         (bool *,   RO):
/// @param[in]      uv_array           (float2 *, RO):
/// @param[in,out]  mapping_array      (uint *,   RW):
/// @param[in,out]  count_array        (uint *,   RW):
/// @param[in,out]  link_array         (uint *,   RW):
///
/// @returns void
///
/// @ingroup structure
///
__kernel void flag_downchannels(
        __global const float2 *seed_point_array,
        __global const bool   *mask_array,
        __global const float2 *uv_array,
        __global        uint  *mapping_array,
        __global        uint  *count_array,
        __global const  uint  *link_array )
{
    // For every channel head pixel...

    const uint global_id = get_global_id(0u)+get_global_id(1u)*get_global_size(0u);
    if (global_id>=N_SEED_POINTS) {
        // This is a "padding" seed, so let's bail
        return;
    }
#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
    __private uint idx, channelhead_idx, prev_idx, counter=1u;
    __private float2 vec = seed_point_array[global_id];

    // Remember here
    channelhead_idx = get_array_idx(vec);
    idx = channelhead_idx;
    prev_idx = idx+1u;
    // Counter=1 at channel head (set by count_downchannels)
    atomic_xchg(&count_array[idx],counter);
    atomic_or(&mapping_array[idx],IS_THINCHANNEL);
    // Step downstream until the masked boundary is reached
    while (!mask_array[idx] && prev_idx!=idx && counter<1000u*MAX_N_STEPS) {
        prev_idx = idx;
        idx = link_array[idx];
        counter++;
        // Assume this idx is on the grid?
        if (!mask_array[idx]) {
            // After label_confluences() only...
            if ( ( ((mapping_array[idx]&IS_MINORINFLOW)>0)
                    || (counter==2u && count_array[idx]>2u))
                    && counter<20u  // HACK - should be scaled by pixel size
                    ) {
                atomic_and(&mapping_array[channelhead_idx], ~IS_CHANNELHEAD);
            }
            atomic_or(&mapping_array[idx],IS_THINCHANNEL);
            // If the current pixel has count less than our counter
            //   set the pixel count to equal our counter, increment it, & continue
            // If not, bail, because we've stepped onto a superior channel
            if (counter>=count_array[idx]) {
                atomic_xchg(&count_array[idx],counter);
            } else {
//                return;
            }
        } else {
            break;
        }
    }
    // We have just stepped onto a masked pixel, so let's tag the previous pixel
    //    as a channel tail
    if (!mask_array[prev_idx] && counter<1000u*MAX_N_STEPS) {
        atomic_or(&mapping_array[prev_idx],IS_CHANNELTAIL);
    } else {
#ifdef DEBUG
        printf(
         "Flagging downstream (%d mask=%d) - not marking tail - error?: @ %d->%d inc counter=%d vs count=%d redux\n",
                global_id,mask_array[idx],prev_idx,idx,counter,count_array[idx]);
#endif
    }
    return;
}
#endif

Logo

Streamlines

Topographic streamline mapping of landscape structure

Quick search

Related

    • connect.cl
    • essentials.cl
©2018, CPS. | Powered by Sphinx 1.8.3 & Alabaster 0.7.12 | Page source