Functionalities for implicit methods
Degrees of freedom (DoF) mapping
Tesserae.DofMap — Type
DofMap(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.0Sparse matrix
Tesserae.create_sparse_matrix — Function
create_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.0Tesserae.extract — Method
extract(matrix::AbstractMatrix, dofmap_row::DofMap, dofmap_col::DofMap = dofmap_row)Extract the active degrees of freedom of a matrix.
Assembly of global matrix
Tesserae.@P2G_Matrix — Macro
@P2G_Matrix grid=>(i,j) particles=>p weights=>(ip,jp) [partition] begin
equations...
endParticle-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 weights=>(ip,jp) begin
K[i,j] = @∑ ∇w[ip] ⊡ c[p] ⊡ ∇w[jp] * V[p]
endwhere 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! — Function
Tesserae.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