code: def surface_deriv(self, param):
          
          squeeze_out = (np.shape(param) == ())
          param = np.array(param, dtype=float, copy=False, ndmin=1)
          if self.check_bounds and not is_inside_bounds(param, self.params):
              raise ValueError('`param` {} not in the valid range '
                               '{}'.format(param, self.params))
          if squeeze_out:
              return self.axis
          else:
              # Produce array of shape `param.shape + (ndim,)` by broadcasting
              bcast_slc = (None,) * param.ndim + (slice(None),)
              return np.broadcast_to(
                  self.axis[bcast_slc], param.shape + self.axis.shape)
docs: Return the surface derivative at ``param``.
  
          This is a constant function evaluating to `axis` everywhere.
  
          Parameters
          ----------
          param : float or `array-like`
              Parameter value(s) at which to evaluate.
  
          Returns
          -------
          deriv : `numpy.ndarray`
              Array representing the derivative vector(s) at ``param``.
              If ``param`` is a single parameter, the returned array has
              shape ``(2,)``, otherwise ``param.shape + (2,)``.
  
          Examples
          --------
          The method works with a single parameter, resulting in a single
          vector:
  
          >>> part = odl.uniform_partition(0, 1, 10)
          >>> det = Flat1dDetector(part, axis=[1, 0])
          >>> det.surface_deriv(0)
          array([ 1.,  0.])
          >>> det.surface_deriv(1)
          array([ 1.,  0.])
  
          It is also vectorized, i.e., it can be called with multiple
          parameters at once (or an n-dimensional array of parameters):
  
          >>> det.surface_deriv([0, 1])
          array([[ 1.,  0.],
                 [ 1.,  0.]])
          >>> det.surface_deriv(np.zeros((4, 5))).shape
          (4, 5, 2)