code: def _sdpdc_fit(data, mask, X, cvxpy_solver):
      """Estimate the model parameters using Semidefinite Programming (SDP),
      while enforcing positivity constraints on the D and C tensors (SDPdc) [2]_
  
      Parameters
      ----------
      data : numpy.ndarray
          Array of shape (..., number of acquisitions).
      mask : numpy.ndarray
          Array with the same shape as the data array of a single acquisition.
      X : numpy.ndarray
          Design matrix of shape (number of acquisitions, 28).
      cvxpy_solver: string, required
          The name of the SDP solver to be used. Default: 'SCS'
  
      Returns
      -------
      params : numpy.ndarray
          Array of shape (..., 28) containing the estimated model parameters.
          Element 0 is the natural logarithm of the estimated signal without
          diffusion-weighting, elements 1-6 are the estimated diffusion tensor
          elements in Voigt notation, and elements 7-27 are the estimated
          covariance tensor elements in Voigt notation.
  
      References
      ----------
      .. [2] Herberthson M., Boito D., Dela Haije T., Feragen A., Westin C.-F.,
          Ozarslan E., "Q-space trajectory imaging with positivity constraints
          (QTI+)" in Neuroimage, Volume 238, 2021.
      """
  
      if not have_cvxpy:
          raise ImportError(
              "CVXPY package needed to enforce constraints"
          )
  
      if cvxpy_solver not in cp.installed_solvers():
          raise ValueError("The selected solver is not available")
  
      params = np.zeros((np.prod(mask.shape), 28)) * np.nan
      data_masked = data[mask]
      size, nvols = data_masked.shape
      scale = np.maximum(np.max(data_masked, axis=1, keepdims=True), 1)
      data_masked = data_masked / scale
      data_masked[data_masked < 0] = 0
      log_data = np.log(data_masked)
      params_masked = np.zeros((size, 28))
  
      x = cp.Variable((28, 1))
      y = cp.Parameter((nvols, 1))
      A = cp.Parameter((nvols, 28))
      dc = cvxpy_1x6_to_3x3(x[1:7])
      cc = cvxpy_1x21_to_6x6(x[7:])
      constraints = [dc >> 0, cc >> 0]
      objective = cp.Minimize(cp.norm(A @ x - y))
      prob = cp.Problem(objective, constraints)
      unconstrained = cp.Problem(objective)
  
      for i in range(0, size, 1):
          vox_data = data_masked[i : i + 1, :].T
          vox_log_data = log_data[i : i + 1, :].T
          vox_log_data[np.isinf(vox_log_data)] = 0
          y.value = vox_data * vox_log_data
          A.value = vox_data * X
  
          try:
              prob.solve(solver=cvxpy_solver, verbose=False)
              m = x.value
          except Exception:
              msg = "Constrained optimization failed, attempting unconstrained"
              msg += " optimization."
              warn(msg)
              try:
                  unconstrained.solve(solver=cvxpy_solver)
                  m = x.value
              except Exception:
                  msg = "Unconstrained optimization failed,"
                  msg += " returning zero array."
                  warn(msg)
                  m = np.zeros(x.shape)
  
          params_masked[i : i + 1, :] = m.T
  
      params_masked[:, 0] += np.log(scale[:, 0])
      params[np.where(mask.ravel())] = params_masked
      params = params.reshape((mask.shape + (28,)))
      return params
  
imports: from warnings import warn
  import numpy
  from dipy.reconst.base import ReconstModel
  from dipy.reconst.dti import auto_attr
  from dipy.utils.optpkg import optional_package
label_desc: Use image node_id 12 for calling a global function with example usage: _sdpdc_fit(data, mask, X, cvxpy_solver) and returns: params