Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release Gridap 0.18 #985

Merged
merged 26 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e3f8ff4
Added missing methods for assemblers
JordiManyer Mar 19, 2024
f5bad1c
Added missing MultiField API
JordiManyer Mar 19, 2024
b772166
Updated NEWS.md
JordiManyer Mar 19, 2024
104a26b
Added kwarg to specify assembler
JordiManyer Mar 20, 2024
a45cc92
Bump version to 0.18.0
JordiManyer Mar 21, 2024
ad51bb4
Added some tests
JordiManyer Mar 21, 2024
fc51103
Added dot for MultiField
JordiManyer Mar 27, 2024
43b88d5
Merge branch 'master' of github.com:gridap/Gridap.jl into add-missing…
JordiManyer Mar 27, 2024
13c2f7e
Updated NEWS.md
JordiManyer Mar 27, 2024
5a01f78
Gridap now extends Statistics.mean
JordiManyer Mar 27, 2024
b582242
Merge branch 'add-missing-api' of github.com:gridap/Gridap.jl into ex…
JordiManyer Mar 27, 2024
d7e95ae
Updated NEWS.md
JordiManyer Mar 27, 2024
3707376
Merge pull request #988 from gridap/extend-statistics-mean
JordiManyer Mar 28, 2024
04b77b8
Deprecated SubVector in favor of view
JordiManyer Mar 29, 2024
1824d46
Updated news
JordiManyer Mar 29, 2024
1a51138
Merge pull request #989 from gridap/remove-subvector
JordiManyer Mar 29, 2024
9f495f5
Added `axpy_entries` for `AbstractBlockMatrix`
oriolcg Apr 8, 2024
f2f4dac
Merge branch 'add-missing-api' of github.com:gridap/Gridap.jl into ax…
JordiManyer Apr 9, 2024
a202bf1
Merge pull request #991 from gridap/axpy_entries_for_blockMatrix
JordiManyer Apr 9, 2024
332c18a
Added missing FEFunction constructor
JordiManyer Apr 9, 2024
33f9c94
Merge branch 'add-missing-api' of github.com:gridap/Gridap.jl into ad…
JordiManyer Apr 9, 2024
ac42704
Added keyword to specify assembler for all TransientFEOperator constr…
AlexandreMagueresse Apr 9, 2024
834289d
Added the possibility to give the initial velocity for GeneralizedAlp…
AlexandreMagueresse Apr 9, 2024
fb042a3
Edited the docs of ODEs with initial velocity/acceleration for Genera…
AlexandreMagueresse Apr 9, 2024
16d4035
Implemented the TimeSlicing operator for improved performance and not…
AlexandreMagueresse Apr 10, 2024
53367a7
Renamed TimeSlicing into TimeSpaceFunction and updated constructor
AlexandreMagueresse Apr 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.17.23] - 2024-01-28
## [0.18.0] - 2024-03-22

### Breaking

