code: def fwdti_prediction(params, gtab, S0=1, Diso=3.0e-3):
      r"""Signal prediction given the free water DTI model parameters.
  
      Parameters
      ----------
      params : (..., 13) ndarray
          Model parameters. The last dimension should have the 12 tensor
          parameters (3 eigenvalues, followed by the 3 corresponding
          eigenvectors) and the volume fraction of the free water compartment.
      gtab : a GradientTable class instance
          The gradient table for this prediction
      S0 : float or ndarray
          The non diffusion-weighted signal in every voxel, or across all
          voxels. Default: 1
      Diso : float, optional
          Value of the free water isotropic diffusion. Default is set to 3e-3
          $mm^{2}.s^{-1}$. Please adjust this value if you are assuming different
          units of diffusion.
  
      Returns
      -------
      S : (..., N) ndarray
          Simulated signal based on the free water DTI model
  
      Notes
      -----
      The predicted signal is given by:
      $S(\theta, b) = S_0 * [(1-f) * e^{-b ADC} + f * e^{-b D_{iso}]$, where
      $ADC = \theta Q \theta^T$, $\theta$ is a unit vector pointing at any
      direction on the sphere for which a signal is to be predicted, $b$ is the b
      value provided in the GradientTable input for that direction, $Q$ is the
      quadratic form of the tensor determined by the input parameters, $f$ is the
      free water diffusion compartment, $D_{iso}$ is the free water diffusivity
      which is equal to $3 * 10^{-3} mm^{2}s^{-1} [1]_.
  
      References
      ----------
      .. [1] Henriques, R.N., Rokem, A., Garyfallidis, E., St-Jean, S.,
             Peterson E.T., Correia, M.M., 2017. [Re] Optimization of a free
             water elimination two-compartment model for diffusion tensor
             imaging. ReScience volume 3, issue 1, article number 2
      """
      evals = params[..., :3]
      evecs = params[..., 3:-1].reshape(params.shape[:-1] + (3, 3))
      f = params[..., 12]
      qform = vec_val_vect(evecs, evals)
      lower_dt = lower_triangular(qform, S0)
      lower_diso = lower_dt.copy()
      lower_diso[..., 0] = lower_diso[..., 2] = lower_diso[
          ..., 5
      ] = Diso
      lower_diso[..., 1] = lower_diso[..., 3] = lower_diso[..., 4] = 0
      D = design_matrix(gtab)
  
      pred_sig = np.zeros(f.shape + (gtab.bvals.shape[0],))
      mask = _positive_evals(
          evals[..., 0], evals[..., 1], evals[..., 2]
      )
      index = ndindex(f.shape)
      for v in index:
          if mask[v]:
              pred_sig[v] = (1 - f[v]) * np.exp(
                  np.dot(lower_dt[v], D.T)
              ) + f[v] * np.exp(np.dot(lower_diso[v], D.T))
  
      return pred_sig
  
imports: import warnings
  import numpy
  import scipy.optimize
  from dipy.reconst.base import ReconstModel
  from dipy.reconst.dti import TensorFit, design_matrix, decompose_tensor, _decompose_tensor_nan, from_lower_triangular, lower_triangular
  from dipy.reconst.dki import _positive_evals
  from dipy.reconst.vec_val_sum import vec_val_vect
  from dipy.core.ndindex import ndindex
  from dipy.core.gradients import check_multi_b
  from dipy.reconst.multi_voxel import multi_voxel_fit
label_desc: Use image node_id 1 for calling a global function with example usage: fwdti_prediction(params, gtab, S0, Diso) and returns: pred_sig