Skip to content

Commit bc1cec3

Browse files
Merge branch 'main' into l1-gs-smoother
2 parents 5e1203a + a332032 commit bc1cec3

34 files changed

Lines changed: 419 additions & 402 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ jobs:
1111
name: Julia ${{ matrix.julia-version }} - ${{ matrix.os }} - ${{ github.event_name }}
1212
runs-on: ${{ matrix.os }}
1313
timeout-minutes: 40
14-
continue-on-error: ${{ matrix.julia-version == 'nightly' }}
1514
strategy:
1615
matrix:
17-
julia-version: ['1', 'nightly']
16+
julia-version: ['1', '1.10']
1817
os: ['ubuntu-latest']
1918
include:
2019
# - os: windows-latest

docs/src/api-reference/models.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ PressureFieldBC
3838
## Solid Mechanics
3939

4040
```@docs
41-
StructuralModel
41+
QuasiStaticModel
4242
ExtendedHillModel
4343
GeneralizedHillModel
4444
ActiveStressModel

docs/src/literate-tutorials/cm01_simple-active-stress.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ active_stress_model = ActiveStressModel(
9494
weak_boundary_conditions = (NormalSpringBC(1.0, "Epicardium"),)
9595

9696
# We finalize the mechanical model by assigning a symbol to identify the unknown solution field and connect the active stress model with the weak boundary conditions.
97-
mechanical_model = StructuralModel(:displacement, active_stress_model, weak_boundary_conditions)
97+
mechanical_model = QuasiStaticModel(:displacement, active_stress_model, weak_boundary_conditions)
9898

9999
# !!! tip
100100
# A full list of all models can be found in the [API reference](@ref models-api).

docs/src/literate-tutorials/cm03_3d0d-coupling.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ active_stress_model = ActiveStressModel(
286286
microstructure,
287287
)
288288
weak_boundary_conditions = (NormalSpringBC(1.0, "Epicardium"),)
289-
solid_model = StructuralModel(:displacement, active_stress_model, weak_boundary_conditions);
289+
solid_model = QuasiStaticModel(:displacement, active_stress_model, weak_boundary_conditions);
290290

291291
# The solid model is now couple with the circuit model by adding a Lagrange multipliers constraining the 3D chamber volume to match the chamber volume in the 0D model.
292292
p3D = LVc.p3D

src/Thunderbolt.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ include("solver/operator_splitting.jl")
2121
solution_size(f::GenericSplitFunction) = OS.function_size(f)
2222

2323
@reexport using Ferrite
24-
import Ferrite: AbstractDofHandler, AbstractGrid, AbstractRefShape, AbstractCell, get_grid
24+
import Ferrite: AbstractDofHandler, AbstractGrid, AbstractRefShape, AbstractCell, get_grid, get_coordinate_eltype
2525
import Ferrite: vertices, edges, faces, sortedge, sortface
2626
import Ferrite: get_coordinate_type, getspatialdim
2727
import Ferrite: reference_shape_value
@@ -125,14 +125,14 @@ export
125125
# Generic models
126126
ODEProblem,
127127
TransientDiffusionModel,
128-
TransientDiffusionFunction,
128+
AffineODEFunction,
129129
# Local API
130130
PointwiseODEProblem,
131131
PointwiseODEFunction,
132132
# Mechanics
133-
StructuralModel,
133+
QuasiStaticModel,
134134
QuasiStaticProblem,
135-
QuasiStaticNonlinearFunction,
135+
QuasiStaticFunction,
136136
PK1Model,
137137
PrestressedMechanicalModel,
138138
# Passive material models

src/discretization/fem.jl

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
"""
22
Descriptor for a finite element discretization of a part of a PDE over some subdomain.
3+
4+
!!! note
5+
The current implementation is restricted to Bubnov-Galerkin methods. Petrov-Galerkin support will come in the future.
36
"""
47
struct FiniteElementDiscretization
58
"""
69
"""
7-
interpolations::Dict{Symbol, InterpolationCollection}
10+
interpolations::Dict{Symbol}#, Union{<:InterpolationCollection, Pair{<:InterpolationCollection, <:QuadratureRuleCollection}}}
811
"""
912
"""
1013
dbcs::Vector{Dirichlet}
@@ -13,17 +16,42 @@ struct FiniteElementDiscretization
1316
subdomains::Vector{String}
1417
"""
1518
"""
16-
function FiniteElementDiscretization(ips::Dict{Symbol, <: InterpolationCollection}, dbcs::Vector{Dirichlet} = Dirichlet[], subdomains::Vector{String} = [""])
17-
new(ips, dbcs, subdomains)
19+
mass_qrc::Union{<:QuadratureRuleCollection,Nothing} # TODO maybe an "extras" field should be used instead :)
20+
"""
21+
"""
22+
function FiniteElementDiscretization(ips::Dict{Symbol}, dbcs::Vector{Dirichlet} = Dirichlet[], subdomains::Vector{String} = [""], mass_qrc = nothing)
23+
new(ips, dbcs, subdomains, mass_qrc)
1824
end
1925
end
2026

27+
_extract_ipc(ipc::InterpolationCollection) = ipc
28+
_extract_ipc(p::Pair{<:InterpolationCollection, <:QuadratureRuleCollection}) = first(p)
29+
30+
function _extract_qrc(ipc::InterpolationCollection)
31+
ansatzorder = getorder(ipc)
32+
return QuadratureRuleCollection(max(2ansatzorder-1,2))
33+
end
34+
_extract_qrc(p::Pair{<:InterpolationCollection, <:QuadratureRuleCollection}) = last(p)
35+
2136
# Internal utility with proper error message
2237
function _get_interpolation_from_discretization(disc::FiniteElementDiscretization, sym::Symbol)
2338
if !haskey(disc.interpolations, sym)
2439
error("Finite element discretization does not have an interpolation for $sym. Available symbols: $(collect(keys(disc.interpolations))).")
2540
end
26-
return disc.interpolations[sym]
41+
return _extract_ipc(disc.interpolations[sym])
42+
end
43+
function _get_quadrature_from_discretization(disc::FiniteElementDiscretization, sym::Symbol)
44+
if !haskey(disc.interpolations, sym)
45+
error("Finite element discretization does not have an interpolation for $sym. Available symbols: $(collect(keys(disc.interpolations))).")
46+
end
47+
return _extract_qrc(disc.interpolations[sym])
48+
end
49+
function _get_facet_quadrature_from_discretization(disc::FiniteElementDiscretization, sym::Symbol)
50+
if !haskey(disc.interpolations, sym)
51+
error("Finite element discretization does not have an interpolation for $sym. Available symbols: $(collect(keys(disc.interpolations))).")
52+
end
53+
intorder = getorder(_extract_ipc(disc.interpolations[sym]))
54+
return FacetQuadratureRuleCollection(intorder)
2755
end
2856

2957
semidiscretize(::CoupledModel, discretization, mesh::AbstractGrid) = @error "No implementation for the generic discretization of coupled problems available yet."
@@ -33,22 +61,34 @@ function semidiscretize(model::TransientDiffusionModel, discretization::FiniteEl
3361

3462
sym = model.solution_variable_symbol
3563
ipc = _get_interpolation_from_discretization(discretization, sym)
64+
qrc = _get_quadrature_from_discretization(discretization, sym)
3665
dh = DofHandler(mesh)
3766
for name in discretization.subdomains
3867
add_subdomain!(dh, name, [ApproximationDescriptor(sym, ipc)])
3968
end
4069
close!(dh)
4170

42-
return TransientDiffusionFunction(
43-
model.κ,
44-
model.source,
45-
dh
71+
T = get_coordinate_eltype(get_grid(dh))
72+
return AffineODEFunction(
73+
BilinearMassIntegrator(
74+
ConstantCoefficient(T(1.0)),
75+
discretization.mass_qrc === nothing ? qrc : mass_qrc, # Allow e.g. mass lumping for explicit integrators.
76+
sym,
77+
),
78+
BilinearDiffusionIntegrator(
79+
model.κ,
80+
qrc,
81+
sym,
82+
),
83+
model.source, # TODO qrc for source term
84+
dh,
4685
)
4786
end
4887

4988
function semidiscretize(model::SteadyDiffusionModel, discretization::FiniteElementDiscretization, mesh::AbstractGrid)
5089
sym = model.solution_variable_symbol
5190
ipc = _get_interpolation_from_discretization(discretization, sym)
91+
qrc = _get_quadrature_from_discretization(discretization, sym)
5292
dh = DofHandler(mesh)
5393
for name in discretization.subdomains
5494
add_subdomain!(dh, name, [ApproximationDescriptor(sym, ipc)])
@@ -61,11 +101,15 @@ function semidiscretize(model::SteadyDiffusionModel, discretization::FiniteEleme
61101
end
62102
close!(ch)
63103

64-
return SteadyDiffusionFunction(
65-
model.κ,
66-
model.source,
104+
return AffineSteadyStateFunction(
105+
BilinearDiffusionIntegrator(
106+
model.κ,
107+
qrc,
108+
sym,
109+
),
110+
model.source, # TODO qrc for source term
67111
dh,
68-
ch
112+
ch,
69113
)
70114
end
71115

@@ -109,9 +153,10 @@ function semidiscretize(split::ReactionDiffusionSplit{<:MonodomainModel}, discre
109153
return semidiscrete_ode
110154
end
111155

112-
function semidiscretize(model::StructuralModel{<:QuasiStaticModel}, discretization::FiniteElementDiscretization, mesh::AbstractGrid)
156+
function semidiscretize(model::QuasiStaticModel, discretization::FiniteElementDiscretization, mesh::AbstractGrid)
113157
sym = model.displacement_symbol
114158
ipc = _get_interpolation_from_discretization(discretization, sym)
159+
qrc = _get_quadrature_from_discretization(discretization, sym)
115160
dh = DofHandler(mesh)
116161
for name in discretization.subdomains
117162
add_subdomain!(dh, name, [ApproximationDescriptor(sym, ipc)])
@@ -124,11 +169,16 @@ function semidiscretize(model::StructuralModel{<:QuasiStaticModel}, discretizati
124169
end
125170
close!(ch)
126171

127-
semidiscrete_problem = QuasiStaticNonlinearFunction(
172+
semidiscrete_problem = QuasiStaticFunction(
128173
dh,
129174
ch,
130-
model.mechanical_model,
131-
model.face_models
175+
NonlinearIntegrator(
176+
model,
177+
model.face_models,
178+
[sym],
179+
qrc,
180+
_get_facet_quadrature_from_discretization(discretization, sym),
181+
),
132182
)
133183

134184
return semidiscrete_problem

0 commit comments

Comments
 (0)