@Override
  protected OperationData process(IDataset input, IMonitor monitor) {

    RectangularROI box = model.getBox();

    Dataset in1 =
        BoxSlicerRodScanUtils.rOIBox(input, monitor, box.getIntLengths(), box.getIntPoint());

    if (g2 == null) g2 = new Polynomial2D(model.getFitPower());
    if ((int) Math.pow(model.getFitPower() + 1, 2) != g2.getNoOfParameters())
      g2 = new Polynomial2D(model.getFitPower());

    Dataset[] fittingBackground =
        BoxSlicerRodScanUtils.LeftRightTopBottomBoxes(
            input, monitor, box.getIntLengths(), box.getIntPoint(), model.getBoundaryBox());

    Dataset offset = DatasetFactory.ones(fittingBackground[2].getShape(), Dataset.FLOAT64);

    Dataset intermediateFitTest = Maths.add(offset, fittingBackground[2]);
    Dataset matrix =
        LinearLeastSquaresServicesForSXRD.polynomial2DLinearLeastSquaresMatrixGenerator(
            model.getFitPower(), fittingBackground[0], fittingBackground[1]);

    DoubleDataset test = (DoubleDataset) LinearAlgebra.solveSVD(matrix, intermediateFitTest);
    double[] params = test.getData();

    DoubleDataset in1Background =
        g2.getOutputValues0(
            params, box.getIntLengths(), model.getBoundaryBox(), model.getFitPower());

    IndexIterator it = in1Background.getIterator();

    while (it.hasNext()) {
      double v = in1Background.getElementDoubleAbs(it.index);
      if (v < 0) in1Background.setObjectAbs(it.index, 0);
    }

    Dataset pBackgroundSubtracted = Maths.subtract(in1, in1Background, null);

    pBackgroundSubtracted.setName("pBackgroundSubtracted");

    IndexIterator it1 = pBackgroundSubtracted.getIterator();

    while (it1.hasNext()) {
      double q = pBackgroundSubtracted.getElementDoubleAbs(it1.index);
      if (q < 0) pBackgroundSubtracted.setObjectAbs(it1.index, 0);
    }

    Dataset output = DatasetUtils.cast(pBackgroundSubtracted, Dataset.FLOAT64);

    output.setName("Region of Interest, polynomial background removed");

    return new OperationData(output);
  }
  private static double[][] convertDoubleDataset2DtoPrimitive(DoubleDataset dataset) {
    if (dataset.getRank() != 2) throw new IllegalArgumentException("dataset Shape must be 2D");

    double[][] rv = new double[dataset.getShape()[0]][dataset.getShape()[1]];

    for (int row = 0; row < dataset.getShape()[0]; row++) {
      System.arraycopy(
          dataset.getData(), row * dataset.getShape()[1], rv[row], 0, dataset.getShape()[1]);
    }

    return rv;
  }
  /**
   * Perform a two-dimensional interpolation
   *
   * @param oldx an IDataset containing a 1D array of X-values, sorted in increasing order,
   *     corresponding to the first dimension of <code>oldxy</code>
   * @param oldy an IDataset containing a 1D array of Y-values, sorted in increasing order,
   *     corresponding to the second dimension of <code>oldxy</code>
   * @param oldxy an IDataset containing a 2D grid of interpolation points
   * @param newx an IDataset containing a 1D array of X-values that will be sent to the
   *     interpolating function
   * @param newy an IDataset containing a 1D array of Y-values that will be sent to the
   *     interpolating function
   * @param interpolator an instance of {@link
   *     org.apache.commons.math3.analysis.interpolation.BivariateGridInterpolator}
   * @param output_type an {@link BicubicInterpolationOutput} that will determine how <code>newx
   *     </code> and <code>newy</code> will be interpreted, and therefore whether a 1D or 2D Dataset
   *     will be returned.
   * @return rank 1 or 2 Dataset, depending on <code>output_type}</code>
   * @throws NonMonotonicSequenceException
   * @throws NumberIsTooSmallException
   */
  public static Dataset interpolate(
      IDataset oldx,
      IDataset oldy,
      IDataset oldxy,
      IDataset newx,
      IDataset newy,
      BivariateGridInterpolator interpolator,
      BicubicInterpolationOutput output_type)
      throws NonMonotonicSequenceException, NumberIsTooSmallException {

    // check shapes
    if (oldx.getRank() != 1) throw new IllegalArgumentException("oldx Shape must be 1D");
    if (oldy.getRank() != 1) throw new IllegalArgumentException("oldy Shape must be 1D");
    if (oldxy.getRank() != 2) throw new IllegalArgumentException("oldxy Shape must be 2D");
    if (oldx.getShape()[0] != oldxy.getShape()[0])
      throw new IllegalArgumentException("oldx Shape must match oldxy Shape[0]");
    if (oldy.getShape()[0] != oldxy.getShape()[1])
      throw new IllegalArgumentException("oldy Shape must match oldxy Shape[1]");
    if (newx.getRank() != 1) throw new IllegalArgumentException("newx Shape must be 1D");
    if (newy.getRank() != 1) throw new IllegalArgumentException("newx Shape must be 1D");
    if (output_type == BicubicInterpolationOutput.ONED && newy.getSize() != newx.getSize())
      throw new IllegalArgumentException(
          "newx and newy Size must be identical when expecting a rank 1 dataset result");

    DoubleDataset oldx_dd = (DoubleDataset) DatasetUtils.cast(oldx, Dataset.FLOAT64);
    DoubleDataset oldy_dd = (DoubleDataset) DatasetUtils.cast(oldy, Dataset.FLOAT64);
    DoubleDataset oldxy_dd = (DoubleDataset) DatasetUtils.cast(oldxy, Dataset.FLOAT64);

    // unlike in Interpolation1D, we will not be sorting here, as it just too complicated
    // the user will be responsible for ensuring the arrays are properly sorted

    // oldxy_dd needs to be transformed into a double[][] array
    // this call may throw an exception that needs handling by the calling method
    BivariateFunction func =
        interpolator.interpolate(
            oldx_dd.getData(), oldy_dd.getData(), convertDoubleDataset2DtoPrimitive(oldxy_dd));

    Dataset rv = null;

    if (output_type == BicubicInterpolationOutput.ONED) {
      rv = DatasetFactory.zeros(new int[] {newx.getSize()}, Dataset.FLOAT64);

      for (int i = 0; i < newx.getSize(); i++) {
        double val = 0.0;
        try {
          val = func.value(newx.getDouble(i), newy.getDouble(i));
          rv.set(val, i);
        } catch (OutOfRangeException e) {
          rv.set(0.0, i);
        }
      }
    } else if (output_type == BicubicInterpolationOutput.TWOD) {
      rv = DatasetFactory.zeros(new int[] {newx.getSize(), newy.getSize()}, Dataset.FLOAT64);

      for (int i = 0; i < newx.getSize(); i++) {
        for (int j = 0; j < newy.getSize(); j++) {
          double val = 0.0;
          try {
            val = func.value(newx.getDouble(i), newy.getDouble(j));
            rv.set(val, i, j);
          } catch (OutOfRangeException e) {
            rv.set(0.0, i, j);
          }
        }
      }
    }

    rv.setName(oldxy.getName() + "_interpolated");

    return rv;
  }