Usage - Steady problem
Installation
GridapROMs is a registered package. You can install it by running:
# Use ] to enter the Pkg REPL mode
pkg> add GridapROMs
Load package
Load the package normally with
using GridapROMs
Workflow
The workflow of the package is analogous to that of Gridap, a library for the grid-based approximation of PDEs. Comprehensive Gridap tutorials can be found here. We load Gridap with
using Gridap
Manufactured solution
In this example we solve a parameter dependent Poisson equation
-ν*Δu = f in Ω
ν*∇u⋅n = h in Γn
where Ω
is a sufficiently regular spatial domain, ν
is a (positive) conductivity coefficient, u
is the problem's unknown, f
is a forcing term, and h
a Neumann datum defined on the Neumann boundary Γn
. In this problem, we consider Ω = [0,1]^2
and Γn
to be the right leg of the square. The remaining boundary is Dirichlet, and here we impose a manufactured, parameter-dependent solution. We consider the problem given by the following data:
ν(μ) = x -> exp(-μ[1]*x[1])
u(μ) = x -> μ[1]*x[1] + μ[2]*x[2]
f(μ) = x -> -ν(μ)(x)*Δ(u(μ))(x)
h(μ) = x -> 1
Next, we parameterize the data defined above exclusively by μ
in the following manner:
νₚ(μ) = ParamFunction(ν,μ)
uₚ(μ) = ParamFunction(u,μ)
fₚ(μ) = ParamFunction(f,μ)
hₚ(μ) = ParamFunction(h,μ)
A ParamFunction
is a function that can be evaluated efficiently for any number of desired parameters. In a steady setting, it takes as argument a function (u
, f
and h
in the cases above) and a parameter variable. In a transient setting, an additional time variable must be included (more details can be found in the following tutorial for transient problems).
Geometry
We define the geometry of the problem using
Ω = (0,1,0,1)
partition = (10,10)
Ωₕ = CartesianDiscreteModel(Ω,partition)
FE spaces
Once the discrete geometry is introduced, we define a tuple of trial, test spaces (U,V)
as
order = 1
reffe = ReferenceFE(lagrangian,Float64,order)
V = TestFESpace(Ωₕ,reffe;dirichlet_tags=[1,3,5,6,7])
U = ParamTrialFESpace(V,uₚ)
A ParamTrialFESpace
extends a traditional TrialFESpace
in Gridap, as it allows to provide a μ
-dependent Dirichlet datum. The tags provided occupy the left, upper and bottom legs of the square (extrema excluded for the upper and bottom legs).
Space of parameters
We define a space of parameters, in this case [1,10]^2
:
D = ParamSpace((1,10,1,10))
A parameter, in our case a 2-dimensional vector, is a single realization from D
. By default, a parameter is sampled according to a Halton sequence. Other sampling methods can be defined by providing appropriate keyword arguments:
ParamSpace((1,10,1,10),sampling=:latin_hypercube)
ParamSpace((1,10,1,10),sampling=:normal)
ParamSpace((1,10,1,10),sampling=:uniform)
ParamSpace((1,10,1,10),sampling=:uniform_tensorial)
A single parameter is sampled from D
by calling
μ = realization(D)
whereas a collection of 10 realizations can be obtained by running
realization(D;nparams=10)
Numerical integration
Before introducing the weak formulation of the problem, we define the quantities needed for the numerical integration
degree = 2*order
τₕ = Triangulation(Ωₕ)
Γₕ = BoundaryTriangulation(Ωₕ;tags=[2,4,8])
dΩₕ = Measure(τₕ,degree)
dΓₕ = Measure(Γₕ,degree)
The physical entities corresponding to the tags provided when defining Γₕ
are: the bottom right vertex (2), the top right vertex (4) and the interior of the right edge (8).
Weak formulation
Multiplying the Poisson equation by a test function v ∈ V
and integrating by parts yields the weak formulation of the problem, whose left- and right-hand (LHS & RHS) side are
a(μ,u,v,dΩₕ) = ∫(νₚ(μ)*∇(v)⋅∇(u))dΩₕ
l(μ,u,v,dΩₕ,dΓₕ) = a(μ,u,v,dΩₕ) - ∫(fₚ(μ)*v)dΩₕ - ∫(hₚ(μ)*v)dΓₕ
Note that, in contrast to a traditional Gridap code, the measures involved in the forms are passed as arguments to the forms themselves. (This prevents us from defining a FE operator just by defining a bilinear form for the LHS and a linear form for the RHS as in Gridap: we must actually write the full expression of the residual).
Parametric FE problem
At this point, we can build a FE operator representing the Poisson equation:
τₕ_l = (τₕ,Γₕ)
τₕ_a = (τₕ,)
domains = FEDomains(τₕ_l,τₕ_a)
feop = LinearParamOperator(l,a,D,U,V,domains)
The structure FEDomains
collects the triangulations relative to the LHS & RHS. With respect to a traditional FE operator in Gridap, a LinearParamOperator
provides the aforementioned FEDomains
for the LHS & RHS, as well as the parametric domain D
.
FE solver
We define the FE solver for our Poisson problem:
solver = LUSolver()
RB solver
Finally, we are ready to begin the GridapROMs part. The first part consists in defining the problem's RBSolver
, i.e. the reduced counterpart of a FE solver:
tol = 1e-4
inner_prod(u,v) = ∫(∇(v)⋅∇(u))dΩₕ
reduction_sol = PODReduction(tol,inner_prod;nparams=20)
reduction_l = MDEIMReduction(tol;nparams=10)
reduction_a = MDEIMReduction(tol;nparams=10)
rbsolver = RBSolver(solver,reduction_sol,reduction_l,reduction_a)
A RBSolver
contains the following information:
The FE solver
solver
The reduction strategy for the solution
reduction_sol
. This information is used to build a projection map representing a low-dimensional approximation subspace (i.e. a trial space) for our differential problem. In the case above, we use a truncated POD with tolerancetol
on a set of 20 snapshots. The output is orthogonal with respect to the forminner_prod
, i.e. theH^1_0
product.The hyper-reduction strategy for the residual
reduction_l
. This information is used to build a projection map representing a low-dimensional subspace for the residual, equipped with a reduced integration domain obtained via MDEIM, i.e. the matrix-based empirical interpolation method. A total of 10 residual snapshots is used to compute the output.Similarly, the hyper-reduction strategy for the Jacobian
reduction_a
.
Other reduction strategies include fixing the rank of the truncation
rank = 5
PODReduction(rank,inner_prod;nparams=20)
and using randomized POD algorithms
PODReduction(tol,inner_prod;nparams=20,sketch=:sprn)
A comprehensive documentation on randomized POD algorithms can be found here.
Offline phase
The offline phase is the part of the code where the projection maps for the solution, LHS & RHS are computed. This phase is quite expensive to run, but on the upside it can just be run once, provided the outputs are saved to file. For this purpose, we load the well-known packages DrWatson and Serialization
using DrWatson
using Serialization
and define a saving directory for our example
dir = datadir("poisson")
create_dir(dir)
Next, we try loading the offline quantities; if the load fails, we must run the offline phase
try # try loading offline quantities
rbop = load_operator(dir,feop)
catch # offline phase
rbop = reduced_operator(rbsolver,feop)
save(dir,rbop)
end
The load might fail, for e.g., if
It is the first time running the code
A different directory was used to save the offline structures in previous runs
For developers, if the definition of one of the loaded types has changed since it was saved to file
The offline structures are completely contained in the variable rbop
, which is the reduced version of the FE operator feop
. To understand better the meaning of this variable, we report the content of the function reduced_operator
:
using GridapROMs.Utils
using GridapROMs.ParamSteady
using GridapROMs.RBSteady
# compute the solution snapshots
fesnaps, = solution_snapshots(rbsolver,feop)
# compute the reduced trial and test spaces
Û,V̂ = reduced_spaces(rbsolver,feop,fesnaps)
# compute the hyper-reduction for LHS & RHS
â,l̂ = reduced_weak_form(rbsolver,feop,Û,V̂,fesnaps)
# fetch the reduced FEDomains
τₕ_l̂,τₕ_â = get_domains(l̂),get_domains(â)
# replace the original FEDomains with the reduced ones
feop′ = change_domains(feop,τₕ_l̂,τₕ_â)
# definition of reduced operator
rbop = GenericRBOperator(feop′,Û,V̂,â,l̂)
Online phase
This step consists in computing the GridapROMs approximation for any desired parameter. We consider, for e.g., 10 parameters distributed uniformly on D
μₒₙ = realization(D;nparams=10,sampling=:uniform)
and we solve the reduced problem
x̂on,rbstats = solve(rbsolver,rbop,μₒₙ)
Post processing
In order to test the quality of the approximation x̂on
, we can run the following post-processing code
xon,festats = solution_snapshots(solver,feop,μₒₙ)
perf = eval_performance(rbsolver,feop,rbop,xon,x̂on,festats,rbstats)
println(perf)
In other words, we first compute the HF solution xon
in the online parameters μₒₙ
, and then we run the performance tester, which in particular returns
The relative error ||xon - x̂on|| / ||xon||, averaged on the 10 parameters in
μₒₙ
. The norm is the one specified byinner_prod
, so in our case theH^1_0
product.The speedup in terms of time and memory achieved with respect to the HF simulations. This is done by comparing the variables
rbstats
andfestats
, which contain the time (in seconds) and memory allocations (in Gb) of the two algorithms.