Skip to content
This repository has been archived by the owner on Feb 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #31 from gridap/diffeqwrapper
Browse files Browse the repository at this point in the history
Diffeqwrapper
  • Loading branch information
santiagobadia authored Aug 14, 2020
2 parents 548291b + f65eef0 commit ee3d0b6
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 1 deletion.
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
Gridap = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e"
LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Sundials = "c3572dad-4567-51f8-b174-8c6c989267f4"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
Expand Down
91 changes: 91 additions & 0 deletions src/DiffEqsWrappers/DiffEqsWrappers.jl
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
2 changes: 1 addition & 1 deletion src/GridapODEs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ include("ODETools/ODETools.jl")

include("TransientFETools/TransientFETools.jl")

# include("Exports.jl")
include("DiffEqsWrappers/DiffEqsWrappers.jl")

end #module
127 changes: 127 additions & 0 deletions test/DiffEqsWrappersTests/DiffEqsTests.jl
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)
#
7 changes: 7 additions & 0 deletions test/DiffEqsWrappersTests/runtests.jl
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
2 changes: 2 additions & 0 deletions test/runtests.jl
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

0 comments on commit ee3d0b6

Please sign in to comment.