/**
  * @param x
  * @param rootName
  * @return
  */
 public static String getName(IDataset x, String rootName) {
   if (x == null) return null;
   try {
     return rootName != null ? x.getName().substring(rootName.length()) : x.getName();
   } catch (StringIndexOutOfBoundsException ne) {
     return x.getName();
   }
 }
 public void setYs(List<IDataset> ys) {
   this.min = Double.MAX_VALUE;
   this.max = -Double.MAX_VALUE;
   for (IDataset y : ys) {
     this.min = Math.min(min, y.min().doubleValue());
     this.max = Math.max(max, y.max().doubleValue());
   }
 }
  @Test
  public void testMerlinDataLoaderU32() throws Exception {
    final String path = testFileFolder + "I13-20150210-101459-1.mib";
    IDataHolder dataHolder = LoaderFactory.getData(path, null);

    IDataset data = dataHolder.getDataset(0);
    int[] shape = data.getShape();
    assertEquals(515, shape[0], 0.0);
    assertEquals(515, shape[1], 0.0);
  }
  @Test
  public void testMerlinDataLoader() throws Exception {
    final String path = testFileFolder + "default1.mib";
    IDataHolder dataHolder = LoaderFactory.getData(path, null);

    IDataset data = dataHolder.getDataset(0);
    int[] shape = data.getShape();
    assertEquals(512, shape[0], 0.0);
    assertEquals(512, shape[1], 0.0);
    assertEquals(4095, data.max().intValue(), 0.0);
  }
 @Test
 public void testLazyRotation() throws Exception {
   int[] shape = data.getShape();
   // rotated shape
   int[] newShape = new int[] {data.getShape()[0], 724, 724};
   String name = "testLazyRotation.h5";
   ILazyWriteableDataset lazy = TestUtils.createTempLazyFile(newShape, name);
   for (int i = 0; i < shape[0]; i++) {
     IDataset slice = data.getSlice(new Slice(i, shape[0], shape[1])).squeeze();
     IDataset rotated = DatasetUtils.convertToDataset(transform.rotate(slice, 45, false));
     // add rotated image to temp file
     TestUtils.appendDataset(lazy, rotated, i, null);
   }
   assertArrayEquals(newShape, lazy.getShape());
   assertEquals(newShape[2], lazy.getShape()[2]);
   IDataset rotatedImage = lazy.getSlice(new Slice(10, shape[0], shape[1])).squeeze();
   assertEquals(newShape[2], rotatedImage.getShape()[1]);
 }
  public List<IDataset> getSelectionData(GalleryItem[] items) {

    final List<IDataset> ys = new ArrayList<IDataset>(11);
    for (GalleryItem item : items) {
      final ImageItem ii = new ImageItem();
      ii.setIndex(item.getItemCount());
      ii.setItem(item);
      try {
        IDataset slice = info.getData(true, ii);
        slice.setName(selectionDataLabel + " " + info.getItemName(item.getItemCount(), false));
        ys.add(slice);
      } catch (Exception e) {
        logger.error("Cannot slice ", e);
        continue;
      }
    }
    return ys;
  }
  @SuppressWarnings("unchecked")
  public static String getTitle(
      final IDataset xIn,
      final List<? extends IDataset> ysIn,
      final boolean isFileName,
      final String rootName) {

    final IDataset x;
    final List<IDataset> ys;
    if (ysIn == null) {
      ys = new ArrayList<IDataset>(1);
      ys.add(xIn);
      x = DatasetFactory.createRange(DoubleDataset.class, ys.get(0).getSize());
      x.setName("Index of " + xIn.getName());
    } else {
      x = xIn;
      ys = (List<IDataset>) ysIn;
    }

    final StringBuilder buf = new StringBuilder();
    buf.append("Plot of ");
    final Set<String> used = new HashSet<String>(7);
    int i = 0;
    int dataSetSize = ys.size();
    for (IDataset dataSet : ys) {
      String name = getName(dataSet, rootName);

      if (isFileName && name != null) {
        // Strip off file name
        final Matcher matcher = Pattern.compile("(.*) \\(.*\\)").matcher(name);
        if (matcher.matches()) name = matcher.group(1);
      }

      if (used.contains(name)) continue;
      if (i == 0) buf.append(name);
      if (ys.size() < 2) break;
      if (i == 1 && 1 == dataSetSize - 1) buf.append("," + name);
      if (i == dataSetSize - 1 && dataSetSize - 1 != 1) buf.append("..." + name);
      i++;
    }
    buf.append(" against ");
    buf.append(x.getName());
    return buf.toString();
  }
  /**
   * 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;
  }
  private void checkNexusFile(
      IRunnableDevice<ScanModel> scanner, List<ScanMetadata> scanMetadata, int... sizes)
      throws Exception {

    final ScanModel scanModel = ((AbstractRunnableDevice<ScanModel>) scanner).getModel();
    assertEquals(DeviceState.READY, scanner.getDeviceState());

    NXroot rootNode = getNexusRoot(scanner);
    NXentry entry = rootNode.getEntry();
    checkMetadata(entry, scanMetadata);
    // check that the scan points have been written correctly
    assertScanPointsGroup(entry, sizes);

    NXinstrument instrument = entry.getInstrument();

    LinkedHashMap<String, List<String>> signalFieldAxes = new LinkedHashMap<>();
    // axis for additional dimensions of a datafield, e.g. image
    signalFieldAxes.put(NXdetector.NX_DATA, Arrays.asList("real", "imaginary"));
    signalFieldAxes.put("spectrum", Arrays.asList("spectrum_axis"));
    signalFieldAxes.put("value", Collections.emptyList());

    String detectorName = scanModel.getDetectors().get(0).getName();
    NXdetector detector = instrument.getDetector(detectorName);
    // map of detector data field to name of nxData group where that field
    // is the @signal field
    Map<String, String> expectedDataGroupNames =
        signalFieldAxes
            .keySet()
            .stream()
            .collect(
                Collectors.toMap(
                    Function.identity(),
                    x -> detectorName + (x.equals(NXdetector.NX_DATA) ? "" : "_" + x)));

    // validate the main NXdata generated by the NexusDataBuilder
    Map<String, NXdata> nxDataGroups = entry.getChildren(NXdata.class);
    assertEquals(signalFieldAxes.size(), nxDataGroups.size());
    assertTrue(nxDataGroups.keySet().containsAll(expectedDataGroupNames.values()));
    for (String nxDataGroupName : nxDataGroups.keySet()) {
      NXdata nxData = entry.getData(nxDataGroupName);

      String sourceFieldName =
          nxDataGroupName.equals(detectorName)
              ? NXdetector.NX_DATA
              : nxDataGroupName.substring(nxDataGroupName.indexOf('_') + 1);
      assertSignal(nxData, sourceFieldName);
      // check the nxData's signal field is a link to the appropriate source data node of the
      // detector
      DataNode dataNode = detector.getDataNode(sourceFieldName);
      IDataset dataset = dataNode.getDataset().getSlice();
      assertSame(dataNode, nxData.getDataNode(sourceFieldName));
      assertTarget(
          nxData,
          sourceFieldName,
          rootNode,
          "/entry/instrument/" + detectorName + "/" + sourceFieldName);

      // check that the other primary data fields of the detector haven't been added to this NXdata
      for (String primaryDataFieldName : signalFieldAxes.keySet()) {
        if (!primaryDataFieldName.equals(sourceFieldName)) {
          assertNull(nxData.getDataNode(primaryDataFieldName));
        }
      }

      int[] shape = dataset.getShape();
      for (int i = 0; i < sizes.length; i++) assertEquals(sizes[i], shape[i]);

      // Make sure none of the numbers are NaNs. The detector
      // is expected to fill this scan with non-nulls.
      final PositionIterator it = new PositionIterator(shape);
      while (it.hasNext()) {
        int[] next = it.getPos();
        assertFalse(Double.isNaN(dataset.getDouble(next)));
      }

      // Check axes
      final IPosition pos = scanModel.getPositionIterable().iterator().next();
      final Collection<String> scannableNames = pos.getNames();

      // Append _value_demand to each name in list, then add detector axis fields to result
      List<String> expectedAxesNames =
          Stream.concat(
                  scannableNames.stream().map(x -> x + "_value_set"),
                  signalFieldAxes.get(sourceFieldName).stream())
              .collect(Collectors.toList());
      assertAxes(nxData, expectedAxesNames.toArray(new String[expectedAxesNames.size()]));

      int[] defaultDimensionMappings = IntStream.range(0, sizes.length).toArray();
      int i = -1;
      for (String scannableName : scannableNames) {

        i++;
        NXpositioner positioner = instrument.getPositioner(scannableName);
        assertNotNull(positioner);

        dataNode = positioner.getDataNode("value_set");
        dataset = dataNode.getDataset().getSlice();
        shape = dataset.getShape();
        assertEquals(1, shape.length);
        assertEquals(sizes[i], shape[0]);

        String nxDataFieldName = scannableName + "_value_set";
        assertSame(dataNode, nxData.getDataNode(nxDataFieldName));
        assertIndices(nxData, nxDataFieldName, i);
        assertTarget(
            nxData, nxDataFieldName, rootNode, "/entry/instrument/" + scannableName + "/value_set");

        // Actual values should be scanD
        dataNode = positioner.getDataNode(NXpositioner.NX_VALUE);
        dataset = dataNode.getDataset().getSlice();
        shape = dataset.getShape();
        assertArrayEquals(sizes, shape);

        nxDataFieldName = scannableName + "_" + NXpositioner.NX_VALUE;
        assertSame(dataNode, nxData.getDataNode(nxDataFieldName));
        assertIndices(nxData, nxDataFieldName, defaultDimensionMappings);
        assertTarget(
            nxData,
            nxDataFieldName,
            rootNode,
            "/entry/instrument/" + scannableName + "/" + NXpositioner.NX_VALUE);
      }
    }
  }
 public static void handleException(
     final ScanFileHolderException e,
     final IDataHolder dh,
     final String fileName,
     final double maxVal,
     final boolean unsigned,
     final int numBits)
     throws ScanFileHolderException, UnsupportedOperationException, IllegalArgumentException {
   /*
    * Need massive error handling here, since we get same type of
    * exception with different messages.
    * The exception throwing might change as time passes, the
    * current handling is determined on 2014-03-04.
    * "Unable" means we can not recover, the image could not be
    * created. Currently this can not happen, instead we get an
    * exception with "Error" in its message. See below.
    * "ScaledSaver" means not allowed parameters, that is use either 32 bits or float,
    * or <=16 bits with big enough max and not unsigned if there is any negative value.
    * "No writer" means the writer could not write the image (for
    * example bmp writer can save only RGBDataset), in this case
    * converting the dataset might help.
    * "Error" means other kind of problem, probably not recoverable.
    */
   do {
     if (StringUtils.matchStringWithPattern(e.getMessage(), ".*Unable.*", true)) break;
     final StringBuffer sb = new StringBuffer();
     if (StringUtils.matchStringWithPattern(e.getMessage(), ".*No writer.*", true)) {
       sb.append(e.getLocalizedMessage());
       sb.append("\n\nSuggestion: ");
       sb.append(
           "To save the image as "
               + FileUtils.getFileExtension(fileName)
               + " type, you can try to ");
       if (dh.getDataset(0) instanceof RGBDataset)
         sb.append("convert the RGB dataset to integer dataset.");
       else sb.append("convert the dataset to RGB dataset.");
       throw new IllegalArgumentException(sb.toString(), e.getCause());
     }
     if (StringUtils.matchStringWithPattern(e.getMessage(), ".*ScaledSaver.*", true)) {
       if (numBits > 16) // Currently impossible case
       break;
       sb.append(e.getLocalizedMessage());
       sb.append("\n\nSuggestion: ");
       sb.append(
           "To save the image as "
               + FileUtils.getFileExtension(fileName)
               + " type, you can try to any of these possibilites:\n");
       sb.append("- Choose 32 bits or float type.\n");
       double maxTotalValue = maxVal;
       boolean addedSignedHint = !unsigned;
       for (int i = 0; i < dh.size() && !addedSignedHint && maxVal > 0; i++) {
         final IDataset data = dh.getDataset(i);
         if (maxVal > 0) maxTotalValue = Math.max(data.max().doubleValue(), maxTotalValue);
         if (!addedSignedHint && (unsigned && data.min().doubleValue() < 0)) {
           sb.append("- Choose signed values.\n");
           addedSignedHint = true;
         }
       }
       if (maxTotalValue > maxVal)
         sb.append("- Choose max value >= max value of image (" + maxTotalValue + ").\n");
       sb.append("- Choose autoscale option.");
       throw new IllegalArgumentException(sb.toString(), e.getCause());
     }
     if (StringUtils.matchStringWithPattern(e.getMessage(), ".*Error.*", true)) break;
     throw new UnsupportedOperationException(
         "Unexpected error: " + e.getLocalizedMessage(), e.getCause());
   } while (false);
   throw e;
 }