From b210206e1584a0ecafb8e7613017b629ce9e2913 Mon Sep 17 00:00:00 2001 From: ErikQQY <2283984853@qq.com> Date: Mon, 1 Apr 2024 20:13:56 +0800 Subject: [PATCH 1/2] FODE solvers overhaul Signed-off-by: ErikQQY <2283984853@qq.com> --- docs/src/dode.md | 10 +- docs/src/get_started.md | 12 +- src/FractionalDiffEq.jl | 10 +- src/fode/bdf.jl | 34 ++- src/fode/explicit_pi.jl | 8 +- src/fode/implicit_pi_rectangle.jl | 288 +++++++++++++++++++ src/fode/implicit_pi_trapzoid.jl | 290 ++++++++++++++++++++ src/fode/newton_gregory.jl | 19 +- src/fode/trapezoid.jl | 20 +- src/multitermsfode/explicit_pi.jl | 25 +- src/multitermsfode/implicit_pi_pece.jl | 35 +-- src/multitermsfode/implicit_pi_rectangle.jl | 35 +-- src/multitermsfode/implicit_pi_trapezoid.jl | 35 +-- src/types/algorithms.jl | 85 ++++-- src/types/problems.jl | 56 +++- src/utils.jl | 7 - test/auxillary.jl | 10 - test/fode.jl | 12 +- test/runtests.jl | 2 +- 19 files changed, 801 insertions(+), 192 deletions(-) create mode 100644 src/fode/implicit_pi_rectangle.jl create mode 100644 src/fode/implicit_pi_trapzoid.jl diff --git a/docs/src/dode.md b/docs/src/dode.md index 59533bac1..0f9225f41 100644 --- a/docs/src/dode.md +++ b/docs/src/dode.md @@ -14,7 +14,7 @@ We can write the general form of distributed order differential equations as: \int_0^m \mathscr{A}(r,\ D_*^r u(t))dr = f(t) ``` -Similar with what we have learned about single-term and multi-term fractional differential equations in linear fractional differential equations, we can also write the single-term distributed order differential equations: +Similar to what we have learned about single-term and multi-term fractional differential equations in linear fractional differential equations, we can also write the single-term distributed order differential equations: ```math D_*^ru(t)=f(t,\ u(t)) @@ -28,20 +28,20 @@ And multi-term distributed order differential equations ## Example1: Distributed order relaxation -The distributed order relaxation equation is similar with fractional relaxation equation, only the order is changed to a distributed function. Let's see an example here, the distributed order relaxation: +The distributed order relaxation equation is similar to fractional relaxation equation, only the order is changed to a distributed function. Let's see an example here, the distributed order relaxation: ```math {_0D_t^{\omega(\alpha)} u(t)}+bu(t)=f(t),\quad x(0)=1 ``` -With distribution of orders ``\alpha``: ``\omega(\alpha)=6\alpha(1-\alpha)`` +With a distribution of orders ``\alpha``: ``\omega(\alpha)=6\alpha(1-\alpha)`` By using the ```DOMatrixDiscrete``` method to solve this problem: !!! info - The usage of ```DOMatrixDiscrete``` method is similiar with the ```FODEMatrixDiscrete``` method, all we need to do is to pass the parameters array and orders array to the problem difinition and solve the problem. + The usage of ```DOMatrixDiscrete``` method is similar to the ```FODEMatrixDiscrete``` method, all we need to do is to pass the parameters array and order array to the problem definition and solve the problem. !!! tip - Pass the weight function and other orders to the order array is the right way: + Pass the weight function and other orders to the order array in the right way: ```julia-repl julia> orders = [x->x*(1-x), 1.2, 3] 3-element Vector{Any}: diff --git a/docs/src/get_started.md b/docs/src/get_started.md index 28fcfabcf..d7ede2b25 100644 --- a/docs/src/get_started.md +++ b/docs/src/get_started.md @@ -25,9 +25,9 @@ We can solve this problem by the following code using FractionalDiffEq.jl: ```julia using FractionalDiffEq, Plots fun(u, p, t) = 1-u -α=1.8; h=0.01; tspan = (0, 20); u0 = [0, 0] -prob = SingleTermFODEProblem(fun, α, u0, tspan) -sol = solve(prob, h, PECE()) +α=1.8; tspan = (0, 20); u0 = [0, 0] +prob = FODEProblem(fun, α, u0, tspan) +sol = solve(prob, PIEX(), dt=0.01) plot(sol) ``` @@ -35,7 +35,7 @@ By plotting the numerical result, we can get the approximation result: ![Relaxation Oscillation](./assets/example.png) -To provide users a simple way to solve fractional differential equations, we follow the design pattern of [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl) +To provide users with a simple way to solve fractional differential equations, we follow the design pattern of [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl) ## Step 1: Defining a Problem @@ -45,10 +45,10 @@ First, we need to specify the problem we want to solve. Just by passing the para using FractionalDiffEq fun(u, p, t) = 1-u α = 1.8; u0 = [0, 0]; tspan = (0, 20); h = 0.01; -prob = SingleTermFODEProblem(fun, α, u0, tspan) +prob = FODEProblem(fun, α, u0, tspan) ``` -The ```SingleTermFODEProblem``` is a class of fractional differential equation, describing equations with ``D^{\alpha}u=f(t, u)`` pattern. For other patterns and classes of fractional differential equation, please refer to [Problem types](@ref problems) +The ```FODEProblem``` is a class of fractional differential equations, describing equations with ``D^{\alpha}u=f(t, u)`` pattern. For other patterns and classes of fractional differential equations, please refer to [Problem types](@ref problems) ## Step 2: Solving a Problem diff --git a/src/FractionalDiffEq.jl b/src/FractionalDiffEq.jl index 70ff24ba8..9543c5feb 100644 --- a/src/FractionalDiffEq.jl +++ b/src/FractionalDiffEq.jl @@ -36,6 +36,8 @@ include("fode/bdf.jl") include("fode/newton_gregory.jl") include("fode/trapezoid.jl") include("fode/explicit_pi.jl") +include("fode/implicit_pi_rectangle.jl") +include("fode/implicit_pi_trapzoid.jl") include("fode/grunwald_letnikov.jl") include("fode/NonLinear.jl") include("fode/newton_polynomials.jl") @@ -103,12 +105,14 @@ export FODESolution, FDifferenceSolution, DODESolution, FFMODESolution export FODESystemSolution, FDDESystemSolution, FFMODESystem # FODE solvers -export PIPECE, PIRect, PITrap, MTPIEX -export PECE, MatrixDiscrete, GL +export PIRect, PITrap, PECE, PIEX +export MatrixDiscrete, GL export AtanganaSedaAB +export MTPIRect, MTPITrap, MTPECE, MTPIEX + # System of FODE solvers -export NonLinearAlg, BDF, NewtonGregory, Trapezoid, PIEX, NewtonPolynomial +export NonLinearAlg, BDF, NewtonGregory, Trapezoid, NewtonPolynomial export AtanganaSedaCF export AtanganaSeda diff --git a/src/fode/bdf.jl b/src/fode/bdf.jl index 22dc8482a..9a46c81ca 100644 --- a/src/fode/bdf.jl +++ b/src/fode/bdf.jl @@ -30,6 +30,7 @@ reltol abstol maxiters + high_order_prob kwargs end @@ -47,13 +48,14 @@ function SciMLBase.__init(prob::FODEProblem, alg::BDF; all(x->x==order[1], order) ? nothing : throw(ArgumentError("BDF method is only for commensurate order FODE")) alpha = order[1] # commensurate ordre FODE - (alpha > 1.0) && throw(ArgumentError("BDF method is only for order <= 1.0")) - + m_alpha = ceil.(Int, alpha) m_alpha_factorial = factorial.(collect(0:m_alpha-1)) - problem_size = length(u0) - + problem_size = length(order) + u0_size = length(u0) + high_order_prob = problem_size !== u0_size + # Number of points in which to evaluate the solution or the BDF_weights r = 16 N = ceil(Int, (tfinal-t0)/dt) @@ -66,7 +68,7 @@ function SciMLBase.__init(prob::FODEProblem, alg::BDF; fy = zeros(T, problem_size, N+1) zn = zeros(T, problem_size, NNr+1) - # generate jacobian of input function + # generate jacobian of the input function Jfdefun(t, u) = jacobian_of_fdefun(prob.f, t, u, p) # Evaluation of convolution and starting BDF_weights of the FLMM @@ -75,13 +77,14 @@ function SciMLBase.__init(prob::FODEProblem, alg::BDF; # Initializing solution and proces of computation mesh = t0 .+ collect(0:N)*dt - y[:, 1] .= u0 - temp = similar(u0) + y[:, 1] = high_order_prob ? u0[1, :] : u0 + temp = high_order_prob ? similar(u0[1, :]) : similar(u0) f(temp, u0, p, t0) fy[:, 1] = temp + return BDFCache{iip, T}(prob, alg, mesh, u0, alpha, halpha, y, fy, zn, Jfdefun, p, problem_size, m_alpha, m_alpha_factorial, r, N, Nr, Q, NNr, - omega, w, s, dt, reltol, abstol, maxiters, kwargs) + omega, w, s, dt, reltol, abstol, maxiters, high_order_prob, kwargs) end function SciMLBase.solve!(cache::BDFCache{iip, T}) where {iip, T} @@ -158,7 +161,7 @@ function BDF_quadrato(cache::BDFCache, nxi::P, nxf::P, nyi::P, nyf::P) where {P cache.zn[:, nxi+1:nxf+1] = cache.zn[:, nxi+1:nxf+1] + zzn[:, nxf-nyf:end-1] end -function BDF_triangolo(cache::BDFCache{iip, T}, nxi::P, nxf::P, j0) where{P <: Integer, iip, T} +function BDF_triangolo(cache::BDFCache{iip, T}, nxi::P, nxf::P, j0) where {P <: Integer, iip, T} @unpack prob, mesh, problem_size, zn, Jfdefun, N, abstol, maxiters, s, w, omega, halpha, u0, m_alpha, m_alpha_factorial, p = cache for n = nxi:min(N, nxf) n1 = n+1 @@ -315,11 +318,12 @@ end Jf_vectorfield(t, y, Jfdefun) = Jfdefun(t, y) function ABM_starting_term(cache::BDFCache{iip, T}, t) where {iip, T} - @unpack u0, m_alpha, mesh, m_alpha_factorial = cache + @unpack u0, m_alpha, mesh, m_alpha_factorial, high_order_prob = cache t0 = mesh[1] + u0 = high_order_prob ? reshape(u0, 1, length(u0)) : u0 ys = zeros(size(u0, 1), 1) for k = 1:m_alpha - ys = ys + (t-t0)^(k-1)/m_alpha_factorial[k]*u0 + ys = ys + (t-t0)^(k-1)/m_alpha_factorial[k]*u0[:, k] end return ys end @@ -336,13 +340,17 @@ _is_need_convert!(prob::FODEProblem) = length(prob.u0) == 1 ? _convert_single_te function _convert_single_term_to_vectorized_prob!(prob::FODEProblem) if SciMLBase.isinplace(prob) - new_prob = remake(prob; u0=[prob.u0], order=[prob.order]) + if isa(prob.u0, AbstractArray) + new_prob = remake(prob; order=[prob.order]) + else + new_prob = remake(prob; u0=[prob.u0], order=[prob.order]) + end return new_prob else function new_f(du, u, p, t) du[1] = prob.f(u[1], p, t) end - new_fun = ODEFunction(new_f) + new_fun = ODEFunction{true}(new_f) # make in-place new_prob = remake(prob; f=new_fun, u0=[prob.u0], order=[prob.order]) return new_prob end diff --git a/src/fode/explicit_pi.jl b/src/fode/explicit_pi.jl index 462895854..27a756d9e 100644 --- a/src/fode/explicit_pi.jl +++ b/src/fode/explicit_pi.jl @@ -9,7 +9,7 @@ y fy p - problem_size + problem_size zn r @@ -247,13 +247,13 @@ end function PIEX_system_starting_term(cache::PIEXCache{iip, T}, t) where {iip, T} @unpack mesh, u0, m_alpha, m_alpha_factorial = cache t0 = mesh[1] - ys = zeros(size(u0, 1), 1) + ys = zeros(length(u0)) for k = 1 : maximum(m_alpha) if length(m_alpha) == 1 - ys = ys + (t-t0)^(k-1)/m_alpha_factorial[k]*u0[:, k] + ys = ys .+ (t-t0)^(k-1)/m_alpha_factorial[k]*u0[k] else i_alpha = findall(x -> x>=k, m_alpha) - ys[i_alpha, 1] = ys[i_alpha, 1] + (t-t0)^(k-1)*u0[i_alpha, k]./m_alpha_factorial[i_alpha, k] + ys[i_alpha] = ys[i_alpha] + (t-t0)^(k-1)*u0[i_alpha, k]./m_alpha_factorial[i_alpha, k] end end return ys diff --git a/src/fode/implicit_pi_rectangle.jl b/src/fode/implicit_pi_rectangle.jl new file mode 100644 index 000000000..07186eb4d --- /dev/null +++ b/src/fode/implicit_pi_rectangle.jl @@ -0,0 +1,288 @@ +@concrete mutable struct PIIMRectCache{iip, T} + prob + alg + mesh + u0 + order + m_alpha + m_alpha_factorial + y + fy + p + problem_size + zn + Jfdefun + + r + N + Nr + Qr + NNr + + bn + + halpha1 + abstol + maxiters + index_fft + bn_fft + + kwargs +end + +Base.eltype(::PIIMRectCache{iip, T}) where {iip, T} = T + +struct PIIMRect <: FODEAlgorithm end + +function SciMLBase.__init(prob::FODEProblem, alg::PIIMRect; dt = 0.0, abstol = 1e-6, maxiters = 1000, kwargs...) + dt ≤ 0 ? throw(ArgumentError("dt must be positive")) : nothing + prob = _is_need_convert!(prob) + @unpack f, order, u0, tspan, p = prob + t0 = tspan[1]; tfinal = tspan[2] + T = eltype(u0) + iip = isinplace(prob) + order = order[:] + + alpha_length = length(order) + problem_size = length(u0) + + m_alpha = ceil.(Int, order) + m_alpha_factorial = zeros(alpha_length, maximum(m_alpha)) + for i = 1 : alpha_length + for j = 0 : m_alpha[i]-1 + m_alpha_factorial[i, j+1] = factorial(j) + end + end + + f_temp = zeros(length(u0[:, 1])) + f(f_temp, u0[:, 1], p, t0) + + r = 16 + N = ceil(Int64, (tfinal-t0)/dt) + Nr = ceil(Int64, (N+1)/r)*r + Qr = ceil(Int64, log2(Nr/r)) - 1 + NNr = 2^(Qr+1)*r + + # Preallocation of some variables + y = zeros(T, problem_size, N+1) + fy = zeros(T, problem_size, N+1) + zn = zeros(problem_size, NNr+1) + + # generate jacobian of the input function + Jfdefun(t, u) = jacobian_of_fdefun(prob.f, t, u, p) + + # Evaluation of coefficients of the PECE method + nvett = 0:NNr+1 |> collect + bn = zeros(alpha_length, NNr+1) + for i_alpha = 1:alpha_length + find_alpha = Float64[] + if order[i_alpha] == order[1:i_alpha-1] + push!(find_alpha, i_alpha) + end + + if isempty(find_alpha) == false + bn[i_alpha, :] = bn[find_alpha[1], :] + elseif abs(order[i_alpha]-1) < 1e-14 + bn[i_alpha, :] = [1; zeros(NNr)] + else + nalpha = nvett.^order[i_alpha] + bn[i_alpha, :] = nalpha[2:end] - nalpha[1:end-1] + end + end + halpha1 = dt.^order./gamma.(order.+1) + + + if Qr >= 0 + index_fft = zeros(Int, 2, Qr+1) + for l = 1 : Qr+1 + if l == 1 + index_fft[1, l] = 1; index_fft[2, l] = r*2 + else + index_fft[1, l] = index_fft[2, l-1]+1; index_fft[2, l] = index_fft[2, l-1]+2^l*r + end + end + + bn_fft = zeros(Complex, alpha_length, index_fft[2, end]) + for l = 1:Qr+1 + coef_end = 2^l*r + for i_alpha = 1 : alpha_length + find_alpha = Float64[] + if order[i_alpha] == order[1:i_alpha-1] + push!(find_alpha, i_alpha) + end + if isempty(find_alpha) == false + bn_fft[i_alpha, index_fft[1, l]:index_fft[2, l]] = bn_fft[find_alpha[1], index_fft[1, l]:index_fft[2, l]] + else + bn_fft[i_alpha, index_fft[1, l]:index_fft[2, l]] = ourfft(bn[i_alpha, 1:coef_end], coef_end) + end + end + end + else + index_fft = 0 + bn_fft = 0 + end + + # Initializing solution and proces of computation + mesh = t0 .+ collect(0:N)*dt + y[:, 1] = u0[:, 1] + fy[:, 1] = f_temp + return PIIMRectCache{iip, T}(prob, alg, mesh, u0, order, m_alpha, m_alpha_factorial, y, fy, p, problem_size, + zn, Jfdefun, r, N, Nr, Qr, NNr, bn, halpha1, abstol, maxiters, index_fft, bn_fft, kwargs) +end +function SciMLBase.solve!(cache::PIIMRectCache{iip, T}) where {iip, T} + @unpack prob, alg, mesh, u0, order, y, fy, r, N, Nr, Qr, NNr, bn, halpha1, abstol, index_fft, bn_fft, kwargs = cache + t0 = mesh[1] + tfinal = mesh[end] + PIIMRect_triangolo(cache, 1, r-1) + + # Main process of computation by means of the FFT algorithm + ff = zeros(1, 2^(Qr+2)); ff[1:2] = [0; 2] ; card_ff = 2 + nx0 = 0; ny0 = 0 + for qr = 0 : Qr + L = 2^qr + PIIMRect_disegna_blocchi(cache, L, ff, nx0+L*r, ny0) + ff[1:2*card_ff] = [ff[1:card_ff]; ff[1:card_ff]] + card_ff = 2*card_ff + ff[card_ff] = 4*L + end + + # Evaluation solution in tfinal when tfinal is not in the mesh + if tfinal < mesh[N+1] + c = (tfinal - mesh[N])/dt + mesh[N+1] = tfinal + y[:, N+1] = (1-c)*y[:, N] + c*y[:, N+1] + end + + mesh = mesh[1:N+1]; y = cache.y[:, 1:N+1] + u = collect(Vector{eltype(u0)}, eachcol(y)) + + return DiffEqBase.build_solution(prob, alg, mesh, u) +end + + +function PIIMRect_disegna_blocchi(cache::PIIMRectCache{iip, T}, L::P, ff, nx0::P, ny0::P) where {P <: Integer, iip, T} + @unpack mesh, N, r, Nr = cache + + nxi::Int = nx0; nxf::Int = nx0 + L*r - 1 + nyi::Int = ny0; nyf::Int = ny0 + L*r - 1 + is = 1 + s_nxi = zeros(T, N) + s_nxf = zeros(T, N) + s_nyi = zeros(T, N) + s_nyf = zeros(T, N) + s_nxi[is] = nxi; s_nxf[is] = nxf; s_nyi[is] = nyi; s_nyf[is] = nyf + + i_triangolo = 0; stop = false + while stop == false + stop = (nxi+r-1 == nx0+L*r-1) || (nxi+r-1>=Nr-1) + + PIIMRect_quadrato(cache, nxi, nxf, nyi, nyf) + PIIMRect_triangolo(cache, nxi, nxi+r-1) + i_triangolo = i_triangolo + 1 + + if stop == false + if nxi+r-1 == nxf + i_Delta = ff[i_triangolo] + Delta = i_Delta*r + nxi = s_nxf[is]+1; nxf = s_nxf[is] + Delta + nyi = s_nxf[is] - Delta +1; nyf = s_nxf[is] + s_nxi[is] = nxi; s_nxf[is] = nxf; s_nyi[is] = nyi; s_nyf[is] = nyf + else + nxi = nxi + r; nxf = nxi + r - 1; nyi = nyf + 1; nyf = nyf + r + is = is + 1 + s_nxi[is] = nxi; s_nxf[is] = nxf; s_nyi[is] = nyi; s_nyf[is] = nyf + end + end + end +end + +function PIIMRect_quadrato(cache::PIIMRectCache{iip, T}, nxi::P, nxf::P, nyi::P, nyf::P) where {P <: Integer, iip, T} + @unpack prob, mesh, r, N, Nr, Qr, NNr, problem_size, bn, halpha1, abstol, index_fft, bn_fft = cache + coef_end = nxf-nyi+1 + alpha_length = length(prob.order) + i_fft::Int = log2(coef_end/r) + funz_beg = nyi+1; funz_end = nyf+1 + Nnxf = min(N, nxf) + + if nyi == 0 + vett_funz = [zeros(problem_size, 1) cache.fy[:, funz_beg+1:funz_end]] + else + vett_funz = cache.fy[:, funz_beg:funz_end] + end + vett_funz_fft = rowfft(vett_funz, coef_end) + zzn = zeros(problem_size, coef_end) + for i = 1 : problem_size + i_alpha::Int = min(alpha_length, i) + if abs(prob.order[i_alpha]-1)>1e-14 + Z = bn_fft[i_alpha, index_fft[1, i_fft]:index_fft[2, i_fft]].*vett_funz_fft[i, :] + zzn[i, :] = real.(ourifft(Z, coef_end)) + end + end + zzn = zzn[:, nxf-nyf+1:end] + cache.zn[:, nxi+1:Nnxf+1] = cache.zn[:, nxi+1:Nnxf+1] + zzn[:, 1:Nnxf-nxi+1] +end + + + +function PIIMRect_triangolo(cache::PIIMRectCache{iip, T}, nxi::P, nxf::P) where {P <: Integer, iip, T} + @unpack prob, mesh, u0, order, m_alpha, m_alpha_factorial, p, problem_size, zn, Jfdefun, N, bn, halpha1, abstol, maxiters, index_fft, bn_fft = cache + + alpha_length = length(order) + for n = nxi:min(N, nxf) + n1 = n+1 + St = PIIMRect_system_starting_term(cache, mesh[n+1]) + # Evaluation of the predictor + Phi = zeros(problem_size, 1) + for j = nxi:n-1 + Phi = Phi + bn[1:alpha_length,n-j+1].*cache.fy[:, j+1] + end + Phi_n = St + halpha1 .*(cache.zn[:, n+1] + Phi) + i_alpha_1 = findall(alpha -> abs(alpha - 1) < 1e-14, order) + Phi_n[i_alpha_1] = cache.y[i_alpha_1, n] + + yn0 = cache.y[:, n] + fn0 = zeros(T, problem_size); Jfn0 = zeros(T, problem_size, problem_size) + prob.f(fn0, yn0, p, mesh[n+1]) + Jfn0 = Jf_vectorfield(mesh[n+1], yn0, Jfdefun) + Gn0 = yn0 - halpha1 .*fn0 - Phi_n + + stop = false; it = 0 + yn1 = similar(yn0) + fn1 = similar(yn0) + while ~stop + JGn0 = zeros(T, problem_size, problem_size)+I - diagm(halpha1)*Jfn0 + yn1 = yn0 - JGn0\Gn0 + prob.f(fn1, yn1, p, mesh[n+1]) + Gn1 = yn1 - halpha1.*fn1 - Phi_n + it = it + 1 + + stop = (norm(yn1-yn0, Inf) < abstol) || (norm(Gn1, Inf) maxiters && ~stop + @warn "Non Convergence" + stop = true + end + + yn0 = yn1; Gn0 = Gn1 + if ~stop + Jfn0 = Jf_vectorfield(mesh[n1], yn0, Jfdefun) + end + end + cache.y[:, n1] = yn1 + cache.fy[:, n1] = fn1 + end +end + +function PIIMRect_system_starting_term(cache::PIIMRectCache{iip, T}, t) where {iip, T} + @unpack mesh, u0, m_alpha, m_alpha_factorial = cache + t0 = mesh[1] + ys = zeros(length(u0)) + for k = 1 : maximum(m_alpha) + if length(m_alpha) == 1 + ys = ys .+ (t-t0)^(k-1)/m_alpha_factorial[k]*u0[k] + else + i_alpha = findall(x -> x>=k, m_alpha) + ys[i_alpha] = ys[i_alpha] + (t-t0)^(k-1)*u0[i_alpha, k]./m_alpha_factorial[i_alpha, k] + end + end + return ys +end \ No newline at end of file diff --git a/src/fode/implicit_pi_trapzoid.jl b/src/fode/implicit_pi_trapzoid.jl new file mode 100644 index 000000000..feb5ec8ae --- /dev/null +++ b/src/fode/implicit_pi_trapzoid.jl @@ -0,0 +1,290 @@ +@concrete mutable struct PITrapCache{iip, T} + prob + alg + mesh + u0 + order + m_alpha + m_alpha_factorial + y + fy + p + problem_size + zn + Jfdefun + + r + N + Nr + Qr + NNr + + an + a0 + + halpha2 + abstol + maxiters + index_fft + an_fft + + kwargs +end + +Base.eltype(::PITrapCache{iip, T}) where {iip, T} = T + +struct PITrap <: FODEAlgorithm end + +function SciMLBase.__init(prob::FODEProblem, alg::PITrap; dt = 0.0, abstol = 1e-6, maxiters = 1000, kwargs...) + dt ≤ 0 ? throw(ArgumentError("dt must be positive")) : nothing + prob = _is_need_convert!(prob) + @unpack f, order, u0, tspan, p = prob + t0 = tspan[1]; tfinal = tspan[2] + T = eltype(u0) + iip = isinplace(prob) + order = order[:] + + alpha_length = length(order) + problem_size = length(u0) + + m_alpha = ceil.(Int, order) + m_alpha_factorial = zeros(alpha_length, maximum(m_alpha)) + for i = 1 : alpha_length + for j = 0 : m_alpha[i]-1 + m_alpha_factorial[i, j+1] = factorial(j) + end + end + + f_temp = zeros(length(u0[:, 1])) + f(f_temp, u0[:, 1], p, t0) + + r = 16 + N = ceil(Int64, (tfinal-t0)/dt) + Nr = ceil(Int64, (N+1)/r)*r + Qr = ceil(Int64, log2(Nr/r)) - 1 + NNr = 2^(Qr+1)*r + + # Preallocation of some variables + y = zeros(T, problem_size, N+1) + fy = zeros(T, problem_size, N+1) + zn = zeros(problem_size, NNr+1) + + # generate jacobian of the input function + Jfdefun(t, u) = jacobian_of_fdefun(prob.f, t, u, p) + + # Evaluation of coefficients of the PECE method + nvett = 0:NNr+1 |> collect + an = zeros(alpha_length, NNr+1) + a0 = copy(an) + for i_alpha = 1:alpha_length + find_alpha = Float64[] + if order[i_alpha] == order[1:i_alpha-1] + push!(find_alpha, i_alpha) + end + + if isempty(find_alpha) == false + an[i_alpha, :] = an[find_alpha[1], :] + a0[i_alpha, :] = a0[find_alpha[1], :] + else + nalpha = nvett.^order[i_alpha] + nalpha1 = nalpha.*nvett + an[i_alpha, :] = [ 1; (nalpha1[1:end-2] - 2*nalpha1[2:end-1] + nalpha1[3:end]) ] ; + a0[i_alpha, :] = [ 0; nalpha1[1:end-2]-nalpha[2:end-1].*(nvett[2:end-1] .- order[i_alpha] .-1)] + end + end + halpha2 = dt.^order./gamma.(order.+2) + + + if Qr >= 0 + index_fft = zeros(Int, 2, Qr+1) + for l = 1 : Qr+1 + if l == 1 + index_fft[1, l] = 1; index_fft[2, l] = r*2 + else + index_fft[1, l] = index_fft[2, l-1]+1; index_fft[2, l] = index_fft[2, l-1]+2^l*r + end + end + + an_fft = zeros(Complex, alpha_length, index_fft[2, Qr+1]) + for l = 1:Qr+1 + coef_end = 2^l*r + for i_alpha = 1 : alpha_length + find_alpha = Float64[] + if order[i_alpha] == order[1:i_alpha-1] + push!(find_alpha, i_alpha) + end + if isempty(find_alpha) == false + an_fft[i_alpha, index_fft[1, l]:index_fft[2, l]] = an_fft[find_alpha[1], index_fft[1, l]:index_fft[2, l]] + else + an_fft[i_alpha, index_fft[1, l]:index_fft[2, l]] = ourfft(an[i_alpha, 1:coef_end], coef_end) + end + end + end + else + index_fft = 0 + an_fft = 0 + end + # Initializing solution and proces of computation + mesh = t0 .+ collect(0:N)*dt + y[:, 1] = u0[:, 1] + fy[:, 1] = f_temp + return PITrapCache{iip, T}(prob, alg, mesh, u0, order, m_alpha, m_alpha_factorial, y, fy, p, problem_size, + zn, Jfdefun, r, N, Nr, Qr, NNr, an, a0, halpha2, abstol, maxiters, index_fft, an_fft, kwargs) +end + +function SciMLBase.solve!(cache::PITrapCache{iip, T}) where {iip, T} + @unpack prob, alg, mesh, u0, order, y, fy, r, N, Nr, Qr, NNr, an, a0, halpha2, abstol, index_fft, an_fft, kwargs = cache + t0 = mesh[1] + tfinal = mesh[end] + PITrap_triangolo(cache, 1, r-1) + + # Main process of computation by means of the FFT algorithm + ff = zeros(1, 2^(Qr+2)); ff[1:2] = [0; 2] ; card_ff = 2 + nx0 = 0; ny0 = 0 + for qr = 0 : Qr + L = 2^qr + PITrap_disegna_blocchi(cache, L, ff, nx0+L*r, ny0) + ff[1:2*card_ff] = [ff[1:card_ff]; ff[1:card_ff]] + card_ff = 2*card_ff + ff[card_ff] = 4*L + end + + # Evaluation solution in tfinal when tfinal is not in the mesh + if tfinal < mesh[N+1] + c = (tfinal - mesh[N])/dt + mesh[N+1] = tfinal + y[:, N+1] = (1-c)*y[:, N] + c*y[:, N+1] + end + + mesh = mesh[1:N+1]; y = cache.y[:, 1:N+1] + u = collect(Vector{eltype(u0)}, eachcol(y)) + + return DiffEqBase.build_solution(prob, alg, mesh, u) +end + + +function PITrap_disegna_blocchi(cache::PITrapCache{iip, T}, L::P, ff, nx0::P, ny0::P) where {P <: Integer, iip, T} + @unpack mesh, N, r, Nr = cache + + nxi::Int = nx0; nxf::Int = nx0 + L*r - 1 + nyi::Int = ny0; nyf::Int = ny0 + L*r - 1 + is = 1 + s_nxi = zeros(T, N) + s_nxf = zeros(T, N) + s_nyi = zeros(T, N) + s_nyf = zeros(T, N) + s_nxi[is] = nxi; s_nxf[is] = nxf; s_nyi[is] = nyi; s_nyf[is] = nyf + + i_triangolo = 0; stop = false + while stop == false + stop = (nxi+r-1 == nx0+L*r-1) || (nxi+r-1>=Nr-1) + + PITrap_quadrato(cache, nxi, nxf, nyi, nyf) + PITrap_triangolo(cache, nxi, nxi+r-1) + i_triangolo = i_triangolo + 1 + + if stop == false + if nxi+r-1 == nxf + i_Delta = ff[i_triangolo] + Delta = i_Delta*r + nxi = s_nxf[is]+1; nxf = s_nxf[is] + Delta + nyi = s_nxf[is] - Delta +1; nyf = s_nxf[is] + s_nxi[is] = nxi; s_nxf[is] = nxf; s_nyi[is] = nyi; s_nyf[is] = nyf + else + nxi = nxi + r; nxf = nxi + r - 1; nyi = nyf + 1; nyf = nyf + r + is = is + 1 + s_nxi[is] = nxi; s_nxf[is] = nxf; s_nyi[is] = nyi; s_nyf[is] = nyf + end + end + end +end + +function PITrap_quadrato(cache::PITrapCache{iip, T}, nxi::P, nxf::P, nyi::P, nyf::P) where {P <: Integer, iip, T} + @unpack prob, mesh, r, N, Nr, Qr, NNr, problem_size, an, a0, halpha2, abstol, index_fft, an_fft = cache + coef_end = nxf-nyi+1 + alpha_length = length(prob.order) + i_fft::Int = log2(coef_end/r) + funz_beg = nyi+1; funz_end = nyf+1 + Nnxf = min(N, nxf) + + if nyi == 0 + vett_funz = [zeros(problem_size, 1) cache.fy[:, funz_beg+1:funz_end]] + else + vett_funz = cache.fy[:, funz_beg:funz_end] + end + vett_funz_fft = rowfft(vett_funz, coef_end) + zzn = zeros(problem_size, coef_end) + for i = 1 : problem_size + i_alpha::Int = min(alpha_length, i) + if abs(prob.order[i_alpha]-1)>1e-14 + Z = an_fft[i_alpha, index_fft[1, i_fft]:index_fft[2, i_fft]].*vett_funz_fft[i, :] + zzn[i, :] = real.(ourifft(Z, coef_end)) + end + end + zzn = zzn[:, nxf-nyf+1:end] + cache.zn[:, nxi+1:Nnxf+1] = cache.zn[:, nxi+1:Nnxf+1] + zzn[:, 1:Nnxf-nxi+1] +end + + + +function PITrap_triangolo(cache::PITrapCache{iip, T}, nxi::P, nxf::P) where {P <: Integer, iip, T} + @unpack prob, mesh, u0, order, m_alpha, m_alpha_factorial, p, problem_size, zn, Jfdefun, N, an, a0, halpha2, abstol, maxiters, index_fft, an_fft = cache + + alpha_length = length(order) + for n = nxi:min(N, nxf) + n1 = n+1 + St = PITrap_system_starting_term(cache, mesh[n+1]) + # Evaluation of the predictor + Phi = zeros(problem_size, 1) + for j = nxi:n-1 + Phi = Phi + an[1:alpha_length,n-j+1].*cache.fy[:, j+1] + end + Phi_n = St + halpha2 .*(a0[1:alpha_length, n+1] .* cache.fy[:, 1] + cache.zn[:, n+1] + Phi) + + yn0 = cache.y[:, n] + fn0 = zeros(T, problem_size); Jfn0 = zeros(T, problem_size, problem_size) + prob.f(fn0, yn0, p, mesh[n+1]) + Jfn0 = Jf_vectorfield(mesh[n+1], yn0, Jfdefun) + Gn0 = yn0 - halpha2 .*fn0 - Phi_n + + stop = false; it = 0 + yn1 = similar(yn0) + fn1 = similar(yn0) + + while ~stop + JGn0 = zeros(T, problem_size, problem_size)+I - diagm(halpha2)*Jfn0 + yn1 = yn0 - JGn0\Gn0 + prob.f(fn1, yn1, p, mesh[n+1]) + Gn1 = yn1 - halpha2.*fn1 - Phi_n + it = it + 1 + + stop = (norm(yn1-yn0, Inf) < abstol) || (norm(Gn1, Inf) maxiters && ~stop + @warn "Non Convergence" + stop = true + end + + yn0 = yn1; Gn0 = Gn1 + if ~stop + Jfn0 = Jf_vectorfield(mesh[n1], yn0, Jfdefun) + end + end + cache.y[:, n1] = yn1 + cache.fy[:, n1] = fn1 + end +end + +function PITrap_system_starting_term(cache::PITrapCache{iip, T}, t) where {iip, T} + @unpack mesh, u0, m_alpha, m_alpha_factorial = cache + t0 = mesh[1] + ys = zeros(length(u0)) + for k = 1 : maximum(m_alpha) + if length(m_alpha) == 1 + ys = ys .+ (t-t0)^(k-1)/m_alpha_factorial[k]*u0[k] + else + i_alpha = findall(x -> x>=k, m_alpha) + ys[i_alpha] = ys[i_alpha] + (t-t0)^(k-1)*u0[i_alpha, k]./m_alpha_factorial[i_alpha, k] + end + end + return ys +end \ No newline at end of file diff --git a/src/fode/newton_gregory.jl b/src/fode/newton_gregory.jl index 8507ad030..b51d9a64f 100644 --- a/src/fode/newton_gregory.jl +++ b/src/fode/newton_gregory.jl @@ -30,6 +30,7 @@ reltol abstol maxiters + high_order_prob kwargs end @@ -46,13 +47,14 @@ function SciMLBase.__init(prob::FODEProblem, alg::NewtonGregory; iip = isinplace(prob) all(x->x==order[1], order) ? nothing : throw(ArgumentError("BDF method is only for commensurate order FODE")) alpha = order[1] # commensurate ordre FODE - (alpha > 1.0) && throw(ArgumentError("Newton Gregory method is only for order <= 1.0")) #Jfdefun(t, u) = jacobian_of_fdefun(f, t, u, p) m_alpha = ceil.(Int, alpha) m_alpha_factorial = factorial.(collect(0:m_alpha-1)) - problem_size = length(u0) + problem_size = length(order) + u0_size = length(u0) + high_order_prob = problem_size !== u0_size # Number of points in which to evaluate the solution or the weights r = 16 @@ -75,14 +77,14 @@ function SciMLBase.__init(prob::FODEProblem, alg::NewtonGregory; # Initializing solution and proces of computation mesh = t0 .+ collect(0:N)*dt - y[:, 1] = u0[:, 1] - temp = similar(u0) + y[:, 1] = high_order_prob ? u0[1, :] : u0 + temp = high_order_prob ? similar(u0[1, :]) : similar(u0) f(temp, u0, p, t0) fy[:, 1] = temp return NewtonGregoryCache{iip, T}(prob, alg, mesh, u0, alpha, halpha, y, fy, zn, Jfdefun, p, problem_size, m_alpha, m_alpha_factorial, r, N, Nr, Q, NNr, - omega, w, s, dt, reltol, abstol, maxiters, kwargs) + omega, w, s, dt, reltol, abstol, maxiters, high_order_prob, kwargs) end function SciMLBase.solve!(cache::NewtonGregoryCache{iip, T}) where {iip, T} @unpack prob, alg, mesh, u0, order, halpha, y, fy, zn, Jfdefun, p, problem_size, m_alpha, m_alpha_factorial, r, N, Nr, Q, NNr, omega, w, s, dt, reltol, abstol, maxiters, kwargs = cache @@ -159,7 +161,7 @@ function NG_quadrato(cache::NewtonGregoryCache{iip, T}, nxi::P, nxf::P, nyi::P, cache.zn[:, nxi+1:nxf+1] = cache.zn[:, nxi+1:nxf+1] + zzn[:, nxf-nyf:end-1] end -function NG_triangolo(cache::NewtonGregoryCache{iip, T}, nxi, nxf, j0) where {iip, T} +function NG_triangolo(cache::NewtonGregoryCache{iip, T}, nxi::P, nxf::P, j0) where {P <: Integer, iip, T} @unpack prob, mesh, problem_size, zn, Jfdefun, N, abstol, maxiters, s, w, omega, halpha, u0, m_alpha, m_alpha_factorial, p = cache for n = nxi:min(N, nxf) n1 = Int64(n+1) @@ -315,11 +317,12 @@ function NG_weights(alpha, N) end function NG_starting_term(cache::NewtonGregoryCache{iip, T}, t) where {iip, T} - @unpack u0, m_alpha, mesh, m_alpha_factorial = cache + @unpack u0, m_alpha, mesh, m_alpha_factorial, high_order_prob = cache t0 = mesh[1] + u0 = high_order_prob ? reshape(u0, 1, length(u0)) : u0 ys = zeros(size(u0, 1), 1) for k = 1:Int64(m_alpha) - ys = ys + (t-t0)^(k-1)/m_alpha_factorial[k]*u0 + ys = ys + (t-t0)^(k-1)/m_alpha_factorial[k]*u0[:, k] end return ys end \ No newline at end of file diff --git a/src/fode/trapezoid.jl b/src/fode/trapezoid.jl index 47700c293..8ae49422f 100644 --- a/src/fode/trapezoid.jl +++ b/src/fode/trapezoid.jl @@ -30,13 +30,13 @@ reltol abstol maxiters + high_order_prob kwargs end Base.eltype(::TrapezoidCache{iip, T}) where {iip, T} = T - function SciMLBase.__init(prob::FODEProblem, alg::Trapezoid; dt = 0.0, reltol=1e-6, abstol=1e-6, maxiters=1000, kwargs...) dt ≤ 0 ? throw(ArgumentError("dt must be positive")) : nothing @@ -49,12 +49,11 @@ function SciMLBase.__init(prob::FODEProblem, alg::Trapezoid; alpha = order[1] # commensurate ordre FODE (alpha > 1.0) && throw(ArgumentError("BDF method is only for order <= 1.0")) - #Jfdefun(t, u) = jacobian_of_fdefun(f, t, u, p) - m_alpha = ceil.(Int, alpha) m_alpha_factorial = factorial.(collect(0:m_alpha-1)) - problem_size = length(u0) - + problem_size = length(order) + u0_size = length(u0) + high_order_prob = problem_size !== u0_size # Check compatibility size of the problem with size of the vector field @@ -79,13 +78,13 @@ function SciMLBase.__init(prob::FODEProblem, alg::Trapezoid; # Initializing solution and proces of computation mesh = t0 .+ collect(0:N)*dt - y[:, 1] = u0 - temp = zeros(problem_size) + y[:, 1] = high_order_prob ? u0[1, :] : u0 + temp = high_order_prob ? similar(u0[1, :]) : similar(u0) f(temp, u0, p, t0) fy[:, 1] = temp return TrapezoidCache{iip, T}(prob, alg, mesh, u0, alpha, halpha, y, fy, zn, Jfdefun, p, problem_size, m_alpha, m_alpha_factorial, r, N, Nr, Q, NNr, - omega, w, s, dt, reltol, abstol, maxiters, kwargs) + omega, w, s, dt, reltol, abstol, maxiters, high_order_prob, kwargs) end function SciMLBase.solve!(cache::TrapezoidCache{iip, T}) where {iip, T} @@ -182,7 +181,7 @@ function TrapTriangolo(cache::TrapezoidCache{iip, T}, nxi::P, nxf::P, j0) where yn0 = cache.y[:, n] temp = zeros(length(yn0)) prob.f(temp, yn0, p, mesh[n1]) - fn0 = temp#f_vectorfield(t[n1], yn0, fdefun) + fn0 = temp Jfn0 = Jf_vectorfield(mesh[n1], yn0, Jfdefun) Gn0 = yn0 - halpha*omega[1]*fn0 - Phi_n stop = false; it = 0 @@ -324,8 +323,9 @@ function TrapWeights(alpha, N) end function TrapStartingTerm(cache::TrapezoidCache{iip, T}, t) where {iip, T} - @unpack u0, m_alpha, mesh, m_alpha_factorial = cache + @unpack u0, m_alpha, mesh, m_alpha_factorial, high_order_prob = cache t0 = mesh[1] + u0 = high_order_prob ? reshape(u0, 1, length(u0)) : u0 ys = zeros(size(u0, 1), 1) for k = 1:m_alpha ys = ys + (t-t0)^(k-1)/m_alpha_factorial[k]*u0[:, k] diff --git a/src/multitermsfode/explicit_pi.jl b/src/multitermsfode/explicit_pi.jl index 276d108e5..712a174b5 100644 --- a/src/multitermsfode/explicit_pi.jl +++ b/src/multitermsfode/explicit_pi.jl @@ -24,7 +24,6 @@ NNr bn - kwargs end @@ -47,7 +46,7 @@ function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::MTPIEX; dt = 0.0, ab highest_order_ceiling = ceil(Int64, highest_order) other_orders_ceiling = ceil.(Int64, orders[1:end-1]) bet = [highest_order .- other_orders; highest_order] - + gamma_val = zeros(orders_length, highest_order_ceiling) for i = 1 : orders_length-1 k = collect(Int, 0:other_orders_ceiling[i]-1) @@ -89,19 +88,20 @@ function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::MTPIEX; dt = 0.0, ab y, fy, p, zn, r, N, Nr, Qr, NNr, bn, kwargs) end + function SciMLBase.solve!(cache::MTPIEXCache{T}) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, y, fy, p, zn, r, N, Nr, Qr, NNr, bn, kwargs = cache t0 = mesh[1]; tfinal = mesh[end] - PIEX_multiterms_triangolo(cache, 1, r-1, t0) + MTPX_multiterms_triangolo(cache, 1, r-1, t0) ff = zeros(1, 2^(Qr+2)); ff[1:2] = [0 2]; card_ff = 2 nx0 = 0; nu0 = 0 for qr = 0 : Qr L = 2^qr - PIEX_multiterms_disegna_blocchi(cache, L, ff, nx0+L*r, nu0, t0) + MTPX_multiterms_disegna_blocchi(cache, L, ff, nx0+L*r, nu0, t0) ff[1:2*card_ff] = [ff[1:card_ff] ff[1:card_ff]] card_ff = 2*card_ff ff[card_ff] = 4*L @@ -117,9 +117,8 @@ function SciMLBase.solve!(cache::MTPIEXCache{T}) where {T} y = collect(Vector{eltype(y)}, eachcol(y)) return DiffEqBase.build_solution(prob, alg, mesh, y) end - -function PIEX_multiterms_disegna_blocchi(cache::MTPIEXCache{T}, L, ff, nx0, nu0, t0) where {T} +function MTPX_multiterms_disegna_blocchi(cache::MTPIEXCache{T}, L, ff, nx0, nu0, t0) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, p, zn, r, N, Nr, Qr, NNr, bn, kwargs = cache @@ -141,9 +140,9 @@ function PIEX_multiterms_disegna_blocchi(cache::MTPIEXCache{T}, L, ff, nx0, nu0, while stop == false stop = (nxi+r-1 == nx0+L*r-1) || (nxi+r-1 >= Nr-1) - PIEX_multiterms_quadrato(cache, nxi, nxf, nyi, nyf) + MTPX_multiterms_quadrato(cache, nxi, nxf, nyi, nyf) - PIEX_multiterms_triangolo(cache, nxi, nxi+r-1, t0) + MTPX_multiterms_triangolo(cache, nxi, nxi+r-1, t0) i_triangolo = i_triangolo + 1 if stop==false @@ -168,7 +167,7 @@ function PIEX_multiterms_disegna_blocchi(cache::MTPIEXCache{T}, L, ff, nx0, nu0, end end -function PIEX_multiterms_quadrato(cache::MTPIEXCache{T}, nxi, nxf, nyi, nyf) where {T} +function MTPX_multiterms_quadrato(cache::MTPIEXCache{T}, nxi, nxf, nyi, nyf) where {T} @unpack prob, alg, mesh, r, N, Nr, Qr, NNr, bn, kwargs = cache orders_length = length(prob.orders) problem_size = size(prob.u0, 2) @@ -186,15 +185,15 @@ function PIEX_multiterms_quadrato(cache::MTPIEXCache{T}, nxi, nxf, nyi, nyf) whe cache.zn[:, nxi+1:nxf+1, i] = cache.zn[:, nxi+1:nxf+1, i] + zzn[:, nxf-nyf:end-1] end end - -function PIEX_multiterms_triangolo(cache::MTPIEXCache{T}, nxi, nxf, t0) where {T} + +function MTPX_multiterms_triangolo(cache::MTPIEXCache{T}, nxi, nxf, t0) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, p, zn, r, N, Nr, Qr, NNr, bn, kwargs = cache problem_size = size(prob.u0, 2) orders_length = length(prob.orders) for n = nxi:min(N, nxf) - Phi_n = PIEX_multiterms_starting_term(mesh[n+1], t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) + Phi_n = MTPX_multiterms_starting_term(mesh[n+1], t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) if nxi == 1 j_beg = 0 else @@ -219,7 +218,7 @@ function PIEX_multiterms_triangolo(cache::MTPIEXCache{T}, nxi, nxf, t0) where {T end end -function PIEX_multiterms_starting_term(t, t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) +function MTPX_multiterms_starting_term(t, t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) ys = zeros(problem_size) for k = 0:highest_order_ceiling-1 diff --git a/src/multitermsfode/implicit_pi_pece.jl b/src/multitermsfode/implicit_pi_pece.jl index 348232e2e..511c035e9 100644 --- a/src/multitermsfode/implicit_pi_pece.jl +++ b/src/multitermsfode/implicit_pi_pece.jl @@ -1,4 +1,4 @@ -@concrete mutable struct PIPECECache{T} +@concrete mutable struct MTPECECache{T} prob alg mesh @@ -35,16 +35,9 @@ kwargs end -Base.eltype(::PIPECECache{T}) where {T} = T +Base.eltype(::MTPECECache{T}) where {T} = T -""" - solve(prob::MultiTermsFODEProblem, dt, PIPECE()) - -Use product integration predictor-corrector method to solve multi-terms FODE. -""" -struct PIPECE <: MultiTermsFODEAlgorithm end - -function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::PIPECE; dt=0.0, abstol=1e-6, kwargs...) +function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::MTPECE; dt=0.0, abstol=1e-6, kwargs...) dt ≤ 0 ? throw(ArgumentError("dt must be positive")) : nothing @unpack parameters, orders, f, u0, tspan, p = prob t0 = tspan[1]; tfinal = tspan[2] @@ -109,13 +102,13 @@ function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::PIPECE; dt=0.0, abst y[:, 1] = u0[:, 1] fy[:, 1] .= f(u0[:, 1], p, t0) - return PIPECECache{T}(prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, + return MTPECECache{T}(prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, y, fy, p, zn_pred, zn_corr, r, N, Nr, Qr, NNr, C, an, bn, a0, mu, abstol, kwargs) end -function SciMLBase.solve!(cache::PIPECECache{T}) where {T} +function SciMLBase.solve!(cache::MTPECECache{T}) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, p, @@ -123,13 +116,13 @@ function SciMLBase.solve!(cache::PIPECECache{T}) where {T} t0 = mesh[1]; tfinal = mesh[end] - PIPECE_triangolo(cache, 1, r-1, t0) + MTPECE_triangolo(cache, 1, r-1, t0) ff = zeros(1, 2^(Qr+2)); ff[1:2] = [0 2]; card_ff = 2 nx0 = 0; nu0 = 0 for qr in 0:Qr L = 2^qr - PIPECE_disegna_blocchi(cache, L, ff, nx0+L*r, nu0, t0) + MTPECE_disegna_blocchi(cache, L, ff, nx0+L*r, nu0, t0) ff[1:2*card_ff] = [ff[1:card_ff] ff[1:card_ff]] card_ff = 2*card_ff ff[card_ff] = 4*L @@ -147,7 +140,7 @@ function SciMLBase.solve!(cache::PIPECECache{T}) where {T} return DiffEqBase.build_solution(prob, alg, mesh, u) end -function PIPECE_disegna_blocchi(cache::PIPECECache{T}, L, ff, nx0, nu0, t0) where {T} +function MTPECE_disegna_blocchi(cache::MTPECECache{T}, L, ff, nx0, nu0, t0) where {T} @unpack r, N = cache nxi::Int = nx0 @@ -168,9 +161,9 @@ function PIPECE_disegna_blocchi(cache::PIPECECache{T}, L, ff, nx0, nu0, t0) wher while stop == false stop = (nxi+r-1 == nx0+L*r-1) || (nxi+r-1 >= Nr-1) - PIPECE_quadrato(cache, nxi, nxf, nyi, nyf) + MTPECE_quadrato(cache, nxi, nxf, nyi, nyf) - PIPECE_triangolo(cache, nxi, nxi+r-1, t0) + MTPECE_triangolo(cache, nxi, nxi+r-1, t0) i_triangolo = i_triangolo + 1 if stop==false @@ -196,7 +189,7 @@ function PIPECE_disegna_blocchi(cache::PIPECECache{T}, L, ff, nx0, nu0, t0) wher end end -function PIPECE_quadrato(cache::PIPECECache{T}, nxi, nxf, nyi, nyf) where {T} +function MTPECE_quadrato(cache::MTPECECache{T}, nxi, nxf, nyi, nyf) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, p, r, N, Nr, Qr, NNr, C, a0, an, bn, mu, abstol, kwargs = cache @@ -245,7 +238,7 @@ end -function PIPECE_triangolo(cache::PIPECECache{T}, nxi, nxf, t0) where {T} +function MTPECE_triangolo(cache::MTPECECache{T}, nxi, nxf, t0) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, p, zn_pred, zn_corr, @@ -255,7 +248,7 @@ function PIPECE_triangolo(cache::PIPECECache{T}, nxi, nxf, t0) where {T} orders_length = length(prob.orders) for n in nxi:min(N, nxf) - St = PIPECE_starting_term_multi(mesh[n+1], t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) + St = MTPECE_starting_term_multi(mesh[n+1], t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) Phi_n = copy(St) if nxi == 1 @@ -322,7 +315,7 @@ function PIPECE_triangolo(cache::PIPECECache{T}, nxi, nxf, t0) where {T} end end -function PIPECE_starting_term_multi(mesh, t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) +function MTPECE_starting_term_multi(mesh, t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) ys = zeros(problem_size) for k in 0:highest_order_ceiling-1 diff --git a/src/multitermsfode/implicit_pi_rectangle.jl b/src/multitermsfode/implicit_pi_rectangle.jl index c984c9421..cba3f2567 100644 --- a/src/multitermsfode/implicit_pi_rectangle.jl +++ b/src/multitermsfode/implicit_pi_rectangle.jl @@ -1,4 +1,4 @@ -@concrete mutable struct PIRectCache{T} +@concrete mutable struct MTPIRectCache{T} prob alg mesh @@ -33,16 +33,9 @@ kwargs end -Base.eltype(::PIRectCache{T}) where {T} = T +Base.eltype(::MTPIRectCache{T}) where {T} = T -""" - solve(prob::MultiTermsFODEProblem,, PIRect(); dt) - -Use implicit product integration rectangular type method to solve multi-terms FODE. -""" -struct PIRect <: MultiTermsFODEAlgorithm end - -function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::PIRect; dt=0.0, abstol=1e-6, maxiters=100, kwargs...) +function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::MTPIRect; dt=0.0, abstol=1e-6, maxiters=100, kwargs...) @unpack parameters, orders, f, u0, tspan, p = prob t0 = tspan[1]; tfinal = tspan[2] u0 = u0[:]' @@ -101,24 +94,24 @@ function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::PIRect; dt=0.0, abst y[:, 1] = u0[:, 1] fy[:, 1] .= f(u0[:, 1], p, t0) - return PIRectCache{T}(prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J_fun, + return MTPIRectCache{T}(prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J_fun, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, y, fy, p, zn, r, N, Nr, Qr, NNr, C, bn, abstol, maxiters, kwargs) end -function SciMLBase.solve!(cache::PIRectCache{T}) where {T} +function SciMLBase.solve!(cache::MTPIRectCache{T}) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, y, fy, p, zn, r, N, Nr, Qr, NNr, C, bn, abstol, maxiters, kwargs = cache t0 = mesh[1] tfinal = mesh[end] - PIRect_triangolo(cache, 1, r-1, t0) + MTPIRect_triangolo(cache, 1, r-1, t0) ff = zeros(1, 2^(Qr+2)); ff[1:2] = [0 2]; card_ff = 2 nx0 = 0; nu0 = 0 for qr = 0 : Qr L = 2^qr - PIRect_disegna_blocchi(cache, L, ff, nx0+L*r, nu0, t0) + MTPIRect_disegna_blocchi(cache, L, ff, nx0+L*r, nu0, t0) ff[1:2*card_ff] = [ff[1:card_ff] ff[1:card_ff]] card_ff = 2*card_ff ff[card_ff] = 4*L @@ -137,7 +130,7 @@ function SciMLBase.solve!(cache::PIRectCache{T}) where {T} end -function PIRect_disegna_blocchi(cache::PIRectCache{T}, L, ff, nx0, nu0, t0) where {T} +function MTPIRect_disegna_blocchi(cache::MTPIRectCache{T}, L, ff, nx0, nu0, t0) where {T} @unpack r, N, Nr = cache nxi::Int = nx0 nxf::Int = nx0 + L*r - 1 @@ -157,9 +150,9 @@ function PIRect_disegna_blocchi(cache::PIRectCache{T}, L, ff, nx0, nu0, t0) wher while stop == false stop = (nxi+r-1 == nx0+L*r-1) || (nxi+r-1 >= Nr-1) - PIRect_quadrato(cache, nxi, nxf, nyi, nyf) + MTPIRect_quadrato(cache, nxi, nxf, nyi, nyf) - PIRect_triangolo(cache, nxi, nxi+r-1, t0) + MTPIRect_triangolo(cache, nxi, nxi+r-1, t0) i_triangolo = i_triangolo + 1 if stop==false @@ -185,7 +178,7 @@ function PIRect_disegna_blocchi(cache::PIRectCache{T}, L, ff, nx0, nu0, t0) wher end end -function PIRect_quadrato(cache::PIRectCache{T}, nxi, nxf, nyi, nyf) where {T} +function MTPIRect_quadrato(cache::MTPIRectCache{T}, nxi, nxf, nyi, nyf) where {T} @unpack prob, u0 = cache coef_beg = nxi-nyf; coef_end = nxf-nyi+1 funz_beg = nyi+1; funz_end = nyf+1 @@ -213,7 +206,7 @@ function PIRect_quadrato(cache::PIRectCache{T}, nxi, nxf, nyi, nyf) where {T} end end -function PIRect_triangolo(cache::PIRectCache{T}, nxi, nxf, t0) where {T} +function MTPIRect_triangolo(cache::MTPIRectCache{T}, nxi, nxf, t0) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, p, zn, r, N, Nr, Qr, NNr, C, bn, abstol, maxiters, kwargs = cache @@ -222,7 +215,7 @@ function PIRect_triangolo(cache::PIRectCache{T}, nxi, nxf, t0) where {T} orders_length = length(prob.orders) for n = nxi:min(N, nxf) - St = PIRect_startingterm_multi(mesh[n+1], t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) + St = MTPIRect_startingterm_multi(mesh[n+1], t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) Phi_n = copy(St) for i = 1:orders_length-1 @@ -267,7 +260,7 @@ function PIRect_triangolo(cache::PIRectCache{T}, nxi, nxf, t0) where {T} end end -function PIRect_startingterm_multi(mesh,t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) +function MTPIRect_startingterm_multi(mesh,t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) ys = zeros(problem_size) for k = 0:highest_order_ceiling-1 diff --git a/src/multitermsfode/implicit_pi_trapezoid.jl b/src/multitermsfode/implicit_pi_trapezoid.jl index 0796877b3..6253f9348 100644 --- a/src/multitermsfode/implicit_pi_trapezoid.jl +++ b/src/multitermsfode/implicit_pi_trapezoid.jl @@ -1,4 +1,4 @@ -@concrete mutable struct PITrapCache{T} +@concrete mutable struct MTPITrapCache{T} prob alg mesh @@ -34,16 +34,9 @@ kwargs end -Base.eltype(::PITrapCache{T}) where {T} = T +Base.eltype(::MTPITrapCache{T}) where {T} = T -""" - solve(prob::MultiTermsFODEProblem, dt, PITrap()) - -Use implicit product integration trapezoidal type method to solve multi-terms FODE. -""" -struct PITrap <: MultiTermsFODEAlgorithm end - -function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::PITrap; dt=0.0, abstol=1e-6, maxiters=100, kwargs...) +function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::MTPITrap; dt=0.0, abstol=1e-6, maxiters=100, kwargs...) dt ≤ 0 ? throw(ArgumentError("dt must be positive")) : nothing @unpack parameters, orders, f, u0, tspan, p = prob t0 = tspan[1]; tfinal = tspan[2] @@ -103,19 +96,19 @@ function SciMLBase.__init(prob::MultiTermsFODEProblem, alg::PITrap; dt=0.0, abst y[:, 1] = u0[:, 1] fy[:, 1] .= f(u0[:, 1], p, t0) - return PITrapCache{T}(prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J_fun, + return MTPITrapCache{T}(prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J_fun, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, y, fy, p, zn, r, N, Nr, Qr, NNr, C, an, a0, abstol, maxiters, kwargs) end -function SciMLBase.solve!(cache::PITrapCache{T}) where {T} +function SciMLBase.solve!(cache::MTPITrapCache{T}) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, y, fy, p, zn, r, N, Nr, Qr, NNr, C, an, a0, abstol, maxiters, kwargs = cache t0 = mesh[1] tfinal = mesh[end] - PITrap_triangolo(cache, 1, r-1, t0) + MTPITrap_triangolo(cache, 1, r-1, t0) ff = zeros(1, 2^(Qr+2)) ff[1:2] = [0 2] @@ -124,7 +117,7 @@ function SciMLBase.solve!(cache::PITrapCache{T}) where {T} nu0 = 0 for qr = 0 : Qr L = 2^qr - PITrap_disegna_blocchi(cache, L, ff, nx0+L*r, nu0, t0) + MTPITrap_disegna_blocchi(cache, L, ff, nx0+L*r, nu0, t0) ff[1:2*card_ff] = [ff[1:card_ff] ff[1:card_ff]] card_ff = 2*card_ff ff[card_ff] = 4*L @@ -143,7 +136,7 @@ function SciMLBase.solve!(cache::PITrapCache{T}) where {T} end -function PITrap_disegna_blocchi(cache::PITrapCache{T}, L, ff, nx0, nu0, t0) where {T} +function MTPITrap_disegna_blocchi(cache::MTPITrapCache{T}, L, ff, nx0, nu0, t0) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, p, zn, r, N, Nr, Qr, NNr, C, an, a0, abstol, maxiters, kwargs = cache @@ -166,9 +159,9 @@ function PITrap_disegna_blocchi(cache::PITrapCache{T}, L, ff, nx0, nu0, t0) wher while stop == false stop = (nxi+r-1 == nx0+L*r-1) || (nxi+r-1 >= Nr-1) - PITrap_quadrato(cache, nxi, nxf, nyi, nyf) + MTPITrap_quadrato(cache, nxi, nxf, nyi, nyf) - PITrap_triangolo(cache, nxi, nxi+r-1, t0) + MTPITrap_triangolo(cache, nxi, nxi+r-1, t0) i_triangolo = i_triangolo + 1 if stop==false @@ -193,7 +186,7 @@ function PITrap_disegna_blocchi(cache::PITrapCache{T}, L, ff, nx0, nu0, t0) wher end end -function PITrap_quadrato(cache::PITrapCache{T}, nxi, nxf, nyi, nyf) where {T} +function MTPITrap_quadrato(cache::MTPITrapCache{T}, nxi, nxf, nyi, nyf) where {T} @unpack prob, u0, an = cache coef_beg = nxi-nyf; coef_end = nxf-nyi+1 @@ -225,7 +218,7 @@ end -function PITrap_triangolo(cache::PITrapCache{T}, nxi, nxf, t0) where {T} +function MTPITrap_triangolo(cache::MTPITrapCache{T}, nxi, nxf, t0) where {T} @unpack prob, alg, mesh, u0, bet, lam_rat_i, gamma_val, J, highest_order_parameter, highest_order_ceiling, other_orders_ceiling, p, zn, r, N, Nr, Qr, NNr, C, an, a0, abstol, maxiters, kwargs = cache @@ -233,7 +226,7 @@ function PITrap_triangolo(cache::PITrapCache{T}, nxi, nxf, t0) where {T} orders_length = length(prob.orders) problem_size = size(u0, 1) for n = nxi:min(N, nxf) - St = PITrap_startingterm_multi(mesh[n+1], t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) + St = MTPITrap_startingterm_multi(mesh[n+1], t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) Phi_n = copy(St) for i = 1:orders_length-1 @@ -281,7 +274,7 @@ function PITrap_triangolo(cache::PITrapCache{T}, nxi, nxf, t0) where {T} end end -function PITrap_startingterm_multi(mesh,t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) +function MTPITrap_startingterm_multi(mesh,t0, problem_size, u0, orders_length, highest_order_ceiling, other_orders_ceiling, bet, lam_rat_i, gamma_val) ys = zeros(problem_size) for k = 0:highest_order_ceiling-1 diff --git a/src/types/algorithms.jl b/src/types/algorithms.jl index f2886b72e..ff84a49e5 100644 --- a/src/types/algorithms.jl +++ b/src/types/algorithms.jl @@ -138,7 +138,6 @@ Use [Trapezoidal](https://en.wikipedia.org/wiki/Trapezoidal_rule_(differential_e """ struct Trapezoid <: FODEAlgorithm end - """ Predictor-Correct scheme. @@ -152,6 +151,46 @@ struct Trapezoid <: FODEAlgorithm end """ struct PECE <: FODEAlgorithm end + +""" + AtanganaSedaAB + +Solve Atangana-Baleanu fractional order differential equations using Newton Polynomials. +""" +struct AtanganaSedaAB <: FODEAlgorithm end + + +""" + MatrixDiscrete + +[Triangular strip matrices](https://en.wikipedia.org/wiki/Triangular_matrix) to discrete fractional ordinary differential equations to simple algebra system and solve the system. + +## References + +@inproceedings{Podlubny2000MATRIXAT, + title={MATRIX APPROACH TO DISCRETE FRACTIONAL CALCULUS}, + author={Igor Podlubny}, + year={2000} +} +""" +struct MatrixDiscrete <: MultiTermsFODEAlgorithm end + +""" + Euler + +The classical Euler method extended for fractional order differential equations. +""" +struct Euler <: FODEAlgorithm end + +""" + PIEX + +Explicit product integral method for initial value problems of fractional order differential equations. +""" +struct PIEX <: FODEAlgorithm end + +###################### FDDE ###################### + """ # Usage @@ -187,25 +226,17 @@ Capable of solving both single term FDDE and multiple FDDE, support time varying struct DelayPECE <: FDDEAlgorithm end """ - Euler + DelayPIEX -The classical Euler method extended for fractional order differential equations. +Explicit product integral method for initial value problems of fractional order differential equations. """ -struct Euler <: FODEAlgorithm end +struct DelayPIEX <: FDDEAlgorithm end -""" - PIEX -Explicit product integral method for initial value problems of fractional order differential equations. -""" -struct PIEX <: FODEAlgorithm end -""" - DelayPIEX -Explicit product integral method for initial value problems of fractional order differential equations. -""" -struct DelayPIEX <: FDDEAlgorithm end + +###################### Multi-terms FODE ###################### """ @@ -215,27 +246,23 @@ Explicit product integral method for initial value problems of fractional order """ struct MTPIEX <: MultiTermsFODEAlgorithm end - - """ - AtanganaSedaAB + solve(prob::MultiTermsFODEProblem, dt, MTPECE()) -Solve Atangana-Baleanu fractional order differential equations using Newton Polynomials. +Use product integration predictor-corrector method to solve multi-terms FODE. """ -struct AtanganaSedaAB <: FODEAlgorithm end - +struct MTPECE <: MultiTermsFODEAlgorithm end """ - MatrixDiscrete + solve(prob::MultiTermsFODEProblem,, MTPIRect(); dt) -[Triangular strip matrices](https://en.wikipedia.org/wiki/Triangular_matrix) to discrete fractional ordinary differential equations to simple algebra system and solve the system. +Use implicit product integration rectangular type method to solve multi-terms FODE. +""" +struct MTPIRect <: MultiTermsFODEAlgorithm end -## References +""" + solve(prob::MultiTermsFODEProblem, MTPITrap(), dt) -@inproceedings{Podlubny2000MATRIXAT, - title={MATRIX APPROACH TO DISCRETE FRACTIONAL CALCULUS}, - author={Igor Podlubny}, - year={2000} -} +Use implicit product integration trapezoidal type method to solve multi-terms FODE. """ -struct MatrixDiscrete <: MultiTermsFODEAlgorithm end \ No newline at end of file +struct MTPITrap <: MultiTermsFODEAlgorithm end diff --git a/src/types/problems.jl b/src/types/problems.jl index 37ca456d3..d41734441 100644 --- a/src/types/problems.jl +++ b/src/types/problems.jl @@ -44,6 +44,48 @@ function MultiTermsFODEProblem(parameters, orders, f, u0, tspan, p = SciMLBase.N return MultiTermsFODEProblem{false}(parameters, orders, ODEFunction(f), nothing, nothing, u0, tspan, p; kwargs...) end + +""" +Defines an distributed order fractional ordinary differential equation (DODE) problem. + +## Mathematical Specification of an distributed order FODE problem + +To define an multi-terms FODE Problem, you simply need to given the parameters, their correspoding orders, right hand side function and the initial condition ``u_0`` which define an FODE: + +```math +\\frac{du^\\alpha}{d^{\\alpha}t} = f(u,p,t) +``` + +Distributed order differential equations. +""" +struct DODEProblem{uType, tType, oType, pType, F, P, K, isinplace} <: SciMLBase.AbstractODEProblem{uType, tType, isinplace} + parameters::pType + orders::oType + f::F + u0::uType + tspan::tType + p::P + kwargs::K + + SciMLBase.@add_kwonly function DODEProblem{iip}(parameters, orders, + f::SciMLBase.AbstractODEFunction, rparameters, rorders, + u0, tspan, p = SciMLBase.NullParameters(); + kwargs...) where {iip} + _tspan = SciMLBase.promote_tspan(tspan) + new{typeof(u0), typeof(_tspan), typeof(orders), typeof(parameters), + typeof(f), typeof(p), typeof(kwargs), iip}(parameters, orders, f, rparameters, rorders, u0, _tspan, p, kwargs) + end + + function DODEProblem{iip}(parameters, orders, f, u0, tspan, p = SciMLBase.NullParameters(); kwargs...) where {iip} + DODEProblem(parameters, orders, ODEFunction{iip}(f), u0, tspan, p; kwargs...) + end +end + +function DODEProblem(parameters, orders, f, u0, tspan, p = SciMLBase.NullParameters(); kwargs... ) + return DODEProblem{false}(parameters, orders, ODEFunction(f), u0, tspan, p; kwargs...) +end + + struct StandardFODEProblem end """ @@ -354,20 +396,6 @@ function FFMODESystem(f::Function, FFMODESystem(f, order, u0, tspan, nothing) end -""" - DODEProblem(parameters, orders, interval, tspan, rightfun) - -Define distributed order differential equation problem. -""" -struct DODEProblem <: FDEProblem - parameters::AbstractArray - orders::AbstractArray - interval::Tuple - rightfun::Function - u0 - tspan -end - """ FractionalDifferenceProblem(f, α, x0) diff --git a/src/utils.jl b/src/utils.jl index 91feb1416..4c4c4f90d 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -23,13 +23,6 @@ function Base.show(io::IO, prob::FDDESystem) println("history function: $(prob.ϕ)") end -function Base.show(io::IO, prob::DODEProblem) - printstyled(typeof(prob), color=:light_blue) - printstyled(" with order ") - printstyled("$(prob.orders)", color=:red) - println() - println("timespan: $(prob.tspan)") -end function Base.show(io::IO, prob::FractionalDiscreteProblem) printstyled(typeof(prob), color=:light_blue) diff --git a/test/auxillary.jl b/test/auxillary.jl index 4733eb316..d61d105dc 100644 --- a/test/auxillary.jl +++ b/test/auxillary.jl @@ -32,16 +32,6 @@ end @test isFunction("Hello")==false end -@testset "Test DODEProblem show method" begin - h = 0.5; t = collect(0:h:1) - dodefun(t)=0 - dodeprob = DODEProblem([1, 0.1], [x->6*x*(1-x), 0], (0, 1), dodefun, 1, t) - dodesol = solve(dodeprob, h, DOMatrixDiscrete()) - - @test_nowarn show(dodeprob) - @test_nowarn show(dodesol) -end - @testset "Test FractionalDiscreteProblem" begin discretefun(x) = 0.5*x+1 α=0.5;x0=1; diff --git a/test/fode.jl b/test/fode.jl index b5ecacdc5..dc0ce4593 100644 --- a/test/fode.jl +++ b/test/fode.jl @@ -188,7 +188,7 @@ end u0 = [0, 0, 0, 0, 0, 0] prob = MultiTermsFODEProblem([1, 1/16, 4/5, 3/2, 1/25, 6/5], [3, 2.5, 2, 1, 0.5, 0], rightfun, [0, 0, 0, 0, 0, 0], tspan) - sol = solve(prob, PIPECE(), dt = h) + sol = solve(prob, MTPECE(), dt = h) @test isapprox(test_sol(sol)', [ 0.0 0.01942631486406702 @@ -218,7 +218,7 @@ end tspan = (0, 30); h = 0.01 rightfun(u, p, x) = 172/125*cos(4/5*x) prob = MultiTermsFODEProblem([1, 1/16, 4/5, 3/2, 1/25, 6/5], [3, 2.5, 2, 1, 0.5, 0], rightfun, [0, 0, 0, 0, 0, 0], tspan) - sol = solve(prob, PITrap(), dt=h) + sol = solve(prob, MTPITrap(), dt=h) @test isapprox(test_sol(sol.u[end-20:end])', [0.2062614941629048 0.21034012743472855 @@ -248,7 +248,7 @@ end tspan = (0, 1); h = 0.01 rightfun(y, p, x) = 172/125*cos(4/5*x) prob = MultiTermsFODEProblem([1, 1/16, 4/5, 3/2, 1/25, 6/5], [3, 2.5, 2, 1, 0.5, 0], rightfun, [0, 0, 0, 0, 0, 0], tspan) - sol = solve(prob, PIPECE(), dt=h) + sol = solve(prob, MTPECE(), dt=h) @test isapprox(test_sol(sol.u[end-10:end])', [0.12517053205360132 0.128867333370644 @@ -270,7 +270,7 @@ end rightfun(y, p, x) = 172/125*cos(4/5*x) prob = MultiTermsFODEProblem([1, 1/16, 4/5, 3/2, 1/25, 6/5], [3, 2.5, 2, 1, 0.5, 0], rightfun, [0, 0, 0, 0, 0, 0], (0, T)) - sol = solve(prob, PIRect(), dt=h) + sol = solve(prob, MTPIRect(), dt=h) @test isapprox(test_sol(sol)', [0.0 0.01586240520261297 @@ -300,7 +300,7 @@ end rightfun(y, p, x) = 172/125*cos(4/5*x) prob = MultiTermsFODEProblem([1, 1/16, 4/5, 3/2, 1/25, 6/5], [3, 2.5, 2, 1, 0.5, 0], rightfun, [0, 0, 0, 0, 0, 0], tspan) - sol = solve(prob, PIRect(), dt=h) + sol = solve(prob, MTPIRect(), dt=h) @test isapprox(test_sol(sol.u[end-20:end])', [0.16675726971457058 0.17176357358985567 @@ -330,7 +330,7 @@ end rightfun(y, p, x) = 172/125*cos(4/5*x) prob = MultiTermsFODEProblem([1, 1/16, 4/5, 3/2, 1/25, 6/5], [3, 2.5, 2, 1, 0.5, 0], rightfun, [0, 0, 0, 0, 0, 0], (0, T)) - sol = solve(prob, PITrap(), dt=h) + sol = solve(prob, MTPITrap(), dt=h) @test isapprox(test_sol(sol)', [0.0 0.02157284502548659 diff --git a/test/runtests.jl b/test/runtests.jl index 6081bd22d..1018b1384 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -13,7 +13,7 @@ end include("fode.jl") include("fdde.jl") include("discrete.jl") - include("dode.jl") + #include("dode.jl") include("ffode.jl") include("auxillary.jl") #include("fole.jl") From 97fca674c2e8309b10c402349ef63cfbdd493826 Mon Sep 17 00:00:00 2001 From: ErikQQY <2283984853@qq.com> Date: Mon, 1 Apr 2024 20:16:47 +0800 Subject: [PATCH 2/2] Update Project.toml Signed-off-by: ErikQQY <2283984853@qq.com> --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 3bf7c934c..2159646a8 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "FractionalDiffEq" uuid = "c7492dd8-6170-483b-af64-cefb6c377d9a" authors = ["Qingyu Qu "] -version = "0.3.4" +version = "0.3.5" [deps] ConcreteStructs = "2569d6c7-a4a2-43d3-a901-331e8e4be471"