ExponentialGrid.java

package net.finmath.finitedifference.grids;

/**
 * Non-uniform exponential grid between {@code minimumValue} and {@code
 * maximumValue}.
 *
 * <p>
 * The grid points are distributed exponentially, with density concentrated near
 * {@code minimumValue} or {@code maximumValue} depending on the parameter
 * {@code alpha}.
 * </p>
 *
 * <p>
 * If {@code alpha = 0}, the grid reduces to a uniform grid.
 * </p>
 *
 * <p>
 * The grid is generated by transforming a uniform grid on {@code [0,1]}
 * through an exponential mapping.
 * </p>
 *
 * @author Michela Birtele
 */
public class ExponentialGrid extends AbstractGrid {

	/**
	 * The number of steps.
	 */
	private final int numberOfSteps;
	/**
	 * The minimum value.
	 */
	private final double minimumValue;
	/**
	 * The maximum value.
	 */
	private final double maximumValue;
	/**
	 * The alpha.
	 */
	private final double alpha;

	/**
	 * The grid.
	 */
	private double[] grid;
	/**
	 * The delta.
	 */
	private double[] delta;

	/**
	 * Constructs an exponential grid with the specified parameters.
	 *
	 * @param numberOfSteps The number of intervals in the grid.
	 * @param minimumValue  The lower bound of the grid interval.
	 * @param maximumValue  The upper bound of the grid interval.
	 * @param alpha         Parameter controlling grid density:
	 *                      <ul>
	 * <li>If {@code alpha > 0}, points cluster near {@code maximumValue}.</li>
	 * <li>If {@code alpha < 0}, points cluster near {@code minimumValue}.</li>
	 *                      <li>If {@code alpha = 0}, the grid is uniform.</li>
	 *                      </ul>
	 */
	public ExponentialGrid(
			final int numberOfSteps,
			final double minimumValue,
			final double maximumValue,
			final double alpha) {

		this.numberOfSteps = numberOfSteps;
		this.minimumValue = minimumValue;
		this.maximumValue = maximumValue;
		this.alpha = alpha;
	}

	/**
	 * Generates the exponential grid points.
	 */
	private void generateGrid() {

		grid = new double[numberOfSteps + 1];

		final Grid uniformGrid = new UniformGrid(numberOfSteps, 0.0, 1.0);
		final double[] x = uniformGrid.getGrid();

		final double eta;
		final double theta;

		if (alpha == 0.0) {
			eta = maximumValue - minimumValue;
			theta = minimumValue;
		} else {
			eta = (maximumValue - minimumValue) / (Math.exp(alpha) - 1.0);
			theta = minimumValue - eta;
		}

		for (int i = 0; i <= numberOfSteps; i++) {
			grid[i] = theta + eta * Math.exp(alpha * x[i]);
		}
	}

	/**
	 * Generates the spacing (delta) array as differences between
	 * consecutive grid points.
	 *
	 * @param vector Array of values at grid points (usually the grid itself).
	 */
	private void generateDelta(final double[] vector) {

		if (grid == null) {
			generateGrid();
		}

		delta = new double[numberOfSteps];

		for (int i = 0; i < vector.length - 1; i++) {
			delta[i] = vector[i + 1] - vector[i];
		}
	}

	/**
	 * Returns the grid points, generating them if necessary.
	 *
	 * @return The exponentially distributed grid points.
	 */
	@Override
	public double[] getGrid() {

		if (grid == null) {
			generateGrid();
		}

		return grid;
	}

	/**
	 * Returns the spacing between grid points, generating it if necessary.
	 *
	 * @param vector Array of values at grid points (usually the grid itself).
	 * @return The spacing between consecutive grid points.
	 */
	@Override
	public double[] getDelta(final double[] vector) {

		if (delta == null) {
			generateDelta(vector);
		}

		return delta;
	}
}