/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.finitedifference;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.math.cube.Cube;
/**
* <b>Note</b> this is for testing purposes and is not recommended for actual use
*/
@SuppressWarnings("deprecation")
public class ExplicitFiniteDifference2D implements ConvectionDiffusionPDESolver2D {
@Override
public double[][] solve(final ConvectionDiffusion2DPDEDataBundle pdeData, final int tSteps, final int xSteps, final int ySteps, final double tMax,
final BoundaryCondition2D xLowerBoundary, final BoundaryCondition2D xUpperBoundary, final BoundaryCondition2D yLowerBoundary,
final BoundaryCondition2D yUpperBoundary) {
return solve(pdeData, tSteps, xSteps, ySteps, tMax, xLowerBoundary, xUpperBoundary, yLowerBoundary, yUpperBoundary, null);
}
@Override
public double[][] solve(final ConvectionDiffusion2DPDEDataBundle pdeData, final int tSteps, final int xSteps, final int ySteps, final double tMax, final BoundaryCondition2D xLowerBoundary,
final BoundaryCondition2D xUpperBoundary, final BoundaryCondition2D yLowerBoundary, final BoundaryCondition2D yUpperBoundary, final Cube<Double, Double, Double, Double> freeBoundary) {
final double dt = tMax / (tSteps);
final double dx = (xUpperBoundary.getLevel() - xLowerBoundary.getLevel()) / (xSteps);
final double dy = (yUpperBoundary.getLevel() - yLowerBoundary.getLevel()) / (ySteps);
final double dtdx2 = dt / dx / dx;
final double dtdx = dt / dx;
final double dtdy2 = dt / dy / dy;
final double dtdy = dt / dy;
final double dtdxdy = dt / dy / dx;
double[][] v = new double[xSteps + 1][ySteps + 1];
final double[] x = new double[xSteps + 1];
final double[] y = new double[ySteps + 1];
double currentX = 0;
double currentY = 0;
for (int j = 0; j <= ySteps; j++) {
currentY = yLowerBoundary.getLevel() + j * dy;
y[j] = currentY;
}
for (int i = 0; i <= xSteps; i++) {
currentX = xLowerBoundary.getLevel() + i * dx;
x[i] = currentX;
for (int j = 0; j <= ySteps; j++) {
v[i][j] = pdeData.getInitialValue(x[i], y[j]);
}
}
double sum;
double t = 0.0;
for (int k = 0; k < tSteps; k++) {
final double[][] vNew = new double[xSteps + 1][ySteps + 1];
for (int i = 1; i < xSteps; i++) {
for (int j = 1; j < ySteps; j++) {
final double a = pdeData.getA(t, x[i], y[j]);
final double b = pdeData.getB(t, x[i], y[j]);
final double c = pdeData.getC(t, x[i], y[j]);
final double d = pdeData.getD(t, x[i], y[j]);
final double e = pdeData.getE(t, x[i], y[j]);
final double f = pdeData.getF(t, x[i], y[j]);
sum = v[i][j];
sum -= a * dtdx2 * (v[i + 1][j] - 2 * v[i][j] + v[i - 1][j]);
sum -= b * dtdx / 2 * (v[i + 1][j] - v[i - 1][j]);
sum -= c * dt * v[i][j];
sum -= d * dtdy2 * (v[i][j + 1] - 2 * v[i][j] + v[i][j - 1]);
sum -= e * dtdxdy / 4 * (v[i + 1][j + 1] + v[i - 1][j - 1] - v[i + 1][j - 1] - v[i - 1][j + 1]);
sum -= f * dtdy / 2 * (v[i][j + 1] - v[i][j - 1]);
vNew[i][j] = sum;
}
}
// The y = ymin and y = ymax boundaries
for (int i = 1; i < xSteps; i++) {
double[] temp = yLowerBoundary.getRightMatrixCondition(t, x[i]);
sum = 0;
for (int n = 0; n < temp.length; n++) {
sum += temp[n] * v[i][n];
}
double q = sum + yLowerBoundary.getConstant(t, x[i], dy);
sum = 0;
temp = yLowerBoundary.getLeftMatrixCondition(x[i], t);
Validate.isTrue(temp[0] != 0.0);
for (int k1 = 1; k1 < temp.length; k1++) {
sum += temp[k1] * vNew[i][k1];
}
vNew[i][0] = (q - sum) / temp[0];
temp = yUpperBoundary.getRightMatrixCondition(t, x[i]);
sum = 0;
for (int n = 0; n < temp.length; n++) {
sum += temp[n] * v[i][ySteps + n + 1 - temp.length];
}
q = sum + yUpperBoundary.getConstant(t, x[i], dy);
sum = 0;
temp = yUpperBoundary.getLeftMatrixCondition(t, x[i]);
for (int k1 = 0; k1 < temp.length - 1; k1++) {
sum += temp[k1] * vNew[i][ySteps + k1 + 1 - temp.length];
}
vNew[i][ySteps] = (q - sum) / temp[temp.length - 1];
}
// The x = xmin and x = xmax boundaries
for (int j = 0; j <= ySteps; j++) {
double[] temp = xLowerBoundary.getRightMatrixCondition(y[j], t);
sum = 0;
for (int n = 0; n < temp.length; n++) {
sum += temp[n] * v[n][j];
}
double q = sum + xLowerBoundary.getConstant(t, y[j], dx);
sum = 0;
temp = xLowerBoundary.getLeftMatrixCondition(t, y[j]);
for (int k1 = 1; k1 < temp.length; k1++) {
sum += temp[k1] * vNew[k1][j];
}
vNew[0][j] = (q - sum) / temp[0];
temp = xUpperBoundary.getRightMatrixCondition(t, y[j]);
sum = 0;
for (int n = 0; n < temp.length; n++) {
sum += temp[n] * v[xSteps + n + 1 - temp.length][j];
}
q = sum + xUpperBoundary.getConstant(t, y[j], dx);
sum = 0;
temp = xUpperBoundary.getLeftMatrixCondition(t, y[j]);
for (int k1 = 0; k1 < temp.length - 1; k1++) {
sum += temp[k1] * vNew[xSteps + k1 + 1 - temp.length][j];
}
vNew[xSteps][j] = (q - sum) / temp[temp.length - 1];
}
// //average to find corners
// vNew[0][0] = (vNew[0][1]+vNew[1][0])/2;
// TODO American payoff
t += dt;
v = vNew;
}
return v;
}
}