def surface_deriv(self, param):
        """Return the surface derivative at ``param``.

        This is a constant function evaluating to `axes` everywhere.

        Parameters
        ----------
        param : `array-like` or sequence
            Parameter value(s) at which to evaluate. A sequence of
            parameters must have length 2.

        Returns
        -------
        deriv : `numpy.ndarray`
            Array containing the derivative vectors. The first dimension
            enumerates the axes, i.e., has always length 2.
            If ``param`` is a single parameter, the returned array has
            shape ``(2, 3)``, otherwise
            ``broadcast(*param).shape + (2, 3)``.

        Notes
        -----
        To get an array that enumerates the derivative vectors in the first
        dimension, move the second-to-last axis to the first position::

            deriv = surface_deriv(param)
            axes_enumeration = np.moveaxis(deriv, -2, 0)

        Examples
        --------
        The method works with a single parameter, resulting in a 2-tuple
        of vectors:

        >>> part = odl.uniform_partition([0, 0], [1, 1], (10, 10))
        >>> det = Flat2dDetector(part, axes=[(1, 0, 0), (0, 0, 1)])
        >>> det.surface_deriv([0, 0])
        array([[ 1.,  0.,  0.],
               [ 0.,  0.,  1.]])
        >>> det.surface_deriv([1, 1])
        array([[ 1.,  0.,  0.],
               [ 0.,  0.,  1.]])

        It is also vectorized, i.e., it can be called with multiple
        parameters at once (or n-dimensional arrays of parameters):

        >>> # 2 pairs of parameters, resulting in 3 vectors for each axis
        >>> deriv = det.surface_deriv([[0, 1],
        ...                            [0, 1]])
        >>> deriv[0]  # first pair of vectors
        array([[ 1.,  0.,  0.],
               [ 0.,  0.,  1.]])
        >>> deriv[1]  # second pair of vectors
        array([[ 1.,  0.,  0.],
               [ 0.,  0.,  1.]])
        >>> # Pairs of parameters in a (4, 5) array each
        >>> param = (np.zeros((4, 5)), np.zeros((4, 5)))  # pairs of params
        >>> det.surface_deriv(param).shape
        (4, 5, 2, 3)
        >>> # Using broadcasting for "outer product" type result
        >>> param = (np.zeros((4, 1)), np.zeros((1, 5)))  # broadcasting
        >>> det.surface_deriv(param).shape
        (4, 5, 2, 3)
        """
        squeeze_out = (np.broadcast(*param).shape == ())
        param_in = param
        param = tuple(np.array(p, dtype=float, copy=False, ndmin=1)
                      for p in param)
        if self.check_bounds and not is_inside_bounds(param, self.params):
            raise ValueError('`param` {} not in the valid range '
                             '{}'.format(param_in, self.params))

        if squeeze_out:
            return self.axes
        else:
            return np.broadcast_to(
                self.axes, np.broadcast(*param).shape + self.axes.shape)
Return the surface derivative at ``param``.

        This is a constant function evaluating to `axes` everywhere.

        Parameters
        ----------
        param : `array-like` or sequence
            Parameter value(s) at which to evaluate. A sequence of
            parameters must have length 2.

        Returns
        -------
        deriv : `numpy.ndarray`
            Array containing the derivative vectors. The first dimension
            enumerates the axes, i.e., has always length 2.
            If ``param`` is a single parameter, the returned array has
            shape ``(2, 3)``, otherwise
            ``broadcast(*param).shape + (2, 3)``.

        Notes
        -----
        To get an array that enumerates the derivative vectors in the first
        dimension, move the second-to-last axis to the first position::

            deriv = surface_deriv(param)
            axes_enumeration = np.moveaxis(deriv, -2, 0)

        Examples
        --------
        The method works with a single parameter, resulting in a 2-tuple
        of vectors:

        >>> part = odl.uniform_partition([0, 0], [1, 1], (10, 10))
        >>> det = Flat2dDetector(part, axes=[(1, 0, 0), (0, 0, 1)])
        >>> det.surface_deriv([0, 0])
        array([[ 1.,  0.,  0.],
               [ 0.,  0.,  1.]])
        >>> det.surface_deriv([1, 1])
        array([[ 1.,  0.,  0.],
               [ 0.,  0.,  1.]])

        It is also vectorized, i.e., it can be called with multiple
        parameters at once (or n-dimensional arrays of parameters):

        >>> # 2 pairs of parameters, resulting in 3 vectors for each axis
        >>> deriv = det.surface_deriv([[0, 1],
        ...                            [0, 1]])
        >>> deriv[0]  # first pair of vectors
        array([[ 1.,  0.,  0.],
               [ 0.,  0.,  1.]])
        >>> deriv[1]  # second pair of vectors
        array([[ 1.,  0.,  0.],
               [ 0.,  0.,  1.]])
        >>> # Pairs of parameters in a (4, 5) array each
        >>> param = (np.zeros((4, 5)), np.zeros((4, 5)))  # pairs of params
        >>> det.surface_deriv(param).shape
        (4, 5, 2, 3)
        >>> # Using broadcasting for "outer product" type result
        >>> param = (np.zeros((4, 1)), np.zeros((1, 5)))  # broadcasting
        >>> det.surface_deriv(param).shape
        (4, 5, 2, 3)