final double sMin = Math.min(0.8 * k, s0 / mult);
final double sMax = Math.max(1.25 * k, s0 * mult);
// set up a near-uniform mesh that includes spot and strike
final double[] fixedPoints = k == 0.0 ? new double[] {s0} : new double[] {s0, k};
final MeshingFunction xMesh = new ExponentialMeshing(sMin, sMax, spaceNodes, 0.0, fixedPoints);
PDEGrid1D[] grid;
double[] theta;
if (_useBurnin) {
final int tBurnNodes = (int) Math.max(2, timeNodes * _burninFrac);
final double tBurn = _burninFrac * t * t / timeNodes;
if (tBurn >= t) { // very unlikely to hit this
final int minNodes = (int) Math.ceil(_burninFrac * t);
final double minFrac = timeNodes / t;
throw new IllegalArgumentException("burn in period greater than total time. Either increase timeNodes to above " + minNodes + ", or reduce burninFrac to below "
+ minFrac);
}
final MeshingFunction tBurnMesh = new ExponentialMeshing(0.0, tBurn, tBurnNodes, 0.0);
final MeshingFunction tMesh = new ExponentialMeshing(tBurn, t, timeNodes - tBurnNodes, 0.0);
grid = new PDEGrid1D[2];
grid[0] = new PDEGrid1D(tBurnMesh, xMesh);
grid[1] = new PDEGrid1D(tMesh, xMesh);
theta = new double[] {_burninTheta, _mainRunTheta};
} else {
grid = new PDEGrid1D[1];
final MeshingFunction tMesh = new ExponentialMeshing(0, t, timeNodes, 0.0);
grid[0] = new PDEGrid1D(tMesh, xMesh);
theta = new double[] {_mainRunTheta};
}
return price(s0, k, r, b, t, sigma, isCall, isAmerican, grid, theta);