protected OperationData process(IDataset input, IMonitor monitor) throws OperationException {

    double d = (2 * Math.PI) / model.getqValue();
    double p = (2 * Math.PI) / (model.getqValue() + model.getqDelta());
    double m = (2 * Math.PI) / (model.getqValue() - model.getqDelta());

    IDiffractionMetadata dm = getFirstDiffractionMetadata(input);
    if (dm == null) throw new OperationException(this, "No calibration information!");

    IParametricROI[] inOut = new IParametricROI[2];

    IParametricROI conic =
        (IParametricROI)
            DSpacing.conicFromDSpacing(
                dm.getDetector2DProperties(), dm.getDiffractionCrystalEnvironment(), d);
    inOut[0] =
        (IParametricROI)
            DSpacing.conicFromDSpacing(
                dm.getDetector2DProperties(), dm.getDiffractionCrystalEnvironment(), m);
    inOut[1] =
        (IParametricROI)
            DSpacing.conicFromDSpacing(
                dm.getDetector2DProperties(), dm.getDiffractionCrystalEnvironment(), p);

    PolylineROI points =
        PeakFittingEllipseFinder.findPointsOnConic(
            DatasetUtils.convertToDataset(input), null, conic, inOut, 256, null);

    double rms = -1;
    double[] semi = new double[2];
    double[] point = new double[2];
    double ang = 0;

    if (points != null && points.getNumberOfPoints() < 3) {

      EllipticalFitROI efroi = PowderRingsUtils.fitAndTrimOutliers(null, points, 2, false);
      rms = efroi.getRMS();
      semi = efroi.getSemiAxes();
      point = efroi.getPoint();
      ang = efroi.getAngleDegrees();
    }

    Dataset r = DatasetFactory.createFromObject(new double[] {rms});
    r.setName("rms");

    Dataset ax = DatasetFactory.createFromObject(semi);
    ax.setName("semi-axes");

    Dataset po = DatasetFactory.createFromObject(point);
    po.setName("centre");

    Dataset a = DatasetFactory.createFromObject(new double[] {ang});
    a.setName("angle");

    return new OperationData(input, new Serializable[] {r, ax, po, a});
  }
  @Override
  protected OperationData process(IDataset input, IMonitor monitor) {

    double theta = 0;
    try {
      theta = ScanMetadata.getTheta(input);
    } catch (Exception e) {
    }

    NormalDistribution beamfootprint =
        new NormalDistribution(
            0, (1e-3 * model.getBeamHeight() / 2 * Math.sqrt(2 * Math.log(2) - 0.5)));
    double areaCorrection =
        2
            * (beamfootprint.cumulativeProbability(
                (model.getFootprint()
                    * Math.sin((theta + model.getAngularFudgeFactor()) * Math.PI / 180))));

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

    output = Maths.multiply(input, areaCorrection);

    Dataset outputSum =
        DatasetFactory.createFromObject((DatasetUtils.cast(output, Dataset.FLOAT64)).sum());

    return new OperationData(output, outputSum);
  }
  private void populateDataBasedFunctions(
      final Map<String, Serializable> data, IFunction function) {

    if (function instanceof CompositeFunction) {
      CompositeFunction compositeFunction = (CompositeFunction) function;
      for (IFunction func : compositeFunction.getFunctions()) {
        populateDataBasedFunctions(data, func);
      }
    }

    if (function instanceof IDataBasedFunction) {
      IDataBasedFunction dbFunction = (IDataBasedFunction) function;

      String sdName = seedDataName.getExpression();
      String sdAxis = seedAxisName.getExpression();
      Dataset seedDataset = DatasetFactory.createFromObject(data.get(sdName)).clone();
      Dataset seedAxisDataset = DatasetFactory.createFromObject(data.get(sdAxis)).clone();
      dbFunction.setData(seedAxisDataset, seedDataset);
    }
  }
  @Override
  protected DataMessageComponent getTransformedMessage(List<DataMessageComponent> cache)
      throws DataMessageException {

    // get the data out of the message, name of the item should be specified
    final Map<String, Serializable> data = MessageUtils.getList(cache);
    Map<String, AFunction> functions;
    try {
      functions = MessageUtils.getFunctions(cache);
    } catch (Exception e) {
      throw new DataMessageException(
          "Could not parse the Funcitons comming into the FunctionToDatsetActor", null, e);
    }

    // prepare the output message
    DataMessageComponent result = MessageUtils.copy(cache);

    // get the required datasets
    String dataset = datasetName.getExpression();
    String xAxis = xAxisName.getExpression();
    String functionString = functionName.getExpression();

    // Get the actual objects
    Dataset xAxisDS = DatasetFactory.createFromObject(data.get(xAxis)).clone();
    AFunction function = functions.get(functionString);

    populateDataBasedFunctions(data, function);

    // process the data
    // TODO Add Null Protection here.
    DoubleDataset createdDS = function.calculateValues(xAxisDS);
    createdDS.setName(dataset);

    // Add it to the result
    result.addList(createdDS.getName(), createdDS);

    return result;
  }
  @Test
  public void testWriteNX() {

    String filename = "/tmp/sample.nxs";
    NexusFileBuilder builder = new DefaultNexusFileBuilder(filename);
    NXsample nxample = sample.getNXsample(builder);

    int nCompo = sample.getPhases().size();

    assertEquals("NX name incorrect", sample.getName(), nxample.getNameScalar());
    assertEquals(
        "NX description incorrect",
        sample.getName() + ", " + sample.getComposition() + ", " + sample.getShapeName(),
        nxample.getDescriptionScalar());
    assertEquals(
        "NX component names incorrect",
        DatasetFactory.createFromList(
            sample.getPhases().stream().map(a -> a.getName()).collect(Collectors.toList())),
        nxample.getComponent());
    assertEquals(
        "NX component formulae incorrect",
        DatasetFactory.createFromObject(
            sample
                .getPhases()
                .stream()
                .map(a -> a.getComposition().getHallNotation(false))
                .collect(Collectors.toList()),
            nCompo,
            1),
        nxample.getChemical_formula());
    assertEquals(
        "NX formula weight incorrect",
        DatasetFactory.createFromList(
            sample
                .getPhases()
                .stream()
                .map(a -> a.getComposition().getFormulaMass())
                .collect(Collectors.toList())),
        nxample.getDataset("chemical_formula_weight"));
    // unit cell parameters...
    assertEquals(
        "NX unit cell volume incorrect",
        DatasetFactory.createFromList(
            sample
                .getPhases()
                .stream()
                .map(a -> a.getUnitCellVolume())
                .collect(Collectors.toList())),
        nxample.getUnit_cell_volume());
    assertEquals(
        "NX unit cell class incorrect",
        DatasetFactory.createFromList(
            sample
                .getPhases()
                .stream()
                .map(a -> a.getCrystalSystem().getName())
                .collect(Collectors.toList())),
        nxample.getUnit_cell_class());
    assertEquals(
        "NX unit cell space group incorrect",
        DatasetFactory.createFromList(
            sample
                .getPhases()
                .stream()
                .map(a -> a.getSpaceGroup().getNumber() + ": " + a.getSpaceGroup().getName())
                .collect(Collectors.toList())),
        nxample.getUnit_cell_group());
    assertEquals(
        "NX theoretical densities incorrect",
        DatasetFactory.createFromList(
            sample.getPhases().stream().map(a -> a.getDensity()).collect(Collectors.toList())),
        nxample.getDataset("theoretical_density"));
  }