calculate local indices, return start and stop index per dimension per process for local data field

    :param shape: global shape of data
    :param num_partitions: number of partition for each dimension (from MPI.Compute_dims())
    :param coordinate: cartesian coordinate descriptor (from CARTESIAN_COMMUNICATOR.Get_coords(rank))

    :return: tuple of start/stop index per dimension ((start_x, stop_x), (start_y, stop_y), ...)

def calc_local_indices(shape, num_partitions, coordinate):
    """ calculate local indices, return start and stop index per dimension per process for local data field

    :param shape: global shape of data
    :param num_partitions: number of partition for each dimension (from MPI.Compute_dims())
    :param coordinate: cartesian coordinate descriptor (from CARTESIAN_COMMUNICATOR.Get_coords(rank))

    :return: tuple of start/stop index per dimension ((start_x, stop_x), (start_y, stop_y), ...)
    """
    dimension = len(shape)
    # check matching of cartesian communicator and shape
    assert dimension == len(num_partitions)

    decomposed_shapes = []
    # build shape list for every dimension
    for idx in range(dimension):
        local_shape = shape[idx] // num_partitions[idx]
        temp_shape_list = []

        for _ in range(num_partitions[idx]):
            temp_shape_list.append(local_shape)

        # expand local partitions to match global shape
        for j in range(shape[idx] % num_partitions[idx]):
            temp_shape_list[j] += 1

        # decomposed_shapes[dimension][partition]
        decomposed_shapes.append(temp_shape_list)

    # calculate indices for partitions
    indices = []

    # TODO: redefine calculation -> first select and calculate
    for i in range(dimension):

        temp_index_list = []

        start_idx = 0
        end_idx = 0

        for j in range(num_partitions[i]):

            end_idx = end_idx + decomposed_shapes[i][j]
            temp_index_list.append([start_idx, end_idx])
            start_idx = end_idx

        indices.append(temp_index_list)

    start_index = []
    stop_index = []
    shape = []

    # select partition, start and stop index
    for idx in range(dimension):
        start_index.append(indices[idx][coordinate[idx]][0])
        stop_index.append(indices[idx][coordinate[idx]][1])
        shape.append(decomposed_shapes[idx][coordinate[idx]])

    shape = tuple(shape)
    start_index = tuple(start_index)
    stop_index = tuple(stop_index)
    return start_index, stop_index, shape