HyperbolicSineGrid.java
package net.finmath.finitedifference.grids;
/**
* Non-uniform grid based on a hyperbolic sine transformation between
* {@code minimumValue} and {@code maximumValue}.
*
* <p>
* This grid clusters points around a specified {@code centering} value.
* The parameter {@code alpha} controls the degree of clustering, with larger
* values leading to a tighter concentration near the {@code centering} point.
* </p>
*
* <p>
* The grid points are generated by applying a hyperbolic sine mapping to a
* uniform parameterization of the interval.
* </p>
*
* @author Michela Birtele
*/
public class HyperbolicSineGrid 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 centering.
*/
private final double centering;
/**
* The alpha.
*/
private final double alpha;
/**
* The grid.
*/
private double[] grid;
/**
* The delta.
*/
private double[] delta;
/**
* Constructs a hyperbolic sine 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 centering The point around which the grid points cluster.
* @param alpha Parameter controlling the clustering strength
* around {@code centering}.
*/
public HyperbolicSineGrid(
final int numberOfSteps,
final double minimumValue,
final double maximumValue,
final double centering,
final double alpha) {
this.numberOfSteps = numberOfSteps;
this.minimumValue = minimumValue;
this.maximumValue = maximumValue;
this.centering = centering;
this.alpha = alpha;
}
/**
* Generates the grid points using the hyperbolic sine transformation.
*/
private void generateGrid() {
grid = new double[numberOfSteps + 1];
final double y1 = (minimumValue - centering) / alpha;
final double y2 = (maximumValue - centering) / alpha;
final double c1 = Math.log(y1 + Math.sqrt(y1 * y1 + 1.0));
final double c2 = Math.log(y2 + Math.sqrt(y2 * y2 + 1.0));
grid[0] = minimumValue;
for (int i = 1; i <= numberOfSteps; i++) {
final double argument =
(c2 * i / numberOfSteps)
+ c1 * (1.0 - i / (double) numberOfSteps);
grid[i] =
centering
+ alpha
* (Math.exp(argument) - Math.exp(-argument)) / 2.0;
}
}
/**
* 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 grid points distributed via the hyperbolic sine
* transformation.
*/
@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;
}
}