# This file was auto generated by Styx.
# Do not edit this file directly.

import typing
import pathlib
from styxdefs import *

METRIC_EXTREMA_METADATA = Metadata(
    id="a62651df948001aa8493b5d383ecb5de960f26cc.boutiques",
    name="metric-extrema",
    package="workbench",
    container_image_tag="brainlife/connectome_workbench:1.5.0-freesurfer-update",
)


MetricExtremaPresmoothParameters = typing.TypedDict('MetricExtremaPresmoothParameters', {
    "@type": typing.NotRequired[typing.Literal["presmooth"]],
    "kernel": float,
    "opt_fwhm": bool,
})
MetricExtremaPresmoothParametersTagged = typing.TypedDict('MetricExtremaPresmoothParametersTagged', {
    "@type": typing.Literal["presmooth"],
    "kernel": float,
    "opt_fwhm": bool,
})


MetricExtremaThresholdParameters = typing.TypedDict('MetricExtremaThresholdParameters', {
    "@type": typing.NotRequired[typing.Literal["threshold"]],
    "low": float,
    "high": float,
})
MetricExtremaThresholdParametersTagged = typing.TypedDict('MetricExtremaThresholdParametersTagged', {
    "@type": typing.Literal["threshold"],
    "low": float,
    "high": float,
})


MetricExtremaParameters = typing.TypedDict('MetricExtremaParameters', {
    "@type": typing.NotRequired[typing.Literal["workbench/metric-extrema"]],
    "surface": InputPathType,
    "metric_in": InputPathType,
    "distance": float,
    "metric_out": str,
    "presmooth": typing.NotRequired[MetricExtremaPresmoothParameters | None],
    "opt_roi_roi_metric": typing.NotRequired[InputPathType | None],
    "threshold": typing.NotRequired[MetricExtremaThresholdParameters | None],
    "opt_sum_columns": bool,
    "opt_consolidate_mode": bool,
    "opt_only_maxima": bool,
    "opt_only_minima": bool,
    "opt_column_column": typing.NotRequired[str | None],
})
MetricExtremaParametersTagged = typing.TypedDict('MetricExtremaParametersTagged', {
    "@type": typing.Literal["workbench/metric-extrema"],
    "surface": InputPathType,
    "metric_in": InputPathType,
    "distance": float,
    "metric_out": str,
    "presmooth": typing.NotRequired[MetricExtremaPresmoothParameters | None],
    "opt_roi_roi_metric": typing.NotRequired[InputPathType | None],
    "threshold": typing.NotRequired[MetricExtremaThresholdParameters | None],
    "opt_sum_columns": bool,
    "opt_consolidate_mode": bool,
    "opt_only_maxima": bool,
    "opt_only_minima": bool,
    "opt_column_column": typing.NotRequired[str | None],
})


def metric_extrema_presmooth_params(
    kernel: float,
    opt_fwhm: bool = False,
) -> MetricExtremaPresmoothParametersTagged:
    """
    Build parameters.
    
    Args:
        kernel: the size of the gaussian smoothing kernel in mm, as sigma by\
            default.
        opt_fwhm: kernel size is FWHM, not sigma.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "presmooth",
        "kernel": kernel,
        "opt_fwhm": opt_fwhm,
    }
    return params


def metric_extrema_presmooth_cargs(
    params: MetricExtremaPresmoothParameters,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.append("-presmooth")
    cargs.append(str(params.get("kernel", None)))
    if params.get("opt_fwhm", False):
        cargs.append("-fwhm")
    return cargs


def metric_extrema_threshold_params(
    low: float,
    high: float,
) -> MetricExtremaThresholdParametersTagged:
    """
    Build parameters.
    
    Args:
        low: the largest value to consider for being a minimum.
        high: the smallest value to consider for being a maximum.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "threshold",
        "low": low,
        "high": high,
    }
    return params


