def row_decomposition(in_array, num_chunks, ghost_zone_size):
    """
    Parameters:
    -----------
    in_array: np.ndarray
        the input array. should have shape (bands, rows, columns)
    num_chunks: int
        the number of chunks to split the data into.
    ghost_zone_size: int
        in the case of focal map algebra computations, the ghost_zone_size
        indicates the number of additional rows to append to each chunk to
        ensure the focal operations are computed accurately (i.e. so that
        each computation receives it's neighbors for accurate and complete
        calculations). This should be in number of pixels.

    NOTE: there is the potential of copying a large amount of redundant data
    between data chunks if the num_chunks is not chosen carefully. It should
    be chosen with the size of the input array in mind.

    Returns:
    ---------
    chunks: nested list
        holds information about the bounds of the data chunks that will be processed
        start_row_idx and end_row_idx are indices that indicate the topmost and bottommost
        rows for processing features. These indices also take into account the buffer needed
        for computing multiscale features
        [[dataid, start_row_idx, end_row_idx], [dataid, start_row_idx, end_row_idx]]
    """

    # 1. first get the number of rows in the interior (total rows - buffer pixels for multiscale computations)
    # 2. ensure that the number of interior rows is divisible by the block size
    # 3. if not 
    #
    tot_rows = in_array.shape[1]
    tot_cols = in_array.shape[2]
    rows_in_interior = tot_rows - ghost_zone_size*2

    chunk_size = rows_in_interior // num_chunks
    remaining = rows_in_interior % num_chunks

    start_idx = 0
    end_idx = 0
    chunk_id = 0
    chunks = []
    while end_idx < tot_rows:
        end_idx = start_idx+chunk_size+(ghost_zone_size*2)
        if remaining > 0:
            end_idx += 1
            remaining -= 1

        #chunks.append([chunk_id,in_array[:,start_idx:end_idx,:]])
        chunks.append([chunk_id, start_idx, end_idx]) # don't actually need the data, just the location for slices
        chunk_id+=1
        start_idx = (end_idx)-(ghost_zone_size*2)
    return chunks