public void testDerivativeWeightsOnNonUniformGrids() { Fdm1dMesher mesherX = new Concentrating1dMesher(-2.0, 3.0, 50, new Pair <double?, double?>(0.5, 0.01)); Fdm1dMesher mesherY = new Concentrating1dMesher(0.5, 5.0, 25, new Pair <double?, double?>(0.5, 0.1)); Fdm1dMesher mesherZ = new Concentrating1dMesher(-1.0, 2.0, 31, new Pair <double?, double?>(1.5, 0.01)); FdmMesher meshers = new FdmMesherComposite(mesherX, mesherY, mesherZ); FdmLinearOpLayout layout = meshers.layout(); FdmLinearOpIterator endIter = layout.end(); double tol = 1e-13; for (int direction = 0; direction < 3; ++direction) { SparseMatrix dfdx = new FirstDerivativeOp(direction, meshers).toMatrix(); SparseMatrix d2fdx2 = new SecondDerivativeOp(direction, meshers).toMatrix(); Vector gridPoints = meshers.locations(direction); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { int c = iter.coordinates()[direction]; int index = iter.index(); int indexM1 = layout.neighbourhood(iter, direction, -1); int indexP1 = layout.neighbourhood(iter, direction, +1); // test only if not on the boundary if (c == 0) { Vector twoPoints = new Vector(2); twoPoints[0] = 0.0; twoPoints[1] = gridPoints[indexP1] - gridPoints[index]; Vector ndWeights1st = new NumericalDifferentiation(x => x, 1, twoPoints).weights(); double beta1 = dfdx[index, index]; double gamma1 = dfdx[index, indexP1]; if (Math.Abs((beta1 - ndWeights1st[0]) / beta1) > tol || Math.Abs((gamma1 - ndWeights1st[1]) / gamma1) > tol) { QAssert.Fail("can not reproduce the weights of the " + "first order derivative operator " + "on the lower boundary" + "\n expected beta: " + ndWeights1st[0] + "\n calculated beta: " + beta1 + "\n difference beta: " + (beta1 - ndWeights1st[0]) + "\n expected gamma: " + ndWeights1st[1] + "\n calculated gamma: " + gamma1 + "\n difference gamma: " + (gamma1 - ndWeights1st[1])); } // free boundary condition by default double beta2 = d2fdx2[index, index]; double gamma2 = d2fdx2[index, indexP1]; if (Math.Abs(beta2) > Const.QL_EPSILON || Math.Abs(gamma2) > Const.QL_EPSILON) { QAssert.Fail("can not reproduce the weights of the " + "second order derivative operator " + "on the lower boundary" + "\n expected beta: " + 0.0 + "\n calculated beta: " + beta2 + "\n expected gamma: " + 0.0 + "\n calculated gamma: " + gamma2); } } else if (c == layout.dim()[direction] - 1) { Vector twoPoints = new Vector(2); twoPoints[0] = gridPoints[indexM1] - gridPoints[index]; twoPoints[1] = 0.0; Vector ndWeights1st = new NumericalDifferentiation(x => x, 1, twoPoints).weights(); double alpha1 = dfdx[index, indexM1]; double beta1 = dfdx[index, index]; if (Math.Abs((alpha1 - ndWeights1st[0]) / alpha1) > tol || Math.Abs((beta1 - ndWeights1st[1]) / beta1) > tol) { QAssert.Fail("can not reproduce the weights of the " + "first order derivative operator " + "on the upper boundary" + "\n expected alpha: " + ndWeights1st[0] + "\n calculated alpha: " + alpha1 + "\n difference alpha: " + (alpha1 - ndWeights1st[0]) + "\n expected beta: " + ndWeights1st[1] + "\n calculated beta: " + beta1 + "\n difference beta: " + (beta1 - ndWeights1st[1])); } // free boundary condition by default double alpha2 = d2fdx2[index, indexM1]; double beta2 = d2fdx2[index, index]; if (Math.Abs(alpha2) > Const.QL_EPSILON || Math.Abs(beta2) > Const.QL_EPSILON) { QAssert.Fail("can not reproduce the weights of the " + "second order derivative operator " + "on the upper boundary" + "\n expected alpha: " + 0.0 + "\n calculated alpha: " + alpha2 + "\n expected beta: " + 0.0 + "\n calculated beta: " + beta2); } } else { Vector threePoints = new Vector(3); threePoints[0] = gridPoints[indexM1] - gridPoints[index]; threePoints[1] = 0.0; threePoints[2] = gridPoints[indexP1] - gridPoints[index]; Vector ndWeights1st = new NumericalDifferentiation(x => x, 1, threePoints).weights(); double alpha1 = dfdx[index, indexM1]; double beta1 = dfdx[index, index]; double gamma1 = dfdx[index, indexP1]; if (Math.Abs((alpha1 - ndWeights1st[0]) / alpha1) > tol || Math.Abs((beta1 - ndWeights1st[1]) / beta1) > tol || Math.Abs((gamma1 - ndWeights1st[2]) / gamma1) > tol) { QAssert.Fail("can not reproduce the weights of the " + "first order derivative operator" + "\n expected alpha: " + ndWeights1st[0] + "\n calculated alpha: " + alpha1 + "\n difference alpha: " + (alpha1 - ndWeights1st[0]) + "\n expected beta: " + ndWeights1st[1] + "\n calculated beta: " + beta1 + "\n difference beta: " + (beta1 - ndWeights1st[1]) + "\n expected gamma: " + ndWeights1st[2] + "\n calculated gamma: " + gamma1 + "\n difference gamma: " + (gamma1 - ndWeights1st[2])); } Vector ndWeights2nd = new NumericalDifferentiation(x => x, 2, threePoints).weights(); double alpha2 = d2fdx2[index, indexM1]; double beta2 = d2fdx2[index, index]; double gamma2 = d2fdx2[index, indexP1]; if (Math.Abs((alpha2 - ndWeights2nd[0]) / alpha2) > tol || Math.Abs((beta2 - ndWeights2nd[1]) / beta2) > tol || Math.Abs((gamma2 - ndWeights2nd[2]) / gamma2) > tol) { QAssert.Fail("can not reproduce the weights of the " + "second order derivative operator" + "\n expected alpha: " + ndWeights2nd[0] + "\n calculated alpha: " + alpha2 + "\n difference alpha: " + (alpha2 - ndWeights2nd[0]) + "\n expected beta: " + ndWeights2nd[1] + "\n calculated beta: " + beta2 + "\n difference beta: " + (beta2 - ndWeights2nd[1]) + "\n expected gamma: " + ndWeights2nd[2] + "\n calculated gamma: " + gamma2 + "\n difference gamma: " + (gamma2 - ndWeights2nd[2])); } } } } }
public void testTripleBandMapSolve() { int[] dims = new int[] { 100, 400 }; List <int> dim = new List <int>(dims); FdmLinearOpLayout layout = new FdmLinearOpLayout(dim); List <Pair <double?, double?> > boundaries = new List <Pair <double?, double?> > (); boundaries.Add(new Pair <double?, double?>(0, 1.0)); boundaries.Add(new Pair <double?, double?>(0, 1.0)); FdmMesher mesher = new UniformGridMesher(layout, boundaries); FirstDerivativeOp dy = new FirstDerivativeOp(1, mesher); dy.axpyb(new Vector(1, 2.0), dy, dy, new Vector(1, 1.0)); // check copy constructor FirstDerivativeOp copyOfDy = new FirstDerivativeOp(dy); Vector u = new Vector(layout.size()); for (int i = 0; i < layout.size(); ++i) { u[i] = Math.Sin(0.1 * i) + Math.Cos(0.35 * i); } Vector t = new Vector(dy.solve_splitting(copyOfDy.apply(u), 1.0, 0.0)); for (int i = 0; i < u.size(); ++i) { if (Math.Abs(u[i] - t[i]) > 1e-6) { QAssert.Fail("solve and apply are not consistent " + "\n expected : " + u[i] + "\n calculated : " + t[i]); } } FirstDerivativeOp dx = new FirstDerivativeOp(0, mesher); dx.axpyb(new Vector(), dx, dx, new Vector(1, 1.0)); FirstDerivativeOp copyOfDx = new FirstDerivativeOp(0, mesher); // check assignment copyOfDx = dx; t = dx.solve_splitting(copyOfDx.apply(u), 1.0, 0.0); for (int i = 0; i < u.size(); ++i) { if (Math.Abs(u[i] - t[i]) > 1e-6) { QAssert.Fail("solve and apply are not consistent " + "\n expected : " + u[i] + "\n calculated : " + t[i]); } } SecondDerivativeOp dxx = new SecondDerivativeOp(0, mesher); dxx.axpyb(new Vector(1, 0.5), dxx, dx, new Vector(1, 1.0)); // check of copy constructor SecondDerivativeOp copyOfDxx = new SecondDerivativeOp(dxx); t = dxx.solve_splitting(copyOfDxx.apply(u), 1.0, 0.0); for (int i = 0; i < u.size(); ++i) { if (Math.Abs(u[i] - t[i]) > 1e-6) { QAssert.Fail("solve and apply are not consistent " + "\n expected : " + u[i] + "\n calculated : " + t[i]); } } //check assignment operator copyOfDxx.add(new SecondDerivativeOp(1, mesher)); copyOfDxx = dxx; t = dxx.solve_splitting(copyOfDxx.apply(u), 1.0, 0.0); for (int i = 0; i < u.size(); ++i) { if (Math.Abs(u[i] - t[i]) > 1e-6) { QAssert.Fail("solve and apply are not consistent " + "\n expected : " + u[i] + "\n calculated : " + t[i]); } } }
public void testSecondDerivativesMapApply() { int[] dims = new int[] { 50, 50, 50 }; List <int> dim = new List <int>(dims); FdmLinearOpLayout index = new FdmLinearOpLayout(dim); List <Pair <double?, double?> > boundaries = new List <Pair <double?, double?> > (); boundaries.Add(new Pair <double?, double?>(0, 0.5)); boundaries.Add(new Pair <double?, double?>(0, 0.5)); boundaries.Add(new Pair <double?, double?>(0, 0.5)); FdmMesher mesher = new UniformGridMesher(index, boundaries); Vector r = new Vector(mesher.layout().size()); FdmLinearOpIterator endIter = index.end(); for (FdmLinearOpIterator iter = index.begin(); iter != endIter; ++iter) { double x = mesher.location(iter, 0); double y = mesher.location(iter, 1); double z = mesher.location(iter, 2); r[iter.index()] = Math.Sin(x) * Math.Cos(y) * Math.Exp(z); } Vector t = new SecondDerivativeOp(0, mesher).apply(r); double tol = 5e-2; for (FdmLinearOpIterator iter = index.begin(); iter != endIter; ++iter) { int i = iter.index(); double x = mesher.location(iter, 0); double y = mesher.location(iter, 1); double z = mesher.location(iter, 2); double d = -Math.Sin(x) * Math.Cos(y) * Math.Exp(z); if (iter.coordinates()[0] == 0 || iter.coordinates()[0] == dims[0] - 1) { d = 0; } if (Math.Abs(d - t[i]) > tol) { QAssert.Fail("numerical derivative in dx^2 deviation is too big" + "\n found at " + x + " " + y + " " + z); } } t = new SecondDerivativeOp(1, mesher).apply(r); for (FdmLinearOpIterator iter = index.begin(); iter != endIter; ++iter) { int i = iter.index(); double x = mesher.location(iter, 0); double y = mesher.location(iter, 1); double z = mesher.location(iter, 2); double d = -Math.Sin(x) * Math.Cos(y) * Math.Exp(z); if (iter.coordinates()[1] == 0 || iter.coordinates()[1] == dims[1] - 1) { d = 0; } if (Math.Abs(d - t[i]) > tol) { QAssert.Fail("numerical derivative in dy^2 deviation is too big" + "\n found at " + x + " " + y + " " + z); } } t = new SecondDerivativeOp(2, mesher).apply(r); for (FdmLinearOpIterator iter = index.begin(); iter != endIter; ++iter) { int i = iter.index(); double x = mesher.location(iter, 0); double y = mesher.location(iter, 1); double z = mesher.location(iter, 2); double d = Math.Sin(x) * Math.Cos(y) * Math.Exp(z); if (iter.coordinates()[2] == 0 || iter.coordinates()[2] == dims[2] - 1) { d = 0; } if (Math.Abs(d - t[i]) > tol) { QAssert.Fail("numerical derivative in dz^2 deviation is too big" + "\n found at " + x + " " + y + " " + z); } } }