code: def test_sf_to_sh():
      # Subdividing a hemi_icosahedron twice produces 81 unique points, which
      # is more than enough to fit a order 8 (45 coefficients) spherical harmonic
      hemisphere = hemi_icosahedron.subdivide(2)
      mevals = np.array(
          [[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]]
      )
      angles = [(0, 0), (60, 0)]
      odf = multi_tensor_odf(
          hemisphere.vertices, mevals, angles, [50, 50]
      )
  
      # 1D case with the 2 symmetric bases functions
      # Tournier basis
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=tournier07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf_sh = sf_to_sh(odf, hemisphere, 8, "tournier07")
          odf_reconst = sh_to_sf(odf_sh, hemisphere, 8, "tournier07")
  
      assert_array_almost_equal(odf, odf_reconst, 2)
  
      # Legacy definition
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=tournier07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf_sh = sf_to_sh(
              odf, hemisphere, 8, "tournier07", legacy=True
          )
          odf_reconst = sh_to_sf(
              odf_sh, hemisphere, 8, "tournier07", legacy=True
          )
  
      assert_array_almost_equal(odf, odf_reconst, 2)
  
      # Descoteaux basis
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=descoteaux07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf_sh = sf_to_sh(odf, hemisphere, 8, "descoteaux07")
          odf_reconst = sh_to_sf(odf_sh, hemisphere, 8, "descoteaux07")
  
      assert_array_almost_equal(odf, odf_reconst, 2)
  
      # Legacy definition
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=descoteaux07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf_sh = sf_to_sh(
              odf, hemisphere, 8, "descoteaux07", legacy=True
          )
          odf_reconst = sh_to_sf(
              odf_sh, hemisphere, 8, "descoteaux07", legacy=True
          )
  
      assert_array_almost_equal(odf, odf_reconst, 2)
  
      # We now create an asymmetric signal
      # to try out our full SH basis
      mevals = np.array([[0.0015, 0.0003, 0.0003]])
      angles = [(0, 0)]
      odf2 = multi_tensor_odf(
          hemisphere.vertices, mevals, angles, [100]
      )
  
      # We simulate our asymmetric signal by using a different ODF
      # per hemisphere. The sphere used is a concatenation of the
      # vertices of our hemisphere, for a total of 162 vertices.
      sphere = Sphere(
          xyz=np.vstack((hemisphere.vertices, -hemisphere.vertices))
      )
      asym_odf = np.append(odf, odf2)
  
      # Try out full bases with order 10 (121 coefficients)
      # Tournier basis
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=tournier07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf_sh = sf_to_sh(
              asym_odf, sphere, 10, "tournier07", full_basis=True
          )
          odf_reconst = sh_to_sf(
              odf_sh, sphere, 10, "tournier07", full_basis=True
          )
  
      assert_array_almost_equal(odf_reconst, asym_odf, 2)
  
      # Legacy definition
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=tournier07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf_sh = sf_to_sh(
              asym_odf,
              sphere,
              10,
              "tournier07",
              full_basis=True,
              legacy=True,
          )
          odf_reconst = sh_to_sf(
              odf_sh,
              sphere,
              10,
              "tournier07",
              full_basis=True,
              legacy=True,
          )
  
      assert_array_almost_equal(odf_reconst, asym_odf, 2)
  
      # Descoteaux basis
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=descoteaux07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf_sh = sf_to_sh(
              asym_odf, sphere, 10, "descoteaux07", full_basis=True
          )
          odf_reconst = sh_to_sf(
              odf_sh, sphere, 10, "descoteaux07", full_basis=True
          )
  
      assert_array_almost_equal(odf_reconst, asym_odf, 2)
  
      # Legacy definition
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=descoteaux07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf_sh = sf_to_sh(
              asym_odf,
              sphere,
              10,
              "descoteaux07",
              full_basis=True,
              legacy=True,
          )
          odf_reconst = sh_to_sf(
              odf_sh,
              sphere,
              10,
              "descoteaux07",
              full_basis=True,
              legacy=True,
          )
  
      assert_array_almost_equal(odf_reconst, asym_odf, 2)
  
      # An invalid basis name should raise an error
      assert_raises(
          ValueError, sh_to_sf, odf, hemisphere, basis_type=""
      )
      assert_raises(
          ValueError, sf_to_sh, odf_sh, hemisphere, basis_type=""
      )
  
      # 2D case
      odf2d = np.vstack((odf, odf))
  
      with warnings.catch_warnings():
          warnings.filterwarnings(
              "ignore",
              message=descoteaux07_legacy_msg,
              category=PendingDeprecationWarning,
          )
  
          odf2d_sh = sf_to_sh(odf2d, hemisphere, 8)
          odf2d_sf = sh_to_sf(odf2d_sh, hemisphere, 8)
  
      assert_array_almost_equal(odf2d, odf2d_sf, 2)
  
imports: import warnings
  import numpy
  import numpy.linalg
  import numpy.testing
  from dipy.testing import assert_true
  from numpy.testing import assert_array_equal, assert_array_almost_equal, assert_equal, assert_raises
  from scipy.special import sph_harm
  from dipy.core.sphere import hemi_icosahedron, Sphere
  from dipy.core.gradients import gradient_table
  from dipy.core.interpolation import NearestNeighborInterpolator
  from dipy.sims.voxel import single_tensor
  from dipy.direction.peaks import peak_directions
  from dipy.reconst.shm import sf_to_sh, sh_to_sf
  from dipy.sims.voxel import multi_tensor_odf
  from dipy.data import mrtrix_spherical_functions
  from dipy.reconst import odf
  from dipy.reconst.shm import real_sh_descoteaux_from_index, real_sym_sh_basis, real_sym_sh_mrtrix, real_sh_descoteaux, real_sh_tournier, sph_harm_ind_list, order_from_ncoef, OpdtModel, normalize_data, hat, lcr_matrix, smooth_pinv, bootstrap_data_array, bootstrap_data_voxel, ResidualBootstrapWrapper, CsaOdfModel, QballModel, SphHarmFit, spherical_harmonics, anisotropic_power, calculate_max_order, sh_to_sf_matrix, gen_dirac, convert_sh_to_full_basis, convert_sh_from_legacy, convert_sh_to_legacy, convert_sh_descoteaux_tournier, descoteaux07_legacy_msg, tournier07_legacy_msg
label_desc: Use image node_id 18 for calling a global function with example usage: test_sf_to_sh() without return types