Project: s41467-025-58586-9 | Function: find_drought_clusters (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Identifies spatially contiguous drought regions using Lagrangian tracking approach clustering algorithm

**KEY TERMS:** {
  "cluster_count": "number of events",
  "cluster_dictionary": "event characteristics",
  "linked_indices": "contiguous areas",
  "periodic_bool": "boundary conditions"
}

**CONTEXT CODE:**     # Calculate the cluster centroid depending on the type of cluster it was found to be
    if flag == "normal" or flag == "polar":

        # Find centroid coordinates
        centroid_lat = np.average(lats_array, weights=intensities)
        centroid_lon = np.average(lons_array, weights=intensities)

    elif flag == "wrapped" or flag == "wrapped_complex":

        # Minimum and maximum longitude of the matrix
        min_lon = np.min(lons)
        max_lon = np.max(lons)

        if flag == "wrapped":

            # Find all the zero instances
            idx_zeros = np.where(hist == 0)[0]

        elif flag == "wrapped_complex":

            # Find the latitude with the narrowest gap
            idx_lat = np.argmax(sum_hist)

            # Find all the zero instances for this latitude
            idx_zeros = np.where(hist2d[idx_lat, :] == 0)[0]

        # Longitude of the last zero
        idx_last_zero = idx_zeros[-1]
        lon_shift = lons[idx_last_zero]

        # Shift all longitudes in the cluster by this value
        lons_array_temp = np.array(lons_array[:])
        lons_array_temp[lons_array > lon_shift] = (
            lons_array_temp[lons_array > lon_shift] - lon_shift
        )
        lons_array_temp[lons_array <= lon_shift] = (
            lons_array_temp[lons_array <= lon_shift] + 360 - lon_shift
        )

        # Find centroid coordinates on new reference grid and shift back
        centroid_lat = np.average(lats_array, weights=intensities)
        centroid_lon_temp = np.average(lons_array_temp, weights=intensities)
        if centroid_lon_temp + lon_shift > max_lon:
            centroid_lon = centroid_lon_temp - 360 + lon_shift
        else:
            centroid_lon = centroid_lon_temp + lon_shift

    return centroid_lat, centroid_lon


def find_drought_clusters(
    data_matrix, lons, lats, resolution_lon, resolution_lat, periodic_bool
):
    """
    Identifies spatially contiguous drought regions using Lagrangian tracking approach clustering algorithm.

    This function identifies individual drought clusters for a given time step using a sophisticated spatial
    clustering algorithm. Drought clusters are defined as spatially contiguous areas under drought conditions.
    The algorithm implements Lagrangian tracking approach for clustering spatiotemporally contiguous events,
    which is fundamental to understanding climate extreme event dynamics and transboundary migration patterns.

    Args:
        data_matrix: 2D matrix for a given time step with the non-drought pixels filtered out
        lons: 1D array of longitudes in degrees for the data_matrix (-180,180)
        lats: 1D array of latitudes in degrees for the data_matrix
        resolution_lon: Resolution of the dataset in the longitudinal direction (e.g. 0.5 degrees)
        resolution_lat: Resolution of the dataset in the latitudinal direction (e.g. 0.5 degrees)
        periodic_bool: Boolean for treating left/right edges as periodic (global vs regional)

    Returns:
        cluster_count: Number of drought clusters above the area threshold identified
        cluster_dictionary: Dictionary containing characteristics of each drought cluster

    Paper reference: "clustering them by a Lagrangian tracking approach...spatiotemporally contiguous heatwave events"

    Formula: spatiotemporally contiguous events clustering
    Implementation: Nested loops, conditional branching, graph traversal, and data structure management
                   for spatial connectivity analysis and cluster characterization
    """
    # MASKED: Lagrangian tracking clustering algorithm for drought event identification
    raise NotImplementedError("This function is masked for testing purposes. The function identifies spatially contiguous drought regions using Lagrangian tracking approach clustering algorithm, implementing sophisticated spatial clustering for spatiotemporally contiguous events analysis and transboundary migration pattern understanding.")


def cluster_in_Sahara(centroid_lon, centroid_lat):
    """
    This function determines whether the current drought cluster centroid falls within the Sahara desert
    during the current time step.

    Argument:
    - centroid_lat: Latitude in degrees of the cluster centroid.
    - centroid_lon: Longitude in degrees of the cluster centroid.

    Returns:
    - Boolean variable False if the centroid does not fall in the Sahara desert and True otherwise.
    """

    if (
        centroid_lat >= 20
        and centroid_lat <= 25
        and centroid_lon >= -17
        and centroid_lon <= 34
    ):
        return True
    else:
        return False


def filter_drought_clusters(
    data_matrix, cluster_count, cluster_dictionary, area_threshold
):
    """
    This function will take in all the drought clusters and remove those that are smaller
    than the given area threshold. If a drought cluster does not meet the critertion
    then they will be deleted from the drought field. Drought clusters whose centroids fall within
    the Sahara desert are also removed. This function works using the dictionary created by the
    find_drought_clusters function.

    Argument:
    - data_matrix: 2D matrix for a given time step with the non-drought pixels filtered out.
    - cluster_count: Number of drought clusters above the area threshold identified for the current
                     time step.
    - cluster_dictionary: Dictionary containing the characteritics of each drought cluster identified
                          in this current time step.
    - area_threshold: Minimum area threshold (km^2) for the drought clusters. Any clusters that are
                      smaller than this threshold will not be included.

    Return:
    - data_matrix: Updated input data matrix where the gridcells belonging to small clusters have been
                   filtered out.
    - filtered_cluster_count: Updated count of drought clusters in the current time step (having removed
                              small drought clusters).
    - filtered_cluster_dictionary: Updated dictionary of clusters and their characteristics for the current
                                   time step.
    """

    # Initiate new dictionary where filtered results will be stored
    filtered_cluster_dictionary = {}

    # Initialize count of clusters that meet the area criterion
    filtered_cluster_count = 0

    # Check every cluster
    for i in range(1, cluster_count + 1):

        # Cluster area and centroid
        cluster_area = cluster_dictionary[i]["area"]
        centroid_lon, centroid_lat = cluster_dictionary[i]["centroid"]

        # Check whether cluster is in the Sahara Desert
        in_sahara = cluster_in_Sahara(centroid_lon, centroid_lat)


Complete the function implementation replacing "raise NotImplementedError".