void JacobianOnD(Mat J, Vec F, unsigned int i, int* pt, myCSField sf){
    if (i < sf->d){
        for (pt[i]=1;pt[i]<=sf->mesh[i];pt[i]++)
            JacobianOnD(J, F, i+1, pt, sf);
        return;
    }
    int r = linIdx_Sys(sf->d, sf->mesh, pt,0,0);
    unsigned int j;
    // a' u' + a u'' = F
    for (j=0;j<sf->d;j++){
        double ldx = dx(j, sf);
        double dx2 = ldx*ldx;
        double ap = Coeff(pt,j,+ldx/2., sf);
        double am = Coeff(pt,j,-ldx/2., sf);

        // Our operators are isotropic
        if (pt[j] > 1){
            int c = linIdx_Sys(sf->d, sf->mesh, pt, j, -1);
            MatSetValue(J, r, c, am/dx2, ADD_VALUES);
        }
        MatSetValue(J, r, r, -(am+ap)/dx2, ADD_VALUES);
        if (pt[j] < sf->mesh[j]){
            int c = linIdx_Sys(sf->d, sf->mesh, pt, j, 1);
            MatSetValue(J, r, c, ap/dx2, ADD_VALUES);
        }
    }

    double forcing = Forcing(pt, sf);
    VecSetValue(F, r, -forcing, INSERT_VALUES);
}
int main()
{
	// Set all ranges
	Range<double> X(Xfrom,Xto);
	Range<double> T(Yfrom,Yto);
	
	// Declare all TwoVarDFunctions
	TwoVarDFunction<double,double,double> Sigma(*sigma);
	TwoVarDFunction<double,double,double> Mu(*mu);
	TwoVarDFunction<double,double,double> Forcing(*forcing);
	TwoVarDFunction<double,double,double> B(*b);
	
	// Declare all AtomicDFunctions
	AtomicDFunction<double,double> Ic(*IC); // Change from Call<->Put
//	AtomicDFunction<double,double> Bcr(*BCR_Topper_p11);
	AtomicDFunction<double,double> Bcr(*BCR);// Change from Call<->Put
	AtomicDFunction<double,double> Bcl(*BCL);// Change from Call<->Put
	
	// Declare the pde
	ParabolicPDE<double,double,double> pde(X,T,Sigma,Mu,B,Forcing,Ic,Bcl,Bcr);

	// Declare the finite difference scheme
//	ParabolicFDM<double,double,double> FDM(pde,XINTERVALS,YINTERVALS,THETA); // V1
	int choice = 3;
	cout << "1) Explicit Euler 2) Implicit Euler 3) Crank Nicolson ";
	cin >> choice;

	//OptionType type = AmericanCallType;
	OptionType type = EuropeanCallType;

	ParabolicFDM<double,double,double> FDM(pde,XINTERVALS,YINTERVALS,choice,
											type);

	// compute option prices
	FDM.start();
	
	// Retrieve and store option prices
	Vector <double,long> result = FDM.line(); // Does include ENDS!!


///////////////////////////////////////////////////////////

	Vector<double, long> xArr = FDM.xarr();
	Vector<double, long> tArr = FDM.tarr();

	double h = xArr[2] - xArr[1];
	double k = tArr[2] - tArr[1];

	cout << "h " << h << endl;

	// Create and fill Delta vector
	Vector <double,long> DeltaMesh(xArr.Size()-2, xArr.MinIndex());
	for (long kk = DeltaMesh.MinIndex(); kk <= DeltaMesh.MaxIndex(); kk++)
	{
		DeltaMesh[kk] = xArr[kk+1];
	}

	Vector <double,long> Delta(result.Size()-2,result.MinIndex());
	for (long i = Delta.MinIndex(); i <= Delta.MaxIndex(); i++)
	{
		Delta[i] = (result[i+1] - result[i])/(h);
	}
	print(result);
	print(Delta);

	// Create and fill Gamma vector
	Vector <double,long> GammaMesh(DeltaMesh.Size()-2, DeltaMesh.MinIndex());
	for (long p = GammaMesh.MinIndex(); p <= GammaMesh.MaxIndex(); p++)
	{
		GammaMesh[p] = DeltaMesh[p+1];
	}

	Vector <double,long> Gamma(Delta.Size()-2, Delta.MinIndex());
	for (long n = Gamma.MinIndex(); n <= Gamma.MaxIndex(); n++)
	{
		Gamma[n] = (Delta[n+1] - Delta[n])/(h);
	}

	/*// Create and fill Theta vector
	Vector <double,long> ThetaMesh(tArr.Size()-1, tArr.MinIndex());
	for (long m = ThetaMesh.MinIndex(); m <= ThetaMesh.MaxIndex(); m++)
	{
		ThetaMesh[m] = tArr[m+1];
	}*/

	long NP1 = FDM.result().MaxRowIndex();
	long NP = FDM.result().MaxRowIndex() -1;

	Vector <double,long> Theta(result.Size(), result.MinIndex());
	for (long ii = Theta.MinIndex(); ii <= Theta.MaxIndex(); ii++)
	{
		Theta[ii] = -(FDM.result()(NP1, ii) -FDM.result()(NP, ii) )/k;
	}

	try
	{
		printOneExcel(FDM.xarr(), result, string("Price"));
		printOneExcel(DeltaMesh, Delta, string("Delta"));
		printOneExcel(GammaMesh, Gamma, string("Gamma"));
		printOneExcel(FDM.xarr(), Theta, string("Theta"));

	}
	catch(DatasimException& e)
	{
		e.print();

		ExcelDriver& excel = ExcelDriver::Instance();
		excel.MakeVisible(true);	

		long y = 1;
		excel.printStringInExcel(e.Message(), y, y, string("Err"));

		list<string> dump;
		dump.push_back(e.MessageDump()[0]);
		dump.push_back(e.MessageDump()[1]);
		dump.push_back(e.MessageDump()[2]);

		excel.printStringInExcel(dump, 1, 1, string("Err"));

		return 0;
	}

	return 0;
}