def _estimate_convol_params(
    field_src,
    field_dst,
    weights,
    mask,
    kernel_type="anisotropic",
    kernel_params=None,
    num_workers=1,
):
    """Estimation of convolution kernel."""
    if kernel_params is None:
        kernel_params = {}
    masks = []
    for weight in weights:
        masks.append(np.logical_and(mask, weight > 1e-3))

    def objf_aniso(p, *args):
        i = args[0]
        p = _get_anisotropic_kernel_params(p)
        kernel = _compute_kernel_anisotropic(p, **kernel_params)

        field_src_c = _masked_convolution(field_src, kernel)
        fval = np.sqrt(weights[i][masks[i]]) * (
            field_dst[masks[i]] - field_src_c[masks[i]]
        )

        return fval

    def objf_iso(p, *args):
        i = args[0]
        kernel = _compute_kernel_isotropic(p, **kernel_params)

        field_src_c = _masked_convolution(field_src, kernel)
        fval = np.sum(
            weights[i][masks[i]] * (field_dst[masks[i]] - field_src_c[masks[i]]) ** 2
        )

        return fval

    def worker(i):
        if kernel_type == "anisotropic":
            bounds = ((-np.inf, 0.1, 0.2), (np.inf, 10.0, 5.0))
            p_opt = opt.least_squares(
                objf_aniso,
                np.array((0.0, 1.0, 1.0)),
                bounds=bounds,
                method="trf",
                ftol=1e-6,
                xtol=1e-4,
                gtol=1e-6,
                args=(i,),
            )
            p_opt = _get_anisotropic_kernel_params(p_opt.x)

            return _compute_kernel_anisotropic(p_opt, **kernel_params)
        else:
            p_opt = opt.minimize_scalar(
                objf_iso, bounds=[0.01, 10.0], method="bounded", args=(i,)
            )
            p_opt = p_opt.x

            return _compute_kernel_isotropic(p_opt, **kernel_params)

    if DASK_IMPORTED and num_workers > 1:
        res = []
        for i in range(len(weights)):
            res.append(dask.delayed(worker)(i))
        kernels = dask.compute(*res, num_workers=num_workers, scheduler="threads")
    else:
        kernels = []
        for i in range(len(weights)):
            kernels.append(worker(i))

    return kernels
Estimation of convolution kernel.
pysteps/nowcasts/linda.py