def metric_extrema_threshold_cargs(
    params: MetricExtremaThresholdParameters,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.append("-threshold")
    cargs.append(str(params.get("low", None)))
    cargs.append(str(params.get("high", None)))
    return cargs


class MetricExtremaOutputs(typing.NamedTuple):
    """
    Output object returned when calling `MetricExtremaParameters(...)`.
    """
    root: OutputPathType
    """Output root folder. This is the root folder for all outputs."""
    metric_out: OutputPathType
    """the output extrema metric"""


def metric_extrema_params(
    surface: InputPathType,
    metric_in: InputPathType,
    distance: float,
    metric_out: str,
    presmooth: MetricExtremaPresmoothParameters | None = None,
    opt_roi_roi_metric: InputPathType | None = None,
    threshold: MetricExtremaThresholdParameters | None = None,
    opt_sum_columns: bool = False,
    opt_consolidate_mode: bool = False,
    opt_only_maxima: bool = False,
    opt_only_minima: bool = False,
    opt_column_column: str | None = None,
) -> MetricExtremaParametersTagged:
    """
    Build parameters.
    
    Args:
        surface: the surface to use for distance information.
        metric_in: the metric to find the extrema of.
        distance: the minimum distance between identified extrema of the same\
            type.
        metric_out: the output extrema metric.
        presmooth: smooth the metric before finding extrema.
        opt_roi_roi_metric: ignore values outside the selected area: the area\
            to find extrema in, as a metric.
        threshold: ignore small extrema.
        opt_sum_columns: output the sum of the extrema columns instead of each\
            column separately.
        opt_consolidate_mode: use consolidation of local minima instead of a\
            large neighborhood.
        opt_only_maxima: only find the maxima.
        opt_only_minima: only find the minima.
        opt_column_column: select a single column to find extrema in: the\
            column number or name.
    Returns:
        Parameter dictionary
    """
    params = {
        "@type": "workbench/metric-extrema",
        "surface": surface,
        "metric_in": metric_in,
        "distance": distance,
        "metric_out": metric_out,
        "opt_sum_columns": opt_sum_columns,
        "opt_consolidate_mode": opt_consolidate_mode,
        "opt_only_maxima": opt_only_maxima,
        "opt_only_minima": opt_only_minima,
    }
    if presmooth is not None:
        params["presmooth"] = presmooth
    if opt_roi_roi_metric is not None:
        params["opt_roi_roi_metric"] = opt_roi_roi_metric
    if threshold is not None:
        params["threshold"] = threshold
    if opt_column_column is not None:
        params["opt_column_column"] = opt_column_column
    return params


def metric_extrema_cargs(
    params: MetricExtremaParameters,
    execution: Execution,
) -> list[str]:
    """
    Build command-line arguments from parameters.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Command-line arguments.
    """
    cargs = []
    cargs.append("wb_command")
    cargs.append("-metric-extrema")
    cargs.append(execution.input_file(params.get("surface", None)))
    cargs.append(execution.input_file(params.get("metric_in", None)))
    cargs.append(str(params.get("distance", None)))
    cargs.append(params.get("metric_out", None))
    if params.get("presmooth", None) is not None:
        cargs.extend(metric_extrema_presmooth_cargs(params.get("presmooth", None), execution))
    if params.get("opt_roi_roi_metric", None) is not None:
        cargs.extend([
            "-roi",
            execution.input_file(params.get("opt_roi_roi_metric", None))
        ])
    if params.get("threshold", None) is not None:
        cargs.extend(metric_extrema_threshold_cargs(params.get("threshold", None), execution))
    if params.get("opt_sum_columns", False):
        cargs.append("-sum-columns")
    if params.get("opt_consolidate_mode", False):
        cargs.append("-consolidate-mode")
    if params.get("opt_only_maxima", False):
        cargs.append("-only-maxima")
    if params.get("opt_only_minima", False):
        cargs.append("-only-minima")
    if params.get("opt_column_column", None) is not None:
        cargs.extend([
            "-column",
            params.get("opt_column_column", None)
        ])
    return cargs


def metric_extrema_outputs(
    params: MetricExtremaParameters,
    execution: Execution,
) -> MetricExtremaOutputs:
    """
    Build outputs object containing output file paths and possibly stdout/stderr.
    
    Args:
        params: The parameters.
        execution: The execution object for resolving input paths.
    Returns:
        Outputs object.
    """
    ret = MetricExtremaOutputs(
        root=execution.output_file("."),
        metric_out=execution.output_file(params.get("metric_out", None)),
    )
    return ret


def metric_extrema_execute(
    params: MetricExtremaParameters,
    runner: Runner | None = None,
) -> MetricExtremaOutputs:
    """
    metric-extrema
    
    Find extrema in a metric file.
    
    Finds extrema in a metric file, such that no two extrema of the same type
    are within <distance> of each other. The extrema are labeled as -1 for
    minima, 1 for maxima, 0 otherwise. If -only-maxima or -only-minima is
    specified, then it will ignore extrema not of the specified type. These
    options are mutually exclusive.
    
    If -roi is specified, not only is data outside the roi not used, but any
    vertex on the edge of the ROI will never be counted as an extrema, in case
    the ROI cuts across a gradient, which would otherwise generate extrema where
    there should be none.
    
    If -sum-columns is specified, these extrema columns are summed, and the
    output has a single column with this result.
    
    By default, a datapoint is an extrema only if it is more extreme than every
    other datapoint that is within <distance> from it. If -consolidate-mode is
    used, it instead starts by finding all datapoints that are more extreme than
    their immediate neighbors, then while there are any extrema within
    <distance> of each other, take the two extrema closest to each other and
    merge them into one by a weighted average based on how many original extrema
    have been merged into each.
    
    By default, all input columns are used with no smoothing, use -column to
    specify a single column to use, and -presmooth to smooth the input before
    finding the extrema.
    
    Author: Connectome Workbench Developers
    
    URL: https://github.com/Washington-University/workbench
    
    Args:
        params: The parameters.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `MetricExtremaOutputs`).
    """
    runner = runner or get_global_runner()
    execution = runner.start_execution(METRIC_EXTREMA_METADATA)
    params = execution.params(params)
    cargs = metric_extrema_cargs(params, execution)
    ret = metric_extrema_outputs(params, execution)
    execution.run(cargs)
    return ret


def metric_extrema(
    surface: InputPathType,
    metric_in: InputPathType,
    distance: float,
    metric_out: str,
    presmooth: MetricExtremaPresmoothParameters | None = None,
    opt_roi_roi_metric: InputPathType | None = None,
    threshold: MetricExtremaThresholdParameters | None = None,
    opt_sum_columns: bool = False,
    opt_consolidate_mode: bool = False,
    opt_only_maxima: bool = False,
    opt_only_minima: bool = False,
    opt_column_column: str | None = None,
    runner: Runner | None = None,
) -> MetricExtremaOutputs:
    """
    metric-extrema
    
    Find extrema in a metric file.
    
    Finds extrema in a metric file, such that no two extrema of the same type
    are within <distance> of each other. The extrema are labeled as -1 for
    minima, 1 for maxima, 0 otherwise. If -only-maxima or -only-minima is
    specified, then it will ignore extrema not of the specified type. These
    options are mutually exclusive.
    
    If -roi is specified, not only is data outside the roi not used, but any
    vertex on the edge of the ROI will never be counted as an extrema, in case
    the ROI cuts across a gradient, which would otherwise generate extrema where
    there should be none.
    
    If -sum-columns is specified, these extrema columns are summed, and the
    output has a single column with this result.
    
    By default, a datapoint is an extrema only if it is more extreme than every
    other datapoint that is within <distance> from it. If -consolidate-mode is
    used, it instead starts by finding all datapoints that are more extreme than
    their immediate neighbors, then while there are any extrema within
    <distance> of each other, take the two extrema closest to each other and
    merge them into one by a weighted average based on how many original extrema
    have been merged into each.
    
    By default, all input columns are used with no smoothing, use -column to
    specify a single column to use, and -presmooth to smooth the input before
    finding the extrema.
    
    Author: Connectome Workbench Developers
    
    URL: https://github.com/Washington-University/workbench
    
    Args:
        surface: the surface to use for distance information.
        metric_in: the metric to find the extrema of.
        distance: the minimum distance between identified extrema of the same\
            type.
        metric_out: the output extrema metric.
        presmooth: smooth the metric before finding extrema.
        opt_roi_roi_metric: ignore values outside the selected area: the area\
            to find extrema in, as a metric.
        threshold: ignore small extrema.
        opt_sum_columns: output the sum of the extrema columns instead of each\
            column separately.
        opt_consolidate_mode: use consolidation of local minima instead of a\
            large neighborhood.
        opt_only_maxima: only find the maxima.
        opt_only_minima: only find the minima.
        opt_column_column: select a single column to find extrema in: the\
            column number or name.
        runner: Command runner.
    Returns:
        NamedTuple of outputs (described in `MetricExtremaOutputs`).
    """
    params = metric_extrema_params(
        surface=surface,
        metric_in=metric_in,
        distance=distance,
        metric_out=metric_out,
        presmooth=presmooth,
        opt_roi_roi_metric=opt_roi_roi_metric,
        threshold=threshold,
        opt_sum_columns=opt_sum_columns,
        opt_consolidate_mode=opt_consolidate_mode,
        opt_only_maxima=opt_only_maxima,
        opt_only_minima=opt_only_minima,
        opt_column_column=opt_column_column,
    )
    return metric_extrema_execute(params, runner)


__all__ = [
    "METRIC_EXTREMA_METADATA",
    "MetricExtremaOutputs",
    "metric_extrema",
    "metric_extrema_execute",
    "metric_extrema_params",
    "metric_extrema_presmooth_params",
    "metric_extrema_threshold_params",
]
