/**
* 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 org.apache.commons.lang.Validate;
//
//import com.opengamma.analytics.financial.model.finitedifference.ThetaMethodFiniteDifference.SolverImpl;
//
///**
// * PDE solver for the type
// * $\frac{\partial f}{\partial t} + a(t,x)\frac{\partial^2}{\partial x^2}\left[ \alpha(t,x) f \right] + * b(t,x)\frac{\partial}{\partial x}\left[\beta(t,x) f \right] + c(t,x)f = 0$
// * , which includes the Fokker-Planck PDE. If the terms $\alpha$ and $\beta$
// * are constant or can be simply differentiated, this can be written in the form
// * $\frac{\partial f}{\partial t} + a^*(t,x)\frac{\partial^2f}{\partial x^2} + b^*(t,x)\frac{\partial f}{\partial x} + c^*(t,x)f = 0$
// * and solved by ThetaMethodFiniteDifference
// */
//public class ExtendedThetaMethodFiniteDifference implements PDE1DSolver<ParabolicPDEExtendedCoefficients> {
//
// public ExtendedThetaMethodFiniteDifference(final double theta, final boolean showFullResults) {
// super(theta, showFullResults);
// }
//
// public PDEResults1D solve(PDE1DDataBundle<ParabolicPDEExtendedCoefficients> pdeData) {
// Validate.notNull(pdeData, "pde data");
// SolverImpl solver = new ExtendedSolverImpl(pdeData);
// return solver.solve();
// }
//
// //TODO this should @Override
// public PDEResults1D solve(final ExtendedConvectionDiffusionPDEDataBundle pdeData, final PDEGrid1D grid, final BoundaryCondition lowerBoundary, final BoundaryCondition upperBoundary) {
//
// Validate.notNull(pdeData, "pde data");
// Validate.notNull(grid, "need a grid");
//
// SolverImpl solver = new ExtendedSolverImpl(pdeData, grid, lowerBoundary, upperBoundary, null);
// return solver.solve();
//
// }
//
// private static PDE1DDataBundle<ConvectionDiffusionPDE1DStandardCofficients> toParabolicPDECoefficients(final PDE1DDataBundle<ParabolicPDEExtendedCoefficients> pdeData) {
// final ConvectionDiffusionPDE1DStandardCofficients coeff = pdeData.getCoefficients().getStandardCoefficients();
// if (pdeData.getFreeBoundary() == null) {
// return new PDE1DDataBundle<ConvectionDiffusionPDE1DStandardCofficients>(coeff, pdeData.getInitialCondition(), pdeData.getLowerBoundary(), pdeData.getUpperBoundary(),
// pdeData.getGrid());
// }
// return new PDE1DDataBundle<ConvectionDiffusionPDE1DStandardCofficients>(coeff, pdeData.getInitialCondition(), pdeData.getLowerBoundary(), pdeData.getUpperBoundary(),
// pdeData.getFreeBoundary(), pdeData.getGrid());
// }
//
// private class ExtendedSolverImpl extends SolverImpl {
//
// //private final ExtendedConvectionDiffusionPDEDataBundle _pdeData;
// private final ParabolicPDEExtendedCoefficients _coeff;
// private final double[] _alpha;
// private final double[] _beta;
//
// public ExtendedSolverImpl(final PDE1DDataBundle<ParabolicPDEExtendedCoefficients> pdeData) {
// super(toParabolicPDECoefficients(pdeData));
// _coeff = pdeData.getCoefficients();
// final int xNodes = pdeData.getGrid().getNumSpaceNodes();
// _alpha = new double[xNodes];
// _beta = new double[xNodes];
// }
//
// /**
// * @param pdeData
// * @param grid
// * @param lowerBoundary
// * @param upperBoundary
// * @param freeBoundary
// */
// // public ExtendedSolverImpl(ExtendedConvectionDiffusionPDEDataBundle pdeData, PDEGrid1D grid, BoundaryCondition lowerBoundary, BoundaryCondition upperBoundary,
// // Surface<Double, Double, Double> freeBoundary) {
// // super(pdeData, grid, lowerBoundary, upperBoundary, freeBoundary);
// // _pdeData = pdeData;
// // final int xNodes = grid.getNumSpaceNodes();
// // _alpha = new double[xNodes];
// // _beta = new double[xNodes];
// // }
//
// @Override
// void initialise() {
// super.initialise();
// double x;
// double t = getT1();
// for (int i = 0; i < getGrid().getNumSpaceNodes(); i++) {
// x = getGrid().getSpaceNode(i);
// _alpha[i] = _coeff.getAlpha(t, x);
// _beta[i] = _coeff.getBeta(t, x);
// }
// }
//
// @Override
// void updateRHSVector() {
// double dt = getT2() - getT1();
// double[] x1st, x2nd;
// double temp;
// for (int i = 1; i < getGrid().getNumSpaceNodes() - 1; i++) {
// x1st = getGrid().getFirstDerivativeCoefficients(i);
// x2nd = getGrid().getSecondDerivativeCoefficients(i);
// //TODO Work out a fitting scheme
// temp = getF(i);
// temp -= (1 - getTheta()) * dt * (x2nd[0] * getA(i - 1) * _alpha[i - 1] + x1st[0] * getB(i - 1) * _beta[i - 1]) * getF(i - 1);
// temp -= (1 - getTheta()) * dt * (x2nd[1] * getA(i - 1) * _alpha[i] + x1st[1] * getB(i - 1) * _beta[i] + getC(i - 1)) * getF(i);
// temp -= (1 - getTheta()) * dt * (x2nd[2] * getA(i - 1) * _alpha[i + 1] + x1st[2] * getB(i - 1) * _beta[i + 1]) * getF(i + 1);
// setQ(i, temp);
// }
// }
//
// @Override
// void updateLHSMatrix() {
// double dt = getT2() - getT1();
// double[] x1st, x2nd;
// for (int i = 1; i < getGrid().getNumSpaceNodes() - 1; i++) {
// x1st = getGrid().getFirstDerivativeCoefficients(i);
// x2nd = getGrid().getSecondDerivativeCoefficients(i);
//
// setM(i, i - 1, getTheta() * dt * (x2nd[0] * getA(i - 1) * _alpha[i - 1] + x1st[0] * getB(i - 1) * _beta[i - 1]));
// setM(i, i, 1 + getTheta() * dt * (x2nd[1] * getA(i - 1) * _alpha[i] + x1st[1] * getB(i - 1) * _beta[i] + getC(i - 1)));
// setM(i, i + 1, getTheta() * dt * (x2nd[2] * getA(i - 1) * _alpha[i + 1] + x1st[2] * getB(i - 1) * _beta[i + 1]));
// }
// }
//
// @Override
// void updateCoefficents() {
// super.updateCoefficents();
// double x;
// for (int i = 0; i < getGrid().getNumSpaceNodes(); i++) {
// x = getGrid().getSpaceNode(i);
// _alpha[i] = _coeff.getAlpha(getT2(), x);
// _beta[i] = _coeff.getBeta(getT2(), x);
// }
// }
//
// }
//
//}