mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-06 04:21:33 +00:00
feat(docs): add elements_multiphysics_teaser.md
docs/src/elements_multiphysics_teaser.md | 141 +++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+)
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# [Elements, DOF placement, materials, and multiphysics](@id elements_multiphysics_teaser)
|
||||
|
||||
This page is a conceptual teaser for the current (0.x) element pipeline: what the
|
||||
types mean, how global numbering attaches to an element, how materials
|
||||
hook in, and how a deliberately mixed DOF specification still follows one
|
||||
mechanical pattern.
|
||||
|
||||
For API listings, see [API Reference](@ref). For maintainer detail and
|
||||
invariants, see `AGENTS.md` and the `README.md` files under `src/elements/`
|
||||
and `src/dofs/`.
|
||||
|
||||
## Element as a typed template
|
||||
|
||||
A finite element is Ciarlet's triple ``(K, P, \Sigma)`` carried almost
|
||||
entirely in the type system:
|
||||
|
||||
| Role | Julia type |
|
||||
|------|----------------|
|
||||
| Reference domain ``K`` | Topology type, e.g. `Tetrahedron{4}`, `Hex8` |
|
||||
| Local space ``P`` | Basis type, e.g. `Lagrange{1}` |
|
||||
| Degrees of freedom ``\Sigma`` | `S`, a `@DOFSet{...}` (NamedTuple of `DOF{Quantity, Entity}`) |
|
||||
| Total local DOF count | Type parameter `N`, inferred from `K` and `S` |
|
||||
|
||||
The runtime struct is minimal:
|
||||
|
||||
```julia
|
||||
struct Element{K, P, S, N}
|
||||
id::UInt
|
||||
dof_indices::NTuple{N, UInt64}
|
||||
end
|
||||
```
|
||||
|
||||
`K` and `P` are not stored; they only refine the type. The only heavy
|
||||
per-element data is the flat tuple `dof_indices`, one global DOF index per
|
||||
local DOF, in the canonical order defined below.
|
||||
|
||||
## Where each DOF "lives"
|
||||
|
||||
You declare fields with `@DOFSet`:
|
||||
|
||||
```julia
|
||||
S = @DOFSet{
|
||||
T::DOF{Temperature, Vertex},
|
||||
u::DOF{Displacement{3}, Vertex},
|
||||
p::DOF{Float64, Cell}, # discontinuous scalar (e.g. pressure bubble)
|
||||
}
|
||||
```
|
||||
|
||||
Each entry is `DOF{Quantity, Entity}`:
|
||||
|
||||
- `Quantity` fixes the number of components per attachment point
|
||||
(scalar temperature, 3-vector displacement, …) via `dof_size`.
|
||||
- `Entity` selects the topological anchor: `Vertex`, `Edge`, `Face`, or
|
||||
`Cell`.
|
||||
|
||||
The constructor for `Element{K,P,S,N}` checks that `N` equals `ndofs(K, S)`.
|
||||
|
||||
`create_elements!(mesh, Element{K,P,S})` builds a `DOFHandler` and fills
|
||||
each element's `dof_indices` so shared mesh entities reuse the same global
|
||||
indices. You do not hand-wire indices by hand in normal use.
|
||||
|
||||
## Compile-time layout: `local_dof_layout`
|
||||
|
||||
The order of entries in `dof_indices` is defined by
|
||||
`local_dof_layout(::Type{Element{K,P,S,N}})`, a `@generated` function that
|
||||
returns `NTuple{N, DOFLayoutEntry}`. Each entry stores
|
||||
`(field_idx, entity_local, component)` for one local DOF index.
|
||||
|
||||
Fields are visited in NamedTuple key order. For each field, all vertex
|
||||
DOFs (if `Entity === Vertex`) are enumerated in local vertex order, then
|
||||
components; then the next field. A `Cell`-anchored field contributes one
|
||||
logical "entity" worth of components per element (pressure bubble, …).
|
||||
|
||||
Assemblers and matrix-free operators index this tuple instead of doing
|
||||
runtime `div`/`mod` arithmetic to decode local DOFs.
|
||||
|
||||
Current limitation: the generated `local_dof_layout` implements `Vertex`
|
||||
and `Cell` attachments. `Edge` and `Face` are part of the long-term design
|
||||
(documented in `src/dofs/fields.jl`) but are not wired through the
|
||||
generator yet; adding them is a localized extension.
|
||||
|
||||
## Materials: traits and kernels
|
||||
|
||||
Materials subtype `AbstractMaterial`. Several open functions form a small
|
||||
trait layer, for example:
|
||||
|
||||
- `material_behavior(material)` — constant tangent, strain-dependent,
|
||||
stateful plasticity, …
|
||||
- `supported_physics(material)` — tuple of physics markers such as
|
||||
`Elasticity{3}()`, `Thermal{3}()`
|
||||
- `required_state_variables(material)` — what must live in IP state
|
||||
storage
|
||||
|
||||
Concrete materials implement these in their own files; see
|
||||
`src/materials/traits.jl` and `src/materials/api.jl`.
|
||||
|
||||
Important separation: the element type `S` describes which global DOFs exist
|
||||
and how they are ordered. A kernel decides which physics runs at a
|
||||
quadrature point and which material(s) supply tangents and forces.
|
||||
|
||||
Example: `ContinuumKernel` pairs one elastic material with a displacement
|
||||
field. `ThermoElasticKernel` (under `src/domains/thermo_elastic/`) holds
|
||||
both a mechanical and a thermal material; `evaluate_entry` dispatches on
|
||||
the `field_idx` pair from `DOFLayoutEntry` so `K_uu`, `K_TT`, and the
|
||||
coupling blocks are assembled from one element loop. That is the intended
|
||||
pattern for multiphysics: one `S`, one element storage model, kernels that
|
||||
know the physics blocks.
|
||||
|
||||
## A deliberately mixed specification
|
||||
|
||||
Thermo-mechanics with temperature and displacement on vertices is the
|
||||
simplest coupled story (four DOFs per node on a tetrahedron). A harsher
|
||||
stress test for the DOF machinery is vertex displacement plus a
|
||||
discontinuous cell pressure (Stokes-style `u`–`p`):
|
||||
|
||||
```julia
|
||||
S = @DOFSet{u::DOF{Displacement{3}, Vertex},
|
||||
p::DOF{Float64, Cell}}
|
||||
```
|
||||
|
||||
The test file `test/dofs/test_multifield_dof_system.jl` walks this path
|
||||
end-to-end: `ndofs` matches `local_dof_layout`, block ordering (all `u`
|
||||
DOFs, then all `p` DOFs), handler connectivity, and helpers such as
|
||||
`field_dof_range` / `element_dofs` aligned with the layout tuple.
|
||||
|
||||
Adding more named fields is mostly declaring another `DOF{…, …}` line in
|
||||
`@DOFSet` and providing a kernel that implements the cross-blocks you care
|
||||
about. The expensive part is physics and testing, not extending the
|
||||
element struct.
|
||||
|
||||
## Summary
|
||||
|
||||
- Elements are types plus a flat global index tuple; `S` is the single
|
||||
source of truth for DOF count and ordering.
|
||||
- `create_elements!` maps mesh topology to those indices in a type-stable
|
||||
way.
|
||||
- Materials expose traits; kernels connect materials to the relevant
|
||||
`field_idx` blocks via `local_dof_layout`.
|
||||
- Multifield and mixed `Vertex`/`Cell` anchoring already exercise the
|
||||
production DOF path; richer entity attachments follow the same layout
|
||||
idea once implemented.
|
||||
Reference in New Issue
Block a user