class LocalVolatilityBackwardsPDEPricer {

  public double price(final ForwardCurve fwd, final Curve<Double, Double> riskFreeRate, final EuropeanVanillaOption option, final LocalVolatilitySurfaceStrike localVol, final boolean isAmerican,
      final int spaceNodes, final int timeNodes) {

    final double t = option.getTimeToExpiry();
    final double s0 = fwd.getSpot();
    final double k = option.getStrike();
    final double sigma = Math.max(localVol.getVolatility(t, k), localVol.getVolatility(t, s0));

    final double mult = Math.exp(6.0 * sigma * Math.sqrt(t));
    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(fwd, riskFreeRate, option, localVol, isAmerican, grid, theta);
  }

  public  LocalVolatilityBackwardsPDEPricer();
  public  LocalVolatilityBackwardsPDEPricer(final boolean useBurnin);
  public  LocalVolatilityBackwardsPDEPricer(final boolean useBurnin, final double burninFrac);
  public  LocalVolatilityBackwardsPDEPricer(final boolean useBurnin, final double burninFrac, final double burninTheta, final double mainTheta);

}