Functionalities for implicit methods
Degrees of freedom (DoF) mapping
Tesserae.DofMap
— TypeDofMap(mask::AbstractArray{Bool})
Create a degree of freedom (DoF) map from a mask
of size (ndofs, size(grid)...)
. ndofs
represents the number of DoFs for a field.
julia> mesh = CartesianMesh(1, (0,2), (0,1));
julia> grid = generate_grid(@NamedTuple{x::Vec{2,Float64}, v::Vec{2,Float64}}, mesh);
julia> grid.v .= reshape(reinterpret(Vec{2,Float64}, 1.0:12.0), 3, 2)
3×2 Matrix{Vec{2, Float64}}:
[1.0, 2.0] [7.0, 8.0]
[3.0, 4.0] [9.0, 10.0]
[5.0, 6.0] [11.0, 12.0]
julia> dofmask = falses(2, size(grid)...);
julia> dofmask[1,1:2,:] .= true; # activate nodes
julia> dofmask[:,3,2] .= true; # activate nodes
julia> reinterpret(reshape, Vec{2,Bool}, dofmask)
3×2 reinterpret(reshape, Vec{2, Bool}, ::BitArray{3}) with eltype Vec{2, Bool}:
[1, 0] [1, 0]
[1, 0] [1, 0]
[0, 0] [1, 1]
julia> dofmap = DofMap(dofmask);
julia> dofmap(grid.v)
6-element view(reinterpret(reshape, Float64, ::Matrix{Vec{2, Float64}}), CartesianIndex{3}[CartesianIndex(1, 1, 1), CartesianIndex(1, 2, 1), CartesianIndex(1, 1, 2), CartesianIndex(1, 2, 2), CartesianIndex(1, 3, 2), CartesianIndex(2, 3, 2)]) with eltype Float64:
1.0
3.0
7.0
9.0
11.0
12.0
Sparse matrix
Tesserae.create_sparse_matrix
— Functioncreate_sparse_matrix(interpolation, mesh; ndofs = ndims(mesh))
Create a sparse matrix. Since the created matrix accounts for all nodes in the mesh, it needs to be extracted for active nodes using the DofMap
. ndofs
represents the number of DoFs for a field.
julia> mesh = CartesianMesh(1, (0,10), (0,10));
julia> A = create_sparse_matrix(BSpline(Linear()), mesh; ndofs = 1)
121×121 SparseArrays.SparseMatrixCSC{Float64, Int64} with 961 stored entries:
⎡⠻⣦⡀⠘⢳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
⎢⣀⠈⠻⣦⡀⠘⢳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠙⢶⣀⠈⠻⣦⡀⠙⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠙⢶⣄⠈⠻⣦⡀⠙⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠙⢷⣄⠈⠻⣦⡀⠉⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠙⢧⡄⠈⠛⣤⡀⠉⠣⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠙⢧⡄⠈⠻⣦⡀⠉⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⢦⡄⠈⠱⣦⡀⠉⠷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢧⡄⠈⠻⣦⡀⠙⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢧⣄⠈⠻⣦⡀⠙⢷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢷⣄⠈⠻⣦⡀⠘⢳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢷⣀⠈⠻⣦⡀⠘⢳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢶⣀⠈⠻⢆⡀⠘⠳⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢶⣀⠈⠻⣦⡀⠘⢳⣄⠀⠀⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢢⣀⠈⠛⣤⡀⠘⢳⣄⠀⠀⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢶⣀⠈⠻⣦⡀⠙⢷⣄⠀⠀⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢶⣄⠈⠻⣦⡀⠙⠷⣄⠀⠀⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢷⣄⠈⠻⣦⡀⠉⠷⣄⎥
⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢧⡄⠈⠻⣦⡀⠉⎥
⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢧⡄⠈⠻⣦⎦
julia> dofmask = falses(1, size(mesh)...);
julia> dofmask[:,1:3,1:3] .= true;
julia> dofmap = DofMap(dofmask);
julia> extract(A, dofmap)
9×9 SparseArrays.SparseMatrixCSC{Float64, Int64} with 49 stored entries:
0.0 0.0 ⋅ 0.0 0.0 ⋅ ⋅ ⋅ ⋅
0.0 0.0 0.0 0.0 0.0 0.0 ⋅ ⋅ ⋅
⋅ 0.0 0.0 ⋅ 0.0 0.0 ⋅ ⋅ ⋅
0.0 0.0 ⋅ 0.0 0.0 ⋅ 0.0 0.0 ⋅
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
⋅ 0.0 0.0 ⋅ 0.0 0.0 ⋅ 0.0 0.0
⋅ ⋅ ⋅ 0.0 0.0 ⋅ 0.0 0.0 ⋅
⋅ ⋅ ⋅ 0.0 0.0 0.0 0.0 0.0 0.0
⋅ ⋅ ⋅ ⋅ 0.0 0.0 ⋅ 0.0 0.0
Tesserae.extract
— Methodextract(matrix::AbstractMatrix, dofmap::DofMap)
Extract the active degrees of freedom.
Assembly of global matrix
Tesserae.@P2G_Matrix
— Macro@P2G_Matrix grid=>(i,j) particles=>p mpvalues=>(ip,jp) [space] begin
equations...
end
Particle-to-grid transfer macro for assembling a global matrix. A typical global stiffness matrix can be assembled as follows:
@P2G_Matrix grid=>(i,j) particles=>p mpvalues=>(ip,jp) begin
K[i,j] = @∑ ∇w[ip] ⋅ c[p] ⋅ ∇w[jp] * V[p]
end
where c
and V
denote the stiffness (symmetric fourth-order) tensor and the volume, respectively. It is recommended to create global stiffness K
using create_sparse_matrix
.
Solvers
Tesserae.newton!
— FunctionTesserae.newton!(x::AbstractVector, f, ∇f,
maxiter = 100, atol = zero(eltype(x)), rtol = sqrt(eps(eltype(x))),
linsolve = (x,A,b) -> copyto!(x, A\b), verbose = false)
A simple implementation of Newton's method. The functions f(x)
and ∇f(x)
should return the residual vector and its Jacobian, respectively.
julia> function f(x)
[(x[1]+3)*(x[2]^3-7)+18,
sin(x[2]*exp(x[1])-1)]
end
f (generic function with 1 method)
julia> function ∇f(x)
u = exp(x[1])*cos(x[2]*exp(x[1])-1)
[x[2]^3-7 3*x[2]^2*(x[1]+3)
x[2]*u u]
end
∇f (generic function with 1 method)
julia> x = [0.1, 1.2];
julia> issuccess = Tesserae.newton!(x, f, ∇f)
true
julia> x ≈ [0,1]
true