/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.math.surface; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.opengamma.util.ArgumentChecker; /** * Shifts a {@link NodalDoublesSurface}. If the <i>x-y</i> value(s) of the shift(s) are not in the nodal points of the * original surface, then the surface cannot be shifted. */ public class NodalSurfaceMultiplicativeShiftFunction implements SurfaceShiftFunction<NodalDoublesSurface> { /** * {@inheritDoc} */ @Override public NodalDoublesSurface evaluate(final NodalDoublesSurface surface, final double percentage) { ArgumentChecker.notNull(surface, "surface"); return evaluate(surface, percentage, "CONSTANT_MULTIPLIER_" + surface.getName()); } /** * {@inheritDoc} */ @Override public NodalDoublesSurface evaluate(final NodalDoublesSurface surface, final double percentage, final String newName) { ArgumentChecker.notNull(surface, "surface"); final double[] xData = surface.getXDataAsPrimitive(); final double[] yData = surface.getYDataAsPrimitive(); final double[] zData = surface.getZDataAsPrimitive(); final int n = zData.length; final double[] shiftedZ = new double[n]; for (int i = 0; i < n; i++) { shiftedZ[i] = zData[i] * (1 + percentage); } return NodalDoublesSurface.from(xData, yData, shiftedZ, newName); } /** * {@inheritDoc} * @throws IllegalArgumentException If the point to shift is not a nodal point of the surface */ @Override public NodalDoublesSurface evaluate(final NodalDoublesSurface surface, final double x, final double y, final double percentage) { ArgumentChecker.notNull(surface, "surface"); return evaluate(surface, x, y, percentage, "SINGLE_MULTIPLIER_" + surface.getName()); } /** * {@inheritDoc} * @throws IllegalArgumentException If the point to shift is not a nodal point of the surface */ @Override public NodalDoublesSurface evaluate(final NodalDoublesSurface surface, final double x, final double y, final double percentage, final String newName) { ArgumentChecker.notNull(surface, "surface"); final double[] xData = surface.getXDataAsPrimitive(); final double[] yData = surface.getYDataAsPrimitive(); final double[] zData = surface.getZDataAsPrimitive(); final int n = zData.length; for (int i = 0; i < n; i++) { if (Double.doubleToLongBits(xData[i]) == Double.doubleToLongBits(x)) { if (Double.doubleToLongBits(yData[i]) == Double.doubleToLongBits(y)) { final double[] shiftedZ = Arrays.copyOf(zData, n); shiftedZ[i] *= 1 + percentage; return NodalDoublesSurface.from(xData, yData, shiftedZ, newName); } } } throw new IllegalArgumentException("No x-y data in surface for (" + x + ", " + y + ")"); } /** * {@inheritDoc} * @throws IllegalArgumentException If the points to shift are not nodal points of the surface */ @Override public NodalDoublesSurface evaluate(final NodalDoublesSurface surface, final double[] xShift, final double[] yShift, final double[] zShift) { ArgumentChecker.notNull(surface, "surface"); return evaluate(surface, xShift, yShift, zShift, "MULTIPLE_MULTIPLIER_" + surface.getName()); } /** * {@inheritDoc} * @throws IllegalArgumentException If the points to shift are not nodal points of the surface */ @Override public NodalDoublesSurface evaluate(final NodalDoublesSurface surface, final double[] xShift, final double[] yShift, final double[] percentage, final String newName) { ArgumentChecker.notNull(surface, "surface"); ArgumentChecker.notNull(xShift, "x shift"); ArgumentChecker.notNull(yShift, "y shift"); ArgumentChecker.notNull(percentage, "shifts"); final int m = xShift.length; if (m == 0) { return NodalDoublesSurface.from(surface.getXDataAsPrimitive(), surface.getYDataAsPrimitive(), surface.getZDataAsPrimitive(), newName); } ArgumentChecker.isTrue(m == yShift.length && m == percentage.length, "number of shifts {} must be equal to number of x shift positions {} and y shift positions {}", percentage.length, m, yShift.length); final double[] xData = surface.getXDataAsPrimitive(); final double[] yData = surface.getYDataAsPrimitive(); final double[] zData = surface.getZDataAsPrimitive(); final int n = zData.length; final double[] shiftedZ = Arrays.copyOf(zData, n); for (int i = 0; i < xShift.length; i++) { final double x = xShift[i]; final List<Integer> indices = new ArrayList<>(); for (int j = 0; j < n; j++) { if (Double.doubleToLongBits(xData[j]) == Double.doubleToLongBits(x)) { indices.add(j); } } if (indices.isEmpty()) { throw new IllegalArgumentException("No x data in surface for value " + x); } boolean foundValue = false; for (final int index : indices) { if (Double.doubleToLongBits(yData[index]) == Double.doubleToLongBits(yShift[i])) { shiftedZ[index] *= 1 + percentage[i]; foundValue = true; } } if (!foundValue) { throw new IllegalArgumentException("No x-y data in surface for (" + x + ", " + yShift[i] + ")"); } } return NodalDoublesSurface.from(xData, yData, shiftedZ, newName); } }