code: def peak_directions_nl(
      sphere_eval,
      relative_peak_threshold=0.25,
      min_separation_angle=25,
      sphere=default_sphere,
      xtol=1e-7,
  ):
      """Non Linear Direction Finder.
  
      Parameters
      ----------
      sphere_eval : callable
          A function which can be evaluated on a sphere.
      relative_peak_threshold : float
          Only return peaks greater than ``relative_peak_threshold * m`` where m
          is the largest peak.
      min_separation_angle : float in [0, 90]
          The minimum distance between directions. If two peaks are too close
          only the larger of the two is returned.
      sphere : Sphere
          A discrete Sphere. The points on the sphere will be used for initial
          estimate of maximums.
      xtol : float
          Relative tolerance for optimization.
  
      Returns
      -------
      directions : array (N, 3)
          Points on the sphere corresponding to N local maxima on the sphere.
      values : array (N,)
          Value of sphere_eval at each point on directions.
  
      """
      # Find discrete peaks for use as seeds in non-linear search
      discrete_values = sphere_eval(sphere)
      values, indices = local_maxima(discrete_values, sphere.edges)
  
      seeds = np.column_stack(
          [sphere.theta[indices], sphere.phi[indices]]
      )
  
      # Helper function
      def _helper(x):
          sphere = Sphere(theta=x[0], phi=x[1])
          return -sphere_eval(sphere)
  
      # Non-linear search
      num_seeds = len(seeds)
      theta = np.empty(num_seeds)
      phi = np.empty(num_seeds)
      for i in range(num_seeds):
          peak = opt.fmin(_helper, seeds[i], xtol=xtol, disp=False)
          theta[i], phi[i] = peak
  
      # Evaluate on new-found peaks
      small_sphere = Sphere(theta=theta, phi=phi)
      values = sphere_eval(small_sphere)
  
      # Sort in descending order
      order = values.argsort()[::-1]
      values = values[order]
      directions = small_sphere.vertices[order]
  
      # Remove directions that are too small
      n = search_descending(values, relative_peak_threshold)
      directions = directions[:n]
  
      # Remove peaks too close to each-other
      directions, idx = remove_similar_vertices(
          directions, min_separation_angle, return_index=True
      )
      values = values[idx]
      return directions, values
  
imports: import tempfile
  from multiprocessing import Pool
  from itertools import repeat
  from os import path
  import numpy
  import scipy.optimize
  from dipy.reconst.odf import gfa
  from dipy.reconst.recspeed import local_maxima, remove_similar_vertices, search_descending
  from dipy.core.sphere import Sphere
  from dipy.data import default_sphere
  from dipy.core.ndindex import ndindex
  from dipy.reconst.shm import sh_to_sf_matrix
  from dipy.reconst.eudx_direction_getter import EuDXDirectionGetter
  from dipy.utils.multiproc import determine_num_processes
  from dipy.utils.deprecator import deprecated_params
label_desc: Use image node_id 1 for calling a global function with example usage: peak_directions_nl(sphere_eval, relative_peak_threshold, min_separation_angle, sphere, xtol) and returns: directions,  values, unknown