This repository has been archived by the owner on Feb 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31 from gridap/diffeqwrapper
Diffeqwrapper
- Loading branch information
Showing
6 changed files
with
229 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
module DiffEqWrappers | ||
|
||
using Test | ||
|
||
using GridapODEs.TransientFETools: TransientFEOperator | ||
|
||
using GridapODEs.ODETools: allocate_cache | ||
using GridapODEs.ODETools: update_cache! | ||
using GridapODEs.ODETools: residual! | ||
using GridapODEs.ODETools: jacobian_and_jacobian_t! | ||
using GridapODEs.ODETools: jacobian! | ||
using GridapODEs.ODETools: jacobian_t! | ||
|
||
using Gridap.Algebra: allocate_jacobian | ||
|
||
using Gridap.FESpaces: get_algebraic_operator | ||
|
||
using Gridap.Algebra: fill_entries! | ||
|
||
export prototype_jacobian | ||
export prototype_mass | ||
export prototype_stiffness | ||
|
||
export diffeq_wrappers | ||
|
||
""" | ||
This method takes a `FEOperator` and returns some methods that can be used | ||
in `DifferentialEquations.jl`. Assuming we want to solve the nonlinear ODE | ||
`res(t,u,du) = 0`, we return: | ||
1. `residual!(res, du, u, p, t)`: It returns the residual (in `res`) at | ||
`(u,du,t)`, following the signature in `DifferentialEquations`. | ||
For the moment, we do not support parameters. | ||
2. `jacobian!(jac, du, u, p, gamma, t)`: Idem for the Jacobian. It returns | ||
`∂res/∂du*γ + ∂res/∂u` | ||
3. `mass!(mass, du, u, p, t)`: Idem for the mass matrix. It returns | ||
`∂res/∂du` | ||
4. `stiffness!(stif, du, u, p, t)`: Idem for the mass matrix. It returns | ||
`∂res/∂u` | ||
""" | ||
function diffeq_wrappers(op) | ||
|
||
ode_op = get_algebraic_operator(op) | ||
ode_cache = allocate_cache(ode_op) | ||
|
||
function _residual!(res, du, u, p, t) | ||
# TO DO (minor): Improve update_cache! st do nothing if same time t as in the cache | ||
# now it would be done twice (residual and jacobian) | ||
ode_cache = update_cache!(ode_cache, ode_op, t) | ||
residual!(res, ode_op, t, u, du, ode_cache) | ||
end | ||
|
||
function _jacobian!(jac, du, u, p, gamma, t) | ||
ode_cache = update_cache!(ode_cache, ode_op, t) | ||
z = zero(eltype(jac)) | ||
fill_entries!(jac, z) | ||
jacobian_and_jacobian_t!(jac, ode_op, t, u, du, gamma, ode_cache) | ||
end | ||
|
||
function _mass!(mass, du, u, p, t) | ||
ode_cache = update_cache!(ode_cache, ode_op, t) | ||
z = zero(eltype(mass)) | ||
fill_entries!(mass, z) | ||
jacobian_t!(mass, ode_op, t, u, du, 1.0, ode_cache) | ||
end | ||
|
||
function _stiffness!(stif, du, u, p, t) | ||
ode_cache = update_cache!(ode_cache, ode_op, t) | ||
z = zero(eltype(stif)) | ||
fill_entries!(stif, z) | ||
jacobian!(stif, ode_op, t, u, du, ode_cache) | ||
end | ||
|
||
return _residual!, _jacobian!, _mass!, _stiffness! | ||
|
||
end | ||
|
||
""" | ||
It allocates the Jacobian (or mass or stiffness) matrix, given the `FEOperator` | ||
and a vector of size total number of unknowns | ||
""" | ||
function prototype_jacobian(op::TransientFEOperator,u0) | ||
ode_op = get_algebraic_operator(op) | ||
ode_cache = allocate_cache(ode_op) # Not acceptable in terms of performance | ||
return allocate_jacobian(ode_op, u0, ode_cache) | ||
end | ||
|
||
const prototype_mass = prototype_jacobian | ||
|
||
const prototype_stiffness = prototype_jacobian | ||
|
||
end #module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
module DiffEqsWrapperTests | ||
|
||
using Test | ||
using Gridap | ||
using GridapODEs | ||
using GridapODEs.ODETools | ||
using GridapODEs.TransientFETools | ||
using GridapODEs.DiffEqWrappers | ||
|
||
# using DifferentialEquations | ||
using Sundials | ||
using Gridap.Algebra: NewtonRaphsonSolver | ||
using Base.Iterators | ||
|
||
# FE problem (heat eq) using Gridap | ||
function fe_problem(u, n) | ||
|
||
f(t) = x -> ∂t(u)(x, t) - Δ(u(t))(x) | ||
|
||
domain = (0, 1, 0, 1) | ||
partition = (n, n) | ||
model = CartesianDiscreteModel(domain, partition) | ||
|
||
order = 1 | ||
|
||
V0 = FESpace( | ||
reffe = :Lagrangian, | ||
order = order, | ||
valuetype = Float64, | ||
conformity = :H1, | ||
model = model, | ||
dirichlet_tags = "boundary", | ||
) | ||
U = TransientTrialFESpace(V0, u) | ||
|
||
trian = Triangulation(model) | ||
degree = 2 * order | ||
quad = CellQuadrature(trian, degree) | ||
|
||
a(u, v) = ∇(v) ⋅ ∇(u) | ||
b(v, t) = v * f(t) | ||
|
||
res(t, u, ut, v) = a(u, v) + ut * v - b(v, t) | ||
jac(t, u, ut, du, v) = a(du, v) | ||
jac_t(t, u, ut, dut, v) = dut * v | ||
|
||
t_Ω = FETerm(res, jac, jac_t, trian, quad) | ||
op = TransientFEOperator(U, V0, t_Ω) | ||
|
||
U0 = U(0.0) | ||
uh0 = interpolate_everywhere(U0, u(0.0)) | ||
u0 = get_free_values(uh0) | ||
|
||
return op, u0 | ||
|
||
end | ||
|
||
# Solving the heat equation using GridapODEs and DiffEqs | ||
tspan = (0.0, 1.0) | ||
|
||
u(x, t) = t | ||
u(t) = x -> u(x, t) | ||
|
||
# ISSUE 1: When I choose n > 2, even though the problem that we will solve is | ||
# linear, the Sundials solvers seems to have convergence issues in the nonlinear | ||
# solver (?). Ut returns errors | ||
# [IDAS ERROR] IDACalcIC Newton/Linesearch algorithm failed to converge. | ||
# ISSUE 2: When I pass `jac_prototype` the code gets stuck | ||
|
||
n = 3 # cells per dim (2D) | ||
op, u0 = fe_problem(u,n) | ||
|
||
# Some checks | ||
res!, jac!, mass!, stif! = diffeq_wrappers(op) | ||
J = prototype_jacobian(op,u0) | ||
r = copy(u0) | ||
θ = 1.0; t0 = 0.0; tF = 1.0; dt = 0.1; tθ = 1.0; dtθ = dt*θ | ||
res!(r, u0, u0, nothing, tθ) | ||
jac!(J, u0, u0, nothing, (1 / dtθ), tθ) | ||
|
||
K = prototype_jacobian(op,u0) | ||
M = prototype_jacobian(op,u0) | ||
stif!(K, u0, u0, nothing, tθ) | ||
mass!(M, u0, u0, nothing, tθ) | ||
# Here you have the mass matrix M | ||
|
||
@test (1/dtθ)*M+K ≈ J | ||
|
||
# To explore the Sundials solver options, e.g., BE with fixed time step dtd | ||
f_iip = DAEFunction{true}(res!; jac = jac!)#, jac_prototype=J) | ||
# jac_prototype is the way to pass my pre-allocated jacobian matrix | ||
prob_iip = DAEProblem{true}(f_iip, u0, u0, tspan, differential_vars = [true]) | ||
# When I pass `jac_prototype` the code get stuck here: | ||
sol_iip = Sundials.solve(prob_iip, IDA(), reltol = 1e-8, abstol = 1e-8) | ||
# @show sol_iip.u | ||
|
||
# or iterator version | ||
integ = init(prob_iip, IDA(), reltol = 1e-8, abstol = 1e-8) | ||
# step!(integ) | ||
|
||
# Show using integrators as iterators | ||
for i in take(integ, 100) | ||
# @show integ.u | ||
end | ||
|
||
end # module | ||
|
||
# FUTURE WORK: Check other options, not only Sundials | ||
|
||
# ISSUE: Future work, add own (non)linear solver. | ||
# Let us assume that we just want to consider a fixed point algorithm | ||
# and we consider an implicit time integration of a nonlinear PDE. | ||
# Our solvers are efficient since they re-use cache among | ||
# nonlinear steps (e.g., symbolic factorization, arrays for numerical factorization) | ||
# and for the transient case in our library, we can also reuse all this | ||
# between time steps. Could we attain something like this using | ||
# DifferentialEquations/Sundials? | ||
# @ChrisRackauckas suggests to take a look at: | ||
# https://docs.sciml.ai/latest/tutorials/advanced_ode_example/ shows swapping out linear solvers. | ||
# https://docs.sciml.ai/latest/features/linear_nonlinear/ is all of the extra details. | ||
|
||
# Try to pass solver too | ||
# ls = LUSolver() | ||
# ls_cache = nothing | ||
# x = copy(u0) | ||
# solve!(x,J,r,ls_cache) | ||
# |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module DiffEqsWrappersTests | ||
|
||
using Test | ||
|
||
@testset "DiffEqWrappers" begin include("DiffEqsTests.jl") end | ||
|
||
end # module |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
module GridapODEsRunTests | ||
|
||
using Test | ||
@time @testset "DiffEqsWrappers" begin include("DiffEqsWrappersTests/runtests.jl") end | ||
|
||
@time @testset "ODETools" begin include("ODEsTests/runtests.jl") end | ||
|
||
@time @testset "TransientFETools" begin include("TransientFEsTests/runtests.jl") end | ||
|
||
|
||
# include("../bench/runbenchs.jl") | ||
|
||
end #module |