public override void update() { TridiagonalOperator L = new TridiagonalOperator(cH_.n_); Array<double> tmp = new Array<double>(cH_.n_); var dx = new Array<double>(cH_.n_ - 1); var S = new Array<double>(cH_.n_ - 1); int i=0; dx[i] = this.xBegin_[i+1] - this.xBegin_[i]; S[i] = (this.yBegin_[i+1] - this.yBegin_[i])/dx[i]; for (i=1; i<cH_.n_-1; ++i) { dx[i] = this.xBegin_[i+1] - this.xBegin_[i]; S[i] = (this.yBegin_[i+1] - this.yBegin_[i])/dx[i]; L.setMidRow(i, dx[i], 2.0*(dx[i]+dx[i-1]), dx[i-1]); tmp[i] = 3.0*(dx[i]*S[i-1] + dx[i-1]*S[i]); } /**** BOUNDARY CONDITIONS ****/ // left condition switch (leftType_) { case CubicSplineInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setFirstRow(dx[1]*(dx[1]+dx[0]), (dx[0]+dx[1])*(dx[0]+dx[1])); tmp[0] = S[0]*dx[1]*(2.0*dx[1]+3.0*dx[0]) + S[1]*dx[0]*dx[0]; break; case CubicSplineInterpolation.BoundaryCondition.FirstDerivative: L.setFirstRow(1.0, 0.0); tmp[0] = leftValue_; break; case CubicSplineInterpolation.BoundaryCondition.SecondDerivative: L.setFirstRow(2.0, 1.0); tmp[0] = 3.0*S[0] - leftValue_*dx[0]/2.0; break; case CubicSplineInterpolation.BoundaryCondition.Periodic: case CubicSplineInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new ApplicationException("this end condition is not implemented yet"); default: throw new ApplicationException("unknown end condition"); } // right condition switch (rightType_) { case CubicSplineInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setLastRow(-(dx[cH_.n_-2]+dx[cH_.n_-3])*(dx[cH_.n_-2]+dx[cH_.n_-3]), -dx[cH_.n_-3]*(dx[cH_.n_-3]+dx[cH_.n_-2])); tmp[cH_.n_-1] = -S[cH_.n_-3]*dx[cH_.n_-2]*dx[cH_.n_-2] - S[cH_.n_-2]*dx[cH_.n_-3]*(3.0*dx[cH_.n_-2]+2.0*dx[cH_.n_-3]); break; case CubicSplineInterpolation.BoundaryCondition.FirstDerivative: L.setLastRow(0.0, 1.0); tmp[cH_.n_-1] = rightValue_; break; case CubicSplineInterpolation.BoundaryCondition.SecondDerivative: L.setLastRow(1.0, 2.0); tmp[cH_.n_-1] = 3.0*S[cH_.n_-2] + rightValue_*dx[cH_.n_-2]/2.0; break; case CubicSplineInterpolation.BoundaryCondition.Periodic: case CubicSplineInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new ApplicationException("this end condition is not implemented yet"); default: throw new ApplicationException("unknown end condition"); } // solve the system tmp = L.solveFor(tmp); for (int j = 0; i < cH_.monotonicityAdjustments_.Count; j++ ) cH_.monotonicityAdjustments_[j] = false; if (constrained_) { double correction; double pm, pu, pd, M; for (i=0; i<cH_.n_; ++i) { if (i==0) { if (tmp[i]*S[0]>0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0*S[0])); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; cH_.monotonicityAdjustments_[i] = true; } } else if (i==cH_.n_-1) { if (tmp[i]*S[cH_.n_-2]>0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0*S[cH_.n_-2])); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; cH_.monotonicityAdjustments_[i] = true; } } else { pm=(S[i-1]*dx[i]+S[i]*dx[i-1])/ (dx[i-1]+dx[i]); M = 3.0 * Math.Min(Math.Min(Math.Abs(S[i-1]), Math.Abs(S[i])), Math.Abs(pm)); if (i>1) { if ((S[i-1]-S[i-2])*(S[i]-S[i-1])>0.0) { pd=(S[i-1]*(2.0*dx[i-1]+dx[i-2]) -S[i-2]*dx[i-1])/ (dx[i-2]+dx[i-1]); if (pm*pd>0.0 && pm*(S[i-1]-S[i-2])>0.0) { M = Math.Max(M, 1.5*Math.Min( Math.Abs(pm),Math.Abs(pd))); } } } if (i<cH_.n_-2) { if ((S[i]-S[i-1])*(S[i+1]-S[i])>0.0) { pu=(S[i]*(2.0*dx[i]+dx[i+1])-S[i+1]*dx[i])/ (dx[i]+dx[i+1]); if (pm*pu>0.0 && -pm*(S[i]-S[i-1])>0.0) { M = Math.Max(M, 1.5*Math.Min( Math.Abs(pm),Math.Abs(pu))); } } } if (tmp[i]*pm>0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), M); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; cH_.monotonicityAdjustments_[i] = true; } } } } for (i=0; i<cH_.n_-1; ++i) { cH_.a_[i] = tmp[i]; cH_.b_[i] = (3.0*S[i] - tmp[i+1] - 2.0*tmp[i])/dx[i]; cH_.c_[i] = (tmp[i+1] + tmp[i] - 2.0*S[i])/(dx[i]*dx[i]); } cH_.primitiveConst_[0] = 0.0; for (i=1; i<cH_.n_-1; ++i) { cH_.primitiveConst_[i] = cH_.primitiveConst_[i-1] + dx[i-1] * (this.yBegin_[i-1] + dx[i-1] * (cH_.a_[i-1]/2.0 + dx[i-1] * (cH_.b_[i-1]/3.0 + dx[i-1] * cH_.c_[i-1]/4.0))); } }
public override void update() { Vector tmp = new Vector(size_); List<double> dx = new InitializedList<double>(size_ - 1), S = new InitializedList<double>(size_ - 1); for (int i = 0; i < size_ - 1; ++i) { dx[i] = xBegin_[i+1] - xBegin_[i]; S[i] = (yBegin_[i+1] - yBegin_[i])/dx[i]; } // first derivative approximation if (da_==CubicInterpolation.DerivativeApprox.Spline) { TridiagonalOperator L = new TridiagonalOperator(size_); for (int i = 1; i < size_ - 1; ++i) { L.setMidRow(i, dx[i], 2.0*(dx[i]+dx[i-1]), dx[i-1]); tmp[i] = 3.0*(dx[i]*S[i-1] + dx[i-1]*S[i]); } // left boundary condition switch (leftType_) { case CubicInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setFirstRow(dx[1]*(dx[1]+dx[0]), (dx[0]+dx[1])*(dx[0]+dx[1])); tmp[0] = S[0]*dx[1]*(2.0*dx[1]+3.0*dx[0]) + S[1]*dx[0]*dx[0]; break; case CubicInterpolation.BoundaryCondition.FirstDerivative: L.setFirstRow(1.0, 0.0); tmp[0] = leftValue_; break; case CubicInterpolation.BoundaryCondition.SecondDerivative: L.setFirstRow(2.0, 1.0); tmp[0] = 3.0*S[0] - leftValue_*dx[0]/2.0; break; case CubicInterpolation.BoundaryCondition.Periodic: case CubicInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); default: throw new ArgumentException("unknown end condition"); } // right boundary condition switch (rightType_) { case CubicInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setLastRow(-(dx[size_ - 2] + dx[size_ - 3]) * (dx[size_ - 2] + dx[size_ - 3]), -dx[size_ - 3] * (dx[size_ - 3] + dx[size_ - 2])); tmp[size_ - 1] = -S[size_ - 3] * dx[size_ - 2] * dx[size_ - 2] - S[size_ - 2] * dx[size_ - 3] * (3.0 * dx[size_ - 2] + 2.0 * dx[size_ - 3]); break; case CubicInterpolation.BoundaryCondition.FirstDerivative: L.setLastRow(0.0, 1.0); tmp[size_ - 1] = rightValue_; break; case CubicInterpolation.BoundaryCondition.SecondDerivative: L.setLastRow(1.0, 2.0); tmp[size_ - 1] = 3.0 * S[size_ - 2] + rightValue_ * dx[size_ - 2] / 2.0; break; case CubicInterpolation.BoundaryCondition.Periodic: case CubicInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); default: throw new ArgumentException("unknown end condition"); } // solve the system tmp = L.solveFor(tmp); } else { // local schemes if (size_ == 2) tmp[0] = tmp[1] = S[0]; else { switch (da_) { case CubicInterpolation.DerivativeApprox.FourthOrder: throw new NotImplementedException("FourthOrder not implemented yet"); break; case CubicInterpolation.DerivativeApprox.Parabolic: // intermediate points for (int i = 1; i < size_ - 1; ++i) { tmp[i] = (dx[i - 1] * S[i] + dx[i] * S[i - 1]) / (dx[i] + dx[i - 1]); } // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; break; case CubicInterpolation.DerivativeApprox.FritschButland: // intermediate points for (int i=1; i<size_-1; ++i) { double Smin = Math.Min(S[i-1], S[i]); double Smax = Math.Max(S[i-1], S[i]); tmp[i] = 3.0*Smin*Smax/(Smax+2.0*Smin); } // end points tmp[0] = ((2.0*dx[ 0]+dx[ 1])*S[ 0] - dx[ 0]*S[ 1]) / (dx[ 0]+dx[ 1]); tmp[size_-1] = ((2.0*dx[size_-2]+dx[size_-3])*S[size_-2] - dx[size_-2]*S[size_-3]) / (dx[size_-2]+dx[size_-3]); break; case CubicInterpolation.DerivativeApprox.Akima: throw new NotImplementedException("Akima not implemented yet"); // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; case CubicInterpolation.DerivativeApprox.Kruger: // intermediate points for (int i = 1; i < size_ - 1; ++i) { if (S[i-1]*S[i]<0.0) // slope changes sign at point tmp[i] = 0.0; else // slope will be between the slopes of the adjacent // straight lines and should approach zero if the // slope of either line approaches zero tmp[i] = 2.0/(1.0/S[i-1]+1.0/S[i]); } // end points tmp[0] = (3.0*S[0]-tmp[1])/2.0; tmp[size_ - 1] = (3.0 * S[size_ - 2] - tmp[size_ - 2]) / 2.0; break; default: throw new ArgumentException("unknown scheme"); } } } monotonicityAdjustments_.Erase(); // Hyman monotonicity constrained filter if (monotonic_) { double correction; double pm, pu, pd, M; for (int i = 0; i < size_; ++i) { if (i==0) { if (tmp[i]*S[0]>0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0*S[0])); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } else if (i == size_ - 1) { if (tmp[i] * S[size_ - 2] > 0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0 * S[size_ - 2])); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } else { pm=(S[i-1]*dx[i]+S[i]*dx[i-1])/ (dx[i-1]+dx[i]); M = 3.0 * Math.Min(Math.Min(Math.Abs(S[i-1]), Math.Abs(S[i])), Math.Abs(pm)); if (i>1) { if ((S[i-1]-S[i-2])*(S[i]-S[i-1])>0.0) { pd=(S[i-1]*(2.0*dx[i-1]+dx[i-2]) -S[i-2]*dx[i-1])/ (dx[i-2]+dx[i-1]); if (pm*pd>0.0 && pm*(S[i-1]-S[i-2])>0.0) { M = Math.Max(M, 1.5*Math.Min( Math.Abs(pm),Math.Abs(pd))); } } } if (i < size_ - 2) { if ((S[i]-S[i-1])*(S[i+1]-S[i])>0.0) { pu=(S[i]*(2.0*dx[i]+dx[i+1])-S[i+1]*dx[i])/ (dx[i]+dx[i+1]); if (pm*pu>0.0 && -pm*(S[i]-S[i-1])>0.0) { M = Math.Max(M, 1.5*Math.Min( Math.Abs(pm),Math.Abs(pu))); } } } if (tmp[i]*pm>0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), M); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } } } // cubic coefficients for (int i = 0; i < size_ - 1; ++i) { a_[i] = tmp[i]; b_[i] = (3.0*S[i] - tmp[i+1] - 2.0*tmp[i])/dx[i]; c_[i] = (tmp[i+1] + tmp[i] - 2.0*S[i])/(dx[i]*dx[i]); } primitiveConst_[0] = 0.0; for (int i = 1; i < size_ - 1; ++i) { primitiveConst_[i] = primitiveConst_[i-1] + dx[i-1] * (yBegin_[i-1] + dx[i-1] * (a_[i-1]/2.0 + dx[i-1] * (b_[i-1]/3.0 + dx[i-1] * c_[i-1]/4.0))); } }
public override void update() { Vector tmp = new Vector(size_); List <double> dx = new InitializedList <double>(size_ - 1), S = new InitializedList <double>(size_ - 1); for (int i = 0; i < size_ - 1; ++i) { dx[i] = xBegin_[i + 1] - xBegin_[i]; S[i] = (yBegin_[i + 1] - yBegin_[i]) / dx[i]; } // first derivative approximation if (da_ == CubicInterpolation.DerivativeApprox.Spline) { TridiagonalOperator L = new TridiagonalOperator(size_); for (int i = 1; i < size_ - 1; ++i) { L.setMidRow(i, dx[i], 2.0 * (dx[i] + dx[i - 1]), dx[i - 1]); tmp[i] = 3.0 * (dx[i] * S[i - 1] + dx[i - 1] * S[i]); } // left boundary condition switch (leftType_) { case CubicInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setFirstRow(dx[1] * (dx[1] + dx[0]), (dx[0] + dx[1]) * (dx[0] + dx[1])); tmp[0] = S[0] * dx[1] * (2.0 * dx[1] + 3.0 * dx[0]) + S[1] * dx[0] * dx[0]; break; case CubicInterpolation.BoundaryCondition.FirstDerivative: L.setFirstRow(1.0, 0.0); tmp[0] = leftValue_; break; case CubicInterpolation.BoundaryCondition.SecondDerivative: L.setFirstRow(2.0, 1.0); tmp[0] = 3.0 * S[0] - leftValue_ * dx[0] / 2.0; break; case CubicInterpolation.BoundaryCondition.Periodic: case CubicInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); default: throw new ArgumentException("unknown end condition"); } // right boundary condition switch (rightType_) { case CubicInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setLastRow(-(dx[size_ - 2] + dx[size_ - 3]) * (dx[size_ - 2] + dx[size_ - 3]), -dx[size_ - 3] * (dx[size_ - 3] + dx[size_ - 2])); tmp[size_ - 1] = -S[size_ - 3] * dx[size_ - 2] * dx[size_ - 2] - S[size_ - 2] * dx[size_ - 3] * (3.0 * dx[size_ - 2] + 2.0 * dx[size_ - 3]); break; case CubicInterpolation.BoundaryCondition.FirstDerivative: L.setLastRow(0.0, 1.0); tmp[size_ - 1] = rightValue_; break; case CubicInterpolation.BoundaryCondition.SecondDerivative: L.setLastRow(1.0, 2.0); tmp[size_ - 1] = 3.0 * S[size_ - 2] + rightValue_ * dx[size_ - 2] / 2.0; break; case CubicInterpolation.BoundaryCondition.Periodic: case CubicInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); default: throw new ArgumentException("unknown end condition"); } // solve the system tmp = L.solveFor(tmp); } else // local schemes { if (size_ == 2) { tmp[0] = tmp[1] = S[0]; } else { switch (da_) { case CubicInterpolation.DerivativeApprox.FourthOrder: throw new NotImplementedException("FourthOrder not implemented yet"); break; case CubicInterpolation.DerivativeApprox.Parabolic: // intermediate points for (int i = 1; i < size_ - 1; ++i) { tmp[i] = (dx[i - 1] * S[i] + dx[i] * S[i - 1]) / (dx[i] + dx[i - 1]); } // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; break; case CubicInterpolation.DerivativeApprox.FritschButland: // intermediate points for (int i = 1; i < size_ - 1; ++i) { double Smin = Math.Min(S[i - 1], S[i]); double Smax = Math.Max(S[i - 1], S[i]); tmp[i] = 3.0 * Smin * Smax / (Smax + 2.0 * Smin); } // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; case CubicInterpolation.DerivativeApprox.Akima: throw new NotImplementedException("Akima not implemented yet"); // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; case CubicInterpolation.DerivativeApprox.Kruger: // intermediate points for (int i = 1; i < size_ - 1; ++i) { if (S[i - 1] * S[i] < 0.0) { // slope changes sign at point tmp[i] = 0.0; } else { // slope will be between the slopes of the adjacent // straight lines and should approach zero if the // slope of either line approaches zero tmp[i] = 2.0 / (1.0 / S[i - 1] + 1.0 / S[i]); } } // end points tmp[0] = (3.0 * S[0] - tmp[1]) / 2.0; tmp[size_ - 1] = (3.0 * S[size_ - 2] - tmp[size_ - 2]) / 2.0; break; default: throw new ArgumentException("unknown scheme"); } } } monotonicityAdjustments_.Erase(); // Hyman monotonicity constrained filter if (monotonic_) { double correction; double pm, pu, pd, M; for (int i = 0; i < size_; ++i) { if (i == 0) { if (tmp[i] * S[0] > 0.0) { correction = tmp[i] / Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0 * S[0])); } else { correction = 0.0; } if (correction != tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } else if (i == size_ - 1) { if (tmp[i] * S[size_ - 2] > 0.0) { correction = tmp[i] / Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0 * S[size_ - 2])); } else { correction = 0.0; } if (correction != tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } else { pm = (S[i - 1] * dx[i] + S[i] * dx[i - 1]) / (dx[i - 1] + dx[i]); M = 3.0 * Math.Min(Math.Min(Math.Abs(S[i - 1]), Math.Abs(S[i])), Math.Abs(pm)); if (i > 1) { if ((S[i - 1] - S[i - 2]) * (S[i] - S[i - 1]) > 0.0) { pd = (S[i - 1] * (2.0 * dx[i - 1] + dx[i - 2]) - S[i - 2] * dx[i - 1]) / (dx[i - 2] + dx[i - 1]); if (pm * pd > 0.0 && pm * (S[i - 1] - S[i - 2]) > 0.0) { M = Math.Max(M, 1.5 * Math.Min( Math.Abs(pm), Math.Abs(pd))); } } } if (i < size_ - 2) { if ((S[i] - S[i - 1]) * (S[i + 1] - S[i]) > 0.0) { pu = (S[i] * (2.0 * dx[i] + dx[i + 1]) - S[i + 1] * dx[i]) / (dx[i] + dx[i + 1]); if (pm * pu > 0.0 && -pm * (S[i] - S[i - 1]) > 0.0) { M = Math.Max(M, 1.5 * Math.Min( Math.Abs(pm), Math.Abs(pu))); } } } if (tmp[i] * pm > 0.0) { correction = tmp[i] / Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), M); } else { correction = 0.0; } if (correction != tmp[i]) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } } } // cubic coefficients for (int i = 0; i < size_ - 1; ++i) { a_[i] = tmp[i]; b_[i] = (3.0 * S[i] - tmp[i + 1] - 2.0 * tmp[i]) / dx[i]; c_[i] = (tmp[i + 1] + tmp[i] - 2.0 * S[i]) / (dx[i] * dx[i]); } primitiveConst_[0] = 0.0; for (int i = 1; i < size_ - 1; ++i) { primitiveConst_[i] = primitiveConst_[i - 1] + dx[i - 1] * (yBegin_[i - 1] + dx[i - 1] * (a_[i - 1] / 2.0 + dx[i - 1] * (b_[i - 1] / 3.0 + dx[i - 1] * c_[i - 1] / 4.0))); } }