- ODE module extensive refactor. Breaking changes! See docs and PR for details. Since PR[965](https://github.com/gridap/Gridap.jl/pull/965).
- Fixed name clash with `Statistics.mean`. Since PR[#988](https://github.com/gridap/Gridap.jl/pull/988).
- Deprecated `SubVector` in favor of Julia's `view`. Since PR[#989](https://github.com/gridap/Gridap.jl/pull/989).

### Added

- Added some missing API methods to `Assemblers` and `MultiField`. Since PR[#985](https://github.com/gridap/Gridap.jl/pull/985).

### Fixed

- Fix when evaluating `\circ` operator with `CellState`. Since PR[#987](https://github.com/gridap/Gridap.jl/pull/987).

## [0.17.23] - 2024-01-28

### Changed

Expand Down
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Gridap"
uuid = "56d4f2e9-7ea1-5844-9cf6-b9c51ca7ce8e"
authors = ["Santiago Badia <[email protected]>", "Francesc Verdugo <[email protected]>", "Alberto F. Martin <[email protected]>"]
version = "0.17.23"
version = "0.18.0"

[deps]
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
Expand All @@ -26,6 +26,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SparseMatricesCSR = "a0a7dd2c-ebf4-11e9-1f05-cf50bc540ca1"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
WriteVTK = "64499a7a-5c06-52f2-abe2-ccb03c286192"

Expand Down
16 changes: 15 additions & 1 deletion docs/src/ODEs.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ A `TransientTrialFESpace` can be evaluated at any time derivative order, and the

For example, the following creates a transient `FESpace` and evaluates its first two time derivatives.
```
g(t::Real) = x -> x[1] + x[2] * t
g(t) = x -> x[1] + x[2] * t
V = FESpace(model, reffe, dirichlet_tags="boundary")
U = TransientTrialFESpace (V, g)

Expand Down Expand Up @@ -155,6 +155,16 @@ TransientLinearFEOperator((stiffness, mass), res, U, V, constant_forms=(false, t
```
If $\kappa$ is constant, the keyword `constant_forms` could be replaced by `(true, true)`.

## The `TimeSpaceFunction` constructor
Apply differential operators on a function that depends on time and space is somewhat cumbersome. Let `f` be a function of time and space, and `g(t) = x -> f(t, x)` (as in the prescription of the boundary conditions `g` above). Applying the operator $\partial_{t} - \Delta$ to `g` and evaluating at $(t, x)$ is written `∂t(g)(t)(x) - Δ(g(t))(x)`.

The constructor `TimeSpaceFunction` allows for simpler notations: let `h = TimeSpaceFunction(g)`. The object `h` is a functor that supports the notations
* `op(h)`: a `TimeSpaceFunction` representing both `t -> x -> op(f)(t, x)` and `(t, x) -> op(f)(t, x)`,
* `op(h)(t)`: a function of space representing `x -> op(f)(t, x)`
* `op(h)(t, x)`: the quantity `op(f)(t, x)` (this notation is equivalent to `op(h)(t)(x)`),

for all spatial and temporal differential operator, i.e. `op` in `(time_derivative, gradient, symmetric_gradient, divergence, curl, laplacian)` and their symbolic aliases (`∂t`, `∂tt`, `∇`, ...). The operator above applied to `h` and evaluated at `(t, x)` can be conveniently written `∂t(h)(t, x) - Δ(h)(t, x)`.

## Solver and solution
The next step is to choose an ODE solver (see below for a full list) and specify the boundary conditions. The solution can then be iterated over until the final time is reached.

Expand Down Expand Up @@ -252,6 +262,8 @@ By looking at the behaviour of the stability function at infinity, we find that
## Generalised- $\alpha$ scheme for first-order ODEs
This scheme relies on the state vector $\\{\boldsymbol{s}(t)\\} = \\{\boldsymbol{u}(t), \partial_{t} \boldsymbol{u}(t)\\}$. In particular, it needs a nontrivial starting procedure that evaluates $\partial_{t} \boldsymbol{u}(t_{0})$ by enforcing a zero residual at $t_{0}$. The finaliser can still return the first vector of the state vectors. For convenience, let $\partial_{t} \boldsymbol{u}\_{n}$ denote the approximation $\partial_{t} \boldsymbol{u}(t_{n})$.

> Alternatively, the initial velocity can be provided manually: when calling `solve(odeslvr, tfeop, t0, tF, uhs0)`, set `uhs0 = (u0, v0, a0)` instead of `uhs0 = (u0, v0)`. This is useful when enforcing a zero initial residual would lead to a singular system.

This method extends the $\theta$-method by considering the two-point quadrature rule $$\boldsymbol{u}(t_{n+1}) = \boldsymbol{u}\_{n} + \int_{t_{n}}^{t_{n+1}} \partial_{t} \boldsymbol{u}(t) \ \mathrm{d} t \approx \boldsymbol{u}\_{n} + h_{n} [(1 - \gamma) \partial_{t} \boldsymbol{u}(t_{n}) + \gamma \partial_{t} \boldsymbol{u}(t_{n+1})],$$
where $0 \leq \gamma \leq 1$ is a free parameter. The question is now how to estimate $\partial_{t} \boldsymbol{u}(t_{n+1})$. This is achieved by enforcing a zero residual at $t_{n + \alpha_{F}} \doteq (1 - \alpha_{F}) t_{n} + \alpha_{F} t_{n+1}$, where $0 \leq \alpha_{F} \leq 1$ is another free parameter. The value of $\boldsymbol{u}$ at that time, $\boldsymbol{u}\_{n + \alpha_{F}}$, is obtained by the same linear combination of $\boldsymbol{u}$ at $t_{n}$ and $t_{n+1}$. Regarding $\partial_{t} \boldsymbol{u}$, it is taken as a linear combination weighted by another free parameter $0 < \alpha_{M} \leq 1$ of the time derivative at times $t_{n}$ and $t_{n+1}$. Note that $\alpha_{M}$ cannot be zero. Altogether, we have defined the discrete operators
```math
Expand Down Expand Up @@ -399,6 +411,8 @@ We note that the first column of the matrix and the first weight are all zero, s
## Generalised- $\alpha$ scheme for second-order ODEs
This scheme relies on the state vector $\\{\boldsymbol{s}(t)\\} = \\{\boldsymbol{u}(t), \partial_{t} \boldsymbol{u}(t), \partial_{tt} \boldsymbol{u}(t)\\}$. It needs a nontrivial starting procedure that evaluates $\partial_{tt} \boldsymbol{u}(t_{0})$ by enforcing a zero residual at $t_{0}$. The finaliser can still return the first vector of the state vectors. For convenience, let $\partial_{tt} \boldsymbol{u}\_{n}$ denote the approximation $\partial_{tt} \boldsymbol{u}(t_{n})$.

> The initial acceleration can alternatively be provided manually: when calling `solve(odeslvr, tfeop, t0, tF, uhs0)`, set `uhs0 = (u0, v0, a0)` instead of `uhs0 = (u0, v0)`. This is useful when enforcing a zero initial residual would lead to a singular system.

This method is built out of the following update rule
```math
\begin{align*}
Expand Down
7 changes: 7 additions & 0 deletions src/Algebra/AlgebraInterfaces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ function axpy_entries!(
B
end

function axpy_entries!(α::Number, A::T, B::T) where {T<:AbstractBlockMatrix}
map(blocks(A), blocks(B)) do a, b
axpy_entries!(α, a, b)
end
B
end

#
# Some API associated with assembly routines
#
Expand Down
3 changes: 1 addition & 2 deletions src/Arrays/Arrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ export find_local_index

export IdentityVector

export SubVector
export pair_arrays
export unpair_arrays

Expand Down Expand Up @@ -162,7 +161,7 @@ include("KeyToValMaps.jl")

include("FilteredArrays.jl")

include("SubVectors.jl")
include("SubVectors.jl") # Deprecated

include("ArrayPairs.jl")

Expand Down
4 changes: 0 additions & 4 deletions src/Arrays/PrintOpTrees.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ function get_children(n::TreeNode, a::LazyArray)
(similar_tree_node(n,a.maps),map(i->similar_tree_node(n,i),a.args)...)
end

function get_children(n::TreeNode, a::SubVector)
(similar_tree_node(n,a.vector),)
end

function get_children(n::TreeNode, a::Reindex)
(similar_tree_node(n,a.values),)
end
Expand Down
2 changes: 2 additions & 0 deletions src/Arrays/SubVectors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
pini::Int
pend::Int
end

`SubVector` is deprecated, use `view` instead.
"""
struct SubVector{T,A<:AbstractVector{T}} <: AbstractVector{T}
vector::A
Expand Down
1 change: 1 addition & 0 deletions src/CellData/CellData.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import Gridap.Geometry: get_triangulation
import Gridap.TensorValues: inner, outer, double_contraction, symmetric_part
import LinearAlgebra: det, tr, cross, dot, ⋅, rmul!
import Base: inv, abs, abs2, *, +, -, /, adjoint, transpose, real, imag, conj
import Statistics: mean

export gradient, ∇
export ∇∇
Expand Down
25 changes: 22 additions & 3 deletions src/FESpaces/Assemblers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ end

"""
"""
function assemble_matrix_add!(mat,a::Assembler, matdata)
function assemble_matrix_add!(mat,a::Assembler,matdata)
@abstractmethod
end

Expand All @@ -215,11 +215,11 @@ end

"""
"""
function assemble_matrix_and_vector!(A,b,a::Assembler, data)
function assemble_matrix_and_vector!(A,b,a::Assembler,data)
@abstractmethod
end

function assemble_matrix_and_vector_add!(A,b,a::Assembler, data)
function assemble_matrix_and_vector_add!(A,b,a::Assembler,data)
@abstractmethod
end

Expand Down Expand Up @@ -279,6 +279,17 @@ end
# Some syntactic sugar for assembling from anonymous functions
# and objects from which one can collect cell matrices/vectors

function allocate_matrix(f::Function,a::Assembler,U::FESpace,V::FESpace)
v = get_fe_basis(V)
u = get_trial_fe_basis(U)
allocate_matrix(a,collect_cell_matrix(U,V,f(u,v)))
end

function allocate_vector(f::Function,a::Assembler,V::FESpace)
v = get_fe_basis(V)
allocate_vector(a,collect_cell_vector(V,f(v)))
end

function assemble_matrix(f::Function,a::Assembler,U::FESpace,V::FESpace)
v = get_fe_basis(V)
u = get_trial_fe_basis(U)
Expand Down Expand Up @@ -313,6 +324,14 @@ function assemble_matrix_and_vector!(f::Function,b::Function,M::AbstractMatrix,r
assemble_matrix_and_vector!(M,r,a,collect_cell_matrix_and_vector(U,V,f(u,v),b(v)))
end

function assemble_matrix_and_vector!(
f::Function,b::Function,M::AbstractMatrix,r::AbstractVector,a::Assembler,U::FESpace,V::FESpace,uhd
)
v = get_fe_basis(V)
u = get_trial_fe_basis(U)
assemble_matrix_and_vector!(M,r,a,collect_cell_matrix_and_vector(U,V,f(u,v),b(v),uhd))
end

function assemble_matrix(f,a::Assembler,U::FESpace,V::FESpace)
assemble_matrix(a,collect_cell_matrix(U,V,f))
end
Expand Down
5 changes: 5 additions & 0 deletions src/MultiField/MultiFieldCellFields.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,8 @@ Base.getindex(a::MultiFieldCellField,i::Integer) = a.single_fields[i]
Base.iterate(a::MultiFieldCellField) = iterate(a.single_fields)
Base.iterate(a::MultiFieldCellField,state) = iterate(a.single_fields,state)
Base.length(a::MultiFieldCellField) = num_fields(a)

function LinearAlgebra.dot(a::MultiFieldCellField,b::MultiFieldCellField)
@check num_fields(a) == num_fields(b)
return sum(map(dot,a.single_fields,b.single_fields))
end
5 changes: 5 additions & 0 deletions src/MultiField/MultiFieldFEFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,8 @@ Base.iterate(m::MultiFieldFEFunction) = iterate(m.single_fe_functions)
Base.iterate(m::MultiFieldFEFunction,state) = iterate(m.single_fe_functions,state)
Base.getindex(m::MultiFieldFEFunction,field_id::Integer) = m.single_fe_functions[field_id]
Base.length(m::MultiFieldFEFunction) = num_fields(m)

function LinearAlgebra.dot(a::MultiFieldFEFunction,b::MultiFieldFEFunction)
@check num_fields(a) == num_fields(b)
return sum(map(dot,a.single_fe_functions,b.single_fe_functions))
end
33 changes: 30 additions & 3 deletions src/MultiField/MultiFieldFESpaces.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ function FESpaces.get_free_dof_ids(f::MultiFieldFESpace,::BlockMultiFieldStyle{N
return BlockArrays.blockedrange(block_num_dofs)
end

function FESpaces.zero_dirichlet_values(f::MultiFieldFESpace)
map(zero_dirichlet_values,f.spaces)
end

FESpaces.get_dof_value_type(f::MultiFieldFESpace{MS,CS,V}) where {MS,CS,V} = eltype(V)

FESpaces.get_vector_type(f::MultiFieldFESpace) = f.vector_type
Expand Down Expand Up @@ -262,6 +266,18 @@ function FESpaces.FEFunction(fe::MultiFieldFESpace, free_values)
MultiFieldFEFunction(free_values,fe,blocks)
end

function FESpaces.FEFunction(
fe::MultiFieldFESpace, free_values::AbstractVector, dir_values::Vector{<:AbstractVector}
)
@check length(dir_values) == num_fields(fe)
blocks = map(1:length(fe.spaces)) do i
free_values_i = restrict_to_field(fe,free_values,i)
dir_values_i = dir_values[i]
FEFunction(fe.spaces[i],free_values_i,dir_values_i)
end
MultiFieldFEFunction(free_values,fe,blocks)
end

function FESpaces.EvaluationFunction(fe::MultiFieldFESpace, free_values)
blocks = map(1:length(fe.spaces)) do i
free_values_i = restrict_to_field(fe,free_values,i)
Expand Down Expand Up @@ -297,7 +313,7 @@ function _restrict_to_field(f,
offsets = _compute_field_offsets(U)
pini = offsets[field] + 1
pend = offsets[field] + num_free_dofs(U[field])
SubVector(free_values,pini,pend)
view(free_values,pini:pend)
end

function _restrict_to_field(f,
Expand All @@ -316,7 +332,7 @@ function _restrict_to_field(f,
offsets = compute_field_offsets(f,mfs)
pini = offsets[field] + 1
pend = offsets[field] + num_free_dofs(U[field])
return SubVector(block_free_values,pini,pend)
return view(block_free_values,pini:pend)
end

"""
Expand Down Expand Up @@ -596,7 +612,18 @@ function FESpaces.interpolate_everywhere(objects, fe::MultiFieldFESpace)
for (field, (U,object)) in enumerate(zip(fe.spaces,objects))
free_values_i = restrict_to_field(fe,free_values,field)
dirichlet_values_i = zero_dirichlet_values(U)
uhi = interpolate_everywhere!(object, free_values_i,dirichlet_values_i,U)
uhi = interpolate_everywhere!(object,free_values_i,dirichlet_values_i,U)
push!(blocks,uhi)
end
MultiFieldFEFunction(free_values,fe,blocks)
end

function FESpaces.interpolate_everywhere!(objects,free_values::AbstractVector,dirichlet_values::Vector,fe::MultiFieldFESpace)
blocks = SingleFieldFEFunction[]
for (field, (U,object)) in enumerate(zip(fe.spaces,objects))
free_values_i = restrict_to_field(fe,free_values,field)
dirichlet_values_i = dirichlet_values[field]
uhi = interpolate_everywhere!(object,free_values_i,dirichlet_values_i,U)
push!(blocks,uhi)
end
MultiFieldFEFunction(free_values,fe,blocks)
Expand Down
61 changes: 53 additions & 8 deletions src/ODEs/ODESolvers/GeneralizedAlpha1.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,27 @@ function GeneralizedAlpha1(
GeneralizedAlpha1(sysslvr, dt, αf, αm, γ)
end

# Default allocate_odecache without velocity
function allocate_odecache(
odeslvr::GeneralizedAlpha1, odeop::ODEOperator,
t0::Real, us0::NTuple{1,AbstractVector}
)
u0 = us0[1]
allocate_odecache(odeslvr, odeop, t0, (u0, u0))
end

##################
# Nonlinear case #
##################
function allocate_odecache(
odeslvr::GeneralizedAlpha1, odeop::ODEOperator,
t0::Real, us0::NTuple{1,AbstractVector}
t0::Real, us0::NTuple{2,AbstractVector}
)
u0 = us0[1]
us0N = (u0, u0)
u0, v0 = us0[1], us0[2]
us0N = (u0, v0)
odeopcache = allocate_odeopcache(odeop, t0, us0N)

uα, vα = copy(u0), copy(u0)
uα, vα = copy(u0), copy(v0)

sysslvrcache = nothing
odeslvrcache = (uα, vα, sysslvrcache)
Expand Down Expand Up @@ -104,6 +113,24 @@ function ode_start(
(state0, odecache)
end

function ode_start(
odeslvr::GeneralizedAlpha1, odeop::ODEOperator,
t0::Real, us0::NTuple{2,AbstractVector},
odecache
)
# Unpack inputs
u0, v0 = us0[1], us0[2]

# Allocate state
s0, s1 = copy(u0), copy(v0)

# Update state
state0 = (s0, s1)

# Pack outputs
(state0, odecache)
end

function ode_march!(
stateF::NTuple{2,AbstractVector},
odeslvr::GeneralizedAlpha1, odeop::ODEOperator,
Expand Down Expand Up @@ -163,13 +190,13 @@ end
###############
function allocate_odecache(
odeslvr::GeneralizedAlpha1, odeop::ODEOperator{<:AbstractLinearODE},
t0::Real, us0::NTuple{1,AbstractVector}
t0::Real, us0::NTuple{2,AbstractVector}
)
u0 = us0[1]
us0N = (u0, u0)
u0, v0 = us0[1], us0[2]
us0N = (u0, v0)
odeopcache = allocate_odeopcache(odeop, t0, us0N)

uα, vα = zero(u0), zero(u0)
uα, vα = zero(u0), zero(v0)

constant_stiffness = is_form_constant(odeop, 0)
constant_mass = is_form_constant(odeop, 1)
Expand Down Expand Up @@ -229,6 +256,24 @@ function ode_start(
(state0, odecache)
end

function ode_start(
odeslvr::GeneralizedAlpha1, odeop::ODEOperator{<:AbstractLinearODE},
t0::Real, us0::NTuple{2,AbstractVector},
odecache
)
# Unpack inputs
u0, v0 = us0[1], us0[2]

# Allocate state
s0, s1 = copy(u0), copy(v0)

# Update state
state0 = (s0, s1)

# Pack outputs
(state0, odecache)
end

function ode_march!(
stateF::NTuple{2,AbstractVector},
odeslvr::GeneralizedAlpha1, odeop::ODEOperator{<:AbstractLinearODE},
Expand Down
Loading
Loading