/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.finitedifference;
import java.util.HashMap;
import java.util.Map;
import org.testng.annotations.Test;
import com.opengamma.analytics.financial.model.finitedifference.applications.CoupledPDEDataBundleProvider;
import com.opengamma.analytics.financial.model.finitedifference.applications.PDEUtilityTools;
import com.opengamma.analytics.financial.model.finitedifference.applications.TwoStateMarkovChainDataBundle;
import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve;
import com.opengamma.analytics.math.function.Function;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.interpolation.DoubleQuadraticInterpolator1D;
import com.opengamma.analytics.math.interpolation.GridInterpolator2D;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle;
import com.opengamma.analytics.math.surface.FunctionalDoublesSurface;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.tuple.DoublesPair;
/**
* @deprecated This class tests deprecated functionality
*/
@Deprecated
@SuppressWarnings("unused")
@Test(groups = TestGroup.UNIT)
public class CoupledFokkerPlankPDEtest {
private static final CoupledPDEDataBundleProvider PDE_DATA_PROVIDER = new CoupledPDEDataBundleProvider();
//private static final BlackImpliedVolatilityFormula BLACK_IMPLIED_VOL = new BlackImpliedVolatilityFormula();
private static final BoundaryCondition LOWER;
private static final BoundaryCondition UPPER;
private static final double SPOT = 1.0;
private static final ForwardCurve FORWARD;
//private static final double STRIKE;
private static final double T = 5.0;
private static final double RATE = 0.0;
//private static final YieldAndDiscountCurve YIELD_CURVE = new YieldCurve(ConstantDoublesCurve.from(RATE));
private static final double VOL1 = 0.20;
private static final double VOL2 = 0.70;
private static final double LAMBDA12 = 0.2;
private static final double LAMBDA21 = 2.0;
private static final double INITIAL_PROB_STATE1 = 1.0;
//private static final EuropeanVanillaOption OPTION;
private static final ExtendedCoupledPDEDataBundle DATA1;
private static final ExtendedCoupledPDEDataBundle DATA2;
private static final DoubleQuadraticInterpolator1D INTERPOLATOR_1D = new DoubleQuadraticInterpolator1D();
private static final GridInterpolator2D GRID_INTERPOLATOR2D = new GridInterpolator2D(INTERPOLATOR_1D, INTERPOLATOR_1D);
static {
FORWARD = new ForwardCurve(SPOT, RATE);
final TwoStateMarkovChainDataBundle chainData = new TwoStateMarkovChainDataBundle(VOL1, VOL2, LAMBDA12, LAMBDA21, INITIAL_PROB_STATE1);
final ExtendedCoupledPDEDataBundle[] pdeData = PDE_DATA_PROVIDER.getCoupledFokkerPlankPair(FORWARD, chainData);
DATA1 = pdeData[0];
DATA2 = pdeData[1];
final Function1D<Double, Double> upper1stDev = new Function1D<Double, Double>() {
@Override
public Double evaluate(final Double t) {
return Math.exp(-RATE * t);
}
};
LOWER = new DirichletBoundaryCondition(0.0, 0.0);
UPPER = new DirichletBoundaryCondition(0.0, 15.0 * SPOT);
}
//TODO quantitative test here (rather than printing surfaces)
@Test(enabled = false)
public void testDensity() {
final ExtendedCoupledFiniteDifference solver = new ExtendedCoupledFiniteDifference(0.5);
final int tNodes = 50;
final int xNodes = 150;
final MeshingFunction timeMesh = new ExponentialMeshing(0, T, tNodes, 5.0);
final MeshingFunction spaceMesh = new HyperbolicMeshing(LOWER.getLevel(), UPPER.getLevel(), SPOT, xNodes, 0.01);
//MeshingFunction spaceMesh = new ExponentialMeshing(LOWER.getLevel(), UPPER.getLevel(), xNodes, 0.0);
final double[] timeGrid = new double[tNodes];
for (int n = 0; n < tNodes; n++) {
timeGrid[n] = timeMesh.evaluate(n);
}
final double[] spaceGrid = new double[xNodes];
for (int i = 0; i < xNodes; i++) {
spaceGrid[i] = spaceMesh.evaluate(i);
}
final PDEGrid1D grid = new PDEGrid1D(timeGrid, spaceGrid);
final PDEResults1D[] res = solver.solve(DATA1, DATA2, grid, LOWER, UPPER, LOWER, UPPER, null);
final PDEFullResults1D res1 = (PDEFullResults1D) res[0];
final PDEFullResults1D res2 = (PDEFullResults1D) res[1];
PDEUtilityTools.printSurface("State 1 density", res1);
PDEUtilityTools.printSurface("State 2 density", res2);
//calculated the local vol surface
final Map<DoublesPair, Double> localVolData = new HashMap<DoublesPair, Double>(xNodes * tNodes);
double norm;
double t, k;
double value;
for (int j = 0; j < tNodes; j++) {
for (int i = 0; i < xNodes; i++) {
t = res1.getTimeValue(j);
k = res1.getSpaceValue(i);
norm = res1.getFunctionValue(i, j) + res2.getFunctionValue(i, j);
if (norm == 0.0) {
value = 0.0;
} else {
value = VOL1 * VOL1 * res1.getFunctionValue(i, j) + VOL2 * VOL2 * res2.getFunctionValue(i, j);
value /= norm;
value = Math.sqrt(value);
}
localVolData.put(DoublesPair.of(t, k), value);
}
}
final Map<Double, Interpolator1DDataBundle> dataBundle = GRID_INTERPOLATOR2D.getDataBundle(localVolData);
final Function<Double, Double> localVolFunction = new Function<Double, Double>() {
@SuppressWarnings("synthetic-access")
@Override
public Double evaluate(final Double... x) {
return GRID_INTERPOLATOR2D.interpolate(dataBundle, DoublesPair.of(x[0].doubleValue(), x[1].doubleValue()));
}
};
final FunctionalDoublesSurface localVolSurface = FunctionalDoublesSurface.from(localVolFunction);
PDEUtilityTools.printSurface("LV surface", localVolSurface, 0, 5.0, SPOT / 4.0, 4.0 * SPOT);
}
}