From 35db3518dc1a9d48e8db25141cfbdd1c3ebc49fd Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Sat, 18 Nov 2023 15:33:17 +0000 Subject: [PATCH] build based on 8177fce --- previews/PR2/.documenter-siteinfo.json | 2 +- previews/PR2/api/dof/dof/index.html | 30 +++++++++---------- .../api/integration/integration/index.html | 10 +++---- .../PR2/api/interpolation/fespace/index.html | 14 ++++----- .../interpolation/function_space/index.html | 6 ++-- .../PR2/api/interpolation/shape/index.html | 2 +- .../PR2/api/interpolation/spaces/index.html | 18 +++++------ previews/PR2/api/mapping/mapping/index.html | 14 ++++----- previews/PR2/api/mesh/gmsh_utils/index.html | 2 +- previews/PR2/api/mesh/mesh/index.html | 10 +++---- .../PR2/api/mesh/mesh_generator/index.html | 6 ++-- previews/PR2/api/operator/operator/index.html | 2 +- previews/PR2/api/output/vtk/index.html | 12 ++++---- previews/PR2/example/covo/index.html | 2 +- .../PR2/example/euler_naca_steady/index.html | 2 +- .../PR2/example/linear_elasticity/index.html | 2 +- .../linear_thermoelasticity/index.html | 2 +- previews/PR2/howto/howto/index.html | 2 +- previews/PR2/index.html | 2 +- previews/PR2/manual/cellfunction/index.html | 2 +- previews/PR2/manual/function_space/index.html | 2 +- previews/PR2/manual/geometry/index.html | 2 +- previews/PR2/manual/integration/index.html | 2 +- previews/PR2/manual/operator/index.html | 2 +- previews/PR2/search_index.js | 2 +- .../PR2/tutorial/heat_equation/index.html | 2 +- previews/PR2/tutorial/helmholtz/index.html | 2 +- .../PR2/tutorial/linear_transport/index.html | 2 +- .../phase_field_supercooled/index.html | 2 +- 29 files changed, 80 insertions(+), 80 deletions(-) diff --git a/previews/PR2/.documenter-siteinfo.json b/previews/PR2/.documenter-siteinfo.json index d4cd0722..c15c2c82 100644 --- a/previews/PR2/.documenter-siteinfo.json +++ b/previews/PR2/.documenter-siteinfo.json @@ -1 +1 @@ -{"documenter":{"julia_version":"1.8.5","generation_timestamp":"2023-11-17T16:23:42","documenter_version":"1.1.2"}} \ No newline at end of file +{"documenter":{"julia_version":"1.8.5","generation_timestamp":"2023-11-18T15:33:08","documenter_version":"1.1.2"}} \ No newline at end of file diff --git a/previews/PR2/api/dof/dof/index.html b/previews/PR2/api/dof/dof/index.html index 46e490de..606dd8af 100644 --- a/previews/PR2/api/dof/dof/index.html +++ b/previews/PR2/api/dof/dof/index.html @@ -1,6 +1,6 @@ -Degree of freedom · Bcube

Degree of freedom

Assembler

Bcube.__assemble_linear!Method

Dev notes

Two levels of "LazyMapOver" because first we LazyMapOver the Tuple of argument of the linear form, and the for each item of this Tuple we LazyMapOver the shape functions.

source
Bcube._assemble_linear!Method
_assemble_linear!(b, l, V, integration::Integration)
-_assemble_linear!(b, l, V, integration::MultiIntegration{N}) where {N}

These functions act as a function barrier in order to:

  • get the function corresponding to the operand in the linear form
  • reshape b internally to deal with cases when V is a AbstractMultiTestFESpace
  • call __assemble_linear! to apply dispatch on the type of measure of the integration and improve type stability during the assembling loop.

Dev note:

The case integration::MultiIntegration{N} is treated by looping over each Integration contained in the MultiIntegration

source
Bcube._blockmap_bilinearMethod

From tuples $a=(a_1, a_2, …, a_i, …, a_m)$ and $b=(b_1, b_2, …, b_j, …, b_n)$, it builds A and B which correspond formally to the following two matrices :

\[A \equiv \begin{pmatrix} +Degree of freedom · Bcube

Degree of freedom

Assembler

Bcube.__assemble_linear!Method

Dev notes

Two levels of "LazyMapOver" because first we LazyMapOver the Tuple of argument of the linear form, and the for each item of this Tuple we LazyMapOver the shape functions.

source
Bcube._assemble_linear!Method
_assemble_linear!(b, l, V, integration::Integration)
+_assemble_linear!(b, l, V, integration::MultiIntegration{N}) where {N}

These functions act as a function barrier in order to:

  • get the function corresponding to the operand in the linear form
  • reshape b internally to deal with cases when V is a AbstractMultiTestFESpace
  • call __assemble_linear! to apply dispatch on the type of measure of the integration and improve type stability during the assembling loop.

Dev note:

The case integration::MultiIntegration{N} is treated by looping over each Integration contained in the MultiIntegration

source
Bcube._blockmap_bilinearMethod

From tuples $a=(a_1, a_2, …, a_i, …, a_m)$ and $b=(b_1, b_2, …, b_j, …, b_n)$, it builds A and B which correspond formally to the following two matrices :

\[A \equiv \begin{pmatrix} a_1 & a_1 & ⋯ & a_1\\ a_2 & a_2 & ⋯ & a_2\\ ⋮ & ⋮ & ⋮ & ⋮ \\ @@ -12,9 +12,9 @@ b_1 & b_2 & ⋯ & b_n\\ ⋮ & ⋮ & ⋮ & ⋮ \\ b_1 & b_2 & ⋯ & b_n -\end{pmatrix}\]

A and B are wrapped in LazyMapOver structures so that all operations on them are done elementwise by default (in other words, it can be considered that the operations are automatically broadcasted).

Dev note :

Both A and B are stored as a tuple of tuples, wrapped by LazyMapOver, where inner tuples correspond to each columns of a matrix. This hierarchical structure reduces both inference and compile times by avoiding the use of large tuples.

source
Bcube._count_n_eltsMethod

Count the (maximum) number of elements in the matrix corresponding to the bilinear assembly of U, V on a cell domain, where U and V are TrialFESpace and TestFESpace

source
Bcube._count_n_eltsMethod

Count the (maximum) number of elements in the matrix corresponding to the bilinear assembly of U, V on a cell domain, where U and V are AbstractMultiFESpace

source
Bcube._diag_tuplesMethod
_diag_tuples(diag::Tuple{Vararg{Any,N}}, b) where N

Return N tuples of length N. For each tuple tᵢ, its values are defined so that tᵢ[k]=diag[k] if k==i, tᵢ[k]=b otherwise. The result can be seen as a dense diagonal-like array using tuple.

Example for N=3:

(diag[1],  b,       b      ),
+\end{pmatrix}\]

A and B are wrapped in LazyMapOver structures so that all operations on them are done elementwise by default (in other words, it can be considered that the operations are automatically broadcasted).

Dev note :

Both A and B are stored as a tuple of tuples, wrapped by LazyMapOver, where inner tuples correspond to each columns of a matrix. This hierarchical structure reduces both inference and compile times by avoiding the use of large tuples.

source
Bcube._count_n_eltsMethod

Count the (maximum) number of elements in the matrix corresponding to the bilinear assembly of U, V on a cell domain, where U and V are TrialFESpace and TestFESpace

source
Bcube._count_n_eltsMethod

Count the (maximum) number of elements in the matrix corresponding to the bilinear assembly of U, V on a cell domain, where U and V are AbstractMultiFESpace

source
Bcube._diag_tuplesMethod
_diag_tuples(diag::Tuple{Vararg{Any,N}}, b) where N

Return N tuples of length N. For each tuple tᵢ, its values are defined so that tᵢ[k]=diag[k] if k==i, tᵢ[k]=b otherwise. The result can be seen as a dense diagonal-like array using tuple.

Example for N=3:

(diag[1],  b,       b      ),
 (b,        diag[2], b      ),
-(b,        b,       diag[3]))
source
Bcube._get_multi_tuple_varMethod

For N=3 for example: (LazyMapOver((LazyMapOver(V[1]), NullOperator(), NullOperator())), LazyMapOver((NullOperator(), LazyMapOver(V[2]), NullOperator())), LazyMapOver((NullOperator(), NullOperator(), LazyMapOver(V[3]))))

source
Bcube._may_reshape_bMethod

For AbstractMultiTestFESpace, it creates a Tuple (of views) of the different "destination" in the vector: one for each FESpace

source
Bcube._get_multi_tuple_varMethod

For N=3 for example: (LazyMapOver((LazyMapOver(V[1]), NullOperator(), NullOperator())), LazyMapOver((NullOperator(), LazyMapOver(V[2]), NullOperator())), LazyMapOver((NullOperator(), NullOperator(), LazyMapOver(V[3]))))

source
Bcube._may_reshape_bMethod

For AbstractMultiTestFESpace, it creates a Tuple (of views) of the different "destination" in the vector: one for each FESpace

source
Bcube.assemble_bilinear!Method
assemble_bilinear!(
     I::Vector{Int},
     J::Vector{Int},
     X::Vector{T},
@@ -22,7 +22,7 @@
     measure::Measure{<:AbstractFaceDomain},
     U::TrialFESpace,
     V::TestFESpace,
-)

In-place version of assemble_bilinear.

source
Bcube.assemble_bilinearMethod
assemble_bilinear(a::Function, U, V)

Assemble the (sparse) Matrix corresponding to the given bilinear form a on the trial and test finite element spaces U and V.

For the in-place version, check-out assemble_bilinear!.

Arguments

  • a::Function : function of two variables (u,v) representing the bilinear form
  • U : trial finite element space (for u)
  • V : test finite element space (for v)

Examples

julia> mesh = rectangle_mesh(3,3)
+)

In-place version of assemble_bilinear.

source
Bcube.assemble_bilinearMethod
assemble_bilinear(a::Function, U, V)

Assemble the (sparse) Matrix corresponding to the given bilinear form a on the trial and test finite element spaces U and V.

For the in-place version, check-out assemble_bilinear!.

Arguments

  • a::Function : function of two variables (u,v) representing the bilinear form
  • U : trial finite element space (for u)
  • V : test finite element space (for v)

Examples

julia> mesh = rectangle_mesh(3,3)
 julia> U = TrialFESpace(FunctionSpace(:Lagrange, 0), mesh)
 julia> V = TestFESpace(U)
 julia> dΩ = Measure(CellDomain(mesh), 3)
@@ -40,7 +40,7 @@
  0.25   ⋅     ⋅     ⋅
   ⋅    0.25   ⋅     ⋅
   ⋅     ⋅    0.25   ⋅
-  ⋅     ⋅     ⋅    0.25
source
Bcube.assemble_linearMethod
assemble_linear(l::Function, V::Union{TestFESpace, AbstractMultiTestFESpace})

Assemble the vector corresponding to a linear form l on the finite element space V

For the in-place version, checkout assemble_linear!.

Arguments

  • l::Function : linear form to assemble, a function of one variable l(v)
  • V : test finite element space

Examples

julia> mesh = rectangle_mesh(3,3)
+  ⋅     ⋅     ⋅    0.25
source
Bcube.assemble_linearMethod
assemble_linear(l::Function, V::Union{TestFESpace, AbstractMultiTestFESpace})

Assemble the vector corresponding to a linear form l on the finite element space V

For the in-place version, checkout assemble_linear!.

Arguments

  • l::Function : linear form to assemble, a function of one variable l(v)
  • V : test finite element space

Examples

julia> mesh = rectangle_mesh(3,3)
 julia> U = TrialFESpace(FunctionSpace(:Lagrange, 0), mesh)
 julia> V = TestFESpace(U)
 julia> dΩ = Measure(CellDomain(mesh), 3)
@@ -50,17 +50,17 @@
  0.25
  0.25
  0.25
- 0.25
source
Bcube.blockmap_bilinear_shape_functionsMethod

Dev notes:

Return blockU and blockV to be able to compute the local matrix corresponding to the bilinear form :

\[ A[i,j] = a(λᵤ[j], λᵥ[i])\]

where λᵤ and λᵥ are the shape functions associated with the trial U and the test V function spaces respectively. In a "map-over" version, it can be written :

\[ A = a(blockU, blockV)\]

where blockU and blockV correspond formally to the lazy-map-over matrices :

\[ ∀k, blockU[k,j] = λᵤ[j], - blockV[i,k] = λᵥ[i]\]

source
Bcube.blockmap_shape_functionsMethod

Dev note :

Materialize the integrand function on all the different possible Tuples of v=(v1,0,0,...), (0,v2,0,...), ..., (..., vi, ...)

source
Bcube.blockmap_shape_functionsMethod
blockmap_shape_functions(fespace::AbstractFESpace, cellinfo::AbstractCellInfo)

Return all shape functions a = LazyMapOver((λ₁, λ₂, …, λₙ)) corresponding to fespace in cell cellinfo. These shape functions are wrapped by a LazyMapOver so that for a function f it gives: f(a) == map(f, a)

source
Bcube.blockmap_shape_functionsMethod
blockmap_shape_functions(multiFESpace::AbstractMultiFESpace, cellinfo::AbstractCellInfo)

Return all shape functions corresponding to each fespace in multiFESSpace for cell cellinfo :

\[ ((v₁, ∅, ∅, …), (∅, v₂, ∅, …), …, ( …, ∅, ∅, vₙ))\]

where:

  • vᵢ = (λᵢ₁, λᵢ₂, …, λᵢ_ₘ) are the shapes functions of the i-th fespace in the cell.
  • ∅ are NullOperators

Note that the LazyMapOver is used to wrap recursively the result.

source
Bcube.computeMethod
compute(integration::Integration)

Compute an integral, independently from a FEM/DG framework (i.e without FESpace)

Return an array of the integral evaluated over each cell (or face). To get the sum over the whole domain, simply apply the sum function.

source

DofHandler

Bcube.DofHandlerType

The DofHandler handles the degree of freedom numbering. To each degree of freedom is associated a unique integer.

source
Bcube.DofHandlerMethod

DofHandler(mesh::Mesh, fSpace::AbstractFunctionSpace, ncomponents::Int, isContinuous::Bool)

Constructor of a DofHandler for a SingleFESpace on a Mesh.

source
Bcube._deal_with_dofs_on_edges!Method
deal_with_dofs_on_edges!(dict, iglob, offset, c2n, celltypes, icell::Int, inodes_g, e2n_g, s::AbstractShape, kvar::Int, fs)

Function dealing with dofs shared by different cell through an edge connection (excluding bord vertices).

TODO : remove kvar

Arguments

  • dict may be modified by this routine
  • iglob may be modified by this routine
  • offset may be modified by this routine
  • fs : FunctionSpace of var kvar
  • icell : cell index
  • kvar : var index
  • s : shape of icell-th cell
  • inodes_g : global indices of nodes of icell
source
Bcube._deal_with_dofs_on_vertices!Method
deal_with_dofs_on_vertices!(dict, iglob, offset, icell::Int, inodes_g, s::AbstractShape, kvar::Int, fs)

Function dealing with dofs shared by different cell through a vertex connection.

TODO : remove kvar

Arguments

  • dict may be modified by this routine
  • iglob may be modified by this routine
  • offset may be modified by this routine
  • fs : FunctionSpace of var kvar
  • icell : cell index
  • kvar : var index
  • s : shape of icell-th cell
  • inodes_g : global indices of nodes of icell
source
Bcube.dofMethod
dof(dhl::DofHandler, icell, icomp::Int, idof::Int)

Global index of the idof local degree of freedom of component icomp in cell icell.

Example

mesh = one_cell_mesh(:line)
+ 0.25
source
Bcube.blockmap_bilinear_shape_functionsMethod

Dev notes:

Return blockU and blockV to be able to compute the local matrix corresponding to the bilinear form :

\[ A[i,j] = a(λᵤ[j], λᵥ[i])\]

where λᵤ and λᵥ are the shape functions associated with the trial U and the test V function spaces respectively. In a "map-over" version, it can be written :

\[ A = a(blockU, blockV)\]

where blockU and blockV correspond formally to the lazy-map-over matrices :

\[ ∀k, blockU[k,j] = λᵤ[j], + blockV[i,k] = λᵥ[i]\]

source
Bcube.blockmap_shape_functionsMethod

Dev note :

Materialize the integrand function on all the different possible Tuples of v=(v1,0,0,...), (0,v2,0,...), ..., (..., vi, ...)

source
Bcube.blockmap_shape_functionsMethod
blockmap_shape_functions(fespace::AbstractFESpace, cellinfo::AbstractCellInfo)

Return all shape functions a = LazyMapOver((λ₁, λ₂, …, λₙ)) corresponding to fespace in cell cellinfo. These shape functions are wrapped by a LazyMapOver so that for a function f it gives: f(a) == map(f, a)

source
Bcube.blockmap_shape_functionsMethod
blockmap_shape_functions(multiFESpace::AbstractMultiFESpace, cellinfo::AbstractCellInfo)

Return all shape functions corresponding to each fespace in multiFESSpace for cell cellinfo :

\[ ((v₁, ∅, ∅, …), (∅, v₂, ∅, …), …, ( …, ∅, ∅, vₙ))\]

where:

  • vᵢ = (λᵢ₁, λᵢ₂, …, λᵢ_ₘ) are the shapes functions of the i-th fespace in the cell.
  • ∅ are NullOperators

Note that the LazyMapOver is used to wrap recursively the result.

source
Bcube.computeMethod
compute(integration::Integration)

Compute an integral, independently from a FEM/DG framework (i.e without FESpace)

Return an array of the integral evaluated over each cell (or face). To get the sum over the whole domain, simply apply the sum function.

source

DofHandler

Bcube.DofHandlerType

The DofHandler handles the degree of freedom numbering. To each degree of freedom is associated a unique integer.

source
Bcube.DofHandlerMethod

DofHandler(mesh::Mesh, fSpace::AbstractFunctionSpace, ncomponents::Int, isContinuous::Bool)

Constructor of a DofHandler for a SingleFESpace on a Mesh.

source
Bcube._deal_with_dofs_on_edges!Method
deal_with_dofs_on_edges!(dict, iglob, offset, c2n, celltypes, icell::Int, inodes_g, e2n_g, s::AbstractShape, kvar::Int, fs)

Function dealing with dofs shared by different cell through an edge connection (excluding bord vertices).

TODO : remove kvar

Arguments

  • dict may be modified by this routine
  • iglob may be modified by this routine
  • offset may be modified by this routine
  • fs : FunctionSpace of var kvar
  • icell : cell index
  • kvar : var index
  • s : shape of icell-th cell
  • inodes_g : global indices of nodes of icell
source
Bcube._deal_with_dofs_on_vertices!Method
deal_with_dofs_on_vertices!(dict, iglob, offset, icell::Int, inodes_g, s::AbstractShape, kvar::Int, fs)

Function dealing with dofs shared by different cell through a vertex connection.

TODO : remove kvar

Arguments

  • dict may be modified by this routine
  • iglob may be modified by this routine
  • offset may be modified by this routine
  • fs : FunctionSpace of var kvar
  • icell : cell index
  • kvar : var index
  • s : shape of icell-th cell
  • inodes_g : global indices of nodes of icell
source
Bcube.dofMethod
dof(dhl::DofHandler, icell, icomp::Int, idof::Int)

Global index of the idof local degree of freedom of component icomp in cell icell.

Example

mesh = one_cell_mesh(:line)
 dhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))
-@show dof(dhl, 1, 1, 1)
source
Bcube.dofMethod
dof(dhl::DofHandler, icell, icomp::Int)

Global indices of all the dofs of a given component in a given cell

Example

mesh = one_cell_mesh(:line)
+@show dof(dhl, 1, 1, 1)
source
Bcube.dofMethod
dof(dhl::DofHandler, icell, icomp::Int)

Global indices of all the dofs of a given component in a given cell

Example

mesh = one_cell_mesh(:line)
 dhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))
-@show dof(dhl, 1, 1)
source
Bcube.max_ndofsMethod
max_ndofs(dhl::DofHandler)

Count maximum number of dofs per cell, all components mixed

source
Bcube.ndofsMethod
ndofs(dhl, icell, icomp::Vector{Int})

Number of dofs for a given set of components in a given cell.

Example

mesh = one_cell_mesh(:line)
+@show dof(dhl, 1, 1)
source
Bcube.max_ndofsMethod
max_ndofs(dhl::DofHandler)

Count maximum number of dofs per cell, all components mixed

source
Bcube.ndofsMethod
ndofs(dhl, icell, icomp::Vector{Int})

Number of dofs for a given set of components in a given cell.

Example

mesh = one_cell_mesh(:line)
 dhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1); size = 2))
-@show ndofs(dhl, 1, [1, 2])
source
Bcube.ndofsMethod
ndofs(dhl, icell, kvar::Int)

Number of dofs for a given variable in a given cell.

Example

mesh = one_cell_mesh(:line)
+@show ndofs(dhl, 1, [1, 2])
source
Bcube.ndofsMethod
ndofs(dhl, icell, kvar::Int)

Number of dofs for a given variable in a given cell.

Example

mesh = one_cell_mesh(:line)
 dhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))
-@show ndofs(dhl, 1, 1)
source
Bcube.ndofsMethod
ndofs(dhl::DofHandler, icell)

Number of dofs for a given cell.

Note that for a vector variable, the total (accross all components) number of dofs is returned.

Example

mesh = one_cell_mesh(:line)
+@show ndofs(dhl, 1, 1)
source
Bcube.ndofsMethod
ndofs(dhl::DofHandler, icell)

Number of dofs for a given cell.

Note that for a vector variable, the total (accross all components) number of dofs is returned.

Example

mesh = one_cell_mesh(:line)
 dhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))
-@show ndofs(dhl, 1, :u)
source
Bcube.ndofsMethod
ndofs(dhl::DofHandler)

Total number of dofs. This function takes into account that dofs can be shared by multiple cells.

Example

mesh = one_cell_mesh(:line)
+@show ndofs(dhl, 1, :u)
source
Bcube.ndofsMethod
ndofs(dhl::DofHandler)

Total number of dofs. This function takes into account that dofs can be shared by multiple cells.

Example

mesh = one_cell_mesh(:line)
 dhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))
-@show ndofs(dhl::DofHandler)
source
+@show ndofs(dhl::DofHandler)
source
diff --git a/previews/PR2/api/integration/integration/index.html b/previews/PR2/api/integration/integration/index.html index 683c88ae..69eefd28 100644 --- a/previews/PR2/api/integration/integration/index.html +++ b/previews/PR2/api/integration/integration/index.html @@ -1,8 +1,8 @@ -Integration · Bcube

Integration

Measure

Bcube.MeasureType

A Measure is geometrical domain of integration associated to a way to integrate on it (i.e a quadrature rule).

Q is the quadrature type used to integrate expressions using this measure.

source
Bcube.MeasureMethod
Measure(domain::AbstractDomain, degree::Integer)
+Integration · Bcube

Integration

Measure

Bcube.MeasureType

A Measure is geometrical domain of integration associated to a way to integrate on it (i.e a quadrature rule).

Q is the quadrature type used to integrate expressions using this measure.

source
Bcube.MeasureMethod
Measure(domain::AbstractDomain, degree::Integer)
 Measure(domain::AbstractDomain, ::Val{degree}) where {degree}

Build a Measure on the designated AbstractDomain with a default quadrature of degree degree.

Arguments

  • domain::AbstractDomain : the domain to integrate over
  • degree : the degree of the quadrature rule (Legendre quadrature type by default)

Examples

julia> mesh = line_mesh(10)
 julia> Ω = CellDomain(mesh)
-julia> dΩ = Measure(Ω, 2)
source

Integration methods

Base.:*Method
*(a::Number, b::Integration)
-*(a::Integration, b::Number)

Multiplication of an Integration is based on a rewriting rule following the linearity rules of integration : k*∫(f(x))dx => ∫(k*f(x))dx

source
Base.:-Method
-(a::Integrand)

Soustraction on an Integrand is treated as a multiplication by "(-1)" : -a ≡ ((-1)*a)

source
Base.:-Method
-(a::Integration)

Soustraction on an Integration is treated as a multiplication by "(-1)" : -a ≡ ((-1)*a)

source
Bcube.apply_quadratureMethod
apply_quadrature(g_ref, shape::AbstractShape, quadrature::AbstractQuadrature, ::T) where{N,T<:AbstractComputeQuadratureStyle}

Apply quadrature rule to function g_ref expressed on reference shape shape. Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

source
Bcube.apply_quadrature2Method
apply_quadrature2(g_ref, shape::AbstractShape, quadrature::AbstractQuadrature, ::MapComputeQuadratureStyle) where{N}

Alternative version of apply_quadrature thats seems to be more efficient for face integration (this observation is not really understood)

source
Bcube.getcache_∫Method
getcache_∫(etype::AbstractEntityType, nodes, quadrature::AbstractQuadrature)

Return the data cache for function

source
Bcube.integrateMethod
integrate(g, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Integrate function g expressed in local element. Depending on the cell type and the space dimension, a volumic or a 'surfacic' integration is performed.

source
Bcube.integrateMethod
integrate(g, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Integrate function g on the iside-th side of the cell defined by its nodes cnodes and its type ctype. Function g(x) is expressed in the local element.

source
Bcube.integrate_face_refMethod

Integration on a surface in a volume. We consider that we integrate on the negative side of the face.

WARNING : I need this now, but I am not satisfied. We need to rethink the whole integration API

source
Bcube.integrate_nMethod
integrate_n(g, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Perform an integration over the isideth face of an element (defined by cnodes and ctype).

Here g is expressed in the cell-local element : n is the normal vector in the local element, and x is in the local element as well.

Dev notes:

This method is DEPRECATED : never used, except in the unit tests...

source
Bcube.integrate_n_refMethod
integrate_n_ref(g_ref, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Perform an integration over the isideth face of an element (defined by cnodes and ctype).

Here g_ref is expressed in the cell-reference element but n is the normal vector in the local element.

source
Bcube.integrate_on_refMethod
integrate_on_ref(g, cellinfo::CellInfo, quadrature::AbstractQuadrature, [::T]) where {N,[T<:AbstractComputeQuadratureStyle]}

Integrate a function g over a cell decribed by cellinfo. The function g can be expressed in the reference or the physical space corresponding to the cell, both cases are automatically handled by applying necessary mapping when needed.

This function is helpfull to integrate shape functions (for instance $\int \lambda_i \lambda_j$) when the inverse mapping is not known explicitely (hence only $\hat{lambda}$ are known, not $\lambda$).

If the last argument is given, computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

source
Bcube.integrate_refMethod
integrate_ref(g_ref, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature, [::T]) where {[T<:AbstractComputeQuadratureStyle]}

Integrate function g_ref expressed in reference element. A variable substitution (involving Jacobian & Cie) is still applied, but the function is considered to be already mapped.

This function is helpfull to integrate shape functions (for instance $\int \lambda_i \lambda_j$) when the inverse mapping is not known explicitely (hence only $\hat{lambda}$ are known, not $\lambda$).

If the last argument is given, computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

source
Bcube.integrate_refMethod
integrate_ref(g_ref, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Integrate function g_ref on the iside-th side of the cell defined by its nodes cnodes and its type ctype. Function g_ref(x) is expressed in the cell-reference element (not the face reference).

This function is helpfull to integrate shape functions (for instance $\int \lambda_i \lambda_j$) when the inverse mapping is not known explicitely (hence only $\hat{lambda}$ are known, not $\lambda$).

source
Bcube.integrate_refMethod
integrate_ref(::isCurvilinear, g_ref, cnodes, ctype::AbstractEntityType{1}, quadrature::AbstractQuadrature, ::T) where {T<:AbstractComputeQuadratureStyle}

Perform an integration of the function g_ref (expressed in local element) over a line in a $\matbb{R}^n$ space.

The applied formulae is: $\int_\Gamma g(x) dx = \int_l ||F'(l)|| g_ref(l) dl$ where $F ~:~ \mathbb{R} \rightarrow \mathbb{R}^n$ is the reference segment [-1,1] to the R^n line mapping.

Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

source
Bcube.integrate_refMethod
integrate_ref(g_ref, cnodes, ctype, quadrature::AbstractQuadrature)

Integration on a node in a $\mathbb{R}^n$ space. This trivial function is only to simplify the 'side integral' expression.

Implementation

For consistency reasons, g_ref is a function but it doesnt actually use its argument : the "reference-element" of a Node can be anything. For instance consider integrating g(x) = x on a node named node. Then g_ref(ξ) = g ∘ node.x. As you can see, g_ref doesnt actually depend on ξ

source
Bcube.integrate_refMethod
integrate_ref(::isVolumic, g_ref, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature, ::T) where{N, T<:AbstractComputeQuadratureStyle}

Integrate function g_ref (expressed in reference element) on mesh element of type ctype defined by its cnodes at the quadrature. Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

To do so, a variable substitution is performed to integrate on the reference element.

Implementation

It has been checked that calling the apply_quadrature method within this function instead of directly applying the quadrature rule (i.e without the anonymous function) does not decrease performance nor allocation.

source

Quadrature rules

Bcube.AbstractQuadratureNodeType
AbstractQuadratureNode{S,Q}

Abstract type representing a quadrature node for a shape S and a quadrature Q. This type is used to represent and identify easily a quadrature node in a quadrature rules.

Derived types must implement the following method:

- get_index(quadnode::AbstractQuadratureNode{S,Q})
-- get_coord(quadnode::AbstractQuadratureNode)
source
Bcube.AbstractQuadratureRuleType
AbstractQuadratureRule{S,Q}

Abstract type representing a quadrature rule for a shape S and quadrature Q.

Derived types must implement the following method: - [get_weights(qr::AbstractQuadratureRule)] - [get_nodes(qr::AbstractQuadratureRule)] - [Base.length(qr::AbstractQuadratureRule)]

source
Bcube.QuadratureNodeType
QuadratureNode{S,Q}

Type representing a quadrature node for a shape S and a quadrature Q. This type can be used to represent and identify easily a quadrature node in the corresponding parent quadrature rule.

source
Bcube.QuadratureRuleMethod
QuadratureRule(shape::AbstractShape, q::AbstractQuadrature)

Return the quadrature rule corresponding to the given Shape according to the selected quadrature 'q'.

source
Base.lengthMethod
length(qr::AbstractQuadratureRule)

Returns the number of quadrature nodes of qr.

source
Bcube._gausslegendre1DMethod
_gausslegendre1D(::Val{N}) where N
-_gausslobatto1D(::Val{N}) where N

Return N-point Gauss quadrature weights and nodes on the domain [-1:1].

source
Bcube._get_num_nodesMethod

Gauss-Legendre formula with $n$ nodes has degree of exactness $2n-1$. Then, to obtain a given degree $D$, the number of nodes must satisfy: $2n-1 ≥ D$ or equivalently $n ≥ (D+1)/2$

source
Bcube._get_num_nodesMethod

Gauss-Lobatto formula with $n+1$ nodes has degree of exactness $2n-1$, which equivalent to a degree of $2n-3$ with $n$ nodes. Then, to obtain a given degree $D$, the number of nodes must satisfy: $2n-3 ≥ D$ or equivalently $n ≥ (D+3)/2$

source
Bcube._get_num_nodes_per_dimMethod
get_num_nodes_per_dim(quadrule::AbstractQuadratureRule{S}) where S<:Shape

Returns the number of nodes per dimension. This function is defined for shapes for which quadratures are based on a cartesian product : Line, Square, Cube

Remark : Here we assume that the same degree is used along each dimension (no anisotropy for now!)

source
Bcube.evalquadnodeMethod
evalquadnode(f, quadnode::AbstractQuadratureNode)

Evaluate the function f at the coordinates of quadnode.

Basically, it computes:

f(get_coord(quadnode))

Remark:

Optimization could be applied if f is a function based on a nodal basis such as one of the DoF and quadnode are collocated.

source
Bcube.get_coordMethod
get_coord(quadnode::AbstractQuadratureNode)

Returns the coordinates of quadnode.

source
Bcube.get_indexMethod
get_index(quadnode::AbstractQuadratureNode{S,Q})

Returns the index of quadnode in the parent quadrature rule AbstractQuadRules{S,Q}

source
Bcube.get_nodesMethod
get_nodes(qr::AbstractQuadratureRule)

Returns an array containing the coordinates of all quadrature nodes of qr.

source
Bcube.get_quadnodesMethod
get_quadnodes(qr::QuadratureRule{S,Q,N}) where {S,Q,N}

Returns an vector containing each QuadratureNode of qr

source
Bcube.get_quadrature_points_gausslegendreMethod

Gauss-Legendre quadrature, 12 point rule on triangle.

Ref: Witherden, F. D.; Vincent, P. E. On the identification of symmetric quadrature rules for finite element methods. Comput. Math. Appl. 69 (2015), no. 10, 1232–1241

source
Bcube.get_quadrature_points_gausslegendreMethod

Gauss-Legendre quadrature, 16 point rule on triangle, degree 8.

Ref: Witherden, F. D.; Vincent, P. E. On the identification of symmetric quadrature rules for finite element methods. Comput. Math. Appl. 69 (2015), no. 10, 1232–1241

Note : quadrature is rescale to match our reference triangular shape which is defined in [0:1]² instead of [-1:1]²

source
Bcube.get_weightsMethod
get_weights(qr::AbstractQuadratureRule)

Returns an array containing the weights of all quadrature nodes of qr.

source
Bcube.quadrature_pointsMethod

ref : https://www.math.umd.edu/~tadmor/references/files/Chen%20&%20Shu%20entropy%20stable%20DG%20JCP2017.pdf

source
Bcube.quadrature_ruleMethod
quadrature_rule(iside::Int, shape::AbstractShape, degree::Val{N}) where N

Return the quadrature rule, computed with barycentric coefficients, corresponding to the given boundary of a shape and the given degree.

source
Bcube.quadrature_rule_baryMethod
quadrature_rule_bary(::Int, ::AbstractShape, degree::Val{N}) where N

Return the quadrature rule, computed with barycentric coefficients, corresponding to the given boundary of a shape and the given degree.

This function returns the quadrature weights and the barycentric weights to apply to each vertex of the reference shape. Hence, to apply the quadrature using this function, one needs to do : for (weight, l) in quadrature_rule_bary(iside, shape(etype), degree) xp = zeros(SVector{td}) for i=1:nvertices xp += l[i]*vertices[i] end # weight, xp is the quadrature couple (weight, node) end

source
+julia> dΩ = Measure(Ω, 2)
source

Integration methods

Base.:*Method
*(a::Number, b::Integration)
+*(a::Integration, b::Number)

Multiplication of an Integration is based on a rewriting rule following the linearity rules of integration : k*∫(f(x))dx => ∫(k*f(x))dx

source
Base.:-Method
-(a::Integrand)

Soustraction on an Integrand is treated as a multiplication by "(-1)" : -a ≡ ((-1)*a)

source
Base.:-Method
-(a::Integration)

Soustraction on an Integration is treated as a multiplication by "(-1)" : -a ≡ ((-1)*a)

source
Bcube.apply_quadratureMethod
apply_quadrature(g_ref, shape::AbstractShape, quadrature::AbstractQuadrature, ::T) where{N,T<:AbstractComputeQuadratureStyle}

Apply quadrature rule to function g_ref expressed on reference shape shape. Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

source
Bcube.apply_quadrature2Method
apply_quadrature2(g_ref, shape::AbstractShape, quadrature::AbstractQuadrature, ::MapComputeQuadratureStyle) where{N}

Alternative version of apply_quadrature thats seems to be more efficient for face integration (this observation is not really understood)

source
Bcube.getcache_∫Method
getcache_∫(etype::AbstractEntityType, nodes, quadrature::AbstractQuadrature)

Return the data cache for function

source
Bcube.integrateMethod
integrate(g, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Integrate function g expressed in local element. Depending on the cell type and the space dimension, a volumic or a 'surfacic' integration is performed.

source
Bcube.integrateMethod
integrate(g, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Integrate function g on the iside-th side of the cell defined by its nodes cnodes and its type ctype. Function g(x) is expressed in the local element.

source
Bcube.integrate_face_refMethod

Integration on a surface in a volume. We consider that we integrate on the negative side of the face.

WARNING : I need this now, but I am not satisfied. We need to rethink the whole integration API

source
Bcube.integrate_nMethod
integrate_n(g, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Perform an integration over the isideth face of an element (defined by cnodes and ctype).

Here g is expressed in the cell-local element : n is the normal vector in the local element, and x is in the local element as well.

Dev notes:

This method is DEPRECATED : never used, except in the unit tests...

source
Bcube.integrate_n_refMethod
integrate_n_ref(g_ref, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Perform an integration over the isideth face of an element (defined by cnodes and ctype).

Here g_ref is expressed in the cell-reference element but n is the normal vector in the local element.

source
Bcube.integrate_on_refMethod
integrate_on_ref(g, cellinfo::CellInfo, quadrature::AbstractQuadrature, [::T]) where {N,[T<:AbstractComputeQuadratureStyle]}

Integrate a function g over a cell decribed by cellinfo. The function g can be expressed in the reference or the physical space corresponding to the cell, both cases are automatically handled by applying necessary mapping when needed.

This function is helpfull to integrate shape functions (for instance $\int \lambda_i \lambda_j$) when the inverse mapping is not known explicitely (hence only $\hat{lambda}$ are known, not $\lambda$).

If the last argument is given, computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

source
Bcube.integrate_refMethod
integrate_ref(g_ref, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature, [::T]) where {[T<:AbstractComputeQuadratureStyle]}

Integrate function g_ref expressed in reference element. A variable substitution (involving Jacobian & Cie) is still applied, but the function is considered to be already mapped.

This function is helpfull to integrate shape functions (for instance $\int \lambda_i \lambda_j$) when the inverse mapping is not known explicitely (hence only $\hat{lambda}$ are known, not $\lambda$).

If the last argument is given, computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

source
Bcube.integrate_refMethod
integrate_ref(g_ref, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)

Integrate function g_ref on the iside-th side of the cell defined by its nodes cnodes and its type ctype. Function g_ref(x) is expressed in the cell-reference element (not the face reference).

This function is helpfull to integrate shape functions (for instance $\int \lambda_i \lambda_j$) when the inverse mapping is not known explicitely (hence only $\hat{lambda}$ are known, not $\lambda$).

source
Bcube.integrate_refMethod
integrate_ref(::isCurvilinear, g_ref, cnodes, ctype::AbstractEntityType{1}, quadrature::AbstractQuadrature, ::T) where {T<:AbstractComputeQuadratureStyle}

Perform an integration of the function g_ref (expressed in local element) over a line in a $\matbb{R}^n$ space.

The applied formulae is: $\int_\Gamma g(x) dx = \int_l ||F'(l)|| g_ref(l) dl$ where $F ~:~ \mathbb{R} \rightarrow \mathbb{R}^n$ is the reference segment [-1,1] to the R^n line mapping.

Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

source
Bcube.integrate_refMethod
integrate_ref(g_ref, cnodes, ctype, quadrature::AbstractQuadrature)

Integration on a node in a $\mathbb{R}^n$ space. This trivial function is only to simplify the 'side integral' expression.

Implementation

For consistency reasons, g_ref is a function but it doesnt actually use its argument : the "reference-element" of a Node can be anything. For instance consider integrating g(x) = x on a node named node. Then g_ref(ξ) = g ∘ node.x. As you can see, g_ref doesnt actually depend on ξ

source
Bcube.integrate_refMethod
integrate_ref(::isVolumic, g_ref, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature, ::T) where{N, T<:AbstractComputeQuadratureStyle}

Integrate function g_ref (expressed in reference element) on mesh element of type ctype defined by its cnodes at the quadrature. Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.

To do so, a variable substitution is performed to integrate on the reference element.

Implementation

It has been checked that calling the apply_quadrature method within this function instead of directly applying the quadrature rule (i.e without the anonymous function) does not decrease performance nor allocation.

source

Quadrature rules

Bcube.AbstractQuadratureNodeType
AbstractQuadratureNode{S,Q}

Abstract type representing a quadrature node for a shape S and a quadrature Q. This type is used to represent and identify easily a quadrature node in a quadrature rules.

Derived types must implement the following method:

- get_index(quadnode::AbstractQuadratureNode{S,Q})
+- get_coord(quadnode::AbstractQuadratureNode)
source
Bcube.AbstractQuadratureRuleType
AbstractQuadratureRule{S,Q}

Abstract type representing a quadrature rule for a shape S and quadrature Q.

Derived types must implement the following method: - [get_weights(qr::AbstractQuadratureRule)] - [get_nodes(qr::AbstractQuadratureRule)] - [Base.length(qr::AbstractQuadratureRule)]

source
Bcube.QuadratureNodeType
QuadratureNode{S,Q}

Type representing a quadrature node for a shape S and a quadrature Q. This type can be used to represent and identify easily a quadrature node in the corresponding parent quadrature rule.

source
Bcube.QuadratureRuleMethod
QuadratureRule(shape::AbstractShape, q::AbstractQuadrature)

Return the quadrature rule corresponding to the given Shape according to the selected quadrature 'q'.

source
Base.lengthMethod
length(qr::AbstractQuadratureRule)

Returns the number of quadrature nodes of qr.

source
Bcube._gausslegendre1DMethod
_gausslegendre1D(::Val{N}) where N
+_gausslobatto1D(::Val{N}) where N

Return N-point Gauss quadrature weights and nodes on the domain [-1:1].

source
Bcube._get_num_nodesMethod

Gauss-Legendre formula with $n$ nodes has degree of exactness $2n-1$. Then, to obtain a given degree $D$, the number of nodes must satisfy: $2n-1 ≥ D$ or equivalently $n ≥ (D+1)/2$

source
Bcube._get_num_nodesMethod

Gauss-Lobatto formula with $n+1$ nodes has degree of exactness $2n-1$, which equivalent to a degree of $2n-3$ with $n$ nodes. Then, to obtain a given degree $D$, the number of nodes must satisfy: $2n-3 ≥ D$ or equivalently $n ≥ (D+3)/2$

source
Bcube._get_num_nodes_per_dimMethod
get_num_nodes_per_dim(quadrule::AbstractQuadratureRule{S}) where S<:Shape

Returns the number of nodes per dimension. This function is defined for shapes for which quadratures are based on a cartesian product : Line, Square, Cube

Remark : Here we assume that the same degree is used along each dimension (no anisotropy for now!)

source
Bcube.evalquadnodeMethod
evalquadnode(f, quadnode::AbstractQuadratureNode)

Evaluate the function f at the coordinates of quadnode.

Basically, it computes:

f(get_coord(quadnode))

Remark:

Optimization could be applied if f is a function based on a nodal basis such as one of the DoF and quadnode are collocated.

source
Bcube.get_coordMethod
get_coord(quadnode::AbstractQuadratureNode)

Returns the coordinates of quadnode.

source
Bcube.get_indexMethod
get_index(quadnode::AbstractQuadratureNode{S,Q})

Returns the index of quadnode in the parent quadrature rule AbstractQuadRules{S,Q}

source
Bcube.get_nodesMethod
get_nodes(qr::AbstractQuadratureRule)

Returns an array containing the coordinates of all quadrature nodes of qr.

source
Bcube.get_quadnodesMethod
get_quadnodes(qr::QuadratureRule{S,Q,N}) where {S,Q,N}

Returns an vector containing each QuadratureNode of qr

source
Bcube.get_quadrature_points_gausslegendreMethod

Gauss-Legendre quadrature, 12 point rule on triangle.

Ref: Witherden, F. D.; Vincent, P. E. On the identification of symmetric quadrature rules for finite element methods. Comput. Math. Appl. 69 (2015), no. 10, 1232–1241

source
Bcube.get_quadrature_points_gausslegendreMethod

Gauss-Legendre quadrature, 16 point rule on triangle, degree 8.

Ref: Witherden, F. D.; Vincent, P. E. On the identification of symmetric quadrature rules for finite element methods. Comput. Math. Appl. 69 (2015), no. 10, 1232–1241

Note : quadrature is rescale to match our reference triangular shape which is defined in [0:1]² instead of [-1:1]²

source
Bcube.get_weightsMethod
get_weights(qr::AbstractQuadratureRule)

Returns an array containing the weights of all quadrature nodes of qr.

source
Bcube.quadrature_pointsMethod

ref : https://www.math.umd.edu/~tadmor/references/files/Chen%20&%20Shu%20entropy%20stable%20DG%20JCP2017.pdf

source
Bcube.quadrature_ruleMethod
quadrature_rule(iside::Int, shape::AbstractShape, degree::Val{N}) where N

Return the quadrature rule, computed with barycentric coefficients, corresponding to the given boundary of a shape and the given degree.

source
Bcube.quadrature_rule_baryMethod
quadrature_rule_bary(::Int, ::AbstractShape, degree::Val{N}) where N

Return the quadrature rule, computed with barycentric coefficients, corresponding to the given boundary of a shape and the given degree.

This function returns the quadrature weights and the barycentric weights to apply to each vertex of the reference shape. Hence, to apply the quadrature using this function, one needs to do : for (weight, l) in quadrature_rule_bary(iside, shape(etype), degree) xp = zeros(SVector{td}) for i=1:nvertices xp += l[i]*vertices[i] end # weight, xp is the quadrature couple (weight, node) end

source
diff --git a/previews/PR2/api/interpolation/fespace/index.html b/previews/PR2/api/interpolation/fespace/index.html index cb37c0ae..aeed857a 100644 --- a/previews/PR2/api/interpolation/fespace/index.html +++ b/previews/PR2/api/interpolation/fespace/index.html @@ -1,5 +1,5 @@ -Finite element spaces · Bcube

Finite element spaces

Bcube.AbstractFESpaceType

Abstract type to represent an finite-element space of size S. See SingleFESpace for more details about what looks like a finite-element space.

Devs notes

All subtypes should implement the following functions:

  • get_function_space(feSpace::AbstractFESpace)
  • get_shape_functions(feSpace::AbstractFESpace, shape::AbstractShape)
  • get_cell_shape_functions(feSpace::AbstractFESpace, shape::AbstractShape)
  • get_ndofs(feSpace::AbstractFESpace)
  • is_continuous(feSpace::AbstractFESpace)

Alternatively, you may define a "parent" to your structure by implementing the Base.parent function. Then, all the above functions will be redirected to the "parent" FESpace.

source
Bcube.AbstractMultiFESpaceType

Devs notes

All subtypes should implement the following functions:

  • get_fespace(mfeSpace::AbstractMultiFESpace)
  • get_mapping(mfeSpace::AbstractMultiFESpace)
  • get_dofs(mfeSpace::AbstractMultiFESpace, icell::Int)
  • get_shape_functions(mfeSpace::AbstractMultiFESpace, shape::AbstractShape)
  • get_cell_shape_functions(mfeSpace::AbstractMultiFESpace, shape::AbstractShape)
source
Bcube.MultiFESpaceType

A MultiFESpace represents a "set" of TrialFESpace or TestFESpace. This structure provides a global dof numbering for each FESpace.

N is the number of FESpace contained in this MultiFESpace.

Note that the FESpace can be different from each other (one continous, one discontinuous; one scalar, one vector...)

source
Bcube.MultiFESpaceMethod
MultiFESpace(
+Finite element spaces · Bcube

Finite element spaces

Bcube.AbstractFESpaceType

Abstract type to represent an finite-element space of size S. See SingleFESpace for more details about what looks like a finite-element space.

Devs notes

All subtypes should implement the following functions:

  • get_function_space(feSpace::AbstractFESpace)
  • get_shape_functions(feSpace::AbstractFESpace, shape::AbstractShape)
  • get_cell_shape_functions(feSpace::AbstractFESpace, shape::AbstractShape)
  • get_ndofs(feSpace::AbstractFESpace)
  • is_continuous(feSpace::AbstractFESpace)

Alternatively, you may define a "parent" to your structure by implementing the Base.parent function. Then, all the above functions will be redirected to the "parent" FESpace.

source
Bcube.AbstractMultiFESpaceType

Devs notes

All subtypes should implement the following functions:

  • get_fespace(mfeSpace::AbstractMultiFESpace)
  • get_mapping(mfeSpace::AbstractMultiFESpace)
  • get_dofs(mfeSpace::AbstractMultiFESpace, icell::Int)
  • get_shape_functions(mfeSpace::AbstractMultiFESpace, shape::AbstractShape)
  • get_cell_shape_functions(mfeSpace::AbstractMultiFESpace, shape::AbstractShape)
source
Bcube.MultiFESpaceType

A MultiFESpace represents a "set" of TrialFESpace or TestFESpace. This structure provides a global dof numbering for each FESpace.

N is the number of FESpace contained in this MultiFESpace.

Note that the FESpace can be different from each other (one continous, one discontinuous; one scalar, one vector...)

source
Bcube.MultiFESpaceMethod
MultiFESpace(
     feSpaces::Tuple{Vararg{TrialOrTest, N}};
     arrayOfStruct::Bool = AOS_DEFAULT,
 ) where {N}
@@ -7,14 +7,14 @@
     feSpaces::AbstractArray{FE};
     arrayOfStruct::Bool = AOS_DEFAULT,
 ) where {FE <: TrialOrTest}
-MultiFESpace(feSpaces::Vararg{TrialOrTest}; arrayOfStruct::Bool = AOS_DEFAULT)

Build a finite element space representing several sub- finite element spaces.

This is particulary handy when several variables are in play since it provides a global dof numbering (for the whole system). The finite element spaces composing the MultiFESpace can be different from each other (some continuous, some discontinuous, some scalar, some vectors...).

Arguments

  • feSpaces : the finite element spaces composing the MultiFESpace. Note that they must be of type TrialFESpace or TestFESpace.

Keywords

  • arrayOfStruct::Bool = AOS_DEFAULT : indicates if the dof numbering should be of type "Array of Structs" (AoS) or "Struct of Arrays" (SoA).
source
Bcube.SingleFESpaceType
SingleFESpace(
+MultiFESpace(feSpaces::Vararg{TrialOrTest}; arrayOfStruct::Bool = AOS_DEFAULT)

Build a finite element space representing several sub- finite element spaces.

This is particulary handy when several variables are in play since it provides a global dof numbering (for the whole system). The finite element spaces composing the MultiFESpace can be different from each other (some continuous, some discontinuous, some scalar, some vectors...).

Arguments

  • feSpaces : the finite element spaces composing the MultiFESpace. Note that they must be of type TrialFESpace or TestFESpace.

Keywords

  • arrayOfStruct::Bool = AOS_DEFAULT : indicates if the dof numbering should be of type "Array of Structs" (AoS) or "Struct of Arrays" (SoA).
source
Bcube.SingleFESpaceType
SingleFESpace(
     fSpace::AbstractFunctionSpace,
     mesh::AbstractMesh,
     dirichletBndNames = String[];
     size::Int = 1,
     isContinuous::Bool = true,
     kwargs...
-)

Build a finite element space (scalar or vector) from a FunctionSpace and a Mesh.

Arguments

  • fSpace::AbstractFunctionSpace : the function space associated to the FESpace
  • mesh::AbstractMesh : the mesh on which the FESpace is discretized
  • dirichletBndNames = String[] : list of mesh boundary labels where a Dirichlet condition applies

Keywords

  • size::Int = 1 : the number of components of the FESpace
  • isContinuous::Bool = true : if true, a continuous dof numbering is created. Otherwise, dof lying

on cell nodes or cell faces are duplicated, not shared (discontinuous dof numbering)

  • kwargs : for things such as parallel cache (internal/dev usage only)
source
Bcube.SingleFESpaceType

An finite-element space (FESpace) is basically a function space, associated to degrees of freedom (on a mesh).

A FESpace can be either scalar (to represent a Temperature for instance) or vector (to represent a Velocity). In case of a "vector" SingleFESpace, all the components necessarily share the same FunctionSpace.

source
Bcube.TestFESpaceType
TestFESpace(trialFESpace::TrialFESpace)
+)

Build a finite element space (scalar or vector) from a FunctionSpace and a Mesh.

Arguments

  • fSpace::AbstractFunctionSpace : the function space associated to the FESpace
  • mesh::AbstractMesh : the mesh on which the FESpace is discretized
  • dirichletBndNames = String[] : list of mesh boundary labels where a Dirichlet condition applies

Keywords

  • size::Int = 1 : the number of components of the FESpace
  • isContinuous::Bool = true : if true, a continuous dof numbering is created. Otherwise, dof lying

on cell nodes or cell faces are duplicated, not shared (discontinuous dof numbering)

  • kwargs : for things such as parallel cache (internal/dev usage only)
source
Bcube.SingleFESpaceType

An finite-element space (FESpace) is basically a function space, associated to degrees of freedom (on a mesh).

A FESpace can be either scalar (to represent a Temperature for instance) or vector (to represent a Velocity). In case of a "vector" SingleFESpace, all the components necessarily share the same FunctionSpace.

source
Bcube.TestFESpaceType
TestFESpace(trialFESpace::TrialFESpace)
 TestFESpace(
     fSpace::AbstractFunctionSpace,
     mesh::AbstractMesh,
@@ -25,7 +25,7 @@
 )

Build a test finite element space.

A TestFESpace can be built from a TrialFESpace. See SingleFESpace for hints about the function arguments. Only arguments specific to TrialFESpace are detailed below.

Examples

julia> mesh = one_cell_mesh(:line)
 julia> fSpace = FunctionSpace(:Lagrange, 2)
 julia> U = TrialFESpace(fSpace, mesh)
-julia> V = TestFESpace(U)
source
Bcube.TestFESpaceType

A TestFESpace is basically a SingleFESpace plus other attributes (related to boundary conditions)

source
Bcube.TestFESpaceType

A TestFESpace is basically a SingleFESpace plus other attributes (related to boundary conditions)

source
Bcube.TrialFESpaceType
TrialFESpace(feSpace, dirichletValues)
 TrialFESpace(
     fSpace::AbstractFunctionSpace,
     mesh::AbstractMesh,
@@ -45,6 +45,6 @@
 julia> fSpace = FunctionSpace(:Lagrange, 2)
 julia> U = TrialFESpace(fSpace, mesh)
 julia> V = TrialFESpace(fSpace, mesh, :discontinuous; size = 3)
-julia> W = TrialFESpace(fSpace, mesh, Dict("North" => 3., "South" => (x,t) -> t .* x))
source
Bcube.TrialFESpaceType

A TrialFESpace is basically a SingleFESpace plus other attributes (related to boundary conditions)

Dev notes

  • we cannot directly store Dirichlet values on dofs because the Dirichlet values needs "time" to apply
source
Bcube.allocate_dofsFunction
allocate_dofs(feSpace::AbstractFESpace, T = Float64)

Allocate a vector with a size equal to the number of dof of the FESpace, with the type T. For a MultiFESpace, a vector of the total size of the space is returned (and not a Tuple of vectors)

source
Bcube.get_cell_shape_functionsMethod

Return the shape functions associated to the AbstractFESpace in "packed" form: λ(x) = (λ₁(x),...,λᵢ(x),...λₙ(x)) for the n dofs.

source
Bcube.get_dofsMethod

Return the dofs indices for the cell icell

Result is an array of integers.

source
Bcube.get_dofsMethod
get_dofs(feSpace::MultiFESpace, icell::Int)

Return the dofs indices for the cell icell for each single-feSpace. Result is a tuple of array of integers, where each array of integers are the indices relative to the numbering of each singleFESpace.

Warning:

Combine get_dofs with get_mapping if global dofs indices are needed.

source
Bcube.get_fespaceMethod
get_fespace(mfeSpace::AbstractMultiFESpace, iSpace)
-get_fespace(mfeSpace::AbstractMultiFESpace)

Return the i-th FESpace composing this AbstractMultiFESpace. If no index is provided, the tuple of FESpace composing this AbstractMultiFESpace` is returnted.

source
Bcube.get_mappingMethod
get_mapping(mfeSpace::AbstractMultiFESpace, iSpace)
-get_mapping(mfeSpace::AbstractMultiFESpace)

Return the mapping for the ith FESpace composing the MultiFESpace. If no index is provided, the tuple of mapping for each FESpace` is returnted.

source
Bcube.get_ndofsMethod

Return the total number of dofs of the FESpace, taking into account the continuous/discontinuous type of the space. If the FESpace contains itself several FESpace (see MultiFESpace), the sum of all dofs is returned.

source
+julia> W = TrialFESpace(fSpace, mesh, Dict("North" => 3., "South" => (x,t) -> t .* x))
source
Bcube.TrialFESpaceType

A TrialFESpace is basically a SingleFESpace plus other attributes (related to boundary conditions)

Dev notes

  • we cannot directly store Dirichlet values on dofs because the Dirichlet values needs "time" to apply
source
Bcube.allocate_dofsFunction
allocate_dofs(feSpace::AbstractFESpace, T = Float64)

Allocate a vector with a size equal to the number of dof of the FESpace, with the type T. For a MultiFESpace, a vector of the total size of the space is returned (and not a Tuple of vectors)

source
Bcube.get_cell_shape_functionsMethod

Return the shape functions associated to the AbstractFESpace in "packed" form: λ(x) = (λ₁(x),...,λᵢ(x),...λₙ(x)) for the n dofs.

source
Bcube.get_dofsMethod

Return the dofs indices for the cell icell

Result is an array of integers.

source
Bcube.get_dofsMethod
get_dofs(feSpace::MultiFESpace, icell::Int)

Return the dofs indices for the cell icell for each single-feSpace. Result is a tuple of array of integers, where each array of integers are the indices relative to the numbering of each singleFESpace.

Warning:

Combine get_dofs with get_mapping if global dofs indices are needed.

source
Bcube.get_fespaceMethod
get_fespace(mfeSpace::AbstractMultiFESpace, iSpace)
+get_fespace(mfeSpace::AbstractMultiFESpace)

Return the i-th FESpace composing this AbstractMultiFESpace. If no index is provided, the tuple of FESpace composing this AbstractMultiFESpace` is returnted.

source
Bcube.get_mappingMethod
get_mapping(mfeSpace::AbstractMultiFESpace, iSpace)
+get_mapping(mfeSpace::AbstractMultiFESpace)

Return the mapping for the ith FESpace composing the MultiFESpace. If no index is provided, the tuple of mapping for each FESpace` is returnted.

source
Bcube.get_ndofsMethod

Return the total number of dofs of the FESpace, taking into account the continuous/discontinuous type of the space. If the FESpace contains itself several FESpace (see MultiFESpace), the sum of all dofs is returned.

source
diff --git a/previews/PR2/api/interpolation/function_space/index.html b/previews/PR2/api/interpolation/function_space/index.html index c88c8f25..cce0c73e 100644 --- a/previews/PR2/api/interpolation/function_space/index.html +++ b/previews/PR2/api/interpolation/function_space/index.html @@ -1,5 +1,5 @@ -Function spaces · Bcube

Function spaces

Bcube.FunctionSpaceMethod
FunctionSpace(fstype::Symbol, degree::Integer)
+Function spaces · Bcube

Function spaces

Bcube.FunctionSpaceMethod
FunctionSpace(fstype::Symbol, degree::Integer)
 FunctionSpace(fstype::AbstractFunctionSpaceType, degree::Integer)

Build a FunctionSpace of the designated FunctionSpaceType and degree.

Examples

julia> FunctionSpace(:Lagrange, 2)
-FunctionSpace{Bcube.Lagrange{:Uniform}, 2}()
source
Bcube.basis_functions_styleMethod
basis_functions_style(fs::AbstractFunctionSpace)

Return the style (modal or nodal) corresponding to the basis functions of the 'fs'.

source
Bcube.coordsMethod
coords(fs::AbstractFunctionSpace,::AbstractShape)

Return node coordinates in the reference space for associated function space and shape.

source
Bcube.get_degreeMethod
get_degree(::AbstractFunctionSpace{type, degree}) where{type, degree}

Return the degree associated to the AbstractFunctionSpace.

source
Bcube.get_typeMethod
get_type(::AbstractFunctionSpace{type})

Getter for the type of the AbstractFunctionSpace

source
Bcube.idof_by_edgeMethod
idof_by_edge(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each edge of the Shape.

Dofs lying on the edge vertices are excluded.

The result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.

source
Bcube.idof_by_edge_with_boundsMethod
idof_by_edge_with_bounds(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each edge of the Shape.

Dofs lying on the edge vertices are included.

The result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.

source
Bcube.idof_by_faceMethod
idof_by_face(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each face of the Shape.

Dofs lying on the face edges are excluded, only "face-interior" dofs are considered.

The result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.

source
Bcube.idof_by_face_with_boundsMethod
idof_by_face_with_bounds(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each face of the Shape.

Dofs lying on the face edges are included

The result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.

source
Bcube.idof_by_vertexMethod
idof_by_vertex(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each vertex of the Shape.

Beware that we are talking about the Shape, not the EntityType. So 'interior' vertices of the EntityType are not taken into account for instance. See Lagrange interpolation for simple examples.

source
Bcube.ndofsMethod
ndofs(fs::AbstractFunctionSpace, shape::AbstractShape)

Number of dofs associated to the given interpolation.

source
Bcube.shape_functionsMethod
shape_functions(::AbstractFunctionSpace, ::Val{N}, shape::AbstractShape, ξ) where N
-shape_functions(::AbstractFunctionSpace, shape::AbstractShape, ξ)

Return the list of shape functions corresponding to a FunctionSpace and a Shape. N is the size of the finite element space (default: N=1 if the argument is not provided).

The result is a vector of all the shape functions evaluated at position ξ, and not a tuple of the different shape functions. This choice is optimal for performance.

Note : λ = ξ -> shape_functions(fs, shape, ξ); λ(ξ)[i] is faster than λ =shape_functions(fs, shape); λ[i](ξ)

Implementation

Default version, should be overriden for each concrete FunctionSpace.

source
Bcube.shape_functions_vecMethod
shape_functions_vec(fs::AbstractFunctionSpace{T,D}, ::Val{N}, shape::AbstractShape, ξ) where {D,N}

Return all the shape functions of FunctionSpace on a Shape evaluated in ξ as a vector.

N is the the size (number of components) of the finite element space.


shape_functions_vec(fs::AbstractFunctionSpace{T,D}, n::Val{N}, shape::AbstractShape) where {T,D, N}

The shape functions are returned as a vector of functions.

Implementation

This is implementation is not always valid, but it is for Lagrange and Taylor spaces (the only two spaces available up to 20/01/23).

source
Bcube.var_on_bnd_nodes_discontinuousFunction
var_on_bnd_nodes_discontinuous(f::AbstractFEFunction, fdomain::BoundaryFaceDomain, degree::Integer=max(1, get_degree(get_function_space(get_fespace(f)))))

Returns an array containing the values of f interpolated to new DoFs on fdomain. The DoFs locations on fdomain correspond to those of a discontinuous FESpace with a :Lagrange function space of selected degree.

source
Bcube.var_on_centersMethod
var_on_centers(f::SingleFEFunction, mesh::Mesh)

Interpolate solution on mesh vertices.

The result is a (ncells, ncomps) matrix if ncomps > 1, or a (ncells) vector otherwise.

source
Bcube.var_on_nodes_discontinuousFunction
var_on_nodes_discontinuous(f::AbstractFEFunction, mesh::Mesh, degree::Integer=max(1, get_degree(get_function_space(get_fespace(f)))))

Returns an array containing the values of f interpolated to new DoFs. The DoFs correspond to those of a discontinuous cell variable with a :Lagrange function space of selected degree.

source
Bcube.var_on_verticesMethod
var_on_vertices(f::AbstractFEFunction, mesh::Mesh)

Interpolate solution on mesh vertices.

The result is a (nnodes, ncomps) matrix.

source
+FunctionSpace{Bcube.Lagrange{:Uniform}, 2}()
source
Bcube.basis_functions_styleMethod
basis_functions_style(fs::AbstractFunctionSpace)

Return the style (modal or nodal) corresponding to the basis functions of the 'fs'.

source
Bcube.coordsMethod
coords(fs::AbstractFunctionSpace,::AbstractShape)

Return node coordinates in the reference space for associated function space and shape.

source
Bcube.get_degreeMethod
get_degree(::AbstractFunctionSpace{type, degree}) where{type, degree}

Return the degree associated to the AbstractFunctionSpace.

source
Bcube.get_typeMethod
get_type(::AbstractFunctionSpace{type})

Getter for the type of the AbstractFunctionSpace

source
Bcube.idof_by_edgeMethod
idof_by_edge(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each edge of the Shape.

Dofs lying on the edge vertices are excluded.

The result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.

source
Bcube.idof_by_edge_with_boundsMethod
idof_by_edge_with_bounds(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each edge of the Shape.

Dofs lying on the edge vertices are included.

The result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.

source
Bcube.idof_by_faceMethod
idof_by_face(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each face of the Shape.

Dofs lying on the face edges are excluded, only "face-interior" dofs are considered.

The result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.

source
Bcube.idof_by_face_with_boundsMethod
idof_by_face_with_bounds(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each face of the Shape.

Dofs lying on the face edges are included

The result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.

source
Bcube.idof_by_vertexMethod
idof_by_vertex(::AbstractFunctionSpace, ::AbstractShape)

Return the local indices of the dofs lying on each vertex of the Shape.

Beware that we are talking about the Shape, not the EntityType. So 'interior' vertices of the EntityType are not taken into account for instance. See Lagrange interpolation for simple examples.

source
Bcube.ndofsMethod
ndofs(fs::AbstractFunctionSpace, shape::AbstractShape)

Number of dofs associated to the given interpolation.

source
Bcube.shape_functionsMethod
shape_functions(::AbstractFunctionSpace, ::Val{N}, shape::AbstractShape, ξ) where N
+shape_functions(::AbstractFunctionSpace, shape::AbstractShape, ξ)

Return the list of shape functions corresponding to a FunctionSpace and a Shape. N is the size of the finite element space (default: N=1 if the argument is not provided).

The result is a vector of all the shape functions evaluated at position ξ, and not a tuple of the different shape functions. This choice is optimal for performance.

Note : λ = ξ -> shape_functions(fs, shape, ξ); λ(ξ)[i] is faster than λ =shape_functions(fs, shape); λ[i](ξ)

Implementation

Default version, should be overriden for each concrete FunctionSpace.

source
Bcube.shape_functions_vecMethod
shape_functions_vec(fs::AbstractFunctionSpace{T,D}, ::Val{N}, shape::AbstractShape, ξ) where {D,N}

Return all the shape functions of FunctionSpace on a Shape evaluated in ξ as a vector.

N is the the size (number of components) of the finite element space.


shape_functions_vec(fs::AbstractFunctionSpace{T,D}, n::Val{N}, shape::AbstractShape) where {T,D, N}

The shape functions are returned as a vector of functions.

Implementation

This is implementation is not always valid, but it is for Lagrange and Taylor spaces (the only two spaces available up to 20/01/23).

source
Bcube.var_on_bnd_nodes_discontinuousFunction
var_on_bnd_nodes_discontinuous(f::AbstractFEFunction, fdomain::BoundaryFaceDomain, degree::Integer=max(1, get_degree(get_function_space(get_fespace(f)))))

Returns an array containing the values of f interpolated to new DoFs on fdomain. The DoFs locations on fdomain correspond to those of a discontinuous FESpace with a :Lagrange function space of selected degree.

source
Bcube.var_on_centersMethod
var_on_centers(f::SingleFEFunction, mesh::Mesh)

Interpolate solution on mesh vertices.

The result is a (ncells, ncomps) matrix if ncomps > 1, or a (ncells) vector otherwise.

source
Bcube.var_on_nodes_discontinuousFunction
var_on_nodes_discontinuous(f::AbstractFEFunction, mesh::Mesh, degree::Integer=max(1, get_degree(get_function_space(get_fespace(f)))))

Returns an array containing the values of f interpolated to new DoFs. The DoFs correspond to those of a discontinuous cell variable with a :Lagrange function space of selected degree.

source
Bcube.var_on_verticesMethod
var_on_vertices(f::AbstractFEFunction, mesh::Mesh)

Interpolate solution on mesh vertices.

The result is a (nnodes, ncomps) matrix.

source
diff --git a/previews/PR2/api/interpolation/shape/index.html b/previews/PR2/api/interpolation/shape/index.html index 0d309c83..4aa6443e 100644 --- a/previews/PR2/api/interpolation/shape/index.html +++ b/previews/PR2/api/interpolation/shape/index.html @@ -1,2 +1,2 @@ -Reference shape · Bcube

Reference shape

Bcube.centerMethod
center(::AbstractShape)

Center of the AbstractShape.

Implementation

Specialize for better performances

source
Bcube.coordsMethod
coords(shape::AbstractShape,i)

Return the coordinates of the ith shape vertices. i can be a tuple of indices, then the multiples vertices's coordinates are returned.

source
Bcube.coordsMethod
coords(::AbstractShape)

Return node coordinates of the shape in the reference space.

source
Bcube.entityMethod
entity(s::AbstractShape, ::Val{D}) where D

Return the geometrical Entity corresponding to the AbstractShape of a given degree D.

Remark : Returned entity must be consistent with the corresponding Lagrange function space.

source
Bcube.face_areaMethod
face_area(::AbstractShape)

Return the length/area of the faces of a shape.

source
Bcube.face_shapesMethod
face_shapes(::AbstractShape)

Return a tuple of the Shape of each face of the given (cell) Shape. For instance, a Triangle has three faces, all of them are Line.

source
Bcube.faces2nodesMethod
faces2nodes(shape::AbstractShape, side)

Return the index of the vertices on the iside-th face of a shape. If side is positive, the face is oriented preserving the cell normal. If side is negative, the face is returned with the opposite direction (i.e reverse node order).

source
Bcube.faces2nodesMethod
faces2nodes(::AbstractShape)

Return the index of the vertices on the faces of a shape.

source
Bcube.nedgesMethod
nedges(::AbstractShape)

Generic function. Indicate how many edges a shape has.

source
Bcube.normalMethod
normal(shape::AbstractShape, i)

Return the outward normal of the ith face of the shape.

source
Bcube.normalsMethod
normals(::AbstractShape)

Return the outward normals of all the faces of the shape.

source
Bcube.shapeMethod
shape(::AbstractEntityType)

Return the reference Shape corresponding to the given AbstractEntityType.

source
+Reference shape · Bcube

Reference shape

Bcube.centerMethod
center(::AbstractShape)

Center of the AbstractShape.

Implementation

Specialize for better performances

source
Bcube.coordsMethod
coords(shape::AbstractShape,i)

Return the coordinates of the ith shape vertices. i can be a tuple of indices, then the multiples vertices's coordinates are returned.

source
Bcube.coordsMethod
coords(::AbstractShape)

Return node coordinates of the shape in the reference space.

source
Bcube.entityMethod
entity(s::AbstractShape, ::Val{D}) where D

Return the geometrical Entity corresponding to the AbstractShape of a given degree D.

Remark : Returned entity must be consistent with the corresponding Lagrange function space.

source
Bcube.face_areaMethod
face_area(::AbstractShape)

Return the length/area of the faces of a shape.

source
Bcube.face_shapesMethod
face_shapes(::AbstractShape)

Return a tuple of the Shape of each face of the given (cell) Shape. For instance, a Triangle has three faces, all of them are Line.

source
Bcube.faces2nodesMethod
faces2nodes(shape::AbstractShape, side)

Return the index of the vertices on the iside-th face of a shape. If side is positive, the face is oriented preserving the cell normal. If side is negative, the face is returned with the opposite direction (i.e reverse node order).

source
Bcube.faces2nodesMethod
faces2nodes(::AbstractShape)

Return the index of the vertices on the faces of a shape.

source
Bcube.nedgesMethod
nedges(::AbstractShape)

Generic function. Indicate how many edges a shape has.

source
Bcube.normalMethod
normal(shape::AbstractShape, i)

Return the outward normal of the ith face of the shape.

source
Bcube.normalsMethod
normals(::AbstractShape)

Return the outward normals of all the faces of the shape.

source
Bcube.shapeMethod
shape(::AbstractEntityType)

Return the reference Shape corresponding to the given AbstractEntityType.

source
diff --git a/previews/PR2/api/interpolation/spaces/index.html b/previews/PR2/api/interpolation/spaces/index.html index faa73195..0c70e761 100644 --- a/previews/PR2/api/interpolation/spaces/index.html +++ b/previews/PR2/api/interpolation/spaces/index.html @@ -4,22 +4,22 @@ \hat{\lambda}_3(\xi, \eta, \zeta) = \eta (1 - \zeta)/2 \hspace{1cm} \hat{\lambda}_5(\xi, \eta, \zeta) = (1 - \xi - \eta)(1 + \zeta)/2 \hspace{1cm} \hat{\lambda}_6(\xi, \eta, \zeta) = \xi (1 + \zeta)/2 \hspace{1cm} -\hat{\lambda}_7(\xi, \eta, \zeta) = \eta (1 + \zeta)/2 \hspace{1cm}\]

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Triangle, ξ)

Shape functions for Triangle Lagrange element of degree 1 in a 2D space.

\[\hat{\lambda}_1(\xi, \eta) = 1 - \xi - \eta \hspace{1cm} +\hat{\lambda}_7(\xi, \eta, \zeta) = \eta (1 + \zeta)/2 \hspace{1cm}\]

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Triangle, ξ)

Shape functions for Triangle Lagrange element of degree 1 in a 2D space.

\[\hat{\lambda}_1(\xi, \eta) = 1 - \xi - \eta \hspace{1cm} \hat{\lambda}_2(\xi, \eta) = \xi \hspace{1cm} -\hat{\lambda}_3(\xi, \eta) = \eta\]

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Lagrange, 2}, ::Triangle, ξ)

Shape functions for Triangle Lagrange element of degree 2 in a 2D space.

\[\begin{aligned} +\hat{\lambda}_3(\xi, \eta) = \eta\]

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Lagrange, 2}, ::Triangle, ξ)

Shape functions for Triangle Lagrange element of degree 2 in a 2D space.

\[\begin{aligned} & \hat{\lambda}_1(\xi, \eta) = (1 - \xi - \eta)(1 - 2 \xi - 2 \eta) \\ & \hat{\lambda}_2(\xi, \eta) = \xi (2\xi - 1) \\ & \hat{\lambda}_3(\xi, \eta) = \eta (2\eta - 1) \\ & \hat{\lambda}_{12}(\xi, \eta) = 4 \xi (1 - \xi - \eta) \\ & \hat{\lambda}_{23}(\xi, \eta) = 4 \xi \eta \\ & \hat{\lambda}_{31}(\xi, \eta) = 4 \eta (1 - \xi - \eta) -\end{aligned}\]

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Lagrange, 3}, ::Triangle, ξ)

Shape functions for Triangle Lagrange element of degree 3 in a 2D space.

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Lagrange, 0}, ::Val{1}, ::Square, x)

Gradient of shape functions for Square Lagrange element of degree 0 in a 2D space.

\[\nabla \hat{\lambda}(\xi, \eta) = +\end{aligned}\]

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Lagrange, 3}, ::Triangle, ξ)

Shape functions for Triangle Lagrange element of degree 3 in a 2D space.

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Lagrange, 0}, ::Val{1}, ::Square, x)

Gradient of shape functions for Square Lagrange element of degree 0 in a 2D space.

\[\nabla \hat{\lambda}(\xi, \eta) = \begin{pmatrix} 0 \\ 0 -\end{pmatrix}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Lagrange, 0}, ::Val{1}, ::Triangle, ξ)

Gradient of shape functions for Triangle Lagrange element of degree 0 in a 2D space.

\[\nabla \hat{\lambda}(\xi, \eta) = +\end{pmatrix}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Lagrange, 0}, ::Val{1}, ::Triangle, ξ)

Gradient of shape functions for Triangle Lagrange element of degree 0 in a 2D space.

\[\nabla \hat{\lambda}(\xi, \eta) = \begin{pmatrix} 0 \\ 0 -\end{pmatrix}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Val{1}, ::Triangle, ξ)

Gradient of shape functions for Triangle Lagrange element of degree 1 in a 2D space.

\[\begin{aligned} +\end{pmatrix}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Val{1}, ::Triangle, ξ)

Gradient of shape functions for Triangle Lagrange element of degree 1 in a 2D space.

\[\begin{aligned} & \nabla \hat{\lambda}_1(\xi, \eta) = \begin{pmatrix} -1 \\ -1 @@ -32,7 +32,7 @@ \begin{pmatrix} 0 \\ 1 \end{pmatrix} \\ -\end{aligned}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Lagrange, 2}, ::Val{1}, ::Triangle, ξ)

Gradient of shape functions for Triangle Lagrange element of degree 2 in a 2D space.

\[\begin{aligned} +\end{aligned}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Lagrange, 2}, ::Val{1}, ::Triangle, ξ)

Gradient of shape functions for Triangle Lagrange element of degree 2 in a 2D space.

\[\begin{aligned} & \nabla \hat{\lambda}_1(\xi, \eta) = \begin{pmatrix} -3 + 4 (\xi + \eta) \\ -3 + 4 (\xi + \eta) @@ -57,12 +57,12 @@ 4 \begin{pmatrix} - \eta \\ 1 - 2 \eta - \xi \end{pmatrix} \\ -\end{aligned}\]

source
Bcube.shape_functionsMethod

Default version : the shape functions are "replicated". If shape_functions returns the vector [λ₁; λ₂; λ₃], and if the FESpace is of size 2, then this default behaviour consists in returning the matrix [λ₁ 0; λ₂ 0; λ₃ 0; 0 λ₁; 0 λ₂; 0 λ₃].

source

Taylor

The Taylor function space corresponds to a function space where functions are approximated by a Taylor series expansion of order $n$ in each cell:

\[ \forall x \in \Omega_i,~g(x) = g(x_0) + (x - x_0) g'(x_0) + o(x)\]

where $x_0$ is the cell center.

Note that a Taylor-P0 is strictly equivalent to a 1st-order Finite Volume discretization (beware that "order" can have different meaning depending on whether one refers to the order of the function space basis or the order of the discretization method).

Recall that any function space implies that any function $g$ is interpolated by $g(x) = \sum g_i \lambda_i(x)$ where $\lambda_i$ are the shape functions. For a Taylor expansion, the definition of $\lambda_i$ is not unique. For instance for the Taylor expansion of order $1$ on a 1D line above, we may be tempted to set $\lambda_1(x) = 1$ and $\lambda_2(x) = (x - x_0)$. If you do so, what are the corresponding shape functions in the reference element, the $\hat{\lambda_i}$? We immediately recover $\hat{\lambda_1}(\hat{x}) = 1$. For $\hat{\lambda_2}$:

\[ \hat{\lambda_2}(\hat{x}) = (\lambda \circ F)(\hat{x}) = (x \rightarrow x - x_0) \circ (\hat{x} \rightarrow \frac{x_r - x_l}{2} \hat{x} + \frac{x_r + x_l}{2}) = \frac{x_r - x_l}{2} \hat{x}\]

So if you set $\lambda_2(x) = (x - x_0)$ then $\hat{\lambda_2}$ depends on the element length ($\Delta x = x_r-x_l$), which is pointless. So $\lambda_2$ must be proportional to the element length to obtain a universal definition for $\hat{\lambda_2}$. For instance, we may choose $\lambda_2(x) = (x - x_0) / \Delta x$, leading to $\hat{\lambda_2}(\hat{x}) = \hat{x} / 2$. But we could have chosen an other element length multiple.

Don't forget that choosing $\lambda_2(x) = (x - x_0) / \Delta x$ leads to $g(x) = g(x_0) + \frac{x - x_0}{\Delta x} g'(x_0) Δx$ hence $g_2 = g'(x_0) Δx$ in the interpolation.

Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Taylor, 0}, ::AbstractShape, x)

Shape functions for any Taylor element of degree 0 : $\hat{\lambda}(\xi) = 1$

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Taylor, 1}, ::Line, ξ)

Shape functions for Line Taylor element of degree 1 in a 1D space.

\[\hat{\lambda}_1(\xi) = 1 \hspace{1cm} \hat{\lambda}_1(\xi) = \frac{\xi}{2}\]

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Taylor, 1}, ::Square, ξ)

Shape functions for Square Taylor element of degree 1 in a 2D space.

\[\begin{aligned} +\end{aligned}\]

source
Bcube.shape_functionsMethod

Default version : the shape functions are "replicated". If shape_functions returns the vector [λ₁; λ₂; λ₃], and if the FESpace is of size 2, then this default behaviour consists in returning the matrix [λ₁ 0; λ₂ 0; λ₃ 0; 0 λ₁; 0 λ₂; 0 λ₃].

source

Taylor

The Taylor function space corresponds to a function space where functions are approximated by a Taylor series expansion of order $n$ in each cell:

\[ \forall x \in \Omega_i,~g(x) = g(x_0) + (x - x_0) g'(x_0) + o(x)\]

where $x_0$ is the cell center.

Note that a Taylor-P0 is strictly equivalent to a 1st-order Finite Volume discretization (beware that "order" can have different meaning depending on whether one refers to the order of the function space basis or the order of the discretization method).

Recall that any function space implies that any function $g$ is interpolated by $g(x) = \sum g_i \lambda_i(x)$ where $\lambda_i$ are the shape functions. For a Taylor expansion, the definition of $\lambda_i$ is not unique. For instance for the Taylor expansion of order $1$ on a 1D line above, we may be tempted to set $\lambda_1(x) = 1$ and $\lambda_2(x) = (x - x_0)$. If you do so, what are the corresponding shape functions in the reference element, the $\hat{\lambda_i}$? We immediately recover $\hat{\lambda_1}(\hat{x}) = 1$. For $\hat{\lambda_2}$:

\[ \hat{\lambda_2}(\hat{x}) = (\lambda \circ F)(\hat{x}) = (x \rightarrow x - x_0) \circ (\hat{x} \rightarrow \frac{x_r - x_l}{2} \hat{x} + \frac{x_r + x_l}{2}) = \frac{x_r - x_l}{2} \hat{x}\]

So if you set $\lambda_2(x) = (x - x_0)$ then $\hat{\lambda_2}$ depends on the element length ($\Delta x = x_r-x_l$), which is pointless. So $\lambda_2$ must be proportional to the element length to obtain a universal definition for $\hat{\lambda_2}$. For instance, we may choose $\lambda_2(x) = (x - x_0) / \Delta x$, leading to $\hat{\lambda_2}(\hat{x}) = \hat{x} / 2$. But we could have chosen an other element length multiple.

Don't forget that choosing $\lambda_2(x) = (x - x_0) / \Delta x$ leads to $g(x) = g(x_0) + \frac{x - x_0}{\Delta x} g'(x_0) Δx$ hence $g_2 = g'(x_0) Δx$ in the interpolation.

Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Taylor, 0}, ::AbstractShape, x)

Shape functions for any Taylor element of degree 0 : $\hat{\lambda}(\xi) = 1$

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Taylor, 1}, ::Line, ξ)

Shape functions for Line Taylor element of degree 1 in a 1D space.

\[\hat{\lambda}_1(\xi) = 1 \hspace{1cm} \hat{\lambda}_1(\xi) = \frac{\xi}{2}\]

source
Bcube._scalar_shape_functionsMethod
shape_functions(::FunctionSpace{<:Taylor, 1}, ::Square, ξ)

Shape functions for Square Taylor element of degree 1 in a 2D space.

\[\begin{aligned} & \hat{\lambda}_1(\xi, \eta) = 0 \\ & \hat{\lambda}_2(\xi, \eta) = \frac{\xi}{2} \\ & \hat{\lambda}_3(\xi, \eta) = \frac{\eta}{2} -\end{aligned}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Taylor, 0}, ::Line, x)

Gradient (=derivative) of shape functions for Line Taylor element of degree 0 in a 1D space : $\nabla \hat{\lambda}(\xi) = 0$

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Taylor, 0}, ::Union{Square,Triangle}, ξ)

Gradient of shape functions for Square or Triangle Taylor element of degree 0 in a 2D space.

\[\hat{\lambda}_1(\xi, \eta) = \begin{pmatrix} 0 \\ 0 \end{pmatrix}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Taylor, 1}, ::Line, ξ)

Gradient (=derivative) of shape functions for Line Taylor element of degree 1 in a 1D space.

\[\nabla \hat{\lambda}_1(\xi) = 0 \hspace{1cm} \nabla \hat{\lambda}_1(\xi) = \frac{1}{2}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Taylor, 1}, ::Square, ξ)

Gradient of shape functions for Square Taylor element of degree 1 in a 2D space.

\[\begin{aligned} +\end{aligned}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Taylor, 0}, ::Line, x)

Gradient (=derivative) of shape functions for Line Taylor element of degree 0 in a 1D space : $\nabla \hat{\lambda}(\xi) = 0$

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Taylor, 0}, ::Union{Square,Triangle}, ξ)

Gradient of shape functions for Square or Triangle Taylor element of degree 0 in a 2D space.

\[\hat{\lambda}_1(\xi, \eta) = \begin{pmatrix} 0 \\ 0 \end{pmatrix}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Taylor, 1}, ::Line, ξ)

Gradient (=derivative) of shape functions for Line Taylor element of degree 1 in a 1D space.

\[\nabla \hat{\lambda}_1(\xi) = 0 \hspace{1cm} \nabla \hat{\lambda}_1(\xi) = \frac{1}{2}\]

source
Bcube.grad_shape_functionsMethod
grad_shape_functions(::FunctionSpace{<:Taylor, 1}, ::Square, ξ)

Gradient of shape functions for Square Taylor element of degree 1 in a 2D space.

\[\begin{aligned} & \nabla \hat{\lambda}_1(\xi, \eta) = \begin{pmatrix} 0 \\ 0 \end{pmatrix} \\ & \nabla \hat{\lambda}_2(\xi, \eta) = \begin{pmatrix} \frac{1}{2} \\ 0 \end{pmatrix} \\ & \nabla \hat{\lambda}_3(\xi, \eta) = \begin{pmatrix} 0 \\ \frac{1}{2} \end{pmatrix} -\end{aligned}\]

source
Bcube.shape_functionsMethod

Default version : the shape functions are "replicated". If shape_functions returns the vector [λ₁; λ₂; λ₃], and if the FESpace is of size 2, then this default behaviour consists in returning the matrix [λ₁ 0; λ₂ 0; λ₃ 0; 0 λ₁; 0 λ₂; 0 λ₃].

source
+\end{aligned}\]

source
Bcube.shape_functionsMethod

Default version : the shape functions are "replicated". If shape_functions returns the vector [λ₁; λ₂; λ₃], and if the FESpace is of size 2, then this default behaviour consists in returning the matrix [λ₁ 0; λ₂ 0; λ₃ 0; 0 λ₁; 0 λ₂; 0 λ₃].

source
diff --git a/previews/PR2/api/mapping/mapping/index.html b/previews/PR2/api/mapping/mapping/index.html index cb83b8a8..a089bb74 100644 --- a/previews/PR2/api/mapping/mapping/index.html +++ b/previews/PR2/api/mapping/mapping/index.html @@ -1,5 +1,5 @@ -Mapping · Bcube

Mapping

Mappings

Bcube.mappingMethod
mapping(nodes, ::AbstractEntityType, ξ)

Map the reference shape on the local shape.

Implementation

This function must be implemented for all shape.

source
Bcube.mappingMethod
mapping(nodes, ::Bar2_t, ξ)

Map the reference 2-nodes bar [-1,1] on the local bar:

$F(\xi) = \dfrac{x_r - x_l}{2} \xi + \dfrac{x_r + x_l}{2}$

source
Bcube.mappingMethod
mapping(nodes, ::Bar3_t, ξ)

Map the reference 3-nodes bar on the local bar (using Lagrange)

source
Bcube.mappingMethod
mapping(nodes, cshape::AbstractShape, ξ)

Returns the mapping of the an abstract shape (=ref element) to a target element defined by its nodes.

For instance, if cshape == Line, then the mapping is the same wether the input is the Shape or a Bar2_t. However if the cell is of type Bar3_t, it is still the Bar2_t mapping that is returned.

source
Bcube.mappingMethod
mapping(nodes, ::Hexa27_t, ξ)

Map the reference 8-nodes cube [-1,1] x [-1,1] x [-1,1] on the 27-hexa.

source
Bcube.mappingMethod
mapping(nodes, ::Penta6_t, ξ)

Map the reference 6-nodes prism [0,1] x [0,1] x [-1,1] on the 6-penta (prism).

source
Bcube.mappingMethod
mapping(nodes, ::Tri6_t, ξ)

Map the reference 6-nodes triangle [0,1] x [0,1] on the P2 curved-triangle.

$F(\xi) = \sum \lambda_i(\xi) x_i$ where $\lambda_i$ are the Lagrange P2 shape functions and $x_i$ are the local curved-triangle vertices' coordinates.

source
Bcube.mappingMethod
mapping(nodes, ::Hexa8_t, ξ)

Map the reference 8-nodes cube [-1,1] x [-1,1] x [-1,1] on the 8-hexa.

source
Bcube.mappingMethod
mapping(nodes, ::Quad4_t, ξ)

Map the reference 4-nodes square [-1,1] x [-1,1] on the 4-quadrilateral.

source
Bcube.mappingMethod
mapping(nodes, ::Quad9_t, ξ)

Map the reference 4-nodes square [-1,1] x [-1,1] on the P2 curved-quadrilateral.

$F(\xi) = \sum \lambda_i(\xi) x_i$ where $\lambda_i$ are the Lagrange P2 shape functions and $x_i$ are the local curved-quadrilateral vertices' coordinates.

source
Bcube.mappingMethod
mapping(nodes, ::Tri3_t, ξ)

Map the reference 3-nodes Triangle [0,1] x [0,1] on the local triangle.

\[F(\xi \\ \eta) = (1 - \xi - \eta) M_1 + x M_2 + y M_3\]

source
Bcube.mapping_det_jacobianMethod
mapping_det_jacobian(nodes, etype::AbstractEntityType, ξ)

Absolute value of the determinant of the mapping Jacobian matrix, expressed in the reference element.

Implementation

Default version using mapping_jacobian, but can be specified for each shape.

source
Bcube.mapping_det_jacobianMethod
mapping_det_jacobian(nodes, ::Bar2_t, ξ)

Absolute value of the determinant of the mapping Jacobian matrix for the reference 2-nodes bar [-1,1] to the local bar mapping.

$|det(J(\xi))| = \dfrac{|x_r - x_l|}{2}$

source
Bcube.mapping_det_jacobianMethod
mapping_det_jacobian(nodes, ::Tri3_t, ξ)

Absolute value of the determinant of the mapping Jacobian matrix for the the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.

$|J| = |(x_2 - x_1) (y_3 - y_1) - (x_3 - x_1) (y_2 - y_1)|$

source
Bcube.mapping_det_jacobianMethod
mapping_det_jacobian(nodes, ::Quad4_t, ξ)

Absolute value of the determinant of the mapping Jacobian matrix for the the reference square [-1,1] x [-1,1] to the 4-quadrilateral mapping.

source
Bcube.mapping_faceMethod
mapping_face(cshape::AbstractShape, side, permutation)

Build a mapping from the face reference element (corresponding to the side-th face of cshape) to the cell reference element (i.e the cshape), using a permutation of the face nodes.

source
Bcube.mapping_faceMethod
mapping_face(cshape::AbstractShape, side)

Build a mapping from the face reference element (corresponding to the side-th face of cshape) to the cell reference element (i.e the cshape).

Implementation

We could define this function as an alias to mapping_face(cshape, side, 1:nnodes(face_shapes(cshape, side)) but for performance issue, I prefer to keep two independant functions for now.

source
Bcube.mapping_invMethod
mapping_inv(nodes, ::AbstractEntityType, x)

Map the local shape on the reference shape.

Implementation

This function does not have to be implemented for all shape.

source
Bcube.mapping_invMethod
mapping_inv(nodes, ::Bar2_t, x)

Map the local bar on the reference 2-nodes bar [-1,1]:

$F^{-1}(x) = \dfrac{2x - x_r - x_l}{x_r - x_l}$

source
Bcube.mapping_invMethod
mapping_inv(nodes, ::Quad4_t, x)

Map the PARALLELOGRAM quadrilateral on the reference 4-nodes square [-1,1] x [-1,1]. Warning : this mapping is only corrects for parallelogram quadrilateral, not for any quadrilateral.


TODO: check this formulae with SYMPY

\[F^{-1} \begin{pmatrix} x \\ y \end{pmatrix} = +Mapping · Bcube

Mapping

Mappings

Bcube.mappingMethod
mapping(nodes, ::AbstractEntityType, ξ)

Map the reference shape on the local shape.

Implementation

This function must be implemented for all shape.

source
Bcube.mappingMethod
mapping(nodes, ::Bar2_t, ξ)

Map the reference 2-nodes bar [-1,1] on the local bar:

$F(\xi) = \dfrac{x_r - x_l}{2} \xi + \dfrac{x_r + x_l}{2}$

source
Bcube.mappingMethod
mapping(nodes, ::Bar3_t, ξ)

Map the reference 3-nodes bar on the local bar (using Lagrange)

source
Bcube.mappingMethod
mapping(nodes, cshape::AbstractShape, ξ)

Returns the mapping of the an abstract shape (=ref element) to a target element defined by its nodes.

For instance, if cshape == Line, then the mapping is the same wether the input is the Shape or a Bar2_t. However if the cell is of type Bar3_t, it is still the Bar2_t mapping that is returned.

source
Bcube.mappingMethod
mapping(nodes, ::Hexa27_t, ξ)

Map the reference 8-nodes cube [-1,1] x [-1,1] x [-1,1] on the 27-hexa.

source
Bcube.mappingMethod
mapping(nodes, ::Penta6_t, ξ)

Map the reference 6-nodes prism [0,1] x [0,1] x [-1,1] on the 6-penta (prism).

source
Bcube.mappingMethod
mapping(nodes, ::Tri6_t, ξ)

Map the reference 6-nodes triangle [0,1] x [0,1] on the P2 curved-triangle.

$F(\xi) = \sum \lambda_i(\xi) x_i$ where $\lambda_i$ are the Lagrange P2 shape functions and $x_i$ are the local curved-triangle vertices' coordinates.

source
Bcube.mappingMethod
mapping(nodes, ::Hexa8_t, ξ)

Map the reference 8-nodes cube [-1,1] x [-1,1] x [-1,1] on the 8-hexa.

source
Bcube.mappingMethod
mapping(nodes, ::Quad4_t, ξ)

Map the reference 4-nodes square [-1,1] x [-1,1] on the 4-quadrilateral.

source
Bcube.mappingMethod
mapping(nodes, ::Quad9_t, ξ)

Map the reference 4-nodes square [-1,1] x [-1,1] on the P2 curved-quadrilateral.

$F(\xi) = \sum \lambda_i(\xi) x_i$ where $\lambda_i$ are the Lagrange P2 shape functions and $x_i$ are the local curved-quadrilateral vertices' coordinates.

source
Bcube.mappingMethod
mapping(nodes, ::Tri3_t, ξ)

Map the reference 3-nodes Triangle [0,1] x [0,1] on the local triangle.

\[F(\xi \\ \eta) = (1 - \xi - \eta) M_1 + x M_2 + y M_3\]

source
Bcube.mapping_det_jacobianMethod
mapping_det_jacobian(nodes, etype::AbstractEntityType, ξ)

Absolute value of the determinant of the mapping Jacobian matrix, expressed in the reference element.

Implementation

Default version using mapping_jacobian, but can be specified for each shape.

source
Bcube.mapping_det_jacobianMethod
mapping_det_jacobian(nodes, ::Bar2_t, ξ)

Absolute value of the determinant of the mapping Jacobian matrix for the reference 2-nodes bar [-1,1] to the local bar mapping.

$|det(J(\xi))| = \dfrac{|x_r - x_l|}{2}$

source
Bcube.mapping_det_jacobianMethod
mapping_det_jacobian(nodes, ::Tri3_t, ξ)

Absolute value of the determinant of the mapping Jacobian matrix for the the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.

$|J| = |(x_2 - x_1) (y_3 - y_1) - (x_3 - x_1) (y_2 - y_1)|$

source
Bcube.mapping_det_jacobianMethod
mapping_det_jacobian(nodes, ::Quad4_t, ξ)

Absolute value of the determinant of the mapping Jacobian matrix for the the reference square [-1,1] x [-1,1] to the 4-quadrilateral mapping.

source
Bcube.mapping_faceMethod
mapping_face(cshape::AbstractShape, side, permutation)

Build a mapping from the face reference element (corresponding to the side-th face of cshape) to the cell reference element (i.e the cshape), using a permutation of the face nodes.

source
Bcube.mapping_faceMethod
mapping_face(cshape::AbstractShape, side)

Build a mapping from the face reference element (corresponding to the side-th face of cshape) to the cell reference element (i.e the cshape).

Implementation

We could define this function as an alias to mapping_face(cshape, side, 1:nnodes(face_shapes(cshape, side)) but for performance issue, I prefer to keep two independant functions for now.

source
Bcube.mapping_invMethod
mapping_inv(nodes, ::AbstractEntityType, x)

Map the local shape on the reference shape.

Implementation

This function does not have to be implemented for all shape.

source
Bcube.mapping_invMethod
mapping_inv(nodes, ::Bar2_t, x)

Map the local bar on the reference 2-nodes bar [-1,1]:

$F^{-1}(x) = \dfrac{2x - x_r - x_l}{x_r - x_l}$

source
Bcube.mapping_invMethod
mapping_inv(nodes, ::Quad4_t, x)

Map the PARALLELOGRAM quadrilateral on the reference 4-nodes square [-1,1] x [-1,1]. Warning : this mapping is only corrects for parallelogram quadrilateral, not for any quadrilateral.


TODO: check this formulae with SYMPY

\[F^{-1} \begin{pmatrix} x \\ y \end{pmatrix} = \begin{pmatrix} a_1 x + b_1 y + c_1 \\ a_2 x + b_2 y + c_2 @@ -10,23 +10,23 @@ a_2 & = \dfrac{-2 (y_1-y_2)}{\Delta} \\ b_2 & = \dfrac{2 (x_1 - x_2)}{\Delta} \\ c_2 & = -1 - a_2 x_1 - b_2 y_1 -\end{aligned}\]

where $\Delta = (x_1 - x_2)(y_3 - y_2) - (x_3 - x_2)(y_1 - y_2)$

source
Bcube.mapping_invMethod
mapping_inv(nodes, ::Tri3_t, x)

Map the local triangle on the reference 3-nodes Triangle [0,1] x [0,1].


TODO: check this formulae with SYMPY

\[F^{-1} \begin{pmatrix} x \\ y \end{pmatrix} = +\end{aligned}\]

where $\Delta = (x_1 - x_2)(y_3 - y_2) - (x_3 - x_2)(y_1 - y_2)$

source
Bcube.mapping_invMethod
mapping_inv(nodes, ::Tri3_t, x)

Map the local triangle on the reference 3-nodes Triangle [0,1] x [0,1].


TODO: check this formulae with SYMPY

\[F^{-1} \begin{pmatrix} x \\ y \end{pmatrix} = \frac{1}{x_1(y_2-y_3) + x_2(y_3-y_1) + x_3(y_1-y_2)} \begin{pmatrix} (y_3-y_1)x + (x_1 - x_3)y + (x_3 y_1 - x_1 y_3) \\ (y_1-y_2)x + (x_2 - x_1)x + (x_1 y_2 - x_2 y_1) -\end{pmatrix}\]

source
Bcube.mapping_inv_jacobianMethod
mapping_inv_jacobian(nodes, etype::AbstractEntityType, x)

Jacobian matrix of the inverse mapping : $\dfrac{\partial F_i^{-1}}{\partial x_j}$

Implementation

Default version using LinearAlgebra to inverse the matrix, but can be specified for each shape (if it exists).

source
Bcube.mapping_inv_jacobianMethod
mapping_inv_jacobian(nodes, ::Bar2_t, x)

Mapping's jacobian matrix for the local bar to the reference 2-nodes bar [-1, 1].

$\dfrac{\partial F^{-1}}{\partial x} = \dfrac{2}{x_r - x_l}$

source
Bcube.mapping_inv_jacobianMethod
mapping_inv_jacobian(nodes, ::Tri3_t, x)

Mapping's jacobian matrix for the local triangle to the reference 3-nodes Triangle [0,1] x [0,1] mapping.


TODO: check this formulae with SYMPY

\[\frac{\partial F_i^{-1}}{\partial x_j} = +\end{pmatrix}\]

source
Bcube.mapping_inv_jacobianMethod
mapping_inv_jacobian(nodes, etype::AbstractEntityType, x)

Jacobian matrix of the inverse mapping : $\dfrac{\partial F_i^{-1}}{\partial x_j}$

Implementation

Default version using LinearAlgebra to inverse the matrix, but can be specified for each shape (if it exists).

source
Bcube.mapping_inv_jacobianMethod
mapping_inv_jacobian(nodes, ::Bar2_t, x)

Mapping's jacobian matrix for the local bar to the reference 2-nodes bar [-1, 1].

$\dfrac{\partial F^{-1}}{\partial x} = \dfrac{2}{x_r - x_l}$

source
Bcube.mapping_inv_jacobianMethod
mapping_inv_jacobian(nodes, ::Tri3_t, x)

Mapping's jacobian matrix for the local triangle to the reference 3-nodes Triangle [0,1] x [0,1] mapping.


TODO: check this formulae with SYMPY

\[\frac{\partial F_i^{-1}}{\partial x_j} = \frac{1}{x_1 (y_2 - y_3) + x_2 (y_3 - y_1) + x_3 (y_1 - y_2)} \begin{pmatrix} y_3 - y_1 & x_1 - x_3 \\ y_1 - y_2 & x_2 - x_1 -\end{pmatrix}\]

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, etype::AbstractEntityType, ξ)

Jacobian matrix of the mapping : $\dfrac{\partial F_i}{\partial \xi_j}$.

Implementation

Default version using ForwardDiff, but can be specified for each shape.

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, ::Bar2_t, ξ)

Mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.

$\dfrac{\partial F}{\partial \xi} = \dfrac{x_r - x_l}{2}$

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, ::Bar3_t, ξ)

Mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.

``\dfrac{\partial F}{\partial \xi} = \frac{1}{2} \left( (2\xi - 1) M1 + (2\xi + 1)M2 - 4 \xi M_3\right)

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, ::Quad4_t, ξ)

Mapping's jacobian matrix for the reference square [-1,1] x [-1,1] to the 4-quadrilateral

\[\frac{\partial F}{\partial \xi} = -M_1 + M_2 + M_3 - M_4 + \eta (M_1 - M_2 + M_3 - M_4) -\frac{\partial F}{\partial \eta} = -M_1 - M_2 + M_3 + M_4 + \xi (M_1 - M_2 + M_3 - M_4)\]

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, ::Tri3_t, ξ)

Mapping's jacobian matrix for the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.

\[\dfrac{\partial F_i}{\partial \xi_j} = +\end{pmatrix}\]

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, etype::AbstractEntityType, ξ)

Jacobian matrix of the mapping : $\dfrac{\partial F_i}{\partial \xi_j}$.

Implementation

Default version using ForwardDiff, but can be specified for each shape.

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, ::Bar2_t, ξ)

Mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.

$\dfrac{\partial F}{\partial \xi} = \dfrac{x_r - x_l}{2}$

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, ::Bar3_t, ξ)

Mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.

``\dfrac{\partial F}{\partial \xi} = \frac{1}{2} \left( (2\xi - 1) M1 + (2\xi + 1)M2 - 4 \xi M_3\right)

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, ::Quad4_t, ξ)

Mapping's jacobian matrix for the reference square [-1,1] x [-1,1] to the 4-quadrilateral

\[\frac{\partial F}{\partial \xi} = -M_1 + M_2 + M_3 - M_4 + \eta (M_1 - M_2 + M_3 - M_4) +\frac{\partial F}{\partial \eta} = -M_1 - M_2 + M_3 + M_4 + \xi (M_1 - M_2 + M_3 - M_4)\]

source
Bcube.mapping_jacobianMethod
mapping_jacobian(nodes, ::Tri3_t, ξ)

Mapping's jacobian matrix for the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.

\[\dfrac{\partial F_i}{\partial \xi_j} = \begin{pmatrix} M_2 - M_1 & M_3 - M_1 -\end{pmatrix}\]

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian_inv(nodes, etype::AbstractEntityType, ξ)

Inverse of the mapping jacobian matrix. This is not exactly equivalent to the mapping_inv_jacobian since this function is evaluated in the reference element.

Implementation

Default version using ForwardDiff, but can be specified for each shape.

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian_inv(nodes, ::Bar2_t, ξ)

Inverse of mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.

$\dfrac{\partial F}{\partial \xi}^{-1} = \dfrac{2}{x_r - x_l}$

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian_inv(nodes, ::Bar3_t, ξ)

Inverse of mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.

$\dfrac{\partial F}{\partial \xi}^{-1} = \frac{2}{(2\xi - 1) M_1 + (2\xi + 1)M_2 - 4 \xi M_3}$

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian_inv(nodes, ::Tri3_t, ξ)

Inverse of mapping's jacobian matrix for the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.

\[\dfrac{\partial F_i}{\partial \xi_j}^{-1} = +\end{pmatrix}\]

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian_inv(nodes, etype::AbstractEntityType, ξ)

Inverse of the mapping jacobian matrix. This is not exactly equivalent to the mapping_inv_jacobian since this function is evaluated in the reference element.

Implementation

Default version using ForwardDiff, but can be specified for each shape.

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian_inv(nodes, ::Bar2_t, ξ)

Inverse of mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.

$\dfrac{\partial F}{\partial \xi}^{-1} = \dfrac{2}{x_r - x_l}$

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian_inv(nodes, ::Bar3_t, ξ)

Inverse of mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.

$\dfrac{\partial F}{\partial \xi}^{-1} = \frac{2}{(2\xi - 1) M_1 + (2\xi + 1)M_2 - 4 \xi M_3}$

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian_inv(nodes, ::Tri3_t, ξ)

Inverse of mapping's jacobian matrix for the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.

\[\dfrac{\partial F_i}{\partial \xi_j}^{-1} = \frac{1}{(x_1 - x_2)(y_1 - y_3) - (x_1 - x_3)(y_1 - y_2)} \begin{pmatrix} -y_1 + y_3 & x_1 - x_3 \\ y_1 - y_2 & -x_1 + x_2 -\end{pmatrix}\]

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian(nodes, ::Quad4_t, ξ)

Inverse of mapping's jacobian matrix for the reference square [-1,1] x [-1,1] to the 4-quadrilateral

source

Reference to local

+\end{pmatrix}\]

source
Bcube.mapping_jacobian_invMethod
mapping_jacobian(nodes, ::Quad4_t, ξ)

Inverse of mapping's jacobian matrix for the reference square [-1,1] x [-1,1] to the 4-quadrilateral

source

Reference to local

diff --git a/previews/PR2/api/mesh/gmsh_utils/index.html b/previews/PR2/api/mesh/gmsh_utils/index.html index df32d505..98dfeab0 100644 --- a/previews/PR2/api/mesh/gmsh_utils/index.html +++ b/previews/PR2/api/mesh/gmsh_utils/index.html @@ -1,2 +1,2 @@ -GMSH · Bcube

GMSH

Bcube._c2n_gmsh2cgnsMethod

Convert a cell->node connectivity with gmsh numbering convention to a cell->node connectivity with CGNs numbering convention.

source
Bcube._compute_space_dimMethod

Deduce the number of space dimensions from the mesh : if one (or more) dimension of the bounding box is way lower than the other dimensions, the number of space dimension is decreased.

Currently, having for instance (x,z) is not supported. Only (x), or (x,y), or (x,y,z).

source
Bcube._read_mshMethod
_read_msh(spaceDim::Int, verbose::Bool)

To use this function, the gmsh file must have been opened already (see read_msh(path::String) for instance).

The number of topological dimensions is given by the highest dimension found in the file. The number of space dimensions is deduced from the axis dimensions if spaceDim = 0. If spaceDim is set to a positive number, this number is used as the number of space dimensions.

Implementation

Global use of gmsh module. Do not try to improve this function by passing an argument such as gmsh or gmsh.model : it leads to problems.

source
Bcube.gen_cylinder_meshMethod
gen_cylinder_mesh(output, Lz; radius = 1., lc = 1e-1, order = 1, npartitions = 0, verbose = false)

Generate a 3D mesh of a cylindrical domain and length L and write the mesh to output.

source
Bcube.gen_disk_meshMethod
gen_disk_mesh(output; radius = 1., lc = 1e-1, order = 1, npartitions = 0, verbose = false)

Generate a 2D mesh of a disk domain and write the mesh to output.

source
Bcube.gen_hexa_meshMethod
gen_hexa_mesh(output, type; recombine = false, n = [2, 2, 2],  l = [1., 1., 1.], center = [0., 0., 0.], order = 1)

Generate a 3D mesh of a hexahedral domain and write the mesh to output. Use type to specify the element types: :tetra or :hexa.

Implementation

Notations from https://cgns.github.io/CGNSdocscurrent/sids/conv.html We could also use extrusion.

source
Bcube.gen_line_meshMethod
gen_line_mesh(output; nx = 2, lx = 1., xc = 0., order = 1)

Generate a 1D mesh of a segment and write to "output"

source
Bcube.gen_rectangle_meshMethod
gen_rectangle_mesh(output, type; recombine = false, nx = 2, ny = 2, lx = 1., ly = 1., xc = -1., yc = -1., order = 1)

Generate a 2D mesh of a rectangle domain and write the mesh to output. Use type to specify the element types: :tri or :quad.

source
Bcube.gen_rectangle_mesh_with_tri_and_quadMethod
gen_rectangle_mesh_with_tri_and_quad(output; nx = 2, ny = 2, lx = 1., ly = 1., xc = -1., yc = -1., order = 1)

Generate a 2D mesh of a rectangle domain and write the mesh to output. The domain is split vertically in two parts: the upper part is composed of 'quad' cells and the lower part with 'tri'. North D –––- C | :quad | West M₁|––––-|M₂ East | :tri | A –––- B South

source
Bcube.gen_star_disk_meshMethod
gen_star_disk_mesh(output, ε, m; nθ = 360, radius = 1., lc = 1e-1, order = 1, npartitions = 0, format22 = false, verbose = false)

Generate a 2D mesh of a star domain and write the mesh to output. The "star" wall is defined by $r_{wall} = R \left( 1 + \varepsilon \cos(m \theta) \right)$.

source
Bcube.nodes_gmsh2cgnsMethod
nodes_gmsh2cgns(entity::AbstractEntityType, nodes::AbstractArray)

Reorder nodes of a given entity from the Gmsh format to CGNS format

source
Bcube.read_mshFunction
read_msh(path::String, spaceDim::Int = 0; verbose::Bool = false)

Read a .msh file designated by its path.

See read_msh() for more details.

source
Bcube.read_msh_with_cell_namesFunction
read_msh_with_cell_names(path::String, spaceDim = 0; verbose = false)

Read a .msh file designated by its path and also return names and tags

source
+GMSH · Bcube

GMSH

Bcube._c2n_gmsh2cgnsMethod

Convert a cell->node connectivity with gmsh numbering convention to a cell->node connectivity with CGNs numbering convention.

source
Bcube._compute_space_dimMethod

Deduce the number of space dimensions from the mesh : if one (or more) dimension of the bounding box is way lower than the other dimensions, the number of space dimension is decreased.

Currently, having for instance (x,z) is not supported. Only (x), or (x,y), or (x,y,z).

source
Bcube._read_mshMethod
_read_msh(spaceDim::Int, verbose::Bool)

To use this function, the gmsh file must have been opened already (see read_msh(path::String) for instance).

The number of topological dimensions is given by the highest dimension found in the file. The number of space dimensions is deduced from the axis dimensions if spaceDim = 0. If spaceDim is set to a positive number, this number is used as the number of space dimensions.

Implementation

Global use of gmsh module. Do not try to improve this function by passing an argument such as gmsh or gmsh.model : it leads to problems.

source
Bcube.gen_cylinder_meshMethod
gen_cylinder_mesh(output, Lz; radius = 1., lc = 1e-1, order = 1, npartitions = 0, verbose = false)

Generate a 3D mesh of a cylindrical domain and length L and write the mesh to output.

source
Bcube.gen_disk_meshMethod
gen_disk_mesh(output; radius = 1., lc = 1e-1, order = 1, npartitions = 0, verbose = false)

Generate a 2D mesh of a disk domain and write the mesh to output.

source
Bcube.gen_hexa_meshMethod
gen_hexa_mesh(output, type; recombine = false, n = [2, 2, 2],  l = [1., 1., 1.], center = [0., 0., 0.], order = 1)

Generate a 3D mesh of a hexahedral domain and write the mesh to output. Use type to specify the element types: :tetra or :hexa.

Implementation

Notations from https://cgns.github.io/CGNSdocscurrent/sids/conv.html We could also use extrusion.

source
Bcube.gen_line_meshMethod
gen_line_mesh(output; nx = 2, lx = 1., xc = 0., order = 1)

Generate a 1D mesh of a segment and write to "output"

source
Bcube.gen_rectangle_meshMethod
gen_rectangle_mesh(output, type; recombine = false, nx = 2, ny = 2, lx = 1., ly = 1., xc = -1., yc = -1., order = 1)

Generate a 2D mesh of a rectangle domain and write the mesh to output. Use type to specify the element types: :tri or :quad.

source
Bcube.gen_rectangle_mesh_with_tri_and_quadMethod
gen_rectangle_mesh_with_tri_and_quad(output; nx = 2, ny = 2, lx = 1., ly = 1., xc = -1., yc = -1., order = 1)

Generate a 2D mesh of a rectangle domain and write the mesh to output. The domain is split vertically in two parts: the upper part is composed of 'quad' cells and the lower part with 'tri'. North D –––- C | :quad | West M₁|––––-|M₂ East | :tri | A –––- B South

source
Bcube.gen_star_disk_meshMethod
gen_star_disk_mesh(output, ε, m; nθ = 360, radius = 1., lc = 1e-1, order = 1, npartitions = 0, format22 = false, verbose = false)

Generate a 2D mesh of a star domain and write the mesh to output. The "star" wall is defined by $r_{wall} = R \left( 1 + \varepsilon \cos(m \theta) \right)$.

source
Bcube.nodes_gmsh2cgnsMethod
nodes_gmsh2cgns(entity::AbstractEntityType, nodes::AbstractArray)

Reorder nodes of a given entity from the Gmsh format to CGNS format

source
Bcube.read_mshFunction
read_msh(path::String, spaceDim::Int = 0; verbose::Bool = false)

Read a .msh file designated by its path.

See read_msh() for more details.

source
Bcube.read_msh_with_cell_namesFunction
read_msh_with_cell_names(path::String, spaceDim = 0; verbose = false)

Read a .msh file designated by its path and also return names and tags

source
diff --git a/previews/PR2/api/mesh/mesh/index.html b/previews/PR2/api/mesh/mesh/index.html index cb03dc09..68e4f157 100644 --- a/previews/PR2/api/mesh/mesh/index.html +++ b/previews/PR2/api/mesh/mesh/index.html @@ -1,10 +1,10 @@ -Mesh · Bcube

Mesh

Entity

Bcube.topology_styleMethod
topology_style(spaceDim::Int, topoDim::Int)

Indicate the TopologyStyle of an entity of topology topoDim living in space of dimension spaceDim.

source

Connectivity

Bcube.inverse_connectivityMethod
inverse_connectivity(c::Connectivity{T}) where {T}

Returns the "inverse" of the connectivity 'c' and the corresponding 'keys'. 'keys' are provided because indices in 'c' could be sparse in the general case.

Example

mesh = basic_mesh()
+Mesh · Bcube

Mesh

Entity

Bcube.topology_styleMethod
topology_style(spaceDim::Int, topoDim::Int)

Indicate the TopologyStyle of an entity of topology topoDim living in space of dimension spaceDim.

source

Connectivity

Bcube.inverse_connectivityMethod
inverse_connectivity(c::Connectivity{T}) where {T}

Returns the "inverse" of the connectivity 'c' and the corresponding 'keys'. 'keys' are provided because indices in 'c' could be sparse in the general case.

Example

mesh = basic_mesh()
 c2n = connectivities_indices(mesh,:c2n)
-n2c, keys = inverse_connectivity(c2n)

Here, 'n2c' is the node->cell graph of connectivity and, 'n2c[i]' contains the indices of the cells connected to the node of index 'keys[i]'. If 'c2n' is dense, 'keys' is not necessary (because keys[i]==i, ∀i)

source

Mesh

Bcube.AbstractMeshType

Implementation

All subtypes should implement the following functions:

  • Base.parent(AbstractMesh) (default should be Base.parent(m::MyMesh) = m)
source
Bcube.MeshType

bc_names : <boundary tag> => <boundary names> bc_nodes : <boundary tag> => <boundary nodes tags> bc_faces : <boundary tag> => <boundary faces tags>

source
Bcube.oriented_cell_sideMethod
oriented_cell_side(mesh::Mesh,icell::Int,iface::Int)

Return the side number to which the face 'iface' belongs in the cell 'icell' of the mesh. A negative side number is returned if the face is inverted. Returns '0' if the face does not belongs the cell.

source

Domain

Bcube.AbstractDomainType

An AbstractDomain designates any set of entities from a mesh. For instance a set of cells, a set of faces etc.

source
Bcube.BoundaryFaceDomainMethod
BoundaryFaceDomain(mesh)
+n2c, keys = inverse_connectivity(c2n)

Here, 'n2c' is the node->cell graph of connectivity and, 'n2c[i]' contains the indices of the cells connected to the node of index 'keys[i]'. If 'c2n' is dense, 'keys' is not necessary (because keys[i]==i, ∀i)

source

Mesh

Bcube.AbstractMeshType

Implementation

All subtypes should implement the following functions:

  • Base.parent(AbstractMesh) (default should be Base.parent(m::MyMesh) = m)
source
Bcube.MeshType

bc_names : <boundary tag> => <boundary names> bc_nodes : <boundary tag> => <boundary nodes tags> bc_faces : <boundary tag> => <boundary faces tags>

source
Bcube.oriented_cell_sideMethod
oriented_cell_side(mesh::Mesh,icell::Int,iface::Int)

Return the side number to which the face 'iface' belongs in the cell 'icell' of the mesh. A negative side number is returned if the face is inverted. Returns '0' if the face does not belongs the cell.

source

Domain

Bcube.AbstractDomainType

An AbstractDomain designates any set of entities from a mesh. For instance a set of cells, a set of faces etc.

source
Bcube.BoundaryFaceDomainMethod
BoundaryFaceDomain(mesh)
 BoundaryFaceDomain(mesh, label::String)
-BoundaryFaceDomain(mesh, labels::Tuple{String, Vararg{String}})

Build a BoundaryFaceDomain corresponding to the boundaries designated by one or several labels (=names).

If no label is provided, all the BoundaryFaceDomain corresponds to all the boundary faces.

source
Bcube.CellDomainType

A CellDomain is a representation of the cells of a mesh. It's primary purpose is to represent a domain to integrate over.

Examples

julia> mesh = rectangle_mesh(10, 10)
+BoundaryFaceDomain(mesh, labels::Tuple{String, Vararg{String}})

Build a BoundaryFaceDomain corresponding to the boundaries designated by one or several labels (=names).

If no label is provided, all the BoundaryFaceDomain corresponds to all the boundary faces.

source
Bcube.CellDomainType

A CellDomain is a representation of the cells of a mesh. It's primary purpose is to represent a domain to integrate over.

Examples

julia> mesh = rectangle_mesh(10, 10)
 julia> Ω_all = CellDomain(mesh)
 julia> selectedCells = [1,3,5,6]
-julia> Ω_selected = CellDomain(mesh, selectedCells)
source
Bcube.CellInfoMethod
CellInfo(mesh, icell)

DEBUG constructor for icell-th cell of mesh. For performance issues, don't use this version in production.

source
Bcube.FaceInfoType
FaceInfo{CN<:CellInfo,CP<:CellInfo,FT,FN,F2N}

Type describing a face as the common side of two adjacent cells. CellInfo of cells from both sides is stored with the local side index of the face relative to each adjacent cell.

Remark:

  • For boundary face with no periodic condition, positive cell side info

are duplicate from the negative ones.

  • For performance reason (type stability), nodes and type of the face

is stored explicitely in FaceInfo even if it could have been computed by collecting info from the side of the negative or positive cells.

source
Bcube.FaceInfoMethod

DEBUG FaceInfo constructor for kface-th cell of mesh. For performance issues, don't use this version in production.

source
+julia> Ω_selected = CellDomain(mesh, selectedCells)
source
Bcube.CellInfoMethod
CellInfo(mesh, icell)

DEBUG constructor for icell-th cell of mesh. For performance issues, don't use this version in production.

source
Bcube.FaceInfoType
FaceInfo{CN<:CellInfo,CP<:CellInfo,FT,FN,F2N}

Type describing a face as the common side of two adjacent cells. CellInfo of cells from both sides is stored with the local side index of the face relative to each adjacent cell.

Remark:

  • For boundary face with no periodic condition, positive cell side info

are duplicate from the negative ones.

  • For performance reason (type stability), nodes and type of the face

is stored explicitely in FaceInfo even if it could have been computed by collecting info from the side of the negative or positive cells.

source
Bcube.FaceInfoMethod

DEBUG FaceInfo constructor for kface-th cell of mesh. For performance issues, don't use this version in production.

source
diff --git a/previews/PR2/api/mesh/mesh_generator/index.html b/previews/PR2/api/mesh/mesh_generator/index.html index 77b3f748..8688d726 100644 --- a/previews/PR2/api/mesh/mesh_generator/index.html +++ b/previews/PR2/api/mesh/mesh_generator/index.html @@ -1,6 +1,6 @@ -Mesh generator · Bcube

Mesh generator

Bcube.basic_meshMethod
basic_mesh()

Generate a toy mesh of two quads and one triangle.

v1 v2 v3 v4 +–-e1–>+–-e5–>+–-e8–>+ ^ | | c3 / e4 c1 e2 c2 e6 e9 | | | / +<–e3–-+<–e7–-+/ v5 v6 v7

source
Bcube.circle_meshMethod
circle_mesh(n; r = 1, order = 1)

Mesh a circle (in 2D) with n nodes on the circumference.

source
Bcube.line_meshMethod
line_mesh(n; xmin = 0., xmax = 1., order = 1, names = ("LEFT", "RIGHT"))

Generate a mesh of a line of n vertices.

Example

julia> mesh = line_mesh(5)
source
Bcube.ncube_meshMethod
ncube_mesh(n::Vector{Int}; order = 1)

Generate either a line mesh, a rectangle mesh, a cubic mesh... depending on the dimension of n.

Argument

  • n number of vertices in each spatial directions

Example

mesh_of_a_line   = ncube_mesh([10])
-mesh_of_a_square = ncube_mesh([4, 5])
source
Bcube.one_cell_meshMethod
one_cell_mesh(type::Symbol, order = 1)

Generate a mesh of one cell. type can be :line, :quad, :tri or :hexa.

The argument order refers to the geometry order. It has the same effect as the -order parameter in gmsh.

source
Bcube.rectangle_meshMethod
rectangle_mesh(
+Mesh generator · Bcube

Mesh generator

Bcube.basic_meshMethod
basic_mesh()

Generate a toy mesh of two quads and one triangle.

v1 v2 v3 v4 +–-e1–>+–-e5–>+–-e8–>+ ^ | | c3 / e4 c1 e2 c2 e6 e9 | | | / +<–e3–-+<–e7–-+/ v5 v6 v7

source
Bcube.circle_meshMethod
circle_mesh(n; r = 1, order = 1)

Mesh a circle (in 2D) with n nodes on the circumference.

source
Bcube.line_meshMethod
line_mesh(n; xmin = 0., xmax = 1., order = 1, names = ("LEFT", "RIGHT"))

Generate a mesh of a line of n vertices.

Example

julia> mesh = line_mesh(5)
source
Bcube.ncube_meshMethod
ncube_mesh(n::Vector{Int}; order = 1)

Generate either a line mesh, a rectangle mesh, a cubic mesh... depending on the dimension of n.

Argument

  • n number of vertices in each spatial directions

Example

mesh_of_a_line   = ncube_mesh([10])
+mesh_of_a_square = ncube_mesh([4, 5])
source
Bcube.one_cell_meshMethod
one_cell_mesh(type::Symbol, order = 1)

Generate a mesh of one cell. type can be :line, :quad, :tri or :hexa.

The argument order refers to the geometry order. It has the same effect as the -order parameter in gmsh.

source
Bcube.rectangle_meshMethod
rectangle_mesh(
     nx,
     ny;
     type = :quad,
@@ -10,4 +10,4 @@
     ymax = 1.0,
     order = 1,
     bnd_names = ("north", "south", "east", "west"),
-)

Generate a 2D mesh of a rectangle with nx and ny vertices in the x and y directions respectively.

Example

julia> mesh = rectangle_mesh(5, 4)
source
Bcube.scaleMethod
scale(mesh, factor)

Scale the input mesh nodes coordinates by a given factor and return the resulted mesh. The factor can be a number or a vector.

Usefull for debugging.

source
Bcube.transformMethod
transform(mesh::AbstractMesh, fun)

Transform the input mesh nodes coordinates by applying the given fun function and return the resulted mesh.

Usefull for debugging.

source
Bcube.translateMethod
translate(mesh::AbstractMesh, t::Vector{Float64})

Translate the input mesh with vector t.

Usefull for debugging.

source
+)

Generate a 2D mesh of a rectangle with nx and ny vertices in the x and y directions respectively.

Example

julia> mesh = rectangle_mesh(5, 4)
source
Bcube.scaleMethod
scale(mesh, factor)

Scale the input mesh nodes coordinates by a given factor and return the resulted mesh. The factor can be a number or a vector.

Usefull for debugging.

source
Bcube.transformMethod
transform(mesh::AbstractMesh, fun)

Transform the input mesh nodes coordinates by applying the given fun function and return the resulted mesh.

Usefull for debugging.

source
Bcube.translateMethod
translate(mesh::AbstractMesh, t::Vector{Float64})

Translate the input mesh with vector t.

Usefull for debugging.

source
diff --git a/previews/PR2/api/operator/operator/index.html b/previews/PR2/api/operator/operator/index.html index a9c66cff..a5f2bcd8 100644 --- a/previews/PR2/api/operator/operator/index.html +++ b/previews/PR2/api/operator/operator/index.html @@ -1,2 +1,2 @@ -Operators · Bcube
+Operators · Bcube
diff --git a/previews/PR2/api/output/vtk/index.html b/previews/PR2/api/output/vtk/index.html index a5288da2..b525f636 100644 --- a/previews/PR2/api/output/vtk/index.html +++ b/previews/PR2/api/output/vtk/index.html @@ -1,17 +1,17 @@ -VTK · Bcube

VTK

Bcube._point_index_from_IJKMethod

Return the node numbering of the node designated by its position in the x and y direction.

See https://www.kitware.com/modeling-arbitrary-order-lagrange-finite-elements-in-the-visualization-toolkit/.

source
Bcube.vtk_entityMethod
vtk_entity(t::AbstractEntityType)

Convert an AbstractEntityType into a VTKCellType. To find the correspondance, browse the WriteVTK package AND check the Doxygen (for numbering) : https://vtk.org/doc/nightly/html/classvtkTriQuadraticHexahedron.html

source
Bcube.write_vtkMethod
write_vtk(basename::String, it::Int,time::Real, mesh::AbstractMesh{topoDim,spaceDim}, vars::Dict{String,Tuple{V,L}}; append=false) where{topoDim,spaceDim,V,L<:WriteVTK.AbstractFieldData}

Write a set of variables on the mesh nodes or cell centers to a VTK file.

Example

mesh = basic_mesh()
+VTK · Bcube

VTK

Bcube._point_index_from_IJKMethod

Return the node numbering of the node designated by its position in the x and y direction.

See https://www.kitware.com/modeling-arbitrary-order-lagrange-finite-elements-in-the-visualization-toolkit/.

source
Bcube.vtk_entityMethod
vtk_entity(t::AbstractEntityType)

Convert an AbstractEntityType into a VTKCellType. To find the correspondance, browse the WriteVTK package AND check the Doxygen (for numbering) : https://vtk.org/doc/nightly/html/classvtkTriQuadraticHexahedron.html

source
Bcube.write_vtkMethod
write_vtk(basename::String, it::Int,time::Real, mesh::AbstractMesh{topoDim,spaceDim}, vars::Dict{String,Tuple{V,L}}; append=false) where{topoDim,spaceDim,V,L<:WriteVTK.AbstractFieldData}

Write a set of variables on the mesh nodes or cell centers to a VTK file.

Example

mesh = basic_mesh()
 u = rand(ncells(mesh))
 v = rand(nnodes(mesh))
 dict_vars = Dict( "u" => (u, VTKCellData()),  "v" => (v, VTKPointData()) )
-write_vtk("output", 0, 0.0, mesh, dict_vars)
source
Bcube.write_vtkMethod

write_vtk(basename::String, mesh::AbstractMesh{topoDim,spaceDim}) where{topoDim,spaceDim}

Write the mesh to a VTK file.

Example

write_vtk("output", basic_mesh())
source
Bcube.write_vtk_discontinuousMethod

VTK writer for a set of discontinuous functions. vars is a dictionnary of variable name => (values, values_location)

where values is an array of numbers.

source
Bcube.write_vtkMethod

write_vtk(basename::String, mesh::AbstractMesh{topoDim,spaceDim}) where{topoDim,spaceDim}

Write the mesh to a VTK file.

Example

write_vtk("output", basic_mesh())
source
Bcube.write_vtk_discontinuousMethod

VTK writer for a set of discontinuous functions. vars is a dictionnary of variable name => (values, values_location)

where values is an array of numbers.

source
Bcube.write_vtk_lagrangeMethod
write_vtk_lagrange(
     basename::String,
     vars::Dict{String, F},
     mesh::AbstractMesh,
     U_export::AbstractFESpace,
-    it::Int = 0,
+    it::Integer = -1,
     time::Real = 0.0;
-    append = false,
-    ascii = false,
+    collection_append = false,
+    vtk_kwargs...,
 ) where {F <: AbstractLazy}

Write the provided FEFunction on the mesh with the precision of the Lagrange FESpace provided.

vars is a dictionnary of variable name => FEFunction to write.

Example

mesh = rectangle_mesh(6, 7; xmin = -1, xmax = 1.0, ymin = -1, ymax = 1.0)
 u = FEFunction(TrialFESpace(FunctionSpace(:Lagrange, 4), mesh))
 projection_l2!(u, PhysicalFunction(x -> x[1]^2 + x[2]^2), mesh)
@@ -26,4 +26,4 @@
         mesh,
         U_export,
     )
-end

Dev notes

  • ascii does not seem to work in WriteVTK
  • remove (once fully validated) : write_vtk_discontinuous
source
+end

Dev notes

  • in order to write an ASCII file, you must pass both ascii = true and append = false
  • collection_append is not named append to enable passing correct kwargs to vtk_grid
  • remove (once fully validated) : write_vtk_discontinuous
source
diff --git a/previews/PR2/example/covo/index.html b/previews/PR2/example/covo/index.html index d7dc2c1d..83bdf2ed 100644 --- a/previews/PR2/example/covo/index.html +++ b/previews/PR2/example/covo/index.html @@ -423,4 +423,4 @@ run_covo() end -end #hide +end #hide diff --git a/previews/PR2/example/euler_naca_steady/index.html b/previews/PR2/example/euler_naca_steady/index.html index e8755052..64656664 100644 --- a/previews/PR2/example/euler_naca_steady/index.html +++ b/previews/PR2/example/euler_naca_steady/index.html @@ -724,4 +724,4 @@ main(stateInit, stateBcFarfield, degreemax) -end #hide +end #hide diff --git a/previews/PR2/example/linear_elasticity/index.html b/previews/PR2/example/linear_elasticity/index.html index 31fc2ab0..76a08b35 100644 --- a/previews/PR2/example/linear_elasticity/index.html +++ b/previews/PR2/example/linear_elasticity/index.html @@ -186,4 +186,4 @@ #run_steady() run_unsteady() -end #hide +end #hide diff --git a/previews/PR2/example/linear_thermoelasticity/index.html b/previews/PR2/example/linear_thermoelasticity/index.html index a83f7e92..aa267181 100644 --- a/previews/PR2/example/linear_thermoelasticity/index.html +++ b/previews/PR2/example/linear_thermoelasticity/index.html @@ -222,4 +222,4 @@ # <img src="../assets/thermo_elasticity.gif" alt="drawing" width="500"/> # ``` -end #hide +end #hide diff --git a/previews/PR2/howto/howto/index.html b/previews/PR2/howto/howto/index.html index d341dd63..d45beeb2 100644 --- a/previews/PR2/howto/howto/index.html +++ b/previews/PR2/howto/howto/index.html @@ -34,4 +34,4 @@ using PkgBenchmark import Bcube results = benchmarkpkg(Bcube, BenchmarkConfig(; env = Dict("JULIA_NUM_THREADS" => "1")); resultfile = joinpath(@__DIR__, "result.json")) -export_markdown("results.md", results)

This will create the markdown file results.md with the results.

+export_markdown("results.md", results)

This will create the markdown file results.md with the results.

diff --git a/previews/PR2/index.html b/previews/PR2/index.html index baaf1665..364040e6 100644 --- a/previews/PR2/index.html +++ b/previews/PR2/index.html @@ -1,2 +1,2 @@ -Home · Bcube

Bcube

Purpose of Bcube

Bcube is a Julia library providing tools for the spatial discretization of partial differential equation(s) (PDE). The main objectives are:

  • to provide a set of tools to quickly assemble an algorithm solving partial differential equation(s) (so the main objective is to help building prototypes without thinking about the numerical core)
  • to be completed : efficient/performant PDE resolution?

This documentation is organised as follow. Checkout the tutorials to see what Bcube is capable of and/or quickly learn how to use it. Then, some more elaborated examples are provided to demonstrate the library capabilities. The "Manual" part explains how the core is organized. Finally, the "API" section is the low level code documentation.

Writing documentation

To write documentation for Bcube, Julia's guidelines should be followed : https://docs.julialang.org/en/v1/manual/documentation/. Moreover, this project tries to apply the SciML Style Guide.

Conventions

This documentation follows the following notation or naming conventions:

  • coordinates inside a reference frame are noted $\hat{x}, \hat{y}$ or $\xi, \eta$ while coordinates in the physical frame are noted $x,y$
  • when talking about a mapping, $F$ or sometimes $F_{rp}$ designates the mapping from the reference element to the physical element. On the other side, $F^{-1}$ or sometimes $F_{pr}$ designates the physical element to the reference element mapping.
  • "dof" means "degree of freedom"
+Home · Bcube

Bcube

Purpose of Bcube

Bcube is a Julia library providing tools for the spatial discretization of partial differential equation(s) (PDE). The main objectives are:

  • to provide a set of tools to quickly assemble an algorithm solving partial differential equation(s) (so the main objective is to help building prototypes without thinking about the numerical core)
  • to be completed : efficient/performant PDE resolution?

This documentation is organised as follow. Checkout the tutorials to see what Bcube is capable of and/or quickly learn how to use it. Then, some more elaborated examples are provided to demonstrate the library capabilities. The "Manual" part explains how the core is organized. Finally, the "API" section is the low level code documentation.

Writing documentation

To write documentation for Bcube, Julia's guidelines should be followed : https://docs.julialang.org/en/v1/manual/documentation/. Moreover, this project tries to apply the SciML Style Guide.

Conventions

This documentation follows the following notation or naming conventions:

  • coordinates inside a reference frame are noted $\hat{x}, \hat{y}$ or $\xi, \eta$ while coordinates in the physical frame are noted $x,y$
  • when talking about a mapping, $F$ or sometimes $F_{rp}$ designates the mapping from the reference element to the physical element. On the other side, $F^{-1}$ or sometimes $F_{pr}$ designates the physical element to the reference element mapping.
  • "dof" means "degree of freedom"
diff --git a/previews/PR2/manual/cellfunction/index.html b/previews/PR2/manual/cellfunction/index.html index 4bf9e818..25342a43 100644 --- a/previews/PR2/manual/cellfunction/index.html +++ b/previews/PR2/manual/cellfunction/index.html @@ -1,2 +1,2 @@ -Cell function · Bcube

Cell function

As explained earlier, at least two coordinates systems exist in Bcube : the "reference" coordinates (ReferenceDomain) and the "physical" coordinates (PhysicalDomain). The evaluation of a function on a point in a cell depends on the way this point has been defined. Hence the definition of CellPoints that embed the coordinate system. Given a CellPoint (or eventually a FacePoint), an AbstractCellFunction will be evaluated and the mapping between the ReferenceDomain to the PhysicalDomain (or reciprocally) will be performed internally if necessary : if an AbstractCellFunction defined in terms of reference coordinates is applied on a CellPoint expressed in the reference coordinates system, no mapping is needed.

+Cell function · Bcube

Cell function

As explained earlier, at least two coordinates systems exist in Bcube : the "reference" coordinates (ReferenceDomain) and the "physical" coordinates (PhysicalDomain). The evaluation of a function on a point in a cell depends on the way this point has been defined. Hence the definition of CellPoints that embed the coordinate system. Given a CellPoint (or eventually a FacePoint), an AbstractCellFunction will be evaluated and the mapping between the ReferenceDomain to the PhysicalDomain (or reciprocally) will be performed internally if necessary : if an AbstractCellFunction defined in terms of reference coordinates is applied on a CellPoint expressed in the reference coordinates system, no mapping is needed.

diff --git a/previews/PR2/manual/function_space/index.html b/previews/PR2/manual/function_space/index.html index e8a87484..6506943f 100644 --- a/previews/PR2/manual/function_space/index.html +++ b/previews/PR2/manual/function_space/index.html @@ -1,2 +1,2 @@ -Function and FE spaces · Bcube

Function and FE spaces

AbstractFunctionSpace

In Bcube, a FunctionSpace is defined by a type (nodal Lagrange polynomials, modal Taylor expansion, etc) and a degree. For each implemented FunctionSpace, a list of shape functions is associated on a given Shape. For instance, one can get the shape functions associated to the Lagrange polynomials or order 3 on a Square. Note that for "tensor" elements such as Line, Square or Cube; the Lagrange polynomials are available at any order; being computed symbolically.

AbstractFESpace

Then, an FESpace (more precisely SingleFESpace) is a function space associated to a numbering of the degrees of freedom. Note that the numbering may depend on the continuous or discontinuous feature of the space. Hence a SingleFESpace takes basically four input to be built : a FunctionSpace, the number of components of this space (scalar or vector), an indicator of the continuous/discontinuous characteristic, and the mesh. The dof numbering is built by combining the mesh numberings (nodes, cells, faces) and the function space. Note that the degree of the FunctionSpace can differ from the "degree" of the mesh elements : it is possible to build a SingleFESpace with P2 polynomials on a mesh only containing straight lines (defined by only two nodes, Bar2_t). Optionaly, a SingleFESpace can also contain the tags of the boundaries where Dirichlet condition(s) applies. A MultiFESpace is simply a set of SingleFESpace, eventually of different natures. Its befenit is that it allows to build a "global" numbering of all the dofs represented by this space. This is especially convenient to solve systems of equations.

AbstractFEFunction

With a SingleFESpace, one can build the representation of a function discretized on this space: a FEFunction. This structure stores a vector of values, one for each degree of freedom of the finite element space. To set or get the values of a FEFunction, the functions set_dof_values! and get_dof_values are available respectively. A FEFunction can be projected on another FESpace; or evaluated at some specific mesh location (a coordinates, all the nodes, all the mesh centers, etc).

+Function and FE spaces · Bcube

Function and FE spaces

AbstractFunctionSpace

In Bcube, a FunctionSpace is defined by a type (nodal Lagrange polynomials, modal Taylor expansion, etc) and a degree. For each implemented FunctionSpace, a list of shape functions is associated on a given Shape. For instance, one can get the shape functions associated to the Lagrange polynomials or order 3 on a Square. Note that for "tensor" elements such as Line, Square or Cube; the Lagrange polynomials are available at any order; being computed symbolically.

AbstractFESpace

Then, an FESpace (more precisely SingleFESpace) is a function space associated to a numbering of the degrees of freedom. Note that the numbering may depend on the continuous or discontinuous feature of the space. Hence a SingleFESpace takes basically four input to be built : a FunctionSpace, the number of components of this space (scalar or vector), an indicator of the continuous/discontinuous characteristic, and the mesh. The dof numbering is built by combining the mesh numberings (nodes, cells, faces) and the function space. Note that the degree of the FunctionSpace can differ from the "degree" of the mesh elements : it is possible to build a SingleFESpace with P2 polynomials on a mesh only containing straight lines (defined by only two nodes, Bar2_t). Optionaly, a SingleFESpace can also contain the tags of the boundaries where Dirichlet condition(s) applies. A MultiFESpace is simply a set of SingleFESpace, eventually of different natures. Its befenit is that it allows to build a "global" numbering of all the dofs represented by this space. This is especially convenient to solve systems of equations.

AbstractFEFunction

With a SingleFESpace, one can build the representation of a function discretized on this space: a FEFunction. This structure stores a vector of values, one for each degree of freedom of the finite element space. To set or get the values of a FEFunction, the functions set_dof_values! and get_dof_values are available respectively. A FEFunction can be projected on another FESpace; or evaluated at some specific mesh location (a coordinates, all the nodes, all the mesh centers, etc).

diff --git a/previews/PR2/manual/geometry/index.html b/previews/PR2/manual/geometry/index.html index d61c9028..e07cb941 100644 --- a/previews/PR2/manual/geometry/index.html +++ b/previews/PR2/manual/geometry/index.html @@ -1,2 +1,2 @@ -Geometry and mesh · Bcube

Geometry and mesh

A Mesh is a set basically of nodes (Node), a set of entities (the mesh elements) and a list of connectivies that link the entities between themselves and with the nodes.

In Bcube every mesh entity has corresponding reference Shape, a simplified or canonical representation of this element. A 1D line is mapped on the [-1,1] segment, and a rectangle is mapped on a square for instance. On these reference shapes, (almost) everything is known : the vertices location, the area, the quadrature points... Hence in Bcube we always compute things in the reference shape. For "Lagrange" elements (such as Bar*_t, Tri*_t, Quad*_t, Tetra*_t, Hexa*_t, Penta*_t etc), the mapping from the reference shape to a geometrical element is directly obtained from the corresponding Lagrange polynomials and the element node coordinates. Given a geometrical element with n nodes M_i, the mapping reads:

\[F(\xi) = \sum_{i=1}^n \hat{\lambda}_i(\xi)M_i\]

where $(\lambda)_i$ are the Lagrange polynomials whose order matches the element order.

+Geometry and mesh · Bcube

Geometry and mesh

A Mesh is a set basically of nodes (Node), a set of entities (the mesh elements) and a list of connectivies that link the entities between themselves and with the nodes.

In Bcube every mesh entity has corresponding reference Shape, a simplified or canonical representation of this element. A 1D line is mapped on the [-1,1] segment, and a rectangle is mapped on a square for instance. On these reference shapes, (almost) everything is known : the vertices location, the area, the quadrature points... Hence in Bcube we always compute things in the reference shape. For "Lagrange" elements (such as Bar*_t, Tri*_t, Quad*_t, Tetra*_t, Hexa*_t, Penta*_t etc), the mapping from the reference shape to a geometrical element is directly obtained from the corresponding Lagrange polynomials and the element node coordinates. Given a geometrical element with n nodes M_i, the mapping reads:

\[F(\xi) = \sum_{i=1}^n \hat{\lambda}_i(\xi)M_i\]

where $(\lambda)_i$ are the Lagrange polynomials whose order matches the element order.

diff --git a/previews/PR2/manual/integration/index.html b/previews/PR2/manual/integration/index.html index 73ba1608..5485a300 100644 --- a/previews/PR2/manual/integration/index.html +++ b/previews/PR2/manual/integration/index.html @@ -1,2 +1,2 @@ -Integration · Bcube

Integration

To compute an integral on a geometrical element, for instance a curved element, a variable substitution is used to compute the integral on the corresponding reference Shape. This variable substitution reads:

\[\int_\Omega g(x) \mathrm{\,d} \Omega = \int_{\hat{\Omega}} |J(x)| \left(g \circ F \right)(\hat{x}) \mathrm{\,d} \hat{\Omega},\]

where we recall that $F$ is the reference to physical mapping and $J$ is the determinant of the jacobian matrix of this mapping. Depending on the shape and element order, this determinant is either hard-coded or computed with ForwardDiff.

Now, to compute the right side, i.e the integral on the reference shape, quadrature rules are applied:

\[\int_{\hat{\Omega}} g(\hat{x}) \mathrm{\,d} \hat{\Omega} = \sum_{i =1}^{N_q} \omega_i g(\hat{x}_i)\]

A specific procedure is applied to compute integrals on a face of a cell (i.e a surfacic integral on a face of a volumic element).

+Integration · Bcube

Integration

To compute an integral on a geometrical element, for instance a curved element, a variable substitution is used to compute the integral on the corresponding reference Shape. This variable substitution reads:

\[\int_\Omega g(x) \mathrm{\,d} \Omega = \int_{\hat{\Omega}} |J(x)| \left(g \circ F \right)(\hat{x}) \mathrm{\,d} \hat{\Omega},\]

where we recall that $F$ is the reference to physical mapping and $J$ is the determinant of the jacobian matrix of this mapping. Depending on the shape and element order, this determinant is either hard-coded or computed with ForwardDiff.

Now, to compute the right side, i.e the integral on the reference shape, quadrature rules are applied:

\[\int_{\hat{\Omega}} g(\hat{x}) \mathrm{\,d} \hat{\Omega} = \sum_{i =1}^{N_q} \omega_i g(\hat{x}_i)\]

A specific procedure is applied to compute integrals on a face of a cell (i.e a surfacic integral on a face of a volumic element).

diff --git a/previews/PR2/manual/operator/index.html b/previews/PR2/manual/operator/index.html index 3fd02f38..3ecb42b9 100644 --- a/previews/PR2/manual/operator/index.html +++ b/previews/PR2/manual/operator/index.html @@ -1,2 +1,2 @@ -LazyOperators · Bcube
+LazyOperators · Bcube
diff --git a/previews/PR2/search_index.js b/previews/PR2/search_index.js index a5c3a7fb..3d34d891 100644 --- a/previews/PR2/search_index.js +++ b/previews/PR2/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"api/operator/operator/#Operators","page":"Operators","title":"Operators","text":"","category":"section"},{"location":"api/operator/operator/","page":"Operators","title":"Operators","text":"Modules = [Bcube]\nPages = [\"operator.jl\"]","category":"page"},{"location":"api/dof/dof/#Degree-of-freedom","page":"Degree of freedom","title":"Degree of freedom","text":"","category":"section"},{"location":"api/dof/dof/#Assembler","page":"Degree of freedom","title":"Assembler","text":"","category":"section"},{"location":"api/dof/dof/","page":"Degree of freedom","title":"Degree of freedom","text":"Modules = [Bcube]\nPages = [\"assembler.jl\"]","category":"page"},{"location":"api/dof/dof/#Bcube.AbstractFaceSidePair","page":"Degree of freedom","title":"Bcube.AbstractFaceSidePair","text":"AbstractFaceSidePair <: AbstractLazy\n\nInterface:\n\nside_n(a::AbstractFaceSidePair)\nside_p(a::AbstractFaceSidePair)\n\n\n\n\n\n","category":"type"},{"location":"api/dof/dof/#Bcube.__assemble_linear!-Tuple{Any, Any, Any, Measure}","page":"Degree of freedom","title":"Bcube.__assemble_linear!","text":"Dev notes\n\nTwo levels of \"LazyMapOver\" because first we LazyMapOver the Tuple of argument of the linear form, and the for each item of this Tuple we LazyMapOver the shape functions.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._append_contribution!-Tuple{Any, Any, Any, Any, Any, Any, CellInfo, Any}","page":"Degree of freedom","title":"Bcube._append_contribution!","text":"bilinear case\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._assemble_linear!-Tuple{Any, Any, Any, Bcube.Integration}","page":"Degree of freedom","title":"Bcube._assemble_linear!","text":"_assemble_linear!(b, l, V, integration::Integration)\n_assemble_linear!(b, l, V, integration::MultiIntegration{N}) where {N}\n\nThese functions act as a function barrier in order to:\n\nget the function corresponding to the operand in the linear form\nreshape b internally to deal with cases when V is a AbstractMultiTestFESpace\ncall __assemble_linear! to apply dispatch on the type of measure of the integration and improve type stability during the assembling loop.\n\nDev note:\n\nThe case integration::MultiIntegration{N} is treated by looping over each Integration contained in the MultiIntegration\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._blockmap_bilinear-Union{Tuple{N2}, Tuple{N1}, Tuple{Tuple{Vararg{T, N1}} where T, Tuple{Vararg{T, N2}} where T}} where {N1, N2}","page":"Degree of freedom","title":"Bcube._blockmap_bilinear","text":"From tuples a=(a_1 a_2 a_i a_m) and b=(b_1 b_2 b_j b_n), it builds A and B which correspond formally to the following two matrices :\n\nA equiv beginpmatrix\na_1 a_1 a_1\na_2 a_2 a_2\n \na_m a_m a_m\nendpmatrix\nqquad and qquad\nB equiv beginpmatrix\nb_1 b_2 b_n\nb_1 b_2 b_n\n \nb_1 b_2 b_n\nendpmatrix\n\nA and B are wrapped in LazyMapOver structures so that all operations on them are done elementwise by default (in other words, it can be considered that the operations are automatically broadcasted).\n\nDev note :\n\nBoth A and B are stored as a tuple of tuples, wrapped by LazyMapOver, where inner tuples correspond to each columns of a matrix. This hierarchical structure reduces both inference and compile times by avoiding the use of large tuples.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._count_n_elts-Union{Tuple{IND}, Tuple{M}, Tuple{TrialFESpace, TestFESpace, CellDomain{M, IND}}} where {M, IND}","page":"Degree of freedom","title":"Bcube._count_n_elts","text":"Count the (maximum) number of elements in the matrix corresponding to the bilinear assembly of U, V on a cell domain, where U and V are TrialFESpace and TestFESpace\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._count_n_elts-Union{Tuple{Tv}, Tuple{Tu}, Tuple{N}, Tuple{IND}, Tuple{M}, Tuple{Bcube.AbstractMultiFESpace{N, Tu}, Bcube.AbstractMultiFESpace{N, Tv}, CellDomain{M, IND}}} where {M, IND, N, Tu<:Tuple{Vararg{TrialFESpace}}, Tv<:Tuple{Vararg{TestFESpace}}}","page":"Degree of freedom","title":"Bcube._count_n_elts","text":"Count the (maximum) number of elements in the matrix corresponding to the bilinear assembly of U, V on a cell domain, where U and V are AbstractMultiFESpace\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._diag_tuples-Union{Tuple{N}, Tuple{Tuple{Vararg{Any, N}}, Any}} where N","page":"Degree of freedom","title":"Bcube._diag_tuples","text":"_diag_tuples(diag::Tuple{Vararg{Any,N}}, b) where N\n\nReturn N tuples of length N. For each tuple tᵢ, its values are defined so that tᵢ[k]=diag[k] if k==i, tᵢ[k]=b otherwise. The result can be seen as a dense diagonal-like array using tuple.\n\nExample for N=3:\n\n(diag[1], b, b ),\n(b, diag[2], b ),\n(b, b, diag[3]))\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._get_multi_tuple_var-Union{Tuple{Tuple{Vararg{Any, N}}}, Tuple{N}} where N","page":"Degree of freedom","title":"Bcube._get_multi_tuple_var","text":"For N=3 for example: (LazyMapOver((LazyMapOver(V[1]), NullOperator(), NullOperator())), LazyMapOver((NullOperator(), LazyMapOver(V[2]), NullOperator())), LazyMapOver((NullOperator(), NullOperator(), LazyMapOver(V[3]))))\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._may_reshape_b-Tuple{AbstractVector, TestFESpace}","page":"Degree of freedom","title":"Bcube._may_reshape_b","text":"For AbstractMultiTestFESpace, it creates a Tuple (of views) of the different \"destination\" in the vector: one for each FESpace\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_bilinear!-Tuple{Vector{Int64}, Vector{Int64}, Vector, Function, Measure{<:Bcube.AbstractFaceDomain}, TrialFESpace, TestFESpace}","page":"Degree of freedom","title":"Bcube.assemble_bilinear!","text":"assemble_bilinear!(\n I::Vector{Int},\n J::Vector{Int},\n X::Vector{T},\n f::Function,\n measure::Measure{<:AbstractFaceDomain},\n U::TrialFESpace,\n V::TestFESpace,\n)\n\nIn-place version of assemble_bilinear.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_bilinear!-Tuple{Vector{Int64}, Vector{Int64}, Vector, Function, Measure{<:CellDomain}, TrialFESpace, TestFESpace}","page":"Degree of freedom","title":"Bcube.assemble_bilinear!","text":"assemble_bilinear!(\n I::Vector{Int},\n J::Vector{Int},\n X::Vector{T},\n f::Function,\n measure::Measure{<:CellDomain},\n U::TrialFESpace,\n V::TestFESpace,\n)\n\nIn-place version of assemble_bilinear.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_bilinear-Union{Tuple{N}, Tuple{Function, Union{Bcube.AbstractMultiFESpace{N, <:Tuple{Vararg{TrialFESpace, N}}}, TrialFESpace}, Union{Bcube.AbstractMultiFESpace{N, <:Tuple{Vararg{TestFESpace, N}}}, TestFESpace}}} where N","page":"Degree of freedom","title":"Bcube.assemble_bilinear","text":"assemble_bilinear(a::Function, U, V)\n\nAssemble the (sparse) Matrix corresponding to the given bilinear form a on the trial and test finite element spaces U and V.\n\nFor the in-place version, check-out assemble_bilinear!.\n\nArguments\n\na::Function : function of two variables (u,v) representing the bilinear form\nU : trial finite element space (for u)\nV : test finite element space (for v)\n\nExamples\n\njulia> mesh = rectangle_mesh(3,3)\njulia> U = TrialFESpace(FunctionSpace(:Lagrange, 0), mesh)\njulia> V = TestFESpace(U)\njulia> dΩ = Measure(CellDomain(mesh), 3)\njulia> a(u, v) = ∫(u * v)dΩ\njulia> assemble_bilinear(a, U, V)\n4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:\n 0.25 ⋅ ⋅ ⋅\n ⋅ 0.25 ⋅ ⋅\n ⋅ ⋅ 0.25 ⋅\n ⋅ ⋅ ⋅ 0.25\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_linear!-Tuple{AbstractVector, Function, Union{Bcube.AbstractMultiFESpace{N, <:Tuple{Vararg{TestFESpace, N}}} where N, TestFESpace}}","page":"Degree of freedom","title":"Bcube.assemble_linear!","text":"assemble_linear!(b::AbstractVector, l::Function, V::Union{TestFESpace, AbstractMultiTestFESpace})\n\nIn-place version of assemble_linear.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_linear-Tuple{Function, Union{Bcube.AbstractMultiFESpace{N, <:Tuple{Vararg{TestFESpace, N}}} where N, TestFESpace}}","page":"Degree of freedom","title":"Bcube.assemble_linear","text":"assemble_linear(l::Function, V::Union{TestFESpace, AbstractMultiTestFESpace})\n\nAssemble the vector corresponding to a linear form l on the finite element space V\n\nFor the in-place version, checkout assemble_linear!.\n\nArguments\n\nl::Function : linear form to assemble, a function of one variable l(v)\nV : test finite element space\n\nExamples\n\njulia> mesh = rectangle_mesh(3,3)\njulia> U = TrialFESpace(FunctionSpace(:Lagrange, 0), mesh)\njulia> V = TestFESpace(U)\njulia> dΩ = Measure(CellDomain(mesh), 3)\njulia> l(v) = ∫(v)dΩ\njulia> assemble_linear(l, V)\n4-element Vector{Float64}:\n 0.25\n 0.25\n 0.25\n 0.25\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.blockmap_bilinear_shape_functions-Tuple{Bcube.AbstractFESpace, Bcube.AbstractFESpace, Bcube.AbstractCellInfo}","page":"Degree of freedom","title":"Bcube.blockmap_bilinear_shape_functions","text":"Dev notes:\n\nReturn blockU and blockV to be able to compute the local matrix corresponding to the bilinear form :\n\n Aij = a(λᵤj λᵥi)\n\nwhere λᵤ and λᵥ are the shape functions associated with the trial U and the test V function spaces respectively. In a \"map-over\" version, it can be written :\n\n A = a(blockU blockV)\n\nwhere blockU and blockV correspond formally to the lazy-map-over matrices :\n\n k blockUkj = λᵤj\n blockVik = λᵥi\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.blockmap_shape_functions-Tuple{Any, FaceInfo}","page":"Degree of freedom","title":"Bcube.blockmap_shape_functions","text":"Dev note :\n\nMaterialize the integrand function on all the different possible Tuples of v=(v1,0,0,...), (0,v2,0,...), ..., (..., vi, ...)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.blockmap_shape_functions-Tuple{Bcube.AbstractFESpace, Bcube.AbstractCellInfo}","page":"Degree of freedom","title":"Bcube.blockmap_shape_functions","text":"blockmap_shape_functions(fespace::AbstractFESpace, cellinfo::AbstractCellInfo)\n\nReturn all shape functions a = LazyMapOver((λ₁, λ₂, …, λₙ)) corresponding to fespace in cell cellinfo. These shape functions are wrapped by a LazyMapOver so that for a function f it gives: f(a) == map(f, a)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.blockmap_shape_functions-Tuple{Bcube.AbstractMultiFESpace, Bcube.AbstractCellInfo}","page":"Degree of freedom","title":"Bcube.blockmap_shape_functions","text":"blockmap_shape_functions(multiFESpace::AbstractMultiFESpace, cellinfo::AbstractCellInfo)\n\nReturn all shape functions corresponding to each fespace in multiFESSpace for cell cellinfo :\n\n ((v₁ ) ( v₂ ) ( vₙ))\n\nwhere:\n\nvᵢ = (λᵢ₁, λᵢ₂, …, λᵢ_ₘ) are the shapes functions of the i-th fespace in the cell.\n∅ are NullOperators\n\nNote that the LazyMapOver is used to wrap recursively the result.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.compute-Tuple{Bcube.Integration}","page":"Degree of freedom","title":"Bcube.compute","text":"compute(integration::Integration)\n\nCompute an integral, independently from a FEM/DG framework (i.e without FESpace)\n\nReturn an array of the integral evaluated over each cell (or face). To get the sum over the whole domain, simply apply the sum function.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#DofHandler","page":"Degree of freedom","title":"DofHandler","text":"","category":"section"},{"location":"api/dof/dof/","page":"Degree of freedom","title":"Degree of freedom","text":"Modules = [Bcube]\nPages = [\"dofhandler.jl\"]","category":"page"},{"location":"api/dof/dof/#Bcube.DofHandler","page":"Degree of freedom","title":"Bcube.DofHandler","text":"The DofHandler handles the degree of freedom numbering. To each degree of freedom is associated a unique integer.\n\n\n\n\n\n","category":"type"},{"location":"api/dof/dof/#Bcube.DofHandler-Tuple{Mesh, Bcube.AbstractFunctionSpace, Int64, Bool}","page":"Degree of freedom","title":"Bcube.DofHandler","text":"DofHandler(mesh::Mesh, fSpace::AbstractFunctionSpace, ncomponents::Int, isContinuous::Bool)\n\nConstructor of a DofHandler for a SingleFESpace on a Mesh.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._deal_with_dofs_on_edges!-Tuple{Dict{Tuple{Int64, Set{Int64}}, Tuple{Int64, Vector{Int64}}}, Any, Any, Any, Any, Int64, Any, Bcube.AbstractShape, Int64, Bcube.AbstractFunctionSpace}","page":"Degree of freedom","title":"Bcube._deal_with_dofs_on_edges!","text":"deal_with_dofs_on_edges!(dict, iglob, offset, c2n, celltypes, icell::Int, inodes_g, e2n_g, s::AbstractShape, kvar::Int, fs)\n\nFunction dealing with dofs shared by different cell through an edge connection (excluding bord vertices).\n\nTODO : remove kvar\n\nArguments\n\ndict may be modified by this routine\niglob may be modified by this routine\noffset may be modified by this routine\nfs : FunctionSpace of var kvar\nicell : cell index\nkvar : var index\ns : shape of icell-th cell\ninodes_g : global indices of nodes of icell\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._deal_with_dofs_on_faces!-Tuple{Any, Any, Any, Any, Any, Int64, Vector{Vector{Int64}}, Bcube.AbstractShape, Bcube.AbstractFunctionSpace, Int64}","page":"Degree of freedom","title":"Bcube._deal_with_dofs_on_faces!","text":"TODO : remove kvar\n\nArguments\n\nf2n_g : local face index -> global nodes indices\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._deal_with_dofs_on_vertices!-Tuple{Dict{Tuple{Int64, Int64}, Tuple{Int64, Vector{Int64}}}, Any, Any, Int64, Any, Bcube.AbstractShape, Int64, Bcube.AbstractFunctionSpace}","page":"Degree of freedom","title":"Bcube._deal_with_dofs_on_vertices!","text":"deal_with_dofs_on_vertices!(dict, iglob, offset, icell::Int, inodes_g, s::AbstractShape, kvar::Int, fs)\n\nFunction dealing with dofs shared by different cell through a vertex connection.\n\nTODO : remove kvar\n\nArguments\n\ndict may be modified by this routine\niglob may be modified by this routine\noffset may be modified by this routine\nfs : FunctionSpace of var kvar\nicell : cell index\nkvar : var index\ns : shape of icell-th cell\ninodes_g : global indices of nodes of icell\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.dof-Tuple{Bcube.DofHandler, Any, Int64, Int64}","page":"Degree of freedom","title":"Bcube.dof","text":"dof(dhl::DofHandler, icell, icomp::Int, idof::Int)\n\nGlobal index of the idof local degree of freedom of component icomp in cell icell.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show dof(dhl, 1, 1, 1)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.dof-Tuple{Bcube.DofHandler, Any, Int64}","page":"Degree of freedom","title":"Bcube.dof","text":"dof(dhl::DofHandler, icell, icomp::Int)\n\nGlobal indices of all the dofs of a given component in a given cell\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show dof(dhl, 1, 1)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.get_ncomponents-Tuple{Bcube.DofHandler}","page":"Degree of freedom","title":"Bcube.get_ncomponents","text":"Number of components handled by a DofHandler\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.max_ndofs-Tuple{Bcube.DofHandler}","page":"Degree of freedom","title":"Bcube.max_ndofs","text":"max_ndofs(dhl::DofHandler)\n\nCount maximum number of dofs per cell, all components mixed\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.ndofs-Tuple{Bcube.DofHandler, Any, AbstractVector{Int64}}","page":"Degree of freedom","title":"Bcube.ndofs","text":"ndofs(dhl, icell, icomp::Vector{Int})\n\nNumber of dofs for a given set of components in a given cell.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1); size = 2))\n@show ndofs(dhl, 1, [1, 2])\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.ndofs-Tuple{Bcube.DofHandler, Any, Int64}","page":"Degree of freedom","title":"Bcube.ndofs","text":"ndofs(dhl, icell, kvar::Int)\n\nNumber of dofs for a given variable in a given cell.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show ndofs(dhl, 1, 1)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.ndofs-Tuple{Bcube.DofHandler, Any}","page":"Degree of freedom","title":"Bcube.ndofs","text":"ndofs(dhl::DofHandler, icell)\n\nNumber of dofs for a given cell.\n\nNote that for a vector variable, the total (accross all components) number of dofs is returned.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show ndofs(dhl, 1, :u)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.ndofs-Tuple{Bcube.DofHandler}","page":"Degree of freedom","title":"Bcube.ndofs","text":"ndofs(dhl::DofHandler)\n\nTotal number of dofs. This function takes into account that dofs can be shared by multiple cells.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show ndofs(dhl::DofHandler)\n\n\n\n\n\n","category":"method"},{"location":"tutorial/helmholtz/#Helmholtz-equation-(FE)","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"","category":"section"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"This tutorial shows how to solve the Helmholtz eigen problem with a finite-element approach using Bcube.","category":"page"},{"location":"tutorial/helmholtz/#Theory","page":"Helmholtz equation (FE)","title":"Theory","text":"","category":"section"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"We consider the following Helmholtz equation, representing for instance the acoustic wave propagation with Neuman boundary condition(s):","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"begincases\n Delta u + omega^2 u = 0 \n dfracpartial upartial n = 0 textrm on Gamma\nendcases","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"An analytic solution of this equation can be obtained: for a rectangular domain Omega = 0L_x times 0L_y,","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"u(xy) = cos left( frack_x piL_x x right) cos left( frack_y piL_y y right) mathrmwith k_xk_y in mathbbN","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"with omega^2 = pi^2 left( dfrack_x^2L_x^2 + dfrack_y^2L_y^2 right)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Now, both the finite-element method and the discontinuous Galerkin method requires to write the weak form of the problem:","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"int_Omega (Delta u Delta v + omega^2u)v mathrmdOmega = 0","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"- int_Omega nabla u cdot nabla v mathrmdOmega\n+ underbraceleft (nabla u cdot n) v right_Gamma_=0 + omega^2 int_Omega u v mathrmd Omega = 0","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"int_Omega nabla u cdot nabla v mathrmd Omega = omega^2 int_Omega u v mathrmd Omega","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Introducing to bilinear forms a(uv) and b(uv) for respectively the left and right side terms, this equation can be written","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"a(uv) = omega^2 b(uv)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"This is actually a generalized eigenvalue problem which can be written:","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"A u = alpha B u","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"where","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"A u = int_Omega nabla u cdot nabla v mathrmd Omega B u = int_Omega u v mathrmd Omega alpha = omega^2","category":"page"},{"location":"tutorial/helmholtz/#Uncommented-code","page":"Helmholtz equation (FE)","title":"Uncommented code","text":"","category":"section"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"The code below solves the described Helmholtz eigen problem. The code with detailed comments is provided in the next section.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"using Bcube\nusing LinearAlgebra\n\nmesh = rectangle_mesh(21, 21)\n\ndegree = 1\n\nU = TrialFESpace(FunctionSpace(:Lagrange, degree), mesh)\nV = TestFESpace(U)\n\ndΩ = Measure(CellDomain(mesh), 2 * degree + 1)\n\na(u, v) = ∫(∇(u) ⋅ ∇(v))dΩ\nb(u, v) = ∫(u ⋅ v)dΩ\n\nA = assemble_bilinear(a, U, V)\nB = assemble_bilinear(b, U, V)\n\nvp, vecp = eigen(Matrix(A), Matrix(B))\n@show sqrt.(abs.(vp[3:8]))","category":"page"},{"location":"tutorial/helmholtz/#Commented-code","page":"Helmholtz equation (FE)","title":"Commented code","text":"","category":"section"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Load the necessary packages","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"using Bcube\nusing LinearAlgebra","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Mesh a 2D rectangular domain with quads.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"mesh = rectangle_mesh(21, 21)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Next, create the function space that will be used for the trial and test spaces. The Lagrange polynomial space is used here. The degree is set to 1.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"degree = 1\nfs = FunctionSpace(:Lagrange, degree)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"The trial space is created from the function space and the mesh. By default, a scalar \"continuous\" FESpace is created. For \"discontinuous\" (\"DG\") example, check out the linear transport tutorial.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"U = TrialFESpace(fs, mesh)\nV = TestFESpace(U)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Then, define the geometrical dommain on which the operators will apply. For this finite-element example, we only need a CellDomain (no FaceDomain).","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"domain = CellDomain(mesh)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Now, integrating on a domain necessitates a \"measure\", basically a quadrature of given degree.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"dΩ = Measure(domain, Quadrature(2 * degree + 1))","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"The definition of the two bilinear forms is quite natural. Note that these definitions are lazy, no computation is done at this step : the computations will be triggered by the assembly.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"a(u, v) = ∫(∇(u) ⋅ ∇(v))dΩ\nb(u, v) = ∫(u ⋅ v)dΩ","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"To obtain the two sparse matrices corresponding to the discretisation of these bilinear forms, simply call the assemble_bilinear function, providing the trial and test spaces.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"A = assemble_bilinear(a, U, V)\nB = assemble_bilinear(b, U, V)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Compute eigen-values and vectors : we convert to dense matrix to avoid importing additionnal packages, but it is quite easy to solve it in a \"sparse way\".","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"vp, vecp = eigen(Matrix(A), Matrix(B))","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Display the \"first\" five eigenvalues:","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"@show sqrt.(abs.(vp[3:8]))\nref_results = [\n 3.144823462554393,\n 4.447451992013584,\n 6.309054755690625,\n 6.309054755690786,\n 7.049403274103087,\n 7.049403274103147,","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Now we can export the solution (the eigenvectors) at nodes of the mesh for several eigenvalues. We will restrict to the first 20 eigenvectors. To do so, we will create a FEFunction for each eigenvector. This FEFunction can then be evaluated on the mesh centers, nodes, etc.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"ϕ = FEFunction(U)\nnvecs = min(20, get_ndofs(U))\nvalues = zeros(nnodes(mesh), nvecs)\nfor ivec in 1:nvecs\n set_dof_values!(ϕ, vecp[:, ivec])\n values[:, ivec] = var_on_vertices(ϕ, mesh)\nend","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"To write a VTK file, we need to build a dictionnary linking the variable name with its values and type","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"using WriteVTK\nout_dir = joinpath(@__DIR__, \"../myout\") # output directory\ndict_vars = Dict(\"u_$i\" => (values[:, i], VTKPointData()) for i in 1:nvecs)\nwrite_vtk(joinpath(out_dir, \"helmholtz_rectangle_mesh\"), 0, 0.0, mesh, dict_vars)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"And here is the eigenvector corresponding to the 4th eigenvalue:","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"\"drawing\"","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"This page was generated using Literate.jl.","category":"page"},{"location":"tutorial/phase_field_supercooled/#Phase-field-model-solidification-of-a-liquid-in-supercooled-state","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"","category":"section"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"In this tutorial, a coupled system of two unsteady equations is solved using finite elements and an imex time scheme. This tutorial doesn't introduce MultiFESpace, check the \"euler\" example for this. Warning : this file is currently quite long to run (a few minutes).","category":"page"},{"location":"tutorial/phase_field_supercooled/#Theory","page":"Phase field model - solidification of a liquid in supercooled state","title":"Theory","text":"","category":"section"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"This case is taken from: Kobayashi, R. (1993). Modeling and numerical simulations of dendritic crystal growth. Physica D: Nonlinear Phenomena, 63(3-4), 410-423. In particular, the variables of the problem are denoted in the same way (p for the phase indicator and T for temperature). Consider a rectangular domain Omega = 0 L_x times 0 L_y on which we wish to solve the following equations:","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":" tau partial_t p = epsilon^2 Delta p + p (1-p)(p - frac12 + m(T))","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":" partial_t T = Delta T + K partial_t p","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"where m(T) = fracalphapi atan left gamma (T_e - T) right. This set of equations represents the solidification of a liquid in a supercooled state. Here T is a dimensionless temperature and p is the solid volume fraction. Lagrange finite elements are used to discretize both equations. Time marching is performed with a forward Euler scheme for the first equation and a backward Euler scheme for the second one.","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"To initiate the solidification process, a Dirichlet boundary condition (p=1,T=1) is applied at x=0 (\"West\" boundary).","category":"page"},{"location":"tutorial/phase_field_supercooled/#Code","page":"Phase field model - solidification of a liquid in supercooled state","title":"Code","text":"","category":"section"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Load the necessary packages","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"using Bcube\nusing LinearAlgebra\nusing WriteVTK\nusing Random\n\nRandom.seed!(1234) # to obtain reproductible results","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Define some physical and numerical constants, as well as the g function appearing in the problem definition.","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"const dir = string(@__DIR__, \"/../\") # Bcube dir\nconst ε = 0.01\nconst τ = 0.0003\nconst α = 0.9\nconst γ = 10.0\nconst K = 1.6\nconst Te = 1.0\nconst β = 0.0 # noise amplitude, original value : 0.01\nconst Δt = 0.0001 # time step\nconst totalTime = 1.0 # original value : 1\nconst nout = 50 # Number of iterations to skip before writing file\nconst degree = 1 # function space degree\nconst lx = 3.0\nconst ly = 1.0\nconst nx = 100\nconst ny = 20\n\ng(T) = (α / π) * atan(γ * (Te - T))","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Read the mesh using gmsh","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"const mesh_path = dir * \"input/mesh/domainPhaseField_tri.msh\"\nconst mesh = read_msh(mesh_path)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Noise function : random between [-1/2,1/2]","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"const χ = MeshCellData(rand(ncells(mesh)) .- 0.5)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Build the function space and the FE Spaces. The two unknowns will share the same FE spaces for this tutorial. Note the way we specify the Dirichlet condition in the definition of U.","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"fs = FunctionSpace(:Lagrange, degree)\nU = TrialFESpace(fs, mesh, Dict(\"West\" => (x, t) -> 1.0))\nV = TestFESpace(U)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Build FE functions","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"ϕ = FEFunction(U)\nT = FEFunction(U)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Define measures for cell integration","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"dΩ = Measure(CellDomain(mesh), 2 * degree + 1)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Define bilinear and linear forms","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"a(u, v) = ∫(∇(u) ⋅ ∇(v))dΩ\nm(u, v) = ∫(u ⋅ v)dΩ\nl(v) = ∫(v * ϕ * (1.0 - ϕ) * (ϕ - 0.5 + g(T) + β * χ))dΩ","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Assemble the two constant matrices","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"A = assemble_bilinear(a, U, V)\nM = assemble_bilinear(m, U, V)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Create iterative matrices","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"C_ϕ = M + Δt / τ * ε^2 * A\nC_T = M + Δt * A","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Apply Dirichlet conditions. For this example, we don't use a lifting method to impose the Dirichlet, but d is used to initialize the solution.","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"d = assemble_dirichlet_vector(U, V, mesh)\napply_dirichlet_to_matrix!((C_ϕ, C_T), U, V, mesh)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Init solution and write it to a VTK file","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"set_dof_values!(ϕ, d)\nset_dof_values!(T, d)\n\ndict_vars = Dict(\n \"Temperature\" => (var_on_vertices(T, mesh), VTKPointData()),\n \"Phi\" => (var_on_vertices(ϕ, mesh), VTKPointData()),\n)\nwrite_vtk(dir * \"myout/result_phaseField_imex_1space\", 0, 0.0, mesh, dict_vars)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Factorize and allocate some vectors to increase performance","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"C_ϕ = factorize(C_ϕ)\nC_T = factorize(C_T)\nL = zero(d)\nrhs = zero(d)\nϕ_new = zero(d)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Time loop (imex time integration)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"t = 0.0\nitime = 0\nwhile t <= totalTime\n global t, itime\n t += Δt\n itime += 1\n @show t, totalTime\n\n # Integrate equation on ϕ\n L .= 0.0 # reset L\n assemble_linear!(L, l, V)\n rhs .= M * get_dof_values(ϕ) .+ Δt / τ .* L\n apply_dirichlet_to_vector!(rhs, U, V, mesh)\n ϕ_new .= C_ϕ \\ rhs\n\n # Integrate equation on T\n rhs .= M * (get_dof_values(T) .+ K .* (ϕ_new .- get_dof_values(ϕ)))\n apply_dirichlet_to_vector!(rhs, U, V, mesh)\n\n # Update solution\n set_dof_values!(ϕ, ϕ_new)\n set_dof_values!(T, C_T \\ rhs)\n\n # write solution in vtk format\n if itime % nout == 0\n dict_vars = Dict(\n \"Temperature\" => (var_on_vertices(T, mesh), VTKPointData()),\n \"Phi\" => (var_on_vertices(ϕ, mesh), VTKPointData()),\n )\n write_vtk(\n dir * \"myout/result_phaseField_imex_1space\",\n itime,\n t,\n mesh,\n dict_vars;\n append = true,\n )\n end\nend","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"And here is an animation of the result:","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"\"drawing\"","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"This page was generated using Literate.jl.","category":"page"},{"location":"api/interpolation/fespace/#Finite-element-spaces","page":"Finite element spaces","title":"Finite element spaces","text":"","category":"section"},{"location":"api/interpolation/fespace/","page":"Finite element spaces","title":"Finite element spaces","text":"Modules = [Bcube]\nPages = [\"fespace.jl\"]","category":"page"},{"location":"api/interpolation/fespace/#Bcube.AbstractFESpace","page":"Finite element spaces","title":"Bcube.AbstractFESpace","text":"Abstract type to represent an finite-element space of size S. See SingleFESpace for more details about what looks like a finite-element space.\n\nDevs notes\n\nAll subtypes should implement the following functions:\n\nget_function_space(feSpace::AbstractFESpace)\nget_shape_functions(feSpace::AbstractFESpace, shape::AbstractShape)\nget_cell_shape_functions(feSpace::AbstractFESpace, shape::AbstractShape)\nget_ndofs(feSpace::AbstractFESpace)\nis_continuous(feSpace::AbstractFESpace)\n\nAlternatively, you may define a \"parent\" to your structure by implementing the Base.parent function. Then, all the above functions will be redirected to the \"parent\" FESpace.\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.AbstractMultiFESpace","page":"Finite element spaces","title":"Bcube.AbstractMultiFESpace","text":"Devs notes\n\nAll subtypes should implement the following functions:\n\nget_fespace(mfeSpace::AbstractMultiFESpace)\nget_mapping(mfeSpace::AbstractMultiFESpace)\nget_dofs(mfeSpace::AbstractMultiFESpace, icell::Int)\nget_shape_functions(mfeSpace::AbstractMultiFESpace, shape::AbstractShape)\nget_cell_shape_functions(mfeSpace::AbstractMultiFESpace, shape::AbstractShape)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.MultiFESpace","page":"Finite element spaces","title":"Bcube.MultiFESpace","text":"A MultiFESpace represents a \"set\" of TrialFESpace or TestFESpace. This structure provides a global dof numbering for each FESpace.\n\nN is the number of FESpace contained in this MultiFESpace.\n\nNote that the FESpace can be different from each other (one continous, one discontinuous; one scalar, one vector...)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.MultiFESpace-Union{Tuple{Tuple{Vararg{Union{TestFESpace{S, FE}, TrialFESpace{S, FE}} where {S, FE}, N}}}, Tuple{N}} where N","page":"Finite element spaces","title":"Bcube.MultiFESpace","text":"MultiFESpace(\n feSpaces::Tuple{Vararg{TrialOrTest, N}};\n arrayOfStruct::Bool = AOS_DEFAULT,\n) where {N}\nMultiFESpace(\n feSpaces::AbstractArray{FE};\n arrayOfStruct::Bool = AOS_DEFAULT,\n) where {FE <: TrialOrTest}\nMultiFESpace(feSpaces::Vararg{TrialOrTest}; arrayOfStruct::Bool = AOS_DEFAULT)\n\nBuild a finite element space representing several sub- finite element spaces.\n\nThis is particulary handy when several variables are in play since it provides a global dof numbering (for the whole system). The finite element spaces composing the MultiFESpace can be different from each other (some continuous, some discontinuous, some scalar, some vectors...).\n\nArguments\n\nfeSpaces : the finite element spaces composing the MultiFESpace. Note that they must be of type TrialFESpace or TestFESpace.\n\nKeywords\n\narrayOfStruct::Bool = AOS_DEFAULT : indicates if the dof numbering should be of type \"Array of Structs\" (AoS) or \"Struct of Arrays\" (SoA).\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.SingleFESpace","page":"Finite element spaces","title":"Bcube.SingleFESpace","text":"SingleFESpace(\n fSpace::AbstractFunctionSpace,\n mesh::AbstractMesh,\n dirichletBndNames = String[];\n size::Int = 1,\n isContinuous::Bool = true,\n kwargs...\n)\n\nBuild a finite element space (scalar or vector) from a FunctionSpace and a Mesh.\n\nArguments\n\nfSpace::AbstractFunctionSpace : the function space associated to the FESpace\nmesh::AbstractMesh : the mesh on which the FESpace is discretized\ndirichletBndNames = String[] : list of mesh boundary labels where a Dirichlet condition applies\n\nKeywords\n\nsize::Int = 1 : the number of components of the FESpace\nisContinuous::Bool = true : if true, a continuous dof numbering is created. Otherwise, dof lying\n\non cell nodes or cell faces are duplicated, not shared (discontinuous dof numbering)\n\nkwargs : for things such as parallel cache (internal/dev usage only)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.SingleFESpace-2","page":"Finite element spaces","title":"Bcube.SingleFESpace","text":"An finite-element space (FESpace) is basically a function space, associated to degrees of freedom (on a mesh).\n\nA FESpace can be either scalar (to represent a Temperature for instance) or vector (to represent a Velocity). In case of a \"vector\" SingleFESpace, all the components necessarily share the same FunctionSpace.\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.TestFESpace","page":"Finite element spaces","title":"Bcube.TestFESpace","text":"TestFESpace(trialFESpace::TrialFESpace)\nTestFESpace(\n fSpace::AbstractFunctionSpace,\n mesh::AbstractMesh,\n dirichletBndNames = String[];\n size::Int = 1,\n isContinuous::Bool = true,\n kwargs...,\n)\n\nBuild a test finite element space.\n\nA TestFESpace can be built from a TrialFESpace. See SingleFESpace for hints about the function arguments. Only arguments specific to TrialFESpace are detailed below.\n\nExamples\n\njulia> mesh = one_cell_mesh(:line)\njulia> fSpace = FunctionSpace(:Lagrange, 2)\njulia> U = TrialFESpace(fSpace, mesh)\njulia> V = TestFESpace(U)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.TestFESpace-2","page":"Finite element spaces","title":"Bcube.TestFESpace","text":"A TestFESpace is basically a SingleFESpace plus other attributes (related to boundary conditions)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.TrialFESpace","page":"Finite element spaces","title":"Bcube.TrialFESpace","text":"TrialFESpace(feSpace, dirichletValues)\nTrialFESpace(\n fSpace::AbstractFunctionSpace,\n mesh::AbstractMesh,\n dirichlet::Dict{String} = Dict{String, Any}();\n size::Int = 1,\n isContinuous::Bool = true,\n kwargs...\n)\nTrialFESpace(\n fSpace::AbstractFunctionSpace,\n mesh::AbstractMesh,\n type::Symbol,\n dirichlet::Dict{String} = Dict{String, Any}();\n size::Int = 1,\n kwargs...\n)\n\nBuild a trial finite element space.\n\nSee SingleFESpace for hints about the function arguments. Only arguments specific to TrialFESpace are detailed below.\n\nArguments\n\ndirichlet::Dict{String} = Dict{String, Any}() : dictionnary specifying the Dirichlet valued-function (or function) associated to each mesh boundary label. The function f(x,t) to apply is expressed in the physical coordinate system. Alternatively, a constant value can be provided instead of a function.\ntype::Symbol : :continuous or :discontinuous\n\nWarning\n\nFor now the Dirichlet condition can only be applied to nodal bases.\n\nExamples\n\njulia> mesh = one_cell_mesh(:line)\njulia> fSpace = FunctionSpace(:Lagrange, 2)\njulia> U = TrialFESpace(fSpace, mesh)\njulia> V = TrialFESpace(fSpace, mesh, :discontinuous; size = 3)\njulia> W = TrialFESpace(fSpace, mesh, Dict(\"North\" => 3., \"South\" => (x,t) -> t .* x))\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.TrialFESpace-2","page":"Finite element spaces","title":"Bcube.TrialFESpace","text":"A TrialFESpace is basically a SingleFESpace plus other attributes (related to boundary conditions)\n\nDev notes\n\nwe cannot directly store Dirichlet values on dofs because the Dirichlet values needs \"time\" to apply\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube._MultiFESpace-Union{Tuple{Tuple{Vararg{Union{TestFESpace{S, FE}, TrialFESpace{S, FE}} where {S, FE}, N}}}, Tuple{N}} where N","page":"Finite element spaces","title":"Bcube._MultiFESpace","text":"Low-level constructor \n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube._build_mapping_AoS-Tuple{Tuple{Vararg{Union{TestFESpace{S, FE}, TrialFESpace{S, FE}} where {S, FE}}}, Int64}","page":"Finite element spaces","title":"Bcube._build_mapping_AoS","text":"Build a global numbering using an Array-Of-Struct strategy\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube._build_mapping_SoA-Tuple{Tuple{Vararg{Union{TestFESpace{S, FE}, TrialFESpace{S, FE}} where {S, FE}}}, Int64}","page":"Finite element spaces","title":"Bcube._build_mapping_SoA","text":"Build a global numbering using an Struct-Of-Array strategy \n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.allocate_dofs","page":"Finite element spaces","title":"Bcube.allocate_dofs","text":"allocate_dofs(feSpace::AbstractFESpace, T = Float64)\n\nAllocate a vector with a size equal to the number of dof of the FESpace, with the type T. For a MultiFESpace, a vector of the total size of the space is returned (and not a Tuple of vectors)\n\n\n\n\n\n","category":"function"},{"location":"api/interpolation/fespace/#Bcube.get_cell_shape_functions-Tuple{Bcube.AbstractFESpace, Bcube.AbstractShape}","page":"Finite element spaces","title":"Bcube.get_cell_shape_functions","text":"Return the shape functions associated to the AbstractFESpace in \"packed\" form: λ(x) = (λ₁(x),...,λᵢ(x),...λₙ(x)) for the n dofs.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_dirichlet_boundary_tags-Tuple{Bcube.AbstractFESpace}","page":"Finite element spaces","title":"Bcube.get_dirichlet_boundary_tags","text":"Return the boundary tags where a Dirichlet condition applies\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_dirichlet_values-Tuple{TrialFESpace}","page":"Finite element spaces","title":"Bcube.get_dirichlet_values","text":"Return the values associated to a Dirichlet condition\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_dofs-Tuple{Bcube.AbstractFESpace, Int64}","page":"Finite element spaces","title":"Bcube.get_dofs","text":"Return the dofs indices for the cell icell\n\nResult is an array of integers.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_dofs-Tuple{MultiFESpace, Int64}","page":"Finite element spaces","title":"Bcube.get_dofs","text":"get_dofs(feSpace::MultiFESpace, icell::Int)\n\nReturn the dofs indices for the cell icell for each single-feSpace. Result is a tuple of array of integers, where each array of integers are the indices relative to the numbering of each singleFESpace.\n\nWarning:\n\nCombine get_dofs with get_mapping if global dofs indices are needed.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_fespace-Tuple{Bcube.AbstractMultiFESpace}","page":"Finite element spaces","title":"Bcube.get_fespace","text":"get_fespace(mfeSpace::AbstractMultiFESpace, iSpace)\nget_fespace(mfeSpace::AbstractMultiFESpace)\n\nReturn the i-th FESpace composing this AbstractMultiFESpace. If no index is provided, the tuple of FESpace composing this AbstractMultiFESpace` is returnted.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_fespace-Tuple{MultiFESpace}","page":"Finite element spaces","title":"Bcube.get_fespace","text":"Return the tuple of FESpace composing this MultiFESpace\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_function_space-Tuple{Bcube.AbstractFESpace}","page":"Finite element spaces","title":"Bcube.get_function_space","text":"Return the FunctionSpace (eventually multiple spaces) associated to the AbstractFESpace.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_mapping-Tuple{Bcube.AbstractMultiFESpace}","page":"Finite element spaces","title":"Bcube.get_mapping","text":"get_mapping(mfeSpace::AbstractMultiFESpace, iSpace)\nget_mapping(mfeSpace::AbstractMultiFESpace)\n\nReturn the mapping for the ith FESpace composing the MultiFESpace. If no index is provided, the tuple of mapping for each FESpace` is returnted.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_n_fespace-Union{Tuple{Bcube.AbstractMultiFESpace{N}}, Tuple{N}} where N","page":"Finite element spaces","title":"Bcube.get_n_fespace","text":"Number of FESpace composing the MultiFESpace \n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_ncomponents-Tuple{Bcube.AbstractFESpace}","page":"Finite element spaces","title":"Bcube.get_ncomponents","text":"Return the size S(= number of components) associated to AbstractFESpace{S}.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_ndofs-Tuple{Bcube.AbstractFESpace}","page":"Finite element spaces","title":"Bcube.get_ndofs","text":"Return the total number of dofs of the FESpace, taking into account the continuous/discontinuous type of the space. If the FESpace contains itself several FESpace (see MultiFESpace), the sum of all dofs is returned.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_ndofs-Tuple{Bcube.AbstractMultiFESpace}","page":"Finite element spaces","title":"Bcube.get_ndofs","text":"Total number of dofs contained in this MultiFESpace \n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_shape_functions-Tuple{Bcube.AbstractFESpace, Bcube.AbstractShape}","page":"Finite element spaces","title":"Bcube.get_shape_functions","text":"Return the shape functions associated to the AbstractFESpace.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_size-Union{Tuple{Bcube.AbstractFESpace{S}}, Tuple{S}} where S","page":"Finite element spaces","title":"Bcube.get_size","text":"Return the size S associated to AbstractFESpace{S}.\n\n\n\n\n\n","category":"method"},{"location":"manual/cellfunction/#Cell-function","page":"Cell function","title":"Cell function","text":"","category":"section"},{"location":"manual/cellfunction/","page":"Cell function","title":"Cell function","text":"As explained earlier, at least two coordinates systems exist in Bcube : the \"reference\" coordinates (ReferenceDomain) and the \"physical\" coordinates (PhysicalDomain). The evaluation of a function on a point in a cell depends on the way this point has been defined. Hence the definition of CellPoints that embed the coordinate system. Given a CellPoint (or eventually a FacePoint), an AbstractCellFunction will be evaluated and the mapping between the ReferenceDomain to the PhysicalDomain (or reciprocally) will be performed internally if necessary : if an AbstractCellFunction defined in terms of reference coordinates is applied on a CellPoint expressed in the reference coordinates system, no mapping is needed.","category":"page"},{"location":"howto/howto/#How-to","page":"How to...","title":"How to","text":"","category":"section"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"To be completed to answer common user questions.","category":"page"},{"location":"howto/howto/#Comparing-manually-the-benchmarks-with-main","page":"How to...","title":"Comparing manually the benchmarks with main","text":"","category":"section"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Let's say you want to compare the performance of your current branch (named \"target\" hereafter) with the main branch (named \"baseline\" hereafter).","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Open from Bcube.jl/ a REPL and type:","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"pkg> activate --temp\npkg> add PkgBenchmark BenchmarkTools\npkg> dev .\nusing PkgBenchmark\nimport Bcube\nbenchmarkpkg(Bcube, BenchmarkConfig(; env = Dict(\"JULIA_NUM_THREADS\" => \"1\")); resultfile = joinpath(@__DIR__, \"result-target.json\"))","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"This will create a result-target.json in the current directory.","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Then checkout the main branch. Start a fresh REPL and type (almost the same):","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"pkg> activate --temp\npkg> add PkgBenchmark BenchmarkTools\npkg> dev .\nusing PkgBenchmark\nimport Bcube\nbenchmarkpkg(Bcube, BenchmarkConfig(; env = Dict(\"JULIA_NUM_THREADS\" => \"1\")); resultfile = joinpath(@__DIR__, \"result-baseline.json\"))","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"This will create a result-baseline.json in the current directory.","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"You can now \"compare\" the two files by running (watch-out for the order):","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"target = PkgBenchmark.readresults(\"result-target.json\")\nbaseline = PkgBenchmark.readresults(\"result-baseline.json\")\njudgement = judge(target, baseline)\nexport_markdown(\"judgement.md\", judgement)","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"This will create the markdown file judgement.md with the results.","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"For more details, once you've built the judgement object, you can also type the following code from https://github.com/tkf/BenchmarkCI.jl:","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"open(\"detailed-judgement.md\", \"w\") do io\n println(io, \"# Judge result\")\n export_markdown(io, judgement)\n println(io)\n println(io)\n println(io, \"---\")\n println(io, \"# Target result\")\n export_markdown(io, PkgBenchmark.target_result(judgement))\n println(io)\n println(io)\n println(io, \"---\")\n println(io, \"# Baseline result\")\n export_markdown(io, PkgBenchmark.baseline_result(judgement))\n println(io)\n println(io)\n println(io, \"---\")\nend","category":"page"},{"location":"howto/howto/#Run-the-benchmark-manually","page":"How to...","title":"Run the benchmark manually","text":"","category":"section"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Let's say you want to run the benchmarks locally (without comparing with main)","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Open from Bcube.jl/ a REPL and type:","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"pkg> activate --temp\npkg> add PkgBenchmark\npkg> dev .\nusing PkgBenchmark\nimport Bcube\nresults = benchmarkpkg(Bcube, BenchmarkConfig(; env = Dict(\"JULIA_NUM_THREADS\" => \"1\")); resultfile = joinpath(@__DIR__, \"result.json\"))\nexport_markdown(\"results.md\", results)","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"This will create the markdown file results.md with the results.","category":"page"},{"location":"api/mesh/gmsh_utils/#GMSH","page":"GMSH","title":"GMSH","text":"","category":"section"},{"location":"api/mesh/gmsh_utils/","page":"GMSH","title":"GMSH","text":"Modules = [Bcube]\nPages = [\"gmsh_utils.jl\"]","category":"page"},{"location":"api/mesh/gmsh_utils/#Bcube._c2n_gmsh2cgns-Tuple{Any, Any}","page":"GMSH","title":"Bcube._c2n_gmsh2cgns","text":"Convert a cell->node connectivity with gmsh numbering convention to a cell->node connectivity with CGNs numbering convention.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube._compute_space_dim-Tuple{Bool}","page":"GMSH","title":"Bcube._compute_space_dim","text":"Deduce the number of space dimensions from the mesh : if one (or more) dimension of the bounding box is way lower than the other dimensions, the number of space dimension is decreased.\n\nCurrently, having for instance (x,z) is not supported. Only (x), or (x,y), or (x,y,z).\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube._read_msh-Tuple{Int64, Bool}","page":"GMSH","title":"Bcube._read_msh","text":"_read_msh(spaceDim::Int, verbose::Bool)\n\nTo use this function, the gmsh file must have been opened already (see read_msh(path::String) for instance).\n\nThe number of topological dimensions is given by the highest dimension found in the file. The number of space dimensions is deduced from the axis dimensions if spaceDim = 0. If spaceDim is set to a positive number, this number is used as the number of space dimensions.\n\nImplementation\n\nGlobal use of gmsh module. Do not try to improve this function by passing an argument such as gmsh or gmsh.model : it leads to problems.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_cylinder_mesh-Tuple{Any, Any, Any}","page":"GMSH","title":"Bcube.gen_cylinder_mesh","text":"gen_cylinder_mesh(output, Lz; radius = 1., lc = 1e-1, order = 1, npartitions = 0, verbose = false)\n\nGenerate a 3D mesh of a cylindrical domain and length L and write the mesh to output.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_disk_mesh-Tuple{Any}","page":"GMSH","title":"Bcube.gen_disk_mesh","text":"gen_disk_mesh(output; radius = 1., lc = 1e-1, order = 1, npartitions = 0, verbose = false)\n\nGenerate a 2D mesh of a disk domain and write the mesh to output.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_hexa_mesh-Tuple{Any, Any}","page":"GMSH","title":"Bcube.gen_hexa_mesh","text":"gen_hexa_mesh(output, type; recombine = false, n = [2, 2, 2], l = [1., 1., 1.], center = [0., 0., 0.], order = 1)\n\nGenerate a 3D mesh of a hexahedral domain and write the mesh to output. Use type to specify the element types: :tetra or :hexa.\n\nImplementation\n\nNotations from https://cgns.github.io/CGNSdocscurrent/sids/conv.html We could also use extrusion.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_line_mesh-Tuple{Any}","page":"GMSH","title":"Bcube.gen_line_mesh","text":"gen_line_mesh(output; nx = 2, lx = 1., xc = 0., order = 1)\n\nGenerate a 1D mesh of a segment and write to \"output\"\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_mesh_around_disk-Tuple{Any}","page":"GMSH","title":"Bcube.gen_mesh_around_disk","text":"Mesh the domain around a disk\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_rectangle_mesh-Tuple{Any, Any}","page":"GMSH","title":"Bcube.gen_rectangle_mesh","text":"gen_rectangle_mesh(output, type; recombine = false, nx = 2, ny = 2, lx = 1., ly = 1., xc = -1., yc = -1., order = 1)\n\nGenerate a 2D mesh of a rectangle domain and write the mesh to output. Use type to specify the element types: :tri or :quad.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_rectangle_mesh_with_tri_and_quad-Tuple{Any}","page":"GMSH","title":"Bcube.gen_rectangle_mesh_with_tri_and_quad","text":"gen_rectangle_mesh_with_tri_and_quad(output; nx = 2, ny = 2, lx = 1., ly = 1., xc = -1., yc = -1., order = 1)\n\nGenerate a 2D mesh of a rectangle domain and write the mesh to output. The domain is split vertically in two parts: the upper part is composed of 'quad' cells and the lower part with 'tri'. North D –––- C | :quad | West M₁|––––-|M₂ East | :tri | A –––- B South\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_star_disk_mesh-Tuple{Any, Any, Any}","page":"GMSH","title":"Bcube.gen_star_disk_mesh","text":"gen_star_disk_mesh(output, ε, m; nθ = 360, radius = 1., lc = 1e-1, order = 1, npartitions = 0, format22 = false, verbose = false)\n\nGenerate a 2D mesh of a star domain and write the mesh to output. The \"star\" wall is defined by r_wall = R left( 1 + varepsilon cos(m theta) right).\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.nodes_gmsh2cgns-Tuple{AbstractEntityType, AbstractArray}","page":"GMSH","title":"Bcube.nodes_gmsh2cgns","text":"nodes_gmsh2cgns(entity::AbstractEntityType, nodes::AbstractArray)\n\nReorder nodes of a given entity from the Gmsh format to CGNS format\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.read_msh","page":"GMSH","title":"Bcube.read_msh","text":"read_msh(path::String, spaceDim::Int = 0; verbose::Bool = false)\n\nRead a .msh file designated by its path.\n\nSee read_msh() for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/mesh/gmsh_utils/#Bcube.read_msh_with_cell_names","page":"GMSH","title":"Bcube.read_msh_with_cell_names","text":"read_msh_with_cell_names(path::String, spaceDim = 0; verbose = false)\n\nRead a .msh file designated by its path and also return names and tags\n\n\n\n\n\n","category":"function"},{"location":"api/interpolation/spaces/#Available-spaces","page":"Available spaces","title":"Available spaces","text":"","category":"section"},{"location":"api/interpolation/spaces/#Lagrange","page":"Available spaces","title":"Lagrange","text":"","category":"section"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Modules = [Bcube]\nPages = [\"lagrange.jl\"]","category":"page"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 1}, Prism, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Prism, ξ)\n\nShape functions for Prism Lagrange element of degree 1 in a 3D space.\n\nhatlambda_1(xi eta zeta) = (1 - xi - eta)(1 - zeta)2 hspace1cm\nhatlambda_2(xi eta zeta) = xi (1 - zeta)2 hspace1cm\nhatlambda_3(xi eta zeta) = eta (1 - zeta)2 hspace1cm\nhatlambda_5(xi eta zeta) = (1 - xi - eta)(1 + zeta)2 hspace1cm\nhatlambda_6(xi eta zeta) = xi (1 + zeta)2 hspace1cm\nhatlambda_7(xi eta zeta) = eta (1 + zeta)2 hspace1cm\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 1}, Triangle, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Triangle, ξ)\n\nShape functions for Triangle Lagrange element of degree 1 in a 2D space.\n\nhatlambda_1(xi eta) = 1 - xi - eta hspace1cm\nhatlambda_2(xi eta) = xi hspace1cm\nhatlambda_3(xi eta) = eta\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 2}, Triangle, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Lagrange, 2}, ::Triangle, ξ)\n\nShape functions for Triangle Lagrange element of degree 2 in a 2D space.\n\nbeginaligned\n hatlambda_1(xi eta) = (1 - xi - eta)(1 - 2 xi - 2 eta) \n hatlambda_2(xi eta) = xi (2xi - 1) \n hatlambda_3(xi eta) = eta (2eta - 1) \n hatlambda_12(xi eta) = 4 xi (1 - xi - eta) \n hatlambda_23(xi eta) = 4 xi eta \n hatlambda_31(xi eta) = 4 eta (1 - xi - eta)\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 3}, Triangle, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Lagrange, 3}, ::Triangle, ξ)\n\nShape functions for Triangle Lagrange element of degree 3 in a 2D space.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 0}, Val{1}, Square, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Lagrange, 0}, ::Val{1}, ::Square, x)\n\nGradient of shape functions for Square Lagrange element of degree 0 in a 2D space.\n\nnabla hatlambda(xi eta) =\nbeginpmatrix\n 0 0\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 0}, Val{1}, Triangle, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Lagrange, 0}, ::Val{1}, ::Triangle, ξ)\n\nGradient of shape functions for Triangle Lagrange element of degree 0 in a 2D space.\n\nnabla hatlambda(xi eta) =\nbeginpmatrix\n 0 0\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 1}, Val{1}, Triangle, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Val{1}, ::Triangle, ξ)\n\nGradient of shape functions for Triangle Lagrange element of degree 1 in a 2D space.\n\nbeginaligned\n nabla hatlambda_1(xi eta) =\n beginpmatrix\n -1 -1\n endpmatrix \n nabla hatlambda_2(xi eta) =\n beginpmatrix\n 1 0\n endpmatrix \n nabla hatlambda_3(xi eta) =\n beginpmatrix\n 0 1\n endpmatrix \nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 2}, Val{1}, Triangle, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Lagrange, 2}, ::Val{1}, ::Triangle, ξ)\n\nGradient of shape functions for Triangle Lagrange element of degree 2 in a 2D space.\n\nbeginaligned\n nabla hatlambda_1(xi eta) =\n beginpmatrix\n -3 + 4 (xi + eta) -3 + 4 (xi + eta)\n endpmatrix \n nabla hatlambda_2(xi eta) =\n beginpmatrix\n -1 + 4 xi 0\n endpmatrix \n nabla hatlambda_3(xi eta) =\n beginpmatrix\n 0 -1 + 4 eta\n endpmatrix \n nabla hatlambda_12(xi eta) =\n 4 beginpmatrix\n 1 - 2 xi - eta - xi\n endpmatrix \n nabla hatlambda_23(xi eta) =\n 4 beginpmatrix\n eta xi\n endpmatrix \n nabla hatlambda_31(xi eta) =\n 4 beginpmatrix\n - eta 1 - 2 eta - xi\n endpmatrix \nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.shape_functions-Union{Tuple{N}, Tuple{D}, Tuple{FunctionSpace{<:Bcube.Lagrange, D}, Val{N}, Bcube.AbstractShape, Any}} where {D, N}","page":"Available spaces","title":"Bcube.shape_functions","text":"Default version : the shape functions are \"replicated\". If shape_functions returns the vector [λ₁; λ₂; λ₃], and if the FESpace is of size 2, then this default behaviour consists in returning the matrix [λ₁ 0; λ₂ 0; λ₃ 0; 0 λ₁; 0 λ₂; 0 λ₃].\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Taylor","page":"Available spaces","title":"Taylor","text":"","category":"section"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"The Taylor function space corresponds to a function space where functions are approximated by a Taylor series expansion of order n in each cell:","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":" forall x in Omega_ig(x) = g(x_0) + (x - x_0) g(x_0) + o(x)","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"where x_0 is the cell center.","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Note that a Taylor-P0 is strictly equivalent to a 1st-order Finite Volume discretization (beware that \"order\" can have different meaning depending on whether one refers to the order of the function space basis or the order of the discretization method).","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Recall that any function space implies that any function g is interpolated by g(x) = sum g_i lambda_i(x) where lambda_i are the shape functions. For a Taylor expansion, the definition of lambda_i is not unique. For instance for the Taylor expansion of order 1 on a 1D line above, we may be tempted to set lambda_1(x) = 1 and lambda_2(x) = (x - x_0). If you do so, what are the corresponding shape functions in the reference element, the hatlambda_i? We immediately recover hatlambda_1(hatx) = 1. For hatlambda_2:","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":" hatlambda_2(hatx) = (lambda circ F)(hatx) = (x rightarrow x - x_0) circ (hatx rightarrow fracx_r - x_l2 hatx + fracx_r + x_l2) = fracx_r - x_l2 hatx","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"So if you set lambda_2(x) = (x - x_0) then hatlambda_2 depends on the element length (Delta x = x_r-x_l), which is pointless. So lambda_2 must be proportional to the element length to obtain a universal definition for hatlambda_2. For instance, we may choose lambda_2(x) = (x - x_0) Delta x, leading to hatlambda_2(hatx) = hatx 2. But we could have chosen an other element length multiple.","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Don't forget that choosing lambda_2(x) = (x - x_0) Delta x leads to g(x) = g(x_0) + fracx - x_0Delta x g(x_0) Δx hence g_2 = g(x_0) Δx in the interpolation.","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Modules = [Bcube]\nPages = [\"taylor.jl\"]","category":"page"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 0}, Bcube.AbstractShape, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Taylor, 0}, ::AbstractShape, x)\n\nShape functions for any Taylor element of degree 0 : hatlambda(xi) = 1\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 1}, Line, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Taylor, 1}, ::Line, ξ)\n\nShape functions for Line Taylor element of degree 1 in a 1D space.\n\nhatlambda_1(xi) = 1 hspace1cm hatlambda_1(xi) = fracxi2\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 1}, Square, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Taylor, 1}, ::Square, ξ)\n\nShape functions for Square Taylor element of degree 1 in a 2D space.\n\nbeginaligned\n hatlambda_1(xi eta) = 0 \n hatlambda_2(xi eta) = fracxi2 \n hatlambda_3(xi eta) = fraceta2\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 0}, Val{1}, Line, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Taylor, 0}, ::Line, x)\n\nGradient (=derivative) of shape functions for Line Taylor element of degree 0 in a 1D space : nabla hatlambda(xi) = 0\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 0}, Val{1}, Union{Square, Triangle}, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Taylor, 0}, ::Union{Square,Triangle}, ξ)\n\nGradient of shape functions for Square or Triangle Taylor element of degree 0 in a 2D space.\n\nhatlambda_1(xi eta) = beginpmatrix 0 0 endpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 1}, Val{1}, Line, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Taylor, 1}, ::Line, ξ)\n\nGradient (=derivative) of shape functions for Line Taylor element of degree 1 in a 1D space.\n\nnabla hatlambda_1(xi) = 0 hspace1cm nabla hatlambda_1(xi) = frac12\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 1}, Val{1}, Square, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Taylor, 1}, ::Square, ξ)\n\nGradient of shape functions for Square Taylor element of degree 1 in a 2D space.\n\nbeginaligned\n nabla hatlambda_1(xi eta) = beginpmatrix 0 0 endpmatrix \n nabla hatlambda_2(xi eta) = beginpmatrix frac12 0 endpmatrix \n nabla hatlambda_3(xi eta) = beginpmatrix 0 frac12 endpmatrix\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.shape_functions-Union{Tuple{N}, Tuple{FunctionSpace{<:Bcube.Taylor}, Val{N}, Bcube.AbstractShape, Any}} where N","page":"Available spaces","title":"Bcube.shape_functions","text":"Default version : the shape functions are \"replicated\". If shape_functions returns the vector [λ₁; λ₂; λ₃], and if the FESpace is of size 2, then this default behaviour consists in returning the matrix [λ₁ 0; λ₂ 0; λ₃ 0; 0 λ₁; 0 λ₂; 0 λ₃].\n\n\n\n\n\n","category":"method"},{"location":"example/linear_thermoelasticity/#Linear-thermo-elasticity","page":"Linear thermo-elasticity","title":"Linear thermo-elasticity","text":"","category":"section"},{"location":"example/linear_thermoelasticity/","page":"Linear thermo-elasticity","title":"Linear thermo-elasticity","text":"module linear_thermo_elasticity #hide\nprintln(\"Running linear thermo-elasticity API example...\") #hide\n\n# # Thermo-elasticity\n\nconst dir = string(@__DIR__, \"/\") # Bcube dir\nusing Bcube\nusing LinearAlgebra\nusing WriteVTK\nusing StaticArrays\n\n# function space (here we shall use Lagrange P1 elements) and quadrature degree.\nconst fspace = :Lagrange\nconst degree = 1 # FunctionSpace degree\nconst degquad = 2 * degree + 1\n\n# Input and output paths\nconst outputpath = joinpath(dir, \"../myout/elasticity/\")\nconst meshpath = joinpath(dir, \"../input/mesh/domainThermoElast_tri.msh\")\n\n# Time stepping scheme params\nconst α = 0.05\nconst γ = 0.5 + α\nconst β = 0.25 * (1.0 + α)^2\n\nconst totalTime = 10.0\nconst Δt = 1.0e-2\n\n# Material parameters (Young's modulus, Poisson coefficient and deduced Lamé coefficients)\nconst E = 200.0e9\nconst ν = 0.3\nconst λ = E * ν / ((1.0 + ν) * (1.0 - 2.0 * ν))\nconst μ = E / (2.0 * (1.0 + ν))\nconst Kₜ = 1.0e-6\nconst ρ = 2500.0\nconst cₚ = 1000.0\nconst k = 250.0\nconst T₀ = 280.0\n\n# Strain tensor and stress tensor (Hooke's law)\nϵ(u) = 0.5 * (∇(u) + transpose(∇(u)))\nσ(u) = λ * tr(ϵ(u)) * I + 2 * μ * (ϵ(u)) # Elastic stress\nσₜ(T) = (3 * λ + 2 * μ) * Kₜ * (T - T₀) * I # Thermal stress\n\nπ(u, v) = σ(u) ⊡ ϵ(v) # with the chosen contraction convention ϵ should be transposed, but as it is symmetric the expression remains correct\nπₜ(T, v) = σₜ(T) ⊡ ϵ(v)\n\n# materialize for identity operator\nBcube.materialize(A::LinearAlgebra.UniformScaling, B) = A\n\n# Function that performs a time step using a Newmark α-HHT scheme\n# The scheme updates the acceleration G, the velocity V and the displacement U using the following formulas:\n# ```math\n# \\begin{cases}\n# M G^{n+1} +(1-\\alpha)A U^{n+1} + \\alpha A U^{n} = (1-\\alpha) L^{n+1} + \\alpha L^n = L \\textrm{(because here $L$ is time independent)} \\\\\n# V^{n+1} = V^{n} + (1-\\gamma) \\Delta t G^n + \\gamma \\Delta t G^{n+1} \\\\\n# U^{n+1} = U^{n} + \\Delta t V^{n} + (\\frac{1}{2} - \\beta)*\\Delta t^2 G^{n} + \\beta \\Delta t^2 G^{n+1}\n# \\end{cases}\n# ```\n# where $$M$$ is the mass matrix, $$A$$ is the stiffness matrix and $$L$$ is the RHS\n# G is then computed by solving the linear system obtained by inserting the expressions for U and V in the equation for G.\nfunction Newmark_α_HHT(dt, L, A, Mat, U0, V0, G0)\n L1 = L - α * A * U0\n L2 = -(1.0 - α) * (A * U0 + dt * A * V0 + (0.5 - β) * dt * dt * A * G0)\n RHS = L1 .+ L2\n\n G = Mat \\ RHS\n U = U0 + dt * V0 + (0.5 - β) * dt * dt * G0 + β * dt * dt * G\n V = V0 + (1.0 - γ) * dt * G0 + γ * dt * G\n\n return U, V, G\nend\n\n# Function that runs the unsteady case:\nfunction run_unsteady()\n mesh = read_msh(meshpath, 2)\n\n fs = FunctionSpace(fspace, degree)\n U_scal = TrialFESpace(fs, mesh, Dict(\"West1\" => 280.0, \"East1\" => 280.0); size = 1)\n V_scal = TestFESpace(U_scal)\n U_vec = TrialFESpace(\n fs,\n mesh,\n Dict(\"West1\" => SA[0.0, 0.0], \"East1\" => SA[0.0, 0.0]);\n size = 2,\n )\n V_vec = TestFESpace(U_vec)\n\n # Initialize solution\n U = FEFunction(U_vec, 0.0)\n U0 = zeros(Bcube.get_ndofs(U_vec))\n V0 = zeros(Bcube.get_ndofs(U_vec))\n G0 = zeros(Bcube.get_ndofs(U_vec))\n\n T = FEFunction(U_scal, T₀)\n\n # Define measures for cell\n dΩ = Measure(CellDomain(mesh), degquad)\n\n # no volume force term\n f = PhysicalFunction(x -> SA[0.0, 0.0])\n\n q = PhysicalFunction(\n x -> x[1] .* (1.0 .- x[1]) .* x[2] .* (0.2 .- x[2]) .* 1500000000.0,\n )\n\n # Definition of bilinear and linear forms for the elasticity problem\n a(u, v) = ∫(π(u, v))dΩ\n m(u, v) = ∫(ρ * u ⋅ v)dΩ\n l(v) = ∫(πₜ(T, v))dΩ\n\n # An alternative way to define this linear form is to use operator composition:\n # l(v) = ∫( πₜ ∘ (T, v, ∇(v)) )dΩ\n # where πₜ(T, v, ∇v) = σₜ(T) ⊡ ϵ(v, ∇v) and ϵ(v, ∇v) = 0.5*( ∇v + transpose(∇v) )\n\n # Definition of bilinear and linear forms for the heat conduction problem\n aₜ(u, v) = ∫(k * ∇(u) ⋅ ∇(v))dΩ\n mₜ(u, v) = ∫(ρ * cₚ * u ⋅ v)dΩ\n lₜ(v) = ∫(q * v)dΩ\n\n # Assemble matrices and vector\n M = assemble_bilinear(m, U_vec, V_vec)\n A = assemble_bilinear(a, U_vec, V_vec)\n L = assemble_linear(l, V_vec)\n AT = assemble_bilinear(aₜ, U_scal, V_scal)\n MT = assemble_bilinear(mₜ, U_scal, V_scal)\n LT = assemble_linear(lₜ, V_scal)\n\n # Apply homogeneous dirichlet on A and b\n Bcube.apply_homogeneous_dirichlet_to_vector!(L, U_vec, V_vec, mesh)\n Bcube.apply_dirichlet_to_matrix!((A, M), U_vec, V_vec, mesh)\n\n # Compute a vector of dofs whose values are zeros everywhere\n # except on dofs lying on a Dirichlet boundary, where they\n # take the Dirichlet value\n Td = Bcube.assemble_dirichlet_vector(U_scal, V_scal, mesh)\n\n # Apply lift\n LT = LT - AT * Td\n\n # Apply homogeneous dirichlet condition\n Bcube.apply_homogeneous_dirichlet_to_vector!(LT, U_scal, V_scal, mesh)\n Bcube.apply_dirichlet_to_matrix!((AT, MT), U_scal, V_scal, mesh)\n\n # Write initial solution\n Un = var_on_vertices(U, mesh)\n Un = transpose(Un)\n Tn = var_on_vertices(T, mesh)\n mkpath(outputpath)\n dict_vars =\n Dict(\"Displacement\" => (Un, VTKPointData()), \"Temperature\" => (Tn, VTKPointData()))\n # Write the obtained FE solution\n write_vtk(\n outputpath * \"result_thermoelasticity\",\n 0,\n 0.0,\n mesh,\n dict_vars;\n append = false,\n )\n\n # Time loop\n itime = 0\n t = 0.0\n\n # Matrix for time stepping\n Mat = factorize(M + (1.0 - α) * (β * Δt * Δt * A))\n Miter = factorize(MT + Δt * AT)\n\n while t <= totalTime\n t += Δt\n itime = itime + 1\n @show t, itime\n\n # solve time step heat equation\n rhs = Δt * LT + MT * (get_dof_values(T) .- Td)\n set_dof_values!(T, Miter \\ rhs .+ Td)\n\n # solve time step elasticity\n U1, V1, G1 = Newmark_α_HHT(Δt, L, A, Mat, U0, V0, G0)\n\n # Update solution\n U0 .= U1\n V0 .= V1\n G0 .= G1\n\n set_dof_values!(U, U1)\n L = assemble_linear(l, V_vec)\n Bcube.apply_homogeneous_dirichlet_to_vector!(L, U_vec, V_vec, mesh)\n\n # Write solution\n if itime % 10 == 0\n Un = var_on_vertices(U, mesh)\n Un = transpose(Un)\n Tn = var_on_vertices(T, mesh)\n mkpath(outputpath)\n dict_vars = Dict(\n \"Displacement\" => (Un, VTKPointData()),\n \"Temperature\" => (Tn, VTKPointData()),\n )\n # Write the obtained FE solution\n write_vtk(\n outputpath * \"result_thermoelasticity\",\n itime,\n t,\n mesh,\n dict_vars;\n append = true,\n )\n # In order to use the warp function in paraview (solid is deformed using the displacement field)\n # the calculator filter has to be used with the following formula to reconstruct a 3D displacement field\n # with 0 z-component: Displacement_X*iHat+Displacement_Y*jHat+0.0*kHat\n end\n end\nend\n\nrun_unsteady()\n\n# Here is an animation of the obtained result:\n# ```@raw html\n# \"drawing\"\n# ```\n\nend #hide","category":"page"},{"location":"manual/function_space/#Function-and-FE-spaces","page":"Function and FE spaces","title":"Function and FE spaces","text":"","category":"section"},{"location":"manual/function_space/#AbstractFunctionSpace","page":"Function and FE spaces","title":"AbstractFunctionSpace","text":"","category":"section"},{"location":"manual/function_space/","page":"Function and FE spaces","title":"Function and FE spaces","text":"In Bcube, a FunctionSpace is defined by a type (nodal Lagrange polynomials, modal Taylor expansion, etc) and a degree. For each implemented FunctionSpace, a list of shape functions is associated on a given Shape. For instance, one can get the shape functions associated to the Lagrange polynomials or order 3 on a Square. Note that for \"tensor\" elements such as Line, Square or Cube; the Lagrange polynomials are available at any order; being computed symbolically.","category":"page"},{"location":"manual/function_space/#AbstractFESpace","page":"Function and FE spaces","title":"AbstractFESpace","text":"","category":"section"},{"location":"manual/function_space/","page":"Function and FE spaces","title":"Function and FE spaces","text":"Then, an FESpace (more precisely SingleFESpace) is a function space associated to a numbering of the degrees of freedom. Note that the numbering may depend on the continuous or discontinuous feature of the space. Hence a SingleFESpace takes basically four input to be built : a FunctionSpace, the number of components of this space (scalar or vector), an indicator of the continuous/discontinuous characteristic, and the mesh. The dof numbering is built by combining the mesh numberings (nodes, cells, faces) and the function space. Note that the degree of the FunctionSpace can differ from the \"degree\" of the mesh elements : it is possible to build a SingleFESpace with P2 polynomials on a mesh only containing straight lines (defined by only two nodes, Bar2_t). Optionaly, a SingleFESpace can also contain the tags of the boundaries where Dirichlet condition(s) applies. A MultiFESpace is simply a set of SingleFESpace, eventually of different natures. Its befenit is that it allows to build a \"global\" numbering of all the dofs represented by this space. This is especially convenient to solve systems of equations.","category":"page"},{"location":"manual/function_space/#AbstractFEFunction","page":"Function and FE spaces","title":"AbstractFEFunction","text":"","category":"section"},{"location":"manual/function_space/","page":"Function and FE spaces","title":"Function and FE spaces","text":"With a SingleFESpace, one can build the representation of a function discretized on this space: a FEFunction. This structure stores a vector of values, one for each degree of freedom of the finite element space. To set or get the values of a FEFunction, the functions set_dof_values! and get_dof_values are available respectively. A FEFunction can be projected on another FESpace; or evaluated at some specific mesh location (a coordinates, all the nodes, all the mesh centers, etc).","category":"page"},{"location":"tutorial/heat_equation/#Heat-equation-(FE)","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"","category":"section"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"In this tutorial, the heat equation (first steady and then unsteady) is solved using finite-elements.","category":"page"},{"location":"tutorial/heat_equation/#Theory","page":"Heat equation (FE)","title":"Theory","text":"","category":"section"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"This example shows how to solve the heat equation with eventually variable physical properties in steady and unsteady formulations:","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":" rho C_p partial_t u - nabla ( lambda u) = f","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"We shall assume that f rho C_p lambda in L^2(Omega). The weak form of the problem is given by: find $ u \\in \\tilde{H}^1_0(\\Omega)$ (there will be at least one Dirichlet boundary condition) such that:","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":" forall v in tildeH^1_0(Omega) underbraceint_Omega partial_t u v dx_m(partial_t uv) + underbraceint_Omega nabla u nabla v dx_a(uv) = underbraceint_Omega f v dx_l(v)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"To numerically solve this problem we seek an approximate solution using Lagrange P^1 or P^2 elements. Here we assume that the domain can be split into two domains having different material properties.","category":"page"},{"location":"tutorial/heat_equation/#Steady-case","page":"Heat equation (FE)","title":"Steady case","text":"","category":"section"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"As usual, start by importing the necessary packages.","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"using Bcube\nusing LinearAlgebra\nusing WriteVTK","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"First we define some physical and numerical constants","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"const htc = 100.0 # Heat transfer coefficient (bnd cdt)\nconst Tr = 268.0 # Recovery temperature (bnd cdt)\nconst phi = 100.0\nconst q = 1500.0\nconst λ = 100.0\nconst η = λ\nconst ρCp = 100.0 * 200.0\nconst degree = 2\nconst outputpath = joinpath(@__DIR__, \"../myout/heat_equation/\")","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Read 2D mesh","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"mesh_path = joinpath(@__DIR__, \"../input/mesh/domainSquare_tri.msh\")\nmesh = read_msh(mesh_path)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Build function space and associated Trial and Test FE spaces. We impose a Dirichlet condition with a temperature of 260K on boundary \"West\"","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"fs = FunctionSpace(:Lagrange, degree)\nU = TrialFESpace(fs, mesh, Dict(\"West\" => 260.0))\nV = TestFESpace(U)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Define measures for cell integration","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"dΩ = Measure(CellDomain(mesh), 2 * degree + 1)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Define bilinear and linear forms","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"a(u, v) = ∫(η * ∇(u) ⋅ ∇(v))dΩ\nl(v) = ∫(q * v)dΩ","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Create an affine FE system and solve it using the AffineFESystem structure. The package LinearSolve is used behind the scenes, so different solver may be used to invert the system (ex: solve(...; alg = IterativeSolversJL_GMRES())) The result is a FEFunction (ϕ). We can interpolate it on mesh centers : the result is named Tcn.","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"sys = AffineFESystem(a, l, U, V)\nϕ = solve(sys)\nTcn = var_on_centers(ϕ, mesh)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Compute analytical solution for comparison. Apply the analytical solution on mesh centers","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"T_analytical = x -> 260.0 + (q / λ) * x[1] * (1.0 - 0.5 * x[1])\nTca = map(T_analytical, get_cell_centers(mesh))","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Write both the obtained FE solution and the analytical solution to a vtk file.","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"mkpath(outputpath)\ndict_vars =\n Dict(\"Temperature\" => (Tcn, VTKCellData()), \"Temperature_a\" => (Tca, VTKCellData()))\nwrite_vtk(outputpath * \"result_steady_heat_equation\", 0, 0.0, mesh, dict_vars)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Compute and display the error","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"@show norm(Tcn .- Tca, Inf) / norm(Tca, Inf)","category":"page"},{"location":"tutorial/heat_equation/#Unsteady-case","page":"Heat equation (FE)","title":"Unsteady case","text":"","category":"section"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"The code for the unsteady case if of course very similar to the steady case, at least for the beginning. Start by defining two additional parameters:","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"totalTime = 100.0\nΔt = 0.1","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Read a slightly different mesh","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"mesh_path = joinpath(@__DIR__, \"../input/mesh/domainSquare_tri_2.msh\")\nmesh = read_msh(mesh_path)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"The rest is similar to the steady case","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"fs = FunctionSpace(:Lagrange, degree)\nU = TrialFESpace(fs, mesh, Dict(\"West\" => 260.0))\nV = TestFESpace(U)\ndΩ = Measure(CellDomain(mesh), 2 * degree + 1)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Compute matrices associated to bilinear and linear forms, and assemble","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"a(u, v) = ∫(η * ∇(u) ⋅ ∇(v))dΩ\nm(u, v) = ∫(ρCp * u ⋅ v)dΩ\nl(v) = ∫(q * v)dΩ\n\nA = assemble_bilinear(a, U, V)\nM = assemble_bilinear(m, U, V)\nL = assemble_linear(l, V)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Compute a vector of dofs whose values are zeros everywhere except on dofs lying on a Dirichlet boundary, where they take the Dirichlet value","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Ud = assemble_dirichlet_vector(U, V, mesh)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Apply lift","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"L = L - A * Ud","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Apply homogeneous dirichlet condition","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"apply_homogeneous_dirichlet_to_vector!(L, U, V, mesh)\napply_dirichlet_to_matrix!((A, M), U, V, mesh)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Form time iteration matrix (note that this is bad for performance since up to now, M and A are sparse matrices)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Miter = factorize(M + Δt * A)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Init the solution with a constant temperature of 260K","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"ϕ = FEFunction(U, 260.0)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Write initial solution to a file","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"mkpath(outputpath)\ndict_vars = Dict(\"Temperature\" => (var_on_centers(ϕ, mesh), VTKCellData()))\nwrite_vtk(outputpath * \"result_unsteady_heat_equation\", 0, 0.0, mesh, dict_vars)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Time loop","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"itime = 0\nt = 0.0\nwhile t <= totalTime\n global t, itime\n t += Δt\n itime = itime + 1\n @show t, itime\n\n # Compute rhs\n rhs = Δt * L + M * (get_dof_values(ϕ) .- Ud)\n\n # Invert system and apply inverse shift\n set_dof_values!(ϕ, Miter \\ rhs .+ Ud)\n\n # Write solution (every 10 iterations)\n if itime % 10 == 0\n dict_vars = Dict(\"Temperature\" => (var_on_centers(ϕ, mesh), VTKCellData()))\n write_vtk(\n outputpath * \"result_unsteady_heat_equation\",\n itime,\n t,\n mesh,\n dict_vars;\n append = true,\n )\n end\nend\n","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"This page was generated using Literate.jl.","category":"page"},{"location":"example/covo/#Euler-equations-covo","page":"Euler equations - covo","title":"Euler equations - covo","text":"","category":"section"},{"location":"example/covo/","page":"Euler equations - covo","title":"Euler equations - covo","text":"module Covo #hide\nprintln(\"Running covo example...\") #hide\n\nconst dir = string(@__DIR__, \"/\")\nusing Bcube\nusing LinearAlgebra\nusing StaticArrays\nusing WriteVTK # only for 'VTKCellData'\nusing Profile\nusing StaticArrays\nusing InteractiveUtils\nusing BenchmarkTools\nusing UnPack\n\nfunction compute_residual(_u, V, params, cache)\n u = get_fe_functions(_u)\n\n # alias on measures\n @unpack dΩ, dΓ, dΓ_perio_x, dΓ_perio_y = params\n\n # face normals for each face domain (lazy, no computation at this step)\n nΓ = get_face_normals(dΓ)\n nΓ_perio_x = get_face_normals(dΓ_perio_x)\n nΓ_perio_y = get_face_normals(dΓ_perio_y)\n\n # flux residuals from faces for all variables\n function l(v)\n ∫(flux_Ω(u, v))dΩ +\n -∫(flux_Γ(u, v, nΓ))dΓ +\n -∫(flux_Γ(u, v, nΓ_perio_x))dΓ_perio_x +\n -∫(flux_Γ(u, v, nΓ_perio_y))dΓ_perio_y\n end\n\n rhs = assemble_linear(l, V)\n\n return cache.mass \\ rhs\nend\n\n\"\"\"\n flux_Ω(u, v)\n\nCompute volume residual using the lazy-operators approach\n\"\"\"\nflux_Ω(u, v) = _flux_Ω ∘ cellvar(u, v)\ncellvar(u, v) = (u, map(∇, v))\nfunction _flux_Ω(u, ∇v)\n ρ, ρu, ρE, ϕ = u\n ∇λ_ρ, ∇λ_ρu, ∇λ_ρE, ∇λ_ϕ = ∇v\n\n vel = ρu ./ ρ\n ρuu = ρu * transpose(vel)\n p = pressure(ρ, ρu, ρE, γ)\n\n flux_ρ = ρu\n flux_ρu = ρuu + p * I\n flux_ρE = (ρE + p) .* vel\n flux_ϕ = ϕ .* vel\n\n return ∇λ_ρ ⋅ flux_ρ + ∇λ_ρu ⊡ flux_ρu + ∇λ_ρE ⋅ flux_ρE + ∇λ_ϕ ⋅ flux_ϕ\nend\n\n\"\"\"\n flux_Γ(u,v,n)\n\nFlux at the interface is defined by a composition of two functions:\n* facevar(u,v,n) defines the input states which are needed for\n the riemann flux using operator notations\n* flux_roe(w) defines the Riemann flux (as usual)\n\"\"\"\nflux_Γ(u, v, n) = flux_roe ∘ (side⁻(u), side⁺(u), jump(v), side⁻(n))\n\n\"\"\"\n flux_roe(w)\n\"\"\"\nfunction flux_roe(ui, uj, δv, nij)\n # destructuring inputs given by `facevar` function\n\n nx, ny = nij\n ρ1, ρu1, ρE1, ϕ1 = ui\n ρ2, ρu2, ρE2, ϕ2 = uj\n δλ_ρ1, δλ_ρu1, δλ_ρE1, δλ_ϕ1 = δv\n ρux1, ρuy1 = ρu1\n ρux2, ρuy2 = ρu2\n\n # Closure\n u1 = ρux1 / ρ1\n v1 = ρuy1 / ρ1\n u2 = ρux2 / ρ2\n v2 = ρuy2 / ρ2\n p1 = pressure(ρ1, ρu1, ρE1, γ)\n p2 = pressure(ρ2, ρu2, ρE2, γ)\n\n H2 = (γ / (γ - 1)) * p2 / ρ2 + (u2 * u2 + v2 * v2) / 2.0\n H1 = (γ / (γ - 1)) * p1 / ρ1 + (u1 * u1 + v1 * v1) / 2.0\n\n R = √(ρ1 / ρ2)\n invR1 = 1.0 / (R + 1)\n uAv = (R * u1 + u2) * invR1\n vAv = (R * v1 + v2) * invR1\n Hav = (R * H1 + H2) * invR1\n cAv = √(abs((γ - 1) * (Hav - (uAv * uAv + vAv * vAv) / 2.0)))\n ecAv = (uAv * uAv + vAv * vAv) / 2.0\n\n λ1 = nx * uAv + ny * vAv\n λ3 = λ1 + cAv\n λ4 = λ1 - cAv\n\n d1 = ρ1 - ρ2\n d2 = ρ1 * u1 - ρ2 * u2\n d3 = ρ1 * v1 - ρ2 * v2\n d4 = ρE1 - ρE2\n\n # computation of the centered part of the flux\n flu11 = nx * ρ2 * u2 + ny * ρ2 * v2\n flu21 = nx * p2 + flu11 * u2\n flu31 = ny * p2 + flu11 * v2\n flu41 = H2 * flu11\n\n # Temp variables\n rc1 = (γ - 1) / cAv\n rc2 = (γ - 1) / cAv / cAv\n uq41 = ecAv / cAv + cAv / (γ - 1)\n uq42 = nx * uAv + ny * vAv\n\n fdc1 = max(λ1, 0.0) * (d1 + rc2 * (-ecAv * d1 + uAv * d2 + vAv * d3 - d4))\n fdc2 = max(λ1, 0.0) * ((nx * vAv - ny * uAv) * d1 + ny * d2 - nx * d3)\n fdc3 =\n max(λ3, 0.0) * (\n (-uq42 * d1 + nx * d2 + ny * d3) / 2.0 +\n rc1 * (ecAv * d1 - uAv * d2 - vAv * d3 + d4) / 2.0\n )\n fdc4 =\n max(λ4, 0.0) * (\n (uq42 * d1 - nx * d2 - ny * d3) / 2.0 +\n rc1 * (ecAv * d1 - uAv * d2 - vAv * d3 + d4) / 2.0\n )\n\n duv1 = fdc1 + (fdc3 + fdc4) / cAv\n duv2 = uAv * fdc1 + ny * fdc2 + (uAv / cAv + nx) * fdc3 + (uAv / cAv - nx) * fdc4\n duv3 = vAv * fdc1 - nx * fdc2 + (vAv / cAv + ny) * fdc3 + (vAv / cAv - ny) * fdc4\n duv4 =\n ecAv * fdc1 +\n (ny * uAv - nx * vAv) * fdc2 +\n (uq41 + uq42) * fdc3 +\n (uq41 - uq42) * fdc4\n\n v₁₂ = 0.5 * ((u1 + u2) * nx + (v1 + v2) * ny)\n fluxϕ = max(0.0, v₁₂) * ϕ1 + min(0.0, v₁₂) * ϕ2\n\n return (\n δλ_ρ1 * (flu11 + duv1) +\n δλ_ρu1 ⋅ (SA[flu21 + duv2, flu31 + duv3]) +\n δλ_ρE1 * (flu41 + duv4) +\n δλ_ϕ1 * (fluxϕ)\n )\nend\n\n\"\"\"\nTime integration of `f(q, t)` over a timestep `Δt`.\n\"\"\"\nforward_euler(q, f::Function, t, Δt) = get_dof_values(q) .+ Δt .* f(q, t)\n\n\"\"\"\n rk3_ssp(q, f::Function, t, Δt)\n\n`f(q, t)` is the function to integrate.\n\"\"\"\nfunction rk3_ssp(q, f::Function, t, Δt)\n stepper(q, t) = forward_euler(q, f, t, Δt)\n _q0 = get_dof_values(q)\n\n _q1 = stepper(q, Δt)\n\n set_dof_values!(q, _q1)\n _q2 = (3 / 4) .* _q0 .+ (1 / 4) .* stepper(q, t + Δt)\n\n set_dof_values!(q, _q2)\n _q1 .= (1 / 3) * _q0 .+ (2 / 3) .* stepper(q, t + Δt / 2)\n\n return _q1\nend\n\n\"\"\"\n pressure(ρ, ρu, ρE, γ)\n\nComputes pressure from perfect gaz law\n\"\"\"\nfunction pressure(ρ::Number, ρu::AbstractVector, ρE::Number, γ)\n vel = ρu ./ ρ\n ρuu = ρu * transpose(vel)\n p = (γ - 1) * (ρE - tr(ρuu) / 2)\n return p\nend\n\n\"\"\"\n Init field with a vortex (for the COVO test case)\n\"\"\"\nfunction covo!(q, dΩ)\n\n # Intermediate vars\n Cₚ = γ * r / (γ - 1)\n\n r²(x) = ((x[1] .- xvc) .^ 2 + (x[2] .- yvc) .^ 2) ./ Rc^2\n # Temperature\n T(x) = T₀ .- β^2 * U₀^2 / (2 * Cₚ) .* exp.(-r²(x))\n # Velocity\n ux(x) = U₀ .- β * U₀ / Rc .* (x[2] .- yvc) .* exp.(-r²(x) ./ 2)\n uy(x) = V₀ .+ β * U₀ / Rc .* (x[1] .- xvc) .* exp.(-r²(x) ./ 2)\n # Density\n ρ(x) = ρ₀ .* (T(x) ./ T₀) .^ (1.0 / (γ - 1))\n # momentum\n ρu(x) = SA[ρ(x) * ux(x), ρ(x) * uy(x)]\n # Energy\n ρE(x) = ρ(x) * ((Cₚ / γ) .* T(x) + (ux(x) .^ 2 + uy(x) .^ 2) ./ 2)\n # Passive scalar\n ϕ(x) = Rc^2 * r²(x) < 0.01 ? exp(-r²(x) ./ 2) : 0.0\n\n f = map(PhysicalFunction, (ρ, ρu, ρE, ϕ))\n projection_l2!(q, f, dΩ)\n return nothing\nend\n\n\"\"\"\n Tiny struct to ease the VTK output\n\"\"\"\nmutable struct VtkHandler\n basename::Any\n ite::Any\n VtkHandler(basename) = new(basename, 0)\nend\n\n\"\"\"\n Write solution to vtk\n Wrapper for `write_vtk`\n\"\"\"\nfunction append_vtk(vtk, mesh, vars, t, params)\n ρ, ρu, ρE, ϕ = vars\n\n mesh_degree = 1\n vtk_degree = maximum(x -> get_degree(Bcube.get_function_space(get_fespace(x))), vars)\n vtk_degree = max(1, mesh_degree, vtk_degree)\n\n _ρ = var_on_nodes_discontinuous(ρ, mesh, vtk_degree)\n _ρu = var_on_nodes_discontinuous(ρu, mesh, vtk_degree)\n _ρE = var_on_nodes_discontinuous(ρE, mesh, vtk_degree)\n _ϕ = var_on_nodes_discontinuous(ϕ, mesh, vtk_degree)\n\n _p = pressure.(_ρ, _ρu, _ρE, γ)\n dict_vars_dg = Dict(\n \"rho\" => (_ρ, VTKPointData()),\n \"rhou\" => (_ρu, VTKPointData()),\n \"rhoE\" => (_ρE, VTKPointData()),\n \"phi\" => (_ϕ, VTKPointData()),\n \"p\" => (_p, VTKPointData()),\n )\n Bcube.write_vtk_discontinuous(\n vtk.basename * \"_DG\",\n vtk.ite,\n t,\n mesh,\n dict_vars_dg,\n vtk_degree;\n append = vtk.ite > 0,\n )\n\n # Update counter\n vtk.ite += 1\nend\n\n# Settings\nif get(ENV, \"BenchmarkMode\", \"false\") == \"false\" #hide\n const cellfactor = 1\n const nx = 32 * cellfactor + 1\n const ny = 32 * cellfactor + 1\n const fspace = :Lagrange\n const timeScheme = :ForwardEuler\nelse #hide\n const nx = 128 + 1 #hide\n const ny = 128 + 1 #hide\n const fspace = :Lagrange\n const timeScheme = :ForwardEuler\nend #hide\nconst nperiod = 1 # number of turn\nconst CFL = 0.1\nconst degree = 1 # FunctionSpace degree\nconst degquad = 2 * degree + 1\nconst γ = 1.4\nconst β = 0.2 # vortex intensity\nconst r = 287.15 # Perfect gaz constant\nconst T₀ = 300 # mean-flow temperature\nconst P₀ = 1e5 # mean-flow pressure\nconst M₀ = 0.5 # mean-flow mach number\nconst ρ₀ = 1.0 # mean-flow density\nconst xvc = 0.0 # x-center of vortex\nconst yvc = 0.0 # y-center of vortex\nconst Rc = 0.005 # Charasteristic vortex radius\nconst c₀ = √(γ * r * T₀) # Sound velocity\nconst U₀ = M₀ * c₀ # mean-flow velocity\nconst V₀ = 0.0 # mean-flow velocity\nconst ϕ₀ = 1.0\nconst l = 0.05 # half-width of the domain\nconst Δt = CFL * 2 * l / (nx - 1) / ((1 + β) * U₀ + c₀) / (2 * degree + 1)\n#const Δt = 5.e-7\nconst nout = 100 # Number of time steps to save\nconst outputpath = \"../myout/covo/\"\nconst output = joinpath(@__DIR__, outputpath, \"covo_deg$degree\")\nconst nite = Int(floor(nperiod * 2 * l / (U₀ * Δt))) + 1\n\nfunction run_covo()\n println(\"Starting run_covo...\")\n\n # Build mesh\n meshParam = (nx = nx, ny = ny, lx = 2l, ly = 2l, xc = 0.0, yc = 0.0)\n tmp_path = \"tmp.msh\"\n if get(ENV, \"BenchmarkMode\", \"false\") == \"false\" #hide\n gen_rectangle_mesh(tmp_path, :quad; meshParam...)\n else #hide\n if get(ENV, \"MeshConfig\", \"quad\") == \"triquad\" #hide\n gen_rectangle_mesh_with_tri_and_quad(tmp_path; meshParam...) #hide\n else #hide\n gen_rectangle_mesh(tmp_path, :quad; meshParam...) #hide\n end #hide\n end #hide\n mesh = read_msh(tmp_path)\n rm(tmp_path)\n\n # Define variables and test functions\n fs = FunctionSpace(fspace, degree)\n U_sca = TrialFESpace(fs, mesh, :discontinuous; size = 1) # DG, scalar\n U_vec = TrialFESpace(fs, mesh, :discontinuous; size = 2) # DG, vectoriel\n V_sca = TestFESpace(U_sca)\n V_vec = TestFESpace(U_vec)\n U = MultiFESpace(U_sca, U_vec, U_sca, U_sca)\n V = MultiFESpace(V_sca, V_vec, V_sca, V_sca)\n u = FEFunction(U)\n\n @show Bcube.get_ndofs(U)\n\n # Define measures for cell and interior face integrations\n dΩ = Measure(CellDomain(mesh), degquad)\n dΓ = Measure(InteriorFaceDomain(mesh), degquad)\n\n # Declare periodic boundary conditions and\n # create associated domains and measures\n periodicBCType_x = PeriodicBCType(Translation(SA[-2l, 0.0]), (\"East\",), (\"West\",))\n periodicBCType_y = PeriodicBCType(Translation(SA[0.0, 2l]), (\"South\",), (\"North\",))\n Γ_perio_x = BoundaryFaceDomain(mesh, periodicBCType_x)\n Γ_perio_y = BoundaryFaceDomain(mesh, periodicBCType_y)\n dΓ_perio_x = Measure(Γ_perio_x, degquad)\n dΓ_perio_y = Measure(Γ_perio_y, degquad)\n\n params = (dΩ = dΩ, dΓ = dΓ, dΓ_perio_x = dΓ_perio_x, dΓ_perio_y = dΓ_perio_y)\n\n # Init vtk\n isdir(joinpath(@__DIR__, outputpath)) || mkpath(joinpath(@__DIR__, outputpath))\n vtk = VtkHandler(output)\n\n # Init solution\n t = 0.0\n\n covo!(u, dΩ)\n\n # cache mass matrices\n cache = (mass = factorize(Bcube.build_mass_matrix(U, V, dΩ)),)\n\n if get(ENV, \"BenchmarkMode\", \"false\") == \"true\" #hide\n return u, U, V, params, cache\n end\n\n # Write initial solution\n append_vtk(vtk, mesh, u, t, params)\n\n # Time loop\n for i in 1:nite\n println(\"\")\n println(\"\")\n println(\"Iteration \", i, \" / \", nite)\n\n ## Step forward in time\n rhs(u, t) = compute_residual(u, V, params, cache)\n if timeScheme == :ForwardEuler\n unew = forward_euler(u, rhs, time, Δt)\n elseif timeScheme == :RK3\n unew = rk3_ssp(u, rhs, time, Δt)\n else\n error(\"Unknown time scheme: $timeScheme\")\n end\n\n set_dof_values!(u, unew)\n\n t += Δt\n\n # Write solution to file\n if (i % Int(max(floor(nite / nout), 1)) == 0)\n println(\"--> VTK export\")\n append_vtk(vtk, mesh, u, t, params)\n end\n end\n\n # Summary and benchmark # ndofs total = 20480\n _rhs(u, t) = compute_residual(u, V, params, cache)\n @btime forward_euler($u, $_rhs, $time, $Δt) # 5.639 ms (1574 allocations: 2.08 MiB)\n # stepper = w -> explicit_step(w, params, cache, Δt)\n # RK3_SSP(stepper, (u, v), cache)\n # @btime RK3_SSP($stepper, ($u, $v), $cache)\n println(\"ndofs total = \", Bcube.get_ndofs(U))\n Profile.init(; n = 10^7) # returns the current settings\n Profile.clear()\n Profile.clear_malloc_data()\n @profile begin\n for i in 1:100\n forward_euler(u, _rhs, time, Δt)\n end\n end\n @show Δt, U₀, U₀ * t\n @show boundary_names(mesh)\n return nothing\nend\n\nif get(ENV, \"BenchmarkMode\", \"false\") == \"false\"\n mkpath(outputpath)\n run_covo()\nend\n\nend #hide","category":"page"},{"location":"tutorial/linear_transport/#Linear-transport-(DG)","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"","category":"section"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"In this tutorial, we show how to solve a linear transport equation using a discontinuous-Galerkin framework with Bcube.","category":"page"},{"location":"tutorial/linear_transport/#Theory","page":"Linear transport (DG)","title":"Theory","text":"","category":"section"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"In this example, we solve the following linear transport equation using discontinuous elements:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"fracpartial phipartial t + nabla cdot (c phi) = 0","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"where c is a constant velocity. Using an explicit time scheme, one obtains:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"phi^n+1 = phi^n - Delta t nabla cdot (c phi^n)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"The corresponding weak form of this equation is:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"int_Omega phi^n+1 v mathrmdOmega = int_Omega phi^n v mathrmdOmega + Delta t left\nint_Omega c phi^n cdot nabla v mathrmdOmega - oint_Gamma left( c phi cdot n right) v mathrmdGamma\nright","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"where Gamma = delta Omega. Adopting the discontinuous Galerkin framework, this equation is written in every mesh cell Omega_i. The cell boundary term involves discontinuous quantities and is replaced by a \"numerical flux\", leading to the expression:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"int_Omega_i phi^n+1 v mathrmdOmega_i = int_Omega_i phi^n v mathrmdOmega_i + Delta t left\nint_Omega_i c phi^n cdot nabla v mathrmdOmega_i - oint_Gamma_i F^*(phi) v mathrmd Gamma_i\nright","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"For this example, an upwind flux will be used for F^*. Using a matrix formulation, the above equation can be written as:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"phi^n+1 = phi^n + M^-1(f_Omega - f_Gamma)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"where M^-1 is the inverse of the mass matrix, f_Omega the volumic flux term and f_Gamma the surfacic flux term.","category":"page"},{"location":"tutorial/linear_transport/#Commented-code","page":"Linear transport (DG)","title":"Commented code","text":"","category":"section"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Start by importing the necessary packages: Load the necessary packages","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"using Bcube\nusing LinearAlgebra\nusing WriteVTK","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Before all, to ease to ease the solution VTK output we will write a structure to store the vtk filename and the number of iteration; and a function that exports the solution on demand. Note the use of var_on_nodes_discontinuous to export the solution on the mesh nodes, respecting the discontinuous feature of the solution.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"mutable struct VtkHandler\n basename::Any\n ite::Any\n mesh::Any\n VtkHandler(basename, mesh) = new(basename, 0, mesh)\nend\n\nfunction append_vtk(vtk, u::Bcube.AbstractFEFunction, t)\n # Values on center\n values = var_on_nodes_discontinuous(u, vtk.mesh)\n\n # Write\n Bcube.write_vtk_discontinuous(\n vtk.basename,\n vtk.ite,\n t,\n vtk.mesh,\n Dict(\"u\" => (values, VTKPointData())),\n 1;\n append = vtk.ite > 0,\n )\n\n # Update counter\n vtk.ite += 1\nend","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"First, we define some physical and numerical constant parameters","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"const degree = 0 # Function-space degree (Taylor(0) = first order Finite Volume)\nconst c = [1.0, 0.0] # Convection velocity (must be a vector)\nconst nite = 100 # Number of time iteration(s)\nconst CFL = 1 # 0.1 for degree 1\nconst nx = 41 # Number of nodes in the x-direction\nconst ny = 41 # Number of nodes in the y-direction\nconst lx = 2.0 # Domain width\nconst ly = 2.0 # Domain height\nconst Δt = CFL * min(lx / nx, ly / ny) / norm(c) # Time step","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Then generate the mesh of a rectangle using Gmsh and read it","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"tmp_path = \"tmp.msh\"\ngen_rectangle_mesh(tmp_path, :quad; nx = nx, ny = ny, lx = lx, ly = ly, xc = 0.0, yc = 0.0)\nmesh = read_msh(tmp_path)\nrm(tmp_path)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"We can now init our VtkHandler","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"out_dir = joinpath(@__DIR__, \"../myout\")\nvtk = VtkHandler(joinpath(out_dir, \"linear_transport\"), mesh)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"As seen in the previous tutorial, the definition of trial and test spaces needs a mesh and a function space. Here, we select Taylor space, and build discontinuous FE spaces with it. Then an FEFunction, that will represent our solution, is created.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"fs = FunctionSpace(:Taylor, degree)\nU = TrialFESpace(fs, mesh, :discontinuous)\nV = TestFESpace(U)\nu = FEFunction(U)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Define measures for cell and interior face integrations","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Γ = InteriorFaceDomain(mesh)\nΓ_in = BoundaryFaceDomain(mesh, \"West\")\nΓ_out = BoundaryFaceDomain(mesh, (\"North\", \"East\", \"South\"))\n\ndΩ = Measure(CellDomain(mesh), 2 * degree + 1)\ndΓ = Measure(Γ, 2 * degree + 1)\ndΓ_in = Measure(Γ_in, 2 * degree + 1)\ndΓ_out = Measure(Γ_out, 2 * degree + 1)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"We will also need the face normals associated to the different face domains. Note that this operation is lazy, nΓ is just an abstract representation on face normals of Γ.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"nΓ = get_face_normals(Γ)\nnΓ_in = get_face_normals(Γ_in)\nnΓ_out = get_face_normals(Γ_out)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Let's move on to the bilinear and linear forms. First, the two easiest ones:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"m(u, v) = ∫(u ⋅ v)dΩ # Mass matrix\nl_Ω(v) = ∫((c * u) ⋅ ∇(v))dΩ # Volumic convective term","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"For the flux term, we first need to define a numerical flux. It is convenient to define it separately in a dedicated function. Here is the definition of simple upwind flux.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"function upwind(ui, uj, nij)\n cij = c ⋅ nij\n if cij > zero(cij)\n flux = cij * ui\n else\n flux = cij * uj\n end\n flux\nend","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"We then define the \"flux\" as the composition of the upwind function and the needed entries: namely the solution on the negative side of the face, the solution on the positive face, and the face normal. The orientation negative/positive is arbitrary, the only convention is that the face normals are oriented from the negative side to the positive side.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"flux = upwind ∘ (side⁻(u), side⁺(u), side⁻(nΓ))\nl_Γ(v) = ∫(flux * jump(v))dΓ","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Finally, we define what to perform on the \"two\" boundaries : inlet / oulet. On the inlet, we directly impose the flux with a user defined function that depends on the time (the input is an oscillating wave). On the outlet, we keep our upwind flux but we impose the ghost cell value.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"bc_in = t -> PhysicalFunction(x -> c .* cos(3 * x[2]) * sin(4 * t)) # flux\nl_Γ_in(v, t) = ∫(side⁻(bc_in(t)) ⋅ side⁻(nΓ_in) * side⁻(v))dΓ_in\nflux_out = upwind ∘ (side⁻(u), 0.0, side⁻(nΓ_out))\nl_Γ_out(v) = ∫(flux_out * side⁻(v))dΓ_out","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Assemble the (constant) mass matrix. The returned matrix is a sparse matrix. To simplify the tutorial, we will directly compute the inverse mass matrix. But note that way more performant strategies should be employed to solve such a problem (since we don't need the inverse, only the matrix-vector product).","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"M = assemble_bilinear(m, U, V)\ninvM = inv(Matrix(M)) #WARNING : really expensive !!!","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Let's also create three vectors to avoid allocating them at each time step","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"nd = get_ndofs(V)\nb_vol = zeros(nd)\nb_fac = similar(b_vol)\nrhs = similar(b_vol)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"The time loop is trivial : at each time step we compute the linear forms using the assemble_ methods, we complete the rhs, perform an explicit step and write the solution.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"t = 0.0\nfor i in 1:nite\n global t\n\n # Reset pre-allocated vectors\n b_vol .= 0.0\n b_fac .= 0.0\n\n # Compute linear forms\n assemble_linear!(b_vol, l_Ω, V)\n assemble_linear!(b_fac, l_Γ, V)\n assemble_linear!(b_fac, v -> l_Γ_in(v, t), V)\n assemble_linear!(b_fac, l_Γ_out, V)\n\n # Assemble rhs\n rhs .= Δt .* invM * (b_vol - b_fac)\n\n # Update solution\n u.dofValues .+= rhs\n\n # Update time\n t += Δt\n\n # Write to file\n append_vtk(vtk, u, t)\nend","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"And here is an animation of the result:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"\"drawing\"","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"This page was generated using Literate.jl.","category":"page"},{"location":"manual/operator/#LazyOperators","page":"LazyOperators","title":"LazyOperators","text":"","category":"section"},{"location":"manual/operator/","page":"LazyOperators","title":"LazyOperators","text":"WORK IN PROGRESS","category":"page"},{"location":"manual/integration/#Integration","page":"Integration","title":"Integration","text":"","category":"section"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"To compute an integral on a geometrical element, for instance a curved element, a variable substitution is used to compute the integral on the corresponding reference Shape. This variable substitution reads:","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"int_Omega g(x) mathrmd Omega = int_hatOmega J(x) left(g circ F right)(hatx) mathrmd hatOmega","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"where we recall that F is the reference to physical mapping and J is the determinant of the jacobian matrix of this mapping. Depending on the shape and element order, this determinant is either hard-coded or computed with ForwardDiff.","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"Now, to compute the right side, i.e the integral on the reference shape, quadrature rules are applied:","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"int_hatOmega g(hatx) mathrmd hatOmega = sum_i =1^N_q omega_i g(hatx_i)","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"A specific procedure is applied to compute integrals on a face of a cell (i.e a surfacic integral on a face of a volumic element).","category":"page"},{"location":"api/interpolation/shape/#Reference-shape","page":"Reference shape","title":"Reference shape","text":"","category":"section"},{"location":"api/interpolation/shape/","page":"Reference shape","title":"Reference shape","text":"Modules = [Bcube]\nPages = [\"shape.jl\"]","category":"page"},{"location":"api/interpolation/shape/#Bcube.center-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.center","text":"center(::AbstractShape)\n\nCenter of the AbstractShape.\n\nImplementation\n\nSpecialize for better performances\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.coords-Tuple{Bcube.AbstractShape, Any}","page":"Reference shape","title":"Bcube.coords","text":"coords(shape::AbstractShape,i)\n\nReturn the coordinates of the ith shape vertices. i can be a tuple of indices, then the multiples vertices's coordinates are returned.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.coords-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.coords","text":"coords(::AbstractShape)\n\nReturn node coordinates of the shape in the reference space.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.entity-Union{Tuple{D}, Tuple{Bcube.AbstractShape, Val{D}}} where D","page":"Reference shape","title":"Bcube.entity","text":"entity(s::AbstractShape, ::Val{D}) where D\n\nReturn the geometrical Entity corresponding to the AbstractShape of a given degree D.\n\nRemark : Returned entity must be consistent with the corresponding Lagrange function space.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.face_area-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.face_area","text":"face_area(::AbstractShape)\n\nReturn the length/area of the faces of a shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.face_shapes-Tuple{Bcube.AbstractShape, Any}","page":"Reference shape","title":"Bcube.face_shapes","text":"face_shapes(shape::AbstractShape, i)\n\nShape of i-th shape of the input shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.face_shapes-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.face_shapes","text":"face_shapes(::AbstractShape)\n\nReturn a tuple of the Shape of each face of the given (cell) Shape. For instance, a Triangle has three faces, all of them are Line.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.faces2nodes-Tuple{Bcube.AbstractShape, Any}","page":"Reference shape","title":"Bcube.faces2nodes","text":"faces2nodes(shape::AbstractShape, side)\n\nReturn the index of the vertices on the iside-th face of a shape. If side is positive, the face is oriented preserving the cell normal. If side is negative, the face is returned with the opposite direction (i.e reverse node order).\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.faces2nodes-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.faces2nodes","text":"faces2nodes(::AbstractShape)\n\nReturn the index of the vertices on the faces of a shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.nedges-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.nedges","text":"nedges(::AbstractShape)\n\nGeneric function. Indicate how many edges a shape has.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.nfaces-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.nfaces","text":"nfaces(::AbstractShape)\n\nIndicate how many faces a shape has.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.normal-Tuple{Bcube.AbstractShape, Any}","page":"Reference shape","title":"Bcube.normal","text":"normal(shape::AbstractShape, i)\n\nReturn the outward normal of the ith face of the shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.normals-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.normals","text":"normals(::AbstractShape)\n\nReturn the outward normals of all the faces of the shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.nvertices-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.nvertices","text":"nvertices(::AbstractShape)\n\nIndicate how many vertices a shape has.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.shape-Tuple{AbstractEntityType}","page":"Reference shape","title":"Bcube.shape","text":"shape(::AbstractEntityType)\n\nReturn the reference Shape corresponding to the given AbstractEntityType.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Function-spaces","page":"Function spaces","title":"Function spaces","text":"","category":"section"},{"location":"api/interpolation/function_space/","page":"Function spaces","title":"Function spaces","text":"Modules = [Bcube]\nPages = [\"function_space.jl\", \"projection.jl\"]","category":"page"},{"location":"api/interpolation/function_space/#Bcube.AbstractFunctionSpaceType","page":"Function spaces","title":"Bcube.AbstractFunctionSpaceType","text":"Abstract structure for the different types of function space, for instance the Lagrange function space, the Taylor function space etc.\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/function_space/#Bcube.FunctionSpace-Tuple{Bcube.AbstractFunctionSpaceType, Integer}","page":"Function spaces","title":"Bcube.FunctionSpace","text":"FunctionSpace(fstype::Symbol, degree::Integer)\nFunctionSpace(fstype::AbstractFunctionSpaceType, degree::Integer)\n\nBuild a FunctionSpace of the designated FunctionSpaceType and degree.\n\nExamples\n\njulia> FunctionSpace(:Lagrange, 2)\nFunctionSpace{Bcube.Lagrange{:Uniform}, 2}()\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.basis_functions_style-Tuple{Bcube.AbstractFunctionSpace}","page":"Function spaces","title":"Bcube.basis_functions_style","text":"basis_functions_style(fs::AbstractFunctionSpace)\n\nReturn the style (modal or nodal) corresponding to the basis functions of the 'fs'.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.coords-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.coords","text":"coords(fs::AbstractFunctionSpace,::AbstractShape)\n\nReturn node coordinates in the reference space for associated function space and shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.get_degree-Union{Tuple{Bcube.AbstractFunctionSpace{type, degree}}, Tuple{degree}, Tuple{type}} where {type, degree}","page":"Function spaces","title":"Bcube.get_degree","text":"get_degree(::AbstractFunctionSpace{type, degree}) where{type, degree}\n\nReturn the degree associated to the AbstractFunctionSpace.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.get_type-Union{Tuple{Bcube.AbstractFunctionSpace{type}}, Tuple{type}} where type","page":"Function spaces","title":"Bcube.get_type","text":"get_type(::AbstractFunctionSpace{type})\n\nGetter for the type of the AbstractFunctionSpace\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_edge-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_edge","text":"idof_by_edge(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each edge of the Shape.\n\nDofs lying on the edge vertices are excluded.\n\nThe result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_edge_with_bounds-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_edge_with_bounds","text":"idof_by_edge_with_bounds(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each edge of the Shape.\n\nDofs lying on the edge vertices are included.\n\nThe result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_face-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_face","text":"idof_by_face(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each face of the Shape.\n\nDofs lying on the face edges are excluded, only \"face-interior\" dofs are considered.\n\nThe result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_face_with_bounds-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_face_with_bounds","text":"idof_by_face_with_bounds(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each face of the Shape.\n\nDofs lying on the face edges are included\n\nThe result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_vertex-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_vertex","text":"idof_by_vertex(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each vertex of the Shape.\n\nBeware that we are talking about the Shape, not the EntityType. So 'interior' vertices of the EntityType are not taken into account for instance. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.ndofs-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.ndofs","text":"ndofs(fs::AbstractFunctionSpace, shape::AbstractShape)\n\nNumber of dofs associated to the given interpolation.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.shape_functions-Union{Tuple{N}, Tuple{Bcube.AbstractFunctionSpace, Val{N}, Bcube.AbstractShape, Any}} where N","page":"Function spaces","title":"Bcube.shape_functions","text":"shape_functions(::AbstractFunctionSpace, ::Val{N}, shape::AbstractShape, ξ) where N\nshape_functions(::AbstractFunctionSpace, shape::AbstractShape, ξ)\n\nReturn the list of shape functions corresponding to a FunctionSpace and a Shape. N is the size of the finite element space (default: N=1 if the argument is not provided).\n\nThe result is a vector of all the shape functions evaluated at position ξ, and not a tuple of the different shape functions. This choice is optimal for performance.\n\nNote : λ = ξ -> shape_functions(fs, shape, ξ); λ(ξ)[i] is faster than λ =shape_functions(fs, shape); λ[i](ξ)\n\nImplementation\n\nDefault version, should be overriden for each concrete FunctionSpace.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.shape_functions_vec-Union{Tuple{N}, Tuple{Bcube.AbstractFunctionSpace, Val{N}, Bcube.AbstractShape, Any}} where N","page":"Function spaces","title":"Bcube.shape_functions_vec","text":"shape_functions_vec(fs::AbstractFunctionSpace{T,D}, ::Val{N}, shape::AbstractShape, ξ) where {D,N}\n\nReturn all the shape functions of FunctionSpace on a Shape evaluated in ξ as a vector.\n\nN is the the size (number of components) of the finite element space.\n\n\n\nshape_functions_vec(fs::AbstractFunctionSpace{T,D}, n::Val{N}, shape::AbstractShape) where {T,D, N}\n\nThe shape functions are returned as a vector of functions.\n\nImplementation\n\nThis is implementation is not always valid, but it is for Lagrange and Taylor spaces (the only two spaces available up to 20/01/23).\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube._var_on_bnd_nodes_discontinuous-Tuple{Bcube.AbstractFEFunction, BoundaryFaceDomain, FunctionSpace}","page":"Function spaces","title":"Bcube._var_on_bnd_nodes_discontinuous","text":"Apply the FEFunction on the nodes of the fdomain using the FunctionSpace representation for the cells.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube._var_on_nodes_discontinuous-Tuple{Bcube.AbstractFEFunction, Mesh, FunctionSpace}","page":"Function spaces","title":"Bcube._var_on_nodes_discontinuous","text":"Apply the FEFunction on the nodes of the mesh using the FunctionSpace representation for the cells.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.var_on_bnd_nodes_discontinuous","page":"Function spaces","title":"Bcube.var_on_bnd_nodes_discontinuous","text":"var_on_bnd_nodes_discontinuous(f::AbstractFEFunction, fdomain::BoundaryFaceDomain, degree::Integer=max(1, get_degree(get_function_space(get_fespace(f)))))\n\nReturns an array containing the values of f interpolated to new DoFs on fdomain. The DoFs locations on fdomain correspond to those of a discontinuous FESpace with a :Lagrange function space of selected degree.\n\n\n\n\n\n","category":"function"},{"location":"api/interpolation/function_space/#Bcube.var_on_centers-Union{Tuple{N}, Tuple{Bcube.SingleFieldFEFunction{N}, Mesh}} where N","page":"Function spaces","title":"Bcube.var_on_centers","text":"var_on_centers(f::SingleFEFunction, mesh::Mesh)\n\nInterpolate solution on mesh vertices.\n\nThe result is a (ncells, ncomps) matrix if ncomps > 1, or a (ncells) vector otherwise.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.var_on_nodes_discontinuous","page":"Function spaces","title":"Bcube.var_on_nodes_discontinuous","text":"var_on_nodes_discontinuous(f::AbstractFEFunction, mesh::Mesh, degree::Integer=max(1, get_degree(get_function_space(get_fespace(f)))))\n\nReturns an array containing the values of f interpolated to new DoFs. The DoFs correspond to those of a discontinuous cell variable with a :Lagrange function space of selected degree.\n\n\n\n\n\n","category":"function"},{"location":"api/interpolation/function_space/#Bcube.var_on_vertices-Tuple{Bcube.AbstractFEFunction, Mesh}","page":"Function spaces","title":"Bcube.var_on_vertices","text":"var_on_vertices(f::AbstractFEFunction, mesh::Mesh)\n\nInterpolate solution on mesh vertices.\n\nThe result is a (nnodes, ncomps) matrix.\n\n\n\n\n\n","category":"method"},{"location":"example/linear_elasticity/#Linear-elasticity","page":"Linear elasticity","title":"Linear elasticity","text":"","category":"section"},{"location":"example/linear_elasticity/","page":"Linear elasticity","title":"Linear elasticity","text":"module linear_elasticity #hide\nprintln(\"Running linear elasticity API example...\") #hide\n\n# # Linear elasticity\n\nconst dir = string(@__DIR__, \"/\") # bcube/example dir\nusing Bcube\nusing LinearAlgebra\nusing WriteVTK\nusing StaticArrays\n\n# function space (here we shall use Lagrange P1 elements) and quadrature degree.\nconst fspace = :Lagrange\nconst degree = 1 # FunctionSpace degree\nconst degquad = 2 * degree + 1\n\n# Input and output paths\nconst outputpath = dir * \"../myout/elasticity/\"\nconst meshpath = dir * \"../input/mesh/domainElast_tri.msh\"\n\n# Time stepping scheme params\nconst α = 0.05\nconst γ = 0.5 + α\nconst β = 0.25 * (1.0 + α)^2\n\n# Material parameters (Young's modulus, Poisson coefficient and deduced Lamé coefficients)\nconst ρ = 2500.0\nconst E = 200.0e9\nconst ν = 0.3\nconst λ = E * ν / ((1.0 + ν) * (1.0 - 2.0 * ν))\nconst μ = E / (2.0 * (1.0 + ν))\n\n# Strain tensor and stress tensor (Hooke's law)\nϵ(u) = 0.5 * (∇(u) + transpose(∇(u)))\nσ(u) = λ * tr(ϵ(u)) * I + 2 * μ * ϵ(u)\n\nπ(u, v) = σ(u) ⊡ ϵ(v) # with the chosen contraction convention ϵ should be transposed, but as it is symmetric the expression remains correct\n\n# materialize for identity operator\nBcube.materialize(A::LinearAlgebra.UniformScaling, B) = A\n\n# Function that runs the steady case:\nfunction run_steady()\n # read mesh, the second argument specifies the spatial dimension\n mesh = read_msh(meshpath, 2)\n\n fs = FunctionSpace(fspace, degree)\n U_vec = TrialFESpace(\n fs,\n mesh,\n Dict(\"West\" => SA[0.0, 0.0], \"East\" => SA[1.0, 0.0]);\n size = 2,\n )\n V_vec = TestFESpace(U_vec)\n\n # Define measures for cell\n dΩ = Measure(CellDomain(mesh), degquad)\n\n # no volume force term\n f = PhysicalFunction(x -> SA[0.0, 0.0])\n\n # definition of bilinear and linear forms\n a(u, v) = ∫(π(u, v))dΩ\n l(v) = ∫(f ⋅ v)dΩ\n\n # solve using AffineFESystem\n sys = Bcube.AffineFESystem(a, l, U_vec, V_vec)\n ϕ = Bcube.solve(sys)\n\n Un = var_on_vertices(ϕ, mesh)\n # Write the obtained FE solution\n dict_vars = Dict(\"Displacement\" => (transpose(Un), VTKPointData()))\n mkpath(outputpath)\n write_vtk(outputpath * \"result_elasticity\", itime, t, mesh, dict_vars; append = false)\nend\n\n# Function that performs a time step using a Newmark α-HHT scheme\n# The scheme updates the acceleration G, the velocity V and the displacement U using the following formulas:\n#\n# M G +(1-α)A U + αA U0 = (1-α) L + α L0 = L (because here L is time independent)\n# V = V0 + (1-γ) Δt G0 + γ Δt G\n# U = U0 + Δt V0 + (0.5-β)*Δt^2 G0 + β Δt^2 G\n#\n# G is then computed by solving the linear system obtained by inserting the expressions for U and V in the equation for G.\nfunction Newmark_α_HHT(dt, L, A, Mat, U0, V0, G0)\n L1 = L - α * A * U0\n L2 = -(1.0 - α) * (A * U0 + dt * A * V0 + (0.5 - β) * dt * dt * A * G0)\n RHS = L1 .+ L2\n\n G = Mat \\ RHS\n V = V0 + (1.0 - γ) * dt * G0 + γ * dt * G\n U = U0 + dt * V0 + (0.5 - β) * dt * dt * G0 + β * dt * dt * G\n\n return U, V, G\nend\n\n# Function that runs the unsteady case:\nfunction run_unsteady()\n # read mesh, the second argument specifies the spatial dimension\n mesh = read_msh(meshpath, 2)\n\n fs = FunctionSpace(fspace, degree)\n U_vec = TrialFESpace(fs, mesh, Dict(\"West\" => SA[0.0, 0.0]); size = 2)\n V_vec = TestFESpace(U_vec)\n\n # Define measures for cell\n dΩ = Measure(CellDomain(mesh), degquad)\n Γ = BoundaryFaceDomain(mesh, (\"East\",))\n dΓ = Measure(Γ, degquad)\n\n # surface force to be applied on East boundary\n f = PhysicalFunction(x -> SA[100000.0, 1000.0])\n\n # Definition of bilinear and linear forms\n a(u, v) = ∫(π(u, v))dΩ\n m(u, v) = ∫(ρ * u ⋅ v)dΩ\n l(v) = ∫(side⁻(f) ⋅ side⁻(v))dΓ\n\n # Assemble matrices and vector\n M = assemble_bilinear(m, U_vec, V_vec)\n A = assemble_bilinear(a, U_vec, V_vec)\n L = assemble_linear(l, V_vec)\n\n # Apply homogeneous dirichlet on A and b\n Bcube.apply_homogeneous_dirichlet_to_vector!(L, U_vec, V_vec, mesh)\n Bcube.apply_dirichlet_to_matrix!((A, M), U_vec, V_vec, mesh)\n\n # Initialize solution\n ϕ = FEFunction(U_vec, 0.0)\n U0 = zeros(Bcube.get_ndofs(U_vec))\n V0 = zeros(Bcube.get_ndofs(U_vec))\n G0 = zeros(Bcube.get_ndofs(U_vec))\n\n # Write initial solution\n Un = var_on_vertices(ϕ, mesh)\n # Write the obtained FE solution\n dict_vars = Dict(\"Displacement\" => (transpose(Un), VTKPointData()))\n mkpath(outputpath)\n write_vtk(outputpath * \"result_elasticity\", 0, 0.0, mesh, dict_vars; append = false)\n\n # Time loop\n totalTime = 1.0e-3\n Δt = 1.0e-6\n itime = 0\n t = 0.0\n\n # Matrix for time stepping\n Mat = factorize(M + (1.0 - α) * (β * Δt * Δt * A))\n\n while t <= totalTime\n t += Δt\n itime = itime + 1\n @show t, itime\n\n # solve time step\n U, V, G = Newmark_α_HHT(Δt, L, A, Mat, U0, V0, G0)\n\n # Update solution\n U0 .= U\n V0 .= V\n G0 .= G\n\n set_dof_values!(ϕ, U)\n\n # Write solution\n if itime % 10 == 0\n Un = var_on_vertices(ϕ, mesh)\n # Write the obtained FE solution\n dict_vars = Dict(\"Displacement\" => (transpose(Un), VTKPointData()))\n write_vtk(\n outputpath * \"result_elasticity\",\n itime,\n t,\n mesh,\n dict_vars;\n append = true,\n )\n # In order to use the warp function in paraview (solid is deformed using the displacement field)\n # the calculator filter has to be used with the following formula to reconstruct a 3D displacement field\n # with 0 z-component: Displacement_X*iHat+Displacement_Y*jHat+0.0*kHat\n end\n end\nend\n\n#run_steady()\nrun_unsteady()\n\nend #hide","category":"page"},{"location":"api/output/vtk/#VTK","page":"VTK","title":"VTK","text":"","category":"section"},{"location":"api/output/vtk/","page":"VTK","title":"VTK","text":"Modules = [Bcube]\nPages = [\"vtk.jl\"]","category":"page"},{"location":"api/output/vtk/#Bcube._point_index_from_IJK-Tuple{Val{:VTK_LAGRANGE_QUADRILATERAL}, Any, Any, Any}","page":"VTK","title":"Bcube._point_index_from_IJK","text":"Return the node numbering of the node designated by its position in the x and y direction.\n\nSee https://www.kitware.com/modeling-arbitrary-order-lagrange-finite-elements-in-the-visualization-toolkit/.\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube._vtk_coords_from_lagrange-Tuple{Union{Cube, Square}, Any}","page":"VTK","title":"Bcube._vtk_coords_from_lagrange","text":"Coordinates of the nodes in the VTK cell, ordered as expected by VTK.\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube._vtk_lagrange_node_index_bcube_to_vtk-Tuple{Union{Cube, Square}, Any}","page":"VTK","title":"Bcube._vtk_lagrange_node_index_bcube_to_vtk","text":"Bcube node numbering -> VTK node numbering (in a cell)\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube._vtk_lagrange_node_index_vtk_to_bcube-Tuple{Union{Cube, Square}, Any}","page":"VTK","title":"Bcube._vtk_lagrange_node_index_vtk_to_bcube","text":"VTK node numbering (in a cell) -> Bcube node numbering\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.vtk_entity-Tuple{AbstractEntityType}","page":"VTK","title":"Bcube.vtk_entity","text":"vtk_entity(t::AbstractEntityType)\n\nConvert an AbstractEntityType into a VTKCellType. To find the correspondance, browse the WriteVTK package AND check the Doxygen (for numbering) : https://vtk.org/doc/nightly/html/classvtkTriQuadraticHexahedron.html\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.write_vtk-Union{Tuple{L}, Tuple{V}, Tuple{spaceDim}, Tuple{topoDim}, Tuple{String, Int64, Real, AbstractMesh{topoDim, spaceDim}, Dict{String, Tuple{V, L}}}} where {topoDim, spaceDim, V, L<:VTKBase.AbstractFieldData}","page":"VTK","title":"Bcube.write_vtk","text":"write_vtk(basename::String, it::Int,time::Real, mesh::AbstractMesh{topoDim,spaceDim}, vars::Dict{String,Tuple{V,L}}; append=false) where{topoDim,spaceDim,V,L<:WriteVTK.AbstractFieldData}\n\nWrite a set of variables on the mesh nodes or cell centers to a VTK file.\n\nExample\n\nmesh = basic_mesh()\nu = rand(ncells(mesh))\nv = rand(nnodes(mesh))\ndict_vars = Dict( \"u\" => (u, VTKCellData()), \"v\" => (v, VTKPointData()) )\nwrite_vtk(\"output\", 0, 0.0, mesh, dict_vars)\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.write_vtk-Union{Tuple{spaceDim}, Tuple{topoDim}, Tuple{String, AbstractMesh{topoDim, spaceDim}}} where {topoDim, spaceDim}","page":"VTK","title":"Bcube.write_vtk","text":"write_vtk(basename::String, mesh::AbstractMesh{topoDim,spaceDim}) where{topoDim,spaceDim}\n\nWrite the mesh to a VTK file.\n\nExample\n\nwrite_vtk(\"output\", basic_mesh())\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.write_vtk_discontinuous-Union{Tuple{L}, Tuple{V}, Tuple{spaceDim}, Tuple{topoDim}, Tuple{String, Int64, Real, AbstractMesh{topoDim, spaceDim}, Dict{String, Tuple{V, L}}, Int64}} where {topoDim, spaceDim, V, L<:VTKBase.AbstractFieldData}","page":"VTK","title":"Bcube.write_vtk_discontinuous","text":"VTK writer for a set of discontinuous functions. vars is a dictionnary of variable name => (values, values_location)\n\nwhere values is an array of numbers.\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.write_vtk_lagrange-Union{Tuple{F}, Tuple{String, Dict{String, F}, AbstractMesh, Bcube.AbstractFESpace}, Tuple{String, Dict{String, F}, AbstractMesh, Bcube.AbstractFESpace, Int64}, Tuple{String, Dict{String, F}, AbstractMesh, Bcube.AbstractFESpace, Int64, Real}} where F<:Bcube.LazyOperators.AbstractLazy","page":"VTK","title":"Bcube.write_vtk_lagrange","text":"write_vtk_lagrange(\n basename::String,\n vars::Dict{String, F},\n mesh::AbstractMesh,\n U_export::AbstractFESpace,\n it::Int = 0,\n time::Real = 0.0;\n append = false,\n ascii = false,\n) where {F <: AbstractLazy}\n\nWrite the provided FEFunction on the mesh with the precision of the Lagrange FESpace provided.\n\nvars is a dictionnary of variable name => FEFunction to write.\n\nExample\n\nmesh = rectangle_mesh(6, 7; xmin = -1, xmax = 1.0, ymin = -1, ymax = 1.0)\nu = FEFunction(TrialFESpace(FunctionSpace(:Lagrange, 4), mesh))\nprojection_l2!(u, PhysicalFunction(x -> x[1]^2 + x[2]^2), mesh)\n\nvars = Dict(\"u\" => u, \"grad_u\" => ∇(u))\n\nfor degree_export in 1:5\n U_export = TrialFESpace(FunctionSpace(:Lagrange, degree_export), mesh)\n Bcube.write_vtk_lagrange(\n joinpath(@__DIR__, \"output\"),\n vars,\n mesh,\n U_export,\n )\nend\n\nDev notes\n\nascii does not seem to work in WriteVTK\nremove (once fully validated) : write_vtk_discontinuous\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Mesh","page":"Mesh","title":"Mesh","text":"","category":"section"},{"location":"api/mesh/mesh/#Entity","page":"Mesh","title":"Entity","text":"","category":"section"},{"location":"api/mesh/mesh/","page":"Mesh","title":"Mesh","text":"Modules = [Bcube]\nPages = [\"entity.jl\"]","category":"page"},{"location":"api/mesh/mesh/#Bcube.Node","page":"Mesh","title":"Bcube.Node","text":"A Node is a point in space of dimension dim.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.topology_style-Union{Tuple{topoDim}, Tuple{T}, Tuple{spaceDim}, Tuple{Node{spaceDim, T}, AbstractEntityType{topoDim}}} where {spaceDim, T, topoDim}","page":"Mesh","title":"Bcube.topology_style","text":"topology_style(spaceDim::Int, topoDim::Int)\n\nIndicate the TopologyStyle of an entity of topology topoDim living in space of dimension spaceDim.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Connectivity","page":"Mesh","title":"Connectivity","text":"","category":"section"},{"location":"api/mesh/mesh/","page":"Mesh","title":"Mesh","text":"Modules = [Bcube]\nPages = [\"connectivity.jl\"]","category":"page"},{"location":"api/mesh/mesh/#Bcube.AbstractConnectivity","page":"Mesh","title":"Bcube.AbstractConnectivity","text":"AbstractConnectivity{T}\n\nSupertype for connectivity with indices of type T.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.Connectivity","page":"Mesh","title":"Bcube.Connectivity","text":"Connectivity{T}\n\nType for connectivity with elements of type T.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.inverse_connectivity-Union{Tuple{Connectivity{T}}, Tuple{T}} where T","page":"Mesh","title":"Bcube.inverse_connectivity","text":"inverse_connectivity(c::Connectivity{T}) where {T}\n\nReturns the \"inverse\" of the connectivity 'c' and the corresponding 'keys'. 'keys' are provided because indices in 'c' could be sparse in the general case.\n\nExample\n\nmesh = basic_mesh()\nc2n = connectivities_indices(mesh,:c2n)\nn2c, keys = inverse_connectivity(c2n)\n\nHere, 'n2c' is the node->cell graph of connectivity and, 'n2c[i]' contains the indices of the cells connected to the node of index 'keys[i]'. If 'c2n' is dense, 'keys' is not necessary (because keys[i]==i, ∀i)\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Mesh-2","page":"Mesh","title":"Mesh","text":"","category":"section"},{"location":"api/mesh/mesh/","page":"Mesh","title":"Mesh","text":"Modules = [Bcube]\nPages = [\"mesh.jl\"]","category":"page"},{"location":"api/mesh/mesh/#Bcube.AbstractMesh","page":"Mesh","title":"Bcube.AbstractMesh","text":"Implementation\n\nAll subtypes should implement the following functions:\n\nBase.parent(AbstractMesh) (default should be Base.parent(m::MyMesh) = m)\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.Mesh","page":"Mesh","title":"Bcube.Mesh","text":"bc_names : => bc_nodes : => bc_faces : => \n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.connectivity_cell2cell_by_faces-Tuple{Any}","page":"Mesh","title":"Bcube.connectivity_cell2cell_by_faces","text":"connectivity_cell2cell_by_faces(mesh)\n\nBuild the cell -> cell connectivity by looking at neighbors by faces.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.connectivity_cell2cell_by_nodes-Tuple{Any}","page":"Mesh","title":"Bcube.connectivity_cell2cell_by_nodes","text":"connectivity_cell2cell_by_nodes(mesh)\n\nBuild the cell -> cell connectivity by looking at neighbors by nodes.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.inner_faces-Tuple{Any}","page":"Mesh","title":"Bcube.inner_faces","text":"inner_faces(mesh)\n\nReturn the indices of the inner faces.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.oriented_cell_side-Tuple{Mesh, Int64, Int64}","page":"Mesh","title":"Bcube.oriented_cell_side","text":"oriented_cell_side(mesh::Mesh,icell::Int,iface::Int)\n\nReturn the side number to which the face 'iface' belongs in the cell 'icell' of the mesh. A negative side number is returned if the face is inverted. Returns '0' if the face does not belongs the cell.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.outer_faces-Tuple{Any}","page":"Mesh","title":"Bcube.outer_faces","text":"outer_faces(mesh)\n\nReturn the indices of the outer (=boundary) faces.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Domain","page":"Mesh","title":"Domain","text":"","category":"section"},{"location":"api/mesh/mesh/","page":"Mesh","title":"Mesh","text":"Modules = [Bcube]\nPages = [\"domain.jl\"]","category":"page"},{"location":"api/mesh/mesh/#Bcube.AbstractDomain","page":"Mesh","title":"Bcube.AbstractDomain","text":"An AbstractDomain designates any set of entities from a mesh. For instance a set of cells, a set of faces etc.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.BoundaryFaceDomain-Tuple{Mesh, Tuple{String, Vararg{String}}}","page":"Mesh","title":"Bcube.BoundaryFaceDomain","text":"BoundaryFaceDomain(mesh)\nBoundaryFaceDomain(mesh, label::String)\nBoundaryFaceDomain(mesh, labels::Tuple{String, Vararg{String}})\n\nBuild a BoundaryFaceDomain corresponding to the boundaries designated by one or several labels (=names).\n\nIf no label is provided, all the BoundaryFaceDomain corresponds to all the boundary faces.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.CellDomain","page":"Mesh","title":"Bcube.CellDomain","text":"A CellDomain is a representation of the cells of a mesh. It's primary purpose is to represent a domain to integrate over.\n\nExamples\n\njulia> mesh = rectangle_mesh(10, 10)\njulia> Ω_all = CellDomain(mesh)\njulia> selectedCells = [1,3,5,6]\njulia> Ω_selected = CellDomain(mesh, selectedCells)\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.CellInfo-Tuple{Any, Any, Any}","page":"Mesh","title":"Bcube.CellInfo","text":"Legacy constructor for CellInfo : no information about node indices \n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.CellInfo-Tuple{Any, Any}","page":"Mesh","title":"Bcube.CellInfo","text":"CellInfo(mesh, icell)\n\nDEBUG constructor for icell-th cell of mesh. For performance issues, don't use this version in production.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.FaceInfo","page":"Mesh","title":"Bcube.FaceInfo","text":"FaceInfo{CN<:CellInfo,CP<:CellInfo,FT,FN,F2N}\n\nType describing a face as the common side of two adjacent cells. CellInfo of cells from both sides is stored with the local side index of the face relative to each adjacent cell.\n\nRemark:\n\nFor boundary face with no periodic condition, positive cell side info\n\nare duplicate from the negative ones.\n\nFor performance reason (type stability), nodes and type of the face\n\nis stored explicitely in FaceInfo even if it could have been computed by collecting info from the side of the negative or positive cells.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.FaceInfo-Tuple{CellInfo, CellInfo, Any, Any, AbstractVector}","page":"Mesh","title":"Bcube.FaceInfo","text":"FaceInfo constructor\n\nCell sides are computed automatically.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.FaceInfo-Tuple{Mesh, Int64}","page":"Mesh","title":"Bcube.FaceInfo","text":"DEBUG FaceInfo constructor for kface-th cell of mesh. For performance issues, don't use this version in production.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube._compute_periodicity","page":"Mesh","title":"Bcube._compute_periodicity","text":"Find periodic face connectivities sush as :\n(faces of `labels2`) = A(faces of `labels1`)\n\n\n\n\n\n","category":"function"},{"location":"api/mesh/mesh/#Bcube.get_face_normals-Tuple{Bcube.AbstractFaceDomain}","page":"Mesh","title":"Bcube.get_face_normals","text":"Return a LazyOperator representing a face normal \n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.opposite_side-Tuple{FaceInfo}","page":"Mesh","title":"Bcube.opposite_side","text":"Return the opposite side of the FaceInfo : cellside \"n\" because cellside \"p\"\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Mesh-generator","page":"Mesh generator","title":"Mesh generator","text":"","category":"section"},{"location":"api/mesh/mesh_generator/","page":"Mesh generator","title":"Mesh generator","text":"Modules = [Bcube]\nPages = [\"mesh_generator.jl\"]","category":"page"},{"location":"api/mesh/mesh_generator/#Bcube._duplicate_mesh-Tuple{AbstractMesh}","page":"Mesh generator","title":"Bcube._duplicate_mesh","text":"_duplicate_mesh(mesh::AbstractMesh)\n\nMake an exact copy of the input mesh.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.basic_mesh-Tuple{}","page":"Mesh generator","title":"Bcube.basic_mesh","text":"basic_mesh()\n\nGenerate a toy mesh of two quads and one triangle.\n\nv1 v2 v3 v4 +–-e1–>+–-e5–>+–-e8–>+ ^ | | c3 / e4 c1 e2 c2 e6 e9 | | | / +<–e3–-+<–e7–-+/ v5 v6 v7\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.circle_mesh-Tuple{Any}","page":"Mesh generator","title":"Bcube.circle_mesh","text":"circle_mesh(n; r = 1, order = 1)\n\nMesh a circle (in 2D) with n nodes on the circumference.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.line_mesh-Tuple{Any}","page":"Mesh generator","title":"Bcube.line_mesh","text":"line_mesh(n; xmin = 0., xmax = 1., order = 1, names = (\"LEFT\", \"RIGHT\"))\n\nGenerate a mesh of a line of n vertices.\n\nExample\n\njulia> mesh = line_mesh(5)\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.ncube_mesh-Tuple{Vector{Int64}}","page":"Mesh generator","title":"Bcube.ncube_mesh","text":"ncube_mesh(n::Vector{Int}; order = 1)\n\nGenerate either a line mesh, a rectangle mesh, a cubic mesh... depending on the dimension of n.\n\nArgument\n\nn number of vertices in each spatial directions\n\nExample\n\nmesh_of_a_line = ncube_mesh([10])\nmesh_of_a_square = ncube_mesh([4, 5])\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.one_cell_mesh-Tuple{Symbol}","page":"Mesh generator","title":"Bcube.one_cell_mesh","text":"one_cell_mesh(type::Symbol, order = 1)\n\nGenerate a mesh of one cell. type can be :line, :quad, :tri or :hexa.\n\nThe argument order refers to the geometry order. It has the same effect as the -order parameter in gmsh.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.rectangle_mesh-Tuple{Any, Any}","page":"Mesh generator","title":"Bcube.rectangle_mesh","text":"rectangle_mesh(\n nx,\n ny;\n type = :quad,\n xmin = 0.0,\n xmax = 1.0,\n ymin = 0.0,\n ymax = 1.0,\n order = 1,\n bnd_names = (\"north\", \"south\", \"east\", \"west\"),\n)\n\nGenerate a 2D mesh of a rectangle with nx and ny vertices in the x and y directions respectively.\n\nExample\n\njulia> mesh = rectangle_mesh(5, 4)\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.scale-Tuple{AbstractMesh, Any}","page":"Mesh generator","title":"Bcube.scale","text":"scale(mesh, factor)\n\nScale the input mesh nodes coordinates by a given factor and return the resulted mesh. The factor can be a number or a vector.\n\nUsefull for debugging.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.transform-Tuple{AbstractMesh, Any}","page":"Mesh generator","title":"Bcube.transform","text":"transform(mesh::AbstractMesh, fun)\n\nTransform the input mesh nodes coordinates by applying the given fun function and return the resulted mesh.\n\nUsefull for debugging.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.translate-Tuple{AbstractMesh, AbstractVector{Float64}}","page":"Mesh generator","title":"Bcube.translate","text":"translate(mesh::AbstractMesh, t::Vector{Float64})\n\nTranslate the input mesh with vector t.\n\nUsefull for debugging.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Integration","page":"Integration","title":"Integration","text":"","category":"section"},{"location":"api/integration/integration/#Measure","page":"Integration","title":"Measure","text":"","category":"section"},{"location":"api/integration/integration/","page":"Integration","title":"Integration","text":"Modules = [Bcube]\nPages = [\"measure.jl\"]","category":"page"},{"location":"api/integration/integration/#Bcube.Measure","page":"Integration","title":"Bcube.Measure","text":"A Measure is geometrical domain of integration associated to a way to integrate on it (i.e a quadrature rule).\n\nQ is the quadrature type used to integrate expressions using this measure.\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.Measure-Tuple{AbstractDomain, Integer}","page":"Integration","title":"Bcube.Measure","text":"Measure(domain::AbstractDomain, degree::Integer)\nMeasure(domain::AbstractDomain, ::Val{degree}) where {degree}\n\nBuild a Measure on the designated AbstractDomain with a default quadrature of degree degree.\n\nArguments\n\ndomain::AbstractDomain : the domain to integrate over\ndegree : the degree of the quadrature rule (Legendre quadrature type by default)\n\nExamples\n\njulia> mesh = line_mesh(10)\njulia> Ω = CellDomain(mesh)\njulia> dΩ = Measure(Ω, 2)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_face_normals-Tuple{Measure{<:Bcube.AbstractFaceDomain}}","page":"Integration","title":"Bcube.get_face_normals","text":"Return a LazyOperator representing a face normal \n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Integration-methods","page":"Integration","title":"Integration methods","text":"","category":"section"},{"location":"api/integration/integration/","page":"Integration","title":"Integration","text":"Modules = [Bcube]\nPages = [\"integration.jl\"]","category":"page"},{"location":"api/integration/integration/#Base.:*-Tuple{Number, Bcube.Integration}","page":"Integration","title":"Base.:*","text":"*(a::Number, b::Integration)\n*(a::Integration, b::Number)\n\nMultiplication of an Integration is based on a rewriting rule following the linearity rules of integration : k*∫(f(x))dx => ∫(k*f(x))dx\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Base.:--Tuple{Bcube.Integrand}","page":"Integration","title":"Base.:-","text":"-(a::Integrand)\n\nSoustraction on an Integrand is treated as a multiplication by \"(-1)\" : -a ≡ ((-1)*a)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Base.:--Tuple{Bcube.Integration}","page":"Integration","title":"Base.:-","text":"-(a::Integration)\n\nSoustraction on an Integration is treated as a multiplication by \"(-1)\" : -a ≡ ((-1)*a)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.apply_quadrature-Tuple{Any, Bcube.AbstractShape, Bcube.AbstractQuadrature, Bcube.MapComputeQuadratureStyle}","page":"Integration","title":"Bcube.apply_quadrature","text":"apply_quadrature(g_ref, shape::AbstractShape, quadrature::AbstractQuadrature, ::T) where{N,T<:AbstractComputeQuadratureStyle}\n\nApply quadrature rule to function g_ref expressed on reference shape shape. Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.apply_quadrature2-Tuple{Any, Bcube.AbstractShape, Bcube.AbstractQuadrature, Bcube.MapComputeQuadratureStyle}","page":"Integration","title":"Bcube.apply_quadrature2","text":"apply_quadrature2(g_ref, shape::AbstractShape, quadrature::AbstractQuadrature, ::MapComputeQuadratureStyle) where{N}\n\nAlternative version of apply_quadrature thats seems to be more efficient for face integration (this observation is not really understood)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.getcache_∫-Tuple{AbstractEntityType, Any, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.getcache_∫","text":"getcache_∫(etype::AbstractEntityType, nodes, quadrature::AbstractQuadrature)\n\nReturn the data cache for function ∫\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate-Tuple{Any, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate","text":"integrate(g, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nIntegrate function g expressed in local element. Depending on the cell type and the space dimension, a volumic or a 'surfacic' integration is performed.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate-Tuple{Any, Int64, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate","text":"integrate(g, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nIntegrate function g on the iside-th side of the cell defined by its nodes cnodes and its type ctype. Function g(x) is expressed in the local element.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_face_ref-Tuple{Any, FaceInfo, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_face_ref","text":"Integration on a surface in a volume. We consider that we integrate on the negative side of the face.\n\nWARNING : I need this now, but I am not satisfied. We need to rethink the whole integration API\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_n-Tuple{Any, Int64, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_n","text":"integrate_n(g, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nPerform an integration over the isideth face of an element (defined by cnodes and ctype).\n\nHere g is expressed in the cell-local element : n is the normal vector in the local element, and x is in the local element as well.\n\nDev notes:\n\nThis method is DEPRECATED : never used, except in the unit tests...\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_n_ref-Tuple{Any, Int64, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_n_ref","text":"integrate_n_ref(g_ref, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nPerform an integration over the isideth face of an element (defined by cnodes and ctype).\n\nHere g_ref is expressed in the cell-reference element but n is the normal vector in the local element.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_on_ref-Tuple{Any, CellInfo, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_on_ref","text":"integrate_on_ref(g, cellinfo::CellInfo, quadrature::AbstractQuadrature, [::T]) where {N,[T<:AbstractComputeQuadratureStyle]}\n\nIntegrate a function g over a cell decribed by cellinfo. The function g can be expressed in the reference or the physical space corresponding to the cell, both cases are automatically handled by applying necessary mapping when needed.\n\nThis function is helpfull to integrate shape functions (for instance int lambda_i lambda_j) when the inverse mapping is not known explicitely (hence only hatlambda are known, not lambda).\n\nIf the last argument is given, computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Any, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(g_ref, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature, [::T]) where {[T<:AbstractComputeQuadratureStyle]}\n\nIntegrate function g_ref expressed in reference element. A variable substitution (involving Jacobian & Cie) is still applied, but the function is considered to be already mapped.\n\nThis function is helpfull to integrate shape functions (for instance int lambda_i lambda_j) when the inverse mapping is not known explicitely (hence only hatlambda are known, not lambda).\n\nIf the last argument is given, computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Any, Int64, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(g_ref, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nIntegrate function g_ref on the iside-th side of the cell defined by its nodes cnodes and its type ctype. Function g_ref(x) is expressed in the cell-reference element (not the face reference).\n\nThis function is helpfull to integrate shape functions (for instance int lambda_i lambda_j) when the inverse mapping is not known explicitely (hence only hatlambda are known, not lambda).\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Bcube.isCurvilinear, Any, Any, AbstractEntityType{1}, Bcube.AbstractQuadrature, Bcube.MapComputeQuadratureStyle}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(::isCurvilinear, g_ref, cnodes, ctype::AbstractEntityType{1}, quadrature::AbstractQuadrature, ::T) where {T<:AbstractComputeQuadratureStyle}\n\nPerform an integration of the function g_ref (expressed in local element) over a line in a matbbR^n space.\n\nThe applied formulae is: int_Gamma g(x) dx = int_l F(l) g_ref(l) dl where F mathbbR rightarrow mathbbR^n is the reference segment [-1,1] to the R^n line mapping.\n\nComputation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Bcube.isNodal, Any, Any, Any, Bcube.AbstractQuadrature, Bcube.AbstractComputeQuadratureStyle}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(g_ref, cnodes, ctype, quadrature::AbstractQuadrature)\n\nIntegration on a node in a mathbbR^n space. This trivial function is only to simplify the 'side integral' expression.\n\nImplementation\n\nFor consistency reasons, g_ref is a function but it doesnt actually use its argument : the \"reference-element\" of a Node can be anything. For instance consider integrating g(x) = x on a node named node. Then g_ref(ξ) = g ∘ node.x. As you can see, g_ref doesnt actually depend on ξ\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Bcube.isVolumic, Any, Any, AbstractEntityType, Bcube.AbstractQuadrature, Bcube.MapComputeQuadratureStyle}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(::isVolumic, g_ref, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature, ::T) where{N, T<:AbstractComputeQuadratureStyle}\n\nIntegrate function g_ref (expressed in reference element) on mesh element of type ctype defined by its cnodes at the quadrature. Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\nTo do so, a variable substitution is performed to integrate on the reference element.\n\nImplementation\n\nIt has been checked that calling the apply_quadrature method within this function instead of directly applying the quadrature rule (i.e without the anonymous function) does not decrease performance nor allocation.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Quadrature-rules","page":"Integration","title":"Quadrature rules","text":"","category":"section"},{"location":"api/integration/integration/","page":"Integration","title":"Integration","text":"Modules = [Bcube]\nPages = [\"quadrature.jl\"]","category":"page"},{"location":"api/integration/integration/#Bcube.AbstractQuadrature","page":"Integration","title":"Bcube.AbstractQuadrature","text":"AbstractQuadrature{T,D}\n\nAbstract type representing quadrature of type T and degree D\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.AbstractQuadratureNode","page":"Integration","title":"Bcube.AbstractQuadratureNode","text":"AbstractQuadratureNode{S,Q}\n\nAbstract type representing a quadrature node for a shape S and a quadrature Q. This type is used to represent and identify easily a quadrature node in a quadrature rules.\n\nDerived types must implement the following method:\n\n- get_index(quadnode::AbstractQuadratureNode{S,Q})\n- get_coord(quadnode::AbstractQuadratureNode)\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.AbstractQuadratureRule","page":"Integration","title":"Bcube.AbstractQuadratureRule","text":"AbstractQuadratureRule{S,Q}\n\nAbstract type representing a quadrature rule for a shape S and quadrature Q.\n\nDerived types must implement the following method: - [get_weights(qr::AbstractQuadratureRule)] - [get_nodes(qr::AbstractQuadratureRule)] - [Base.length(qr::AbstractQuadratureRule)]\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.Quadrature","page":"Integration","title":"Bcube.Quadrature","text":"Quadrature{T,D}\n\nQuadrature of type T and degree D\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.QuadratureNode","page":"Integration","title":"Bcube.QuadratureNode","text":"QuadratureNode{S,Q}\n\nType representing a quadrature node for a shape S and a quadrature Q. This type can be used to represent and identify easily a quadrature node in the corresponding parent quadrature rule.\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.QuadratureRule","page":"Integration","title":"Bcube.QuadratureRule","text":"QuadratureRule{S,Q}\n\nAbstract type representing a quadrature rule for a shape S and quadrature Q\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.QuadratureRule-Tuple{Bcube.AbstractShape, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.QuadratureRule","text":"QuadratureRule(shape::AbstractShape, q::AbstractQuadrature)\n\nReturn the quadrature rule corresponding to the given Shape according to the selected quadrature 'q'.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Base.length-Tuple{Bcube.AbstractQuadratureRule}","page":"Integration","title":"Base.length","text":"length(qr::AbstractQuadratureRule)\n\nReturns the number of quadrature nodes of qr.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube._gausslegendre1D-Union{Tuple{Val{N}}, Tuple{N}} where N","page":"Integration","title":"Bcube._gausslegendre1D","text":"_gausslegendre1D(::Val{N}) where N\n_gausslobatto1D(::Val{N}) where N\n\nReturn N-point Gauss quadrature weights and nodes on the domain [-1:1].\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube._get_num_nodes-Union{Tuple{degree}, Tuple{Line, Val{degree}, QuadratureLegendre}} where degree","page":"Integration","title":"Bcube._get_num_nodes","text":"Gauss-Legendre formula with n nodes has degree of exactness 2n-1. Then, to obtain a given degree D, the number of nodes must satisfy: 2n-1 D or equivalently n (D+1)2\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube._get_num_nodes-Union{Tuple{degree}, Tuple{Line, Val{degree}, QuadratureLobatto}} where degree","page":"Integration","title":"Bcube._get_num_nodes","text":"Gauss-Lobatto formula with n+1 nodes has degree of exactness 2n-1, which equivalent to a degree of 2n-3 with n nodes. Then, to obtain a given degree D, the number of nodes must satisfy: 2n-3 D or equivalently n (D+3)2\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube._get_num_nodes_per_dim-Union{Tuple{Bcube.AbstractQuadratureRule{<:S}}, Tuple{S}} where S","page":"Integration","title":"Bcube._get_num_nodes_per_dim","text":"get_num_nodes_per_dim(quadrule::AbstractQuadratureRule{S}) where S<:Shape\n\nReturns the number of nodes per dimension. This function is defined for shapes for which quadratures are based on a cartesian product : Line, Square, Cube\n\nRemark : Here we assume that the same degree is used along each dimension (no anisotropy for now!)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.evalquadnode-Tuple{Any, Bcube.AbstractQuadratureNode}","page":"Integration","title":"Bcube.evalquadnode","text":"evalquadnode(f, quadnode::AbstractQuadratureNode)\n\nEvaluate the function f at the coordinates of quadnode.\n\nBasically, it computes:\n\nf(get_coord(quadnode))\n\nRemark:\n\nOptimization could be applied if f is a function based on a nodal basis such as one of the DoF and quadnode are collocated.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_coord-Tuple{Bcube.AbstractQuadratureNode}","page":"Integration","title":"Bcube.get_coord","text":"get_coord(quadnode::AbstractQuadratureNode)\n\nReturns the coordinates of quadnode.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_index-Tuple{Bcube.AbstractQuadratureNode}","page":"Integration","title":"Bcube.get_index","text":"get_index(quadnode::AbstractQuadratureNode{S,Q})\n\nReturns the index of quadnode in the parent quadrature rule AbstractQuadRules{S,Q}\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_nodes-Tuple{Bcube.AbstractQuadratureRule}","page":"Integration","title":"Bcube.get_nodes","text":"get_nodes(qr::AbstractQuadratureRule)\n\nReturns an array containing the coordinates of all quadrature nodes of qr.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_quadnodes-Union{Tuple{QuadratureRule{S, Q, N}}, Tuple{N}, Tuple{Q}, Tuple{S}} where {S, Q, N}","page":"Integration","title":"Bcube.get_quadnodes","text":"get_quadnodes(qr::QuadratureRule{S,Q,N}) where {S,Q,N}\n\nReturns an vector containing each QuadratureNode of qr\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_quadrature_points_gausslegendre-Tuple{Type{Val{:GLTRI12}}}","page":"Integration","title":"Bcube.get_quadrature_points_gausslegendre","text":"Gauss-Legendre quadrature, 12 point rule on triangle.\n\nRef: Witherden, F. D.; Vincent, P. E. On the identification of symmetric quadrature rules for finite element methods. Comput. Math. Appl. 69 (2015), no. 10, 1232–1241\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_quadrature_points_gausslegendre-Tuple{Type{Val{:GLTRI16}}}","page":"Integration","title":"Bcube.get_quadrature_points_gausslegendre","text":"Gauss-Legendre quadrature, 16 point rule on triangle, degree 8.\n\nRef: Witherden, F. D.; Vincent, P. E. On the identification of symmetric quadrature rules for finite element methods. Comput. Math. Appl. 69 (2015), no. 10, 1232–1241\n\nNote : quadrature is rescale to match our reference triangular shape which is defined in [0:1]² instead of [-1:1]²\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_quadrature_points_gausslegendre-Tuple{Type{Val{:GLTRI7}}}","page":"Integration","title":"Bcube.get_quadrature_points_gausslegendre","text":"Gauss-Legendre quadrature, 7 point rule on triangle. \n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_weights-Tuple{Bcube.AbstractQuadratureRule}","page":"Integration","title":"Bcube.get_weights","text":"get_weights(qr::AbstractQuadratureRule)\n\nReturns an array containing the weights of all quadrature nodes of qr.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.quadrature_points-Tuple{Triangle, Val{4}, QuadratureLobatto}","page":"Integration","title":"Bcube.quadrature_points","text":"ref : https://www.math.umd.edu/~tadmor/references/files/Chen%20&%20Shu%20entropy%20stable%20DG%20JCP2017.pdf\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.quadrature_rule-Union{Tuple{N}, Tuple{Int64, Bcube.AbstractShape, Val{N}}} where N","page":"Integration","title":"Bcube.quadrature_rule","text":"quadrature_rule(iside::Int, shape::AbstractShape, degree::Val{N}) where N\n\nReturn the quadrature rule, computed with barycentric coefficients, corresponding to the given boundary of a shape and the given degree.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.quadrature_rule_bary-Union{Tuple{N}, Tuple{Int64, Bcube.AbstractShape, Val{N}}} where N","page":"Integration","title":"Bcube.quadrature_rule_bary","text":"quadrature_rule_bary(::Int, ::AbstractShape, degree::Val{N}) where N\n\nReturn the quadrature rule, computed with barycentric coefficients, corresponding to the given boundary of a shape and the given degree.\n\nThis function returns the quadrature weights and the barycentric weights to apply to each vertex of the reference shape. Hence, to apply the quadrature using this function, one needs to do : for (weight, l) in quadrature_rule_bary(iside, shape(etype), degree) xp = zeros(SVector{td}) for i=1:nvertices xp += l[i]*vertices[i] end # weight, xp is the quadrature couple (weight, node) end\n\n\n\n\n\n","category":"method"},{"location":"example/euler_naca_steady/#Euler-equations-on-a-NACA0012","page":"Euler equations on a NACA0012","title":"Euler equations on a NACA0012","text":"","category":"section"},{"location":"example/euler_naca_steady/","page":"Euler equations on a NACA0012","title":"Euler equations on a NACA0012","text":"module EulerNacaSteady #hide\nprintln(\"Running euler_naca_steady example...\") #hide\n# # Solve Euler equation around a NACA0012 airfoil\n\nusing Bcube\nusing LinearAlgebra\nusing WriteVTK\nusing StaticArrays\nusing BenchmarkTools\nusing Roots\nusing SparseArrays\nusing Profile\nusing InteractiveUtils\nusing WriteVTK\nusing DifferentialEquations\nusing Symbolics\nusing SparseDiffTools\n\nconst dir = string(@__DIR__, \"/\")\n\nfunction compute_residual(qdof, Q, V, params)\n q = (FEFunction(Q, qdof)...,)\n\n # alias on measures\n dΓ = params.dΓ\n dΩ = params.dΩ\n dΓ_wall = params.dΓ_wall\n dΓ_farfield = params.dΓ_farfield\n\n # Allocate rhs vectors\n b_vol = zero(qdof)\n b_fac = zero(qdof)\n\n # compute volume residuals\n l_vol(v) = ∫(flux_Ω(q, v))dΩ\n assemble_linear!(b_vol, l_vol, V)\n\n # face normals for each face domain (lazy, no computation at this step)\n nΓ = get_face_normals(dΓ)\n nΓ_wall = get_face_normals(dΓ_wall)\n nΓ_farfield = get_face_normals(dΓ_farfield)\n\n # flux residuals from interior faces for all variables\n l_Γ(v) = ∫(flux_Γ(q, v, nΓ))dΓ\n assemble_linear!(b_fac, l_Γ, V)\n\n # flux residuals from bc faces for all variables\n l_Γ_wall(v) = ∫(flux_Γ_wall(q, v, nΓ_wall))dΓ_wall\n l_Γ_farfield(v) = ∫(flux_Γ_farfield(q, v, nΓ_farfield))dΓ_farfield\n assemble_linear!(b_fac, l_Γ_wall, V)\n assemble_linear!(b_fac, l_Γ_farfield, V)\n dQ = b_vol .- b_fac\n\n return dQ\nend\n\n\"\"\"\n flux_Ω(q, v)\n\nCompute volume residual using the lazy-operators approach\n\"\"\"\nflux_Ω(q, v) = _flux_Ω ∘ (q, map(∇, v))\n\nfunction _flux_Ω(q, ∇v)\n ρ, ρu, ρE = q\n ∇λ_ρ, ∇λ_ρu, ∇λ_ρE = ∇v\n γ = stateInit.γ\n\n vel = ρu ./ ρ\n ρuu = ρu * transpose(vel)\n p = pressure(ρ, ρu, ρE, γ)\n\n flux_ρ = ρu\n flux_ρu = ρuu + p * I\n flux_ρE = (ρE + p) .* vel\n\n return return ∇λ_ρ ⋅ flux_ρ + ∇λ_ρu ⊡ flux_ρu + ∇λ_ρE ⋅ flux_ρE\nend\n\n\"\"\"\n flux_Γ(q, v, n)\n\nFlux at the interface is defined by a composition of two functions:\n* the input states at face sides which are needed for the riemann flux\n* `flux_roe` defines the Riemann flux (as usual)\n\"\"\"\nflux_Γ(q, v, n) = flux_roe ∘ (side⁻(q), side⁺(q), jump(v), side⁻(n))\n\n\"\"\"\n flux_roe(q⁻, q⁺, δv, n)\n\"\"\"\nfunction flux_roe(q⁻, q⁺, δv, n)\n γ = stateInit.γ\n nx, ny = n\n ρ1, (ρu1, ρv1), ρE1 = q⁻\n ρ2, (ρu2, ρv2), ρE2 = q⁺\n δλ_ρ1, δλ_ρu1, δλ_ρE1 = δv\n\n ρ1 = max(eps(ρ1), ρ1)\n ρ2 = max(eps(ρ2), ρ2)\n\n # Closure\n u1 = ρu1 / ρ1\n v1 = ρv1 / ρ1\n u2 = ρu2 / ρ2\n v2 = ρv2 / ρ2\n p1 = pressure(ρ1, SA[ρu1, ρv1], ρE1, γ)\n p2 = pressure(ρ2, SA[ρu2, ρv2], ρE2, γ)\n\n H2 = (γ / (γ - 1)) * p2 / ρ2 + (u2 * u2 + v2 * v2) / 2.0\n H1 = (γ / (γ - 1)) * p1 / ρ1 + (u1 * u1 + v1 * v1) / 2.0\n\n R = √(ρ1 / ρ2)\n invR1 = 1.0 / (R + 1)\n uAv = (R * u1 + u2) * invR1\n vAv = (R * v1 + v2) * invR1\n Hav = (R * H1 + H2) * invR1\n cAv = √(abs((γ - 1) * (Hav - (uAv * uAv + vAv * vAv) / 2.0)))\n ecAv = (uAv * uAv + vAv * vAv) / 2.0\n\n λ1 = nx * uAv + ny * vAv\n λ3 = λ1 + cAv\n λ4 = λ1 - cAv\n\n d1 = ρ1 - ρ2\n d2 = ρ1 * u1 - ρ2 * u2\n d3 = ρ1 * v1 - ρ2 * v2\n d4 = ρE1 - ρE2\n\n # computation of the centered part of the flux\n flux_ρ = nx * ρ2 * u2 + ny * ρ2 * v2\n flux_ρu = nx * p2 + flux_ρ * u2\n flux_ρv = ny * p2 + flux_ρ * v2\n flux_ρE = H2 * flux_ρ\n\n # Temp variables\n rc1 = (γ - 1) / cAv\n rc2 = (γ - 1) / cAv / cAv\n uq41 = ecAv / cAv + cAv / (γ - 1)\n uq42 = nx * uAv + ny * vAv\n\n fdc1 = max(λ1, 0.0) * (d1 + rc2 * (-ecAv * d1 + uAv * d2 + vAv * d3 - d4))\n fdc2 = max(λ1, 0.0) * ((nx * vAv - ny * uAv) * d1 + ny * d2 - nx * d3)\n fdc3 =\n max(λ3, 0.0) * (\n (-uq42 * d1 + nx * d2 + ny * d3) / 2.0 +\n rc1 * (ecAv * d1 - uAv * d2 - vAv * d3 + d4) / 2.0\n )\n fdc4 =\n max(λ4, 0.0) * (\n (uq42 * d1 - nx * d2 - ny * d3) / 2.0 +\n rc1 * (ecAv * d1 - uAv * d2 - vAv * d3 + d4) / 2.0\n )\n\n duv1 = fdc1 + (fdc3 + fdc4) / cAv\n duv2 = uAv * fdc1 + ny * fdc2 + (uAv / cAv + nx) * fdc3 + (uAv / cAv - nx) * fdc4\n duv3 = vAv * fdc1 - nx * fdc2 + (vAv / cAv + ny) * fdc3 + (vAv / cAv - ny) * fdc4\n duv4 =\n ecAv * fdc1 +\n (ny * uAv - nx * vAv) * fdc2 +\n (uq41 + uq42) * fdc3 +\n (uq41 - uq42) * fdc4\n\n flux_ρ += duv1\n flux_ρu += duv2\n flux_ρv += duv3\n flux_ρE += duv4\n\n return (δλ_ρ1 ⋅ flux_ρ + δλ_ρu1 ⋅ SA[flux_ρu, flux_ρv] + δλ_ρE1 ⋅ flux_ρE)\nend\n\n\"\"\"\n flux_Γ_farfield(q, v, n)\n\nCompute `Roe` flux on boundary face by imposing\n`stateBcFarfield.u_in` on `side_p`\n\"\"\"\nflux_Γ_farfield(q, v, n) = flux_roe ∘ (side⁻(q), stateBcFarfield.u_inf, side⁻(v), side⁻(n))\n\n\"\"\"\n flux_Γ_wall(q, v, n)\n\"\"\"\nflux_Γ_wall(q, v, n) = _flux_Γ_wall ∘ (side⁻(q), side⁻(v), side⁻(n))\n\nfunction _flux_Γ_wall(q⁻, v⁻, n)\n γ = stateInit.γ\n ρ1, ρu1, ρE1 = q⁻\n λ_ρ1, λ_ρu1, λ_ρE1 = v⁻\n\n p1 = pressure(ρ1, ρu1, ρE1, γ)\n\n flux_ρ = zero(ρ1)\n flux_ρu = p1 * n\n flux_ρE = zero(ρE1)\n\n return (λ_ρ1 ⋅ flux_ρ + λ_ρu1 ⋅ flux_ρu + λ_ρE1 ⋅ flux_ρE)\nend\n\nfunction sparse2vtk(\n a::AbstractSparseMatrix,\n name::String = string(@__DIR__, \"/../myout/sparse\"),\n)\n vtk_write_array(name, Array(a), \"my_property_name\")\nend\n\nmutable struct VtkHandler\n basename::String\n basename_residual::String\n ite::Int\n VtkHandler(basename) = new(basename, basename * \"_residual\", 0)\nend\n\n\"\"\"\n Write solution (at cell centers) to vtk\n Wrapper for `write_vtk`\n\"\"\"\nfunction append_vtk(vtk, mesh, vars, t, params; res = nothing)\n ρ, ρu, ρE = vars\n\n # Mean cell values\n # name2val_mean = (;zip(get_name.(vars), mean_values.(vars, degquad))...)\n # p_mean = pressure.(name2val_mean[:ρ], name2val_mean[:ρu], name2val_mean[:ρE], params.stateInit.γ)\n\n vtk_degree = maximum(x -> get_degree(Bcube.get_function_space(get_fespace(x))), vars)\n vtk_degree = max(1, mesh_degree, vtk_degree)\n _ρ = var_on_nodes_discontinuous(ρ, mesh, vtk_degree)\n _ρu = var_on_nodes_discontinuous(ρu, mesh, vtk_degree)\n _ρE = var_on_nodes_discontinuous(ρE, mesh, vtk_degree)\n\n Cp = pressure_coefficient.(_ρ, _ρu, _ρE)\n Ma = mach.(_ρ, _ρu, _ρE)\n dict_vars_dg = Dict(\n \"rho\" => (_ρ, VTKPointData()),\n \"rhou\" => (_ρu, VTKPointData()),\n \"rhoE\" => (_ρE, VTKPointData()),\n \"Cp\" => (Cp, VTKPointData()),\n \"Mach\" => (Ma, VTKPointData()),\n \"rho_mean\" => (get_values(Bcube.cell_mean(ρ, params.dΩ)), VTKCellData()),\n \"rhou_mean\" => (get_values(Bcube.cell_mean(ρu, params.dΩ)), VTKCellData()),\n \"rhoE_mean\" => (get_values(Bcube.cell_mean(ρE, params.dΩ)), VTKCellData()),\n \"lim_rho\" => (get_values(params.limρ), VTKCellData()),\n \"lim_all\" => (get_values(params.limAll), VTKCellData()),\n )\n Bcube.write_vtk_discontinuous(\n vtk.basename * \"_DG\",\n vtk.ite,\n t,\n mesh,\n dict_vars_dg,\n vtk_degree;\n append = vtk.ite > 0,\n )\n\n _ρ_wall = var_on_bnd_nodes_discontinuous(ρ, params.Γ_wall, vtk_degree)\n _ρu_wall = var_on_bnd_nodes_discontinuous(ρu, params.Γ_wall, vtk_degree)\n _ρE_wall = var_on_bnd_nodes_discontinuous(ρE, params.Γ_wall, vtk_degree)\n\n Cp_wall = pressure_coefficient.(_ρ_wall, _ρu_wall, _ρE_wall)\n Ma_wall = pressure_coefficient.(_ρ_wall, _ρu_wall, _ρE_wall)\n\n dict_vars_wall = Dict(\n \"rho\" => (_ρ_wall, VTKPointData()),\n \"rhou\" => (_ρu_wall, VTKPointData()),\n \"rhoE\" => (_ρE_wall, VTKPointData()),\n \"Cp\" => (Cp_wall, VTKPointData()),\n \"Mach\" => (Ma_wall, VTKPointData()),\n )\n Bcube.write_vtk_bnd_discontinuous(\n vtk.basename * \"_bnd_DG\",\n 1,\n 0.0,\n params.Γ_wall,\n dict_vars_wall,\n vtk_degree;\n append = false,\n )\n\n #residual:\n if !isa(res, Nothing)\n vtkfile = vtk_grid(vtk.basename_residual, Float64.(res.iter), [0.0, 1.0])\n for (k, valₖ) in enumerate(res.val)\n vtkfile[\"res_\" * string(k), VTKPointData()] = [valₖ valₖ]\n end\n vtk_save(vtkfile)\n end\n\n # Update counter\n vtk.ite += 1\n\n return nothing\nend\n\nfunction init!(q, dΩ, initstate)\n AoA = initstate.AoA\n Minf = initstate.M_inf\n Pinf = initstate.P_inf\n Tinf = initstate.T_inf\n r = initstate.r_gas\n γ = initstate.γ\n\n ρinf = Pinf / r / Tinf\n ainf = √(γ * r * Tinf)\n Vinf = Minf * ainf\n ρVxinf = ρinf * Vinf * cos(AoA)\n ρVyinf = ρinf * Vinf * sin(AoA)\n ρEinf = Pinf / (γ - 1) + 0.5 * ρinf * Vinf^2\n\n ρ0 = PhysicalFunction(x -> ρinf)\n ρu0 = PhysicalFunction(x -> SA[ρVxinf, ρVyinf])\n ρE0 = PhysicalFunction(x -> ρEinf)\n projection_l2!(q, (ρ0, ρu0, ρE0), dΩ)\n return nothing\nend\n\nfunction main(stateInit, stateBcFarfield, degree)\n @show degree, degquad\n\n mesh = read_msh(dir * \"../input/mesh/naca0012_o\" * string(mesh_degree) * \".msh\", 2)\n scale!(mesh, 1.0 / 0.5334)\n\n dimcar = compute_dimcar(mesh)\n\n DMPrelax = DMPcurv₀ .* dimcar .^ 2\n\n # Then we create a `NamedTuple` to hold the simulation parameters.\n params = (\n degquad = degquad,\n stateInit = stateInit,\n stateBcFarfield = stateBcFarfield,\n DMPrelax = DMPrelax,\n )\n\n # Define measures for cell and interior face integrations\n dΩ = Measure(CellDomain(mesh), degquad)\n dΓ = Measure(InteriorFaceDomain(mesh), degquad)\n\n # Declare boundary conditions and\n # create associated domains and measures\n Γ_wall = BoundaryFaceDomain(mesh, (\"NACA\",))\n Γ_farfield = BoundaryFaceDomain(mesh, (\"FARFIELD\",))\n dΓ_wall = Measure(Γ_wall, degquad)\n dΓ_farfield = Measure(Γ_farfield, degquad)\n\n params = (\n params...,\n Γ_wall = Γ_wall,\n dΓ = dΓ,\n dΩ = dΩ,\n dΓ_wall = dΓ_wall,\n dΓ_farfield = dΓ_farfield,\n )\n\n qLowOrder = nothing\n\n for deg in 0:degree\n params = (params..., degree = deg)\n\n fs = FunctionSpace(fspace, deg)\n Q_sca = TrialFESpace(fs, mesh, :discontinuous; size = 1) # DG, scalar\n Q_vec = TrialFESpace(fs, mesh, :discontinuous; size = 2) # DG, vectoriel\n V_sca = TestFESpace(Q_sca)\n V_vec = TestFESpace(Q_vec)\n Q = MultiFESpace(Q_sca, Q_vec, Q_sca)\n V = MultiFESpace(V_sca, V_vec, V_sca)\n\n q = FEFunction(Q)\n\n # select an initial configurations:\n if deg == 0\n init!(q, mesh, stateInit)\n else\n println(\"Start projection\")\n projection_l2!(q, qLowOrder, dΩ)\n println(\"End projection\")\n end\n\n # create CellData to store limiter values\n limρ = Bcube.MeshCellData(ones(ncells(mesh)))\n limAll = Bcube.MeshCellData(ones(ncells(mesh)))\n params = (params..., limρ = limρ, limAll = limAll)\n\n # Init vtk handler\n mkpath(outputpath)\n vtk = VtkHandler(\n outputpath * \"euler_naca_mdeg\" * string(mesh_degree) * \"_deg\" * string(deg),\n )\n\n # Init time\n time = 0.0\n\n # Save initial solution\n append_vtk(vtk, mesh, q, time, params)\n\n # Build the cache and store everything you want to compute only once (such as the mass matrice inverse...)\n\n cache = ()\n # Allocate buffer for compute_residual\n b_vol = zeros(Bcube.get_ndofs(Q))\n b_fac = zeros(Bcube.get_ndofs(Q))\n cache = (cache..., b_vol = b_vol, b_fac = b_fac)\n\n cache = (\n cache...,\n cacheCellMean = Bcube.build_cell_mean_cache(q, dΩ),\n mass = factorize(Bcube.build_mass_matrix(Q, V, dΩ)),\n mass_sca = factorize(Bcube.build_mass_matrix(Q_sca, V_sca, dΩ)),\n mass_vec = factorize(Bcube.build_mass_matrix(Q_vec, V_vec, dΩ)),\n )\n\n time, q = steady_solve!(Q, V, q, mesh, params, cache, vtk, deg)\n append_vtk(vtk, mesh, q, time, params)\n println(\"end steady_solve for deg=\", deg, \" !\")\n\n deg < degree && (qLowOrder = deepcopy(q))\n end\n return nothing\nend\n\nfunction steady_solve!(Q, V, q, mesh, params, cache, vtk, deg)\n counter = [0]\n q0 = deepcopy(get_dof_values(q))\n ode_params =\n (Q = Q, V = V, params = params, cache = cache, counter = counter, vtk = vtk)\n\n rhs!(dq, q, p, t) = dq .= compute_residual(q, p.Q, p.V, p.params)\n\n # compute sparsity pattern and coloring\n println(\"computing jacobian cache...\")\n if withbench\n _rhs!(dq, q) = rhs!(dq, q, ode_params, 0.0)\n @btime $_rhs!(similar($q0), $q0)\n q_bench = FEFunction(Q, q0)\n @btime $apply_limitation!($q_bench, $ode_params)\n @show length(q0)\n end\n\n #sparsity_pattern = Symbolics.jacobian_sparsity(_rhs!, similar(Q0), Q0)\n #tjac = @elapsed Symbolics.jacobian_sparsity(_rhs!, similar(Q0), Q0)\n #@show tjac\n sparsity_pattern = Bcube.build_jacobian_sparsity_pattern(Q, mesh)\n println(\"sparsity pattern computed !\")\n display(sparsity_pattern)\n colors = matrix_colors(sparsity_pattern)\n println(\"coloring done!\")\n @show maximum(colors)\n\n ode = ODEFunction(\n rhs!;\n mass_matrix = Bcube.build_mass_matrix(Q, V, params.dΩ),\n jac_prototype = sparsity_pattern,\n colorvec = colors,\n )\n\n Tfinal = Inf\n problem = ODEProblem(ode, q0, (0.0, Tfinal), ode_params)\n timestepper = ImplicitEuler(; nlsolve = NLNewton(; max_iter = 20))\n\n cb_cache = DiscreteCallback(always_true, update_cache!; save_positions = (false, false))\n cb_vtk = DiscreteCallback(always_true, output_vtk; save_positions = (false, false))\n cb_steady = TerminateSteadyState(1e-6, 1e-6, condition_steadystate)\n\n error = 1e-1\n\n sol = solve(\n problem,\n timestepper;\n initializealg = NoInit(),\n adaptive = true,\n abstol = error,\n reltol = error,\n progress = false,\n progress_steps = 1000,\n save_everystep = false,\n save_start = false,\n save_end = false,\n isoutofdomain = isoutofdomain,\n callback = CallbackSet(cb_cache, cb_vtk, cb_steady),\n )\n\n set_dof_values!(q, sol.u[end])\n return sol.t[end], q\nend\n\nalways_true(args...) = true\n\nfunction isoutofdomain(dof, p, t)\n any(isnan, dof) && return true\n\n q = FEFunction(p.Q, dof)\n q_mean = map(get_values, Bcube.cell_mean(q, p.cache.cacheCellMean))\n p_mean = pressure.(q_mean..., stateInit.γ)\n\n negative_ρ = any(x -> x < 0, q_mean[1])\n negative_p = any(x -> x < 0, p_mean)\n isout = negative_ρ || negative_p\n isout && @show negative_ρ, negative_p\n return isout\nend\n\nfunction update_cache!(integrator)\n Q = integrator.p.Q\n Q1, = Q\n deg = get_degree(Bcube.get_function_space(Q1))\n println(\n \"deg=\",\n deg,\n \" update_cache! : iter=\",\n integrator.p.counter[1],\n \" dt=\",\n integrator.dt,\n )\n\n q = FEFunction(integrator.p.Q, integrator.u)\n limiter_projection && apply_limitation!(q, integrator.p)\n return nothing\nend\n\nfunction output_vtk(integrator)\n u_modified!(integrator, false)\n mesh = get_mesh(get_domain(integrator.p.params.dΩ))\n q = FEFunction(integrator.p.Q, integrator.u)\n counter = integrator.p.counter\n counter .+= 1\n if (counter[1] % nout == 0)\n println(\"output_vtk \", counter[1])\n append_vtk(integrator.p.vtk, mesh, q, integrator.t, integrator.p.params)\n end\n return nothing\nend\n\nfunction condition_steadystate(integrator, abstol, reltol, min_t)\n u_modified!(integrator, false)\n if DiffEqBase.isinplace(integrator.sol.prob)\n testval = first(get_tmp_cache(integrator))\n @. testval = (integrator.u - integrator.uprev) / (integrator.t - integrator.tprev)\n else\n testval = (integrator.u - integrator.uprev) / (integrator.t - integrator.tprev)\n end\n\n if typeof(integrator.u) <: Array\n any(\n abs(d) > abstol && abs(d) > reltol * abs(u) for (d, abstol, reltol, u) in\n zip(testval, Iterators.cycle(abstol), Iterators.cycle(reltol), integrator.u)\n ) && (return false)\n else\n any((abs.(testval) .> abstol) .& (abs.(testval) .> reltol .* abs.(integrator.u))) &&\n (return false)\n end\n\n if min_t === nothing\n return true\n else\n return integrator.t >= min_t\n end\nend\n\n\"\"\"\nCompute the characteristic dimension of each cell of `mesh`:\ndimcar = (cell volume) / (cell surface)\n\n# TODO :\nto be moved to Bcube\n\"\"\"\nfunction compute_dimcar(mesh)\n fs = FunctionSpace(:Lagrange, 0)\n V = TestFESpace(fs, mesh; size = 1, isContinuous = false)\n\n # Define measures for cell and interior face integrations\n dΩ = Measure(CellDomain(mesh), degquad)\n dΓ = Measure(InteriorFaceDomain(mesh), degquad)\n dΓ_bc = Measure(BoundaryFaceDomain(mesh), degquad)\n\n f1 = PhysicalFunction(x -> 1.0)\n l(v) = ∫(f1 ⋅ v)dΩ\n l_face(v, dω) = ∫(side⁻(f1) ⋅ side⁻(v) + side⁺(f1) ⋅ side⁺(v))dω\n\n vol = assemble_linear(l, V)\n surf = assemble_linear(Base.Fix2(l_face, dΓ), V)\n surf += assemble_linear(Base.Fix2(l_face, dΓ_bc), V)\n return vol ./ surf\nend\n\n\"\"\"\nReferences:\n* Xiangxiong Zhang, Chi-Wang Shu, On positivity-preserving high order discontinuous\n Galerkin schemes for compressible Euler equations on rectangular meshes,\n Journal of Computational Physics, Volume 229, Issue 23, 2010.\n https://doi.org/10.1016/j.jcp.2010.08.016\n* Zhang, X., Xia, Y. & Shu, CW. Maximum-Principle-Satisfying and Positivity-Preserving\n High Order Discontinuous Galerkin Schemes for Conservation Laws on Triangular Meshes.\n J Sci Comput 50, 29–62 (2012). https://doi.org/10.1007/s10915-011-9472-8\n\"\"\"\nfunction apply_limitation!(q::Bcube.AbstractFEFunction, ode_params)\n params = ode_params.params\n cache = ode_params.cache\n mesh = get_mesh(get_domain(params.dΩ))\n ρ, ρu, ρE = q\n\n ρ_mean, ρu_mean, ρE_mean = Bcube.cell_mean(q, cache.cacheCellMean)\n\n _limρ, ρ_proj = linear_scaling_limiter(\n ρ,\n params.dΩ;\n bounds = (ρmin₀, ρmax₀),\n DMPrelax = params.DMPrelax,\n mass = cache.mass_sca,\n )\n\n op_t = limiter_param_p ∘ (ρ_proj, ρu, ρE, ρ_mean, ρu_mean, ρE_mean)\n t = Bcube._minmax_cells(op_t, mesh, Val(params.degquad))\n tmin = Bcube.MeshCellData(getindex.(t, 1))\n\n if eltype(_limρ) == eltype(params.limρ) # skip Dual number case\n set_values!(params.limρ, get_values(_limρ))\n set_values!(params.limAll, get_values(tmin))\n end\n\n limited_var(u, ū, lim_u) = ū + lim_u * (u - ū)\n projection_l2!(ρ, limited_var(ρ_proj, ρ_mean, tmin), params.dΩ; mass = cache.mass_sca)\n projection_l2!(ρu, limited_var(ρu, ρu_mean, tmin), params.dΩ; mass = cache.mass_vec)\n projection_l2!(ρE, limited_var(ρE, ρE_mean, tmin), params.dΩ; mass = cache.mass_sca)\n return nothing\nend\n\nfunction limiter_param_p(ρ̂, ρu, ρE, ρ_mean, ρu_mean, ρE_mean)\n γ = stateInit.γ\n p = pressure(ρ̂, ρu, ρE, γ)\n\n if p ≥ pmin₀\n t = 1.0\n else\n @show p, ρ̂, ρu, ρE\n @show ρ_mean, ρu_mean, ρE_mean\n @show pressure(ρ_mean, ρu_mean, ρE_mean, γ)\n if pressure(ρ_mean, ρu_mean, ρE_mean, γ) > pmin₀\n fₜ =\n t ->\n pressure(\n t * ρ̂ + (1 - t) * ρ_mean,\n t * ρu + (1 - t) * ρu_mean,\n t * ρE + (1 - t) * ρE_mean,\n γ,\n ) - pmin₀\n bounds = (0.0, 1.0)\n t = find_zero(fₜ, bounds, Bisection())\n else\n t = NaN\n println(\"t = NaN\")\n end\n end\n\n return t\nend\n\nfunction pressure(ρ::Number, ρu::AbstractVector, ρE::Number, γ)\n vel = ρu ./ ρ\n ρuu = ρu * transpose(vel)\n p = (γ - 1) * (ρE - tr(ρuu) / 2)\n return p\nend\n\ncompute_Pᵢ(P, γ, M) = P * (1 + 0.5 * (γ - 1) * M^2)^(γ / (γ - 1))\ncompute_Tᵢ(T, γ, M) = T * (1 + 0.5 * (γ - 1) * M^2)\n\nfunction bc_state_farfield(AoA, M, P, T, r, γ)\n a = √(γ * r * T)\n vn = M * a\n ρ = P / r / T\n ρu = SA[ρ * vn * cos(AoA), ρ * vn * sin(AoA)]\n ρE = P / (γ - 1) + 0.5 * ρ * vn^2\n return (ρ, ρu, ρE)\nend\n\nfunction pressure_coefficient(ρ, ρu, ρE)\n (pressure(ρ, ρu, ρE, stateInit.γ) - stateInit.P_inf) /\n (stateBcFarfield.Pᵢ_inf - stateInit.P_inf)\nend\nfunction mach(ρ, ρu, ρE)\n norm(ρu ./ ρ) / √(stateInit.γ * max(0.0, pressure(ρ, ρu, ρE, stateInit.γ) / ρ))\nend\n\nconst degreemax = 2 # Function-space degree\nconst mesh_degree = 2\nconst fspace = :Lagrange\nconst limiter_projection = true\nconst ρmin₀ = 1.0e-8\nconst ρmax₀ = 1.0e+10\nconst pmin₀ = 1.0e-8\nconst pmax₀ = 1.0e+10\nconst DMPcurv₀ = 10.0e3\nconst withbench = false\n\nconst stateInit = (\n AoA = deg2rad(1.25),\n M_inf = 0.8,\n P_inf = 101325.0,\n T_inf = 275.0,\n r_gas = 287.0,\n γ = 1.4,\n)\nconst nite_max = 300 #300000 # Number of time iteration(s)\nconst nout = 1 # number of step between two vtk outputs\nconst mass_matrix_in_solve = true\nconst degquad = 6\nconst outputpath = string(@__DIR__, \"/../myout/euler_naca_steady/\")\n\nconst stateBcFarfield = (\n AoA = stateInit.AoA,\n M_inf = stateInit.M_inf,\n Pᵢ_inf = compute_Pᵢ(stateInit.P_inf, stateInit.γ, stateInit.M_inf),\n Tᵢ_inf = compute_Tᵢ(stateInit.T_inf, stateInit.γ, stateInit.M_inf),\n u_inf = bc_state_farfield(\n stateInit.AoA,\n stateInit.M_inf,\n stateInit.P_inf,\n stateInit.T_inf,\n stateInit.r_gas,\n stateInit.γ,\n ),\n r_gas = stateInit.r_gas,\n γ = stateInit.γ,\n)\n\nmain(stateInit, stateBcFarfield, degreemax)\n\nend #hide","category":"page"},{"location":"manual/geometry/#Geometry-and-mesh","page":"Geometry and mesh","title":"Geometry and mesh","text":"","category":"section"},{"location":"manual/geometry/","page":"Geometry and mesh","title":"Geometry and mesh","text":"A Mesh is a set basically of nodes (Node), a set of entities (the mesh elements) and a list of connectivies that link the entities between themselves and with the nodes.","category":"page"},{"location":"manual/geometry/","page":"Geometry and mesh","title":"Geometry and mesh","text":"In Bcube every mesh entity has corresponding reference Shape, a simplified or canonical representation of this element. A 1D line is mapped on the [-1,1] segment, and a rectangle is mapped on a square for instance. On these reference shapes, (almost) everything is known : the vertices location, the area, the quadrature points... Hence in Bcube we always compute things in the reference shape. For \"Lagrange\" elements (such as Bar*_t, Tri*_t, Quad*_t, Tetra*_t, Hexa*_t, Penta*_t etc), the mapping from the reference shape to a geometrical element is directly obtained from the corresponding Lagrange polynomials and the element node coordinates. Given a geometrical element with n nodes M_i, the mapping reads:","category":"page"},{"location":"manual/geometry/","page":"Geometry and mesh","title":"Geometry and mesh","text":"F(xi) = sum_i=1^n hatlambda_i(xi)M_i","category":"page"},{"location":"manual/geometry/","page":"Geometry and mesh","title":"Geometry and mesh","text":"where (lambda)_i are the Lagrange polynomials whose order matches the element order.","category":"page"},{"location":"","page":"Home","title":"Home","text":"CurrentModule = Bcube","category":"page"},{"location":"#Bcube","page":"Home","title":"Bcube","text":"","category":"section"},{"location":"#Purpose-of-Bcube","page":"Home","title":"Purpose of Bcube","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Bcube is a Julia library providing tools for the spatial discretization of partial differential equation(s) (PDE). The main objectives are:","category":"page"},{"location":"","page":"Home","title":"Home","text":"to provide a set of tools to quickly assemble an algorithm solving partial differential equation(s) (so the main objective is to help building prototypes without thinking about the numerical core)\nto be completed : efficient/performant PDE resolution?","category":"page"},{"location":"","page":"Home","title":"Home","text":"This documentation is organised as follow. Checkout the tutorials to see what Bcube is capable of and/or quickly learn how to use it. Then, some more elaborated examples are provided to demonstrate the library capabilities. The \"Manual\" part explains how the core is organized. Finally, the \"API\" section is the low level code documentation.","category":"page"},{"location":"#Writing-documentation","page":"Home","title":"Writing documentation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"To write documentation for Bcube, Julia's guidelines should be followed : https://docs.julialang.org/en/v1/manual/documentation/. Moreover, this project tries to apply the SciML Style Guide.","category":"page"},{"location":"#Conventions","page":"Home","title":"Conventions","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"This documentation follows the following notation or naming conventions:","category":"page"},{"location":"","page":"Home","title":"Home","text":"coordinates inside a reference frame are noted hatx haty or xi eta while coordinates in the physical frame are noted xy\nwhen talking about a mapping, F or sometimes F_rp designates the mapping from the reference element to the physical element. On the other side, F^-1 or sometimes F_pr designates the physical element to the reference element mapping.\n\"dof\" means \"degree of freedom\"","category":"page"},{"location":"api/mapping/mapping/#Mapping","page":"Mapping","title":"Mapping","text":"","category":"section"},{"location":"api/mapping/mapping/#Mappings","page":"Mapping","title":"Mappings","text":"","category":"section"},{"location":"api/mapping/mapping/","page":"Mapping","title":"Mapping","text":"Modules = [Bcube]\nPages = [\"mapping.jl\"]","category":"page"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::AbstractEntityType, ξ)\n\nMap the reference shape on the local shape.\n\nImplementation\n\nThis function must be implemented for all shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Bar2_t, ξ)\n\nMap the reference 2-nodes bar [-1,1] on the local bar:\n\nF(xi) = dfracx_r - x_l2 xi + dfracx_r + x_l2\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bar3_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Bar3_t, ξ)\n\nMap the reference 3-nodes bar on the local bar (using Lagrange)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bcube.AbstractShape, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, cshape::AbstractShape, ξ)\n\nReturns the mapping of the an abstract shape (=ref element) to a target element defined by its nodes.\n\nFor instance, if cshape == Line, then the mapping is the same wether the input is the Shape or a Bar2_t. However if the cell is of type Bar3_t, it is still the Bar2_t mapping that is returned.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bcube.Hexa27_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Hexa27_t, ξ)\n\nMap the reference 8-nodes cube [-1,1] x [-1,1] x [-1,1] on the 27-hexa.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bcube.Penta6_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Penta6_t, ξ)\n\nMap the reference 6-nodes prism [0,1] x [0,1] x [-1,1] on the 6-penta (prism).\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bcube.Tri6_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Tri6_t, ξ)\n\nMap the reference 6-nodes triangle [0,1] x [0,1] on the P2 curved-triangle.\n\nF(xi) = sum lambda_i(xi) x_i where lambda_i are the Lagrange P2 shape functions and x_i are the local curved-triangle vertices' coordinates.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Hexa8_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Hexa8_t, ξ)\n\nMap the reference 8-nodes cube [-1,1] x [-1,1] x [-1,1] on the 8-hexa.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Quad4_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Quad4_t, ξ)\n\nMap the reference 4-nodes square [-1,1] x [-1,1] on the 4-quadrilateral.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Quad9_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Quad9_t, ξ)\n\nMap the reference 4-nodes square [-1,1] x [-1,1] on the P2 curved-quadrilateral.\n\nF(xi) = sum lambda_i(xi) x_i where lambda_i are the Lagrange P2 shape functions and x_i are the local curved-quadrilateral vertices' coordinates.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Tri3_t, ξ)\n\nMap the reference 3-nodes Triangle [0,1] x [0,1] on the local triangle.\n\nF(xi eta) = (1 - xi - eta) M_1 + x M_2 + y M_3\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_det_jacobian-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_det_jacobian","text":"mapping_det_jacobian(nodes, etype::AbstractEntityType, ξ)\n\nAbsolute value of the determinant of the mapping Jacobian matrix, expressed in the reference element.\n\nImplementation\n\nDefault version using mapping_jacobian, but can be specified for each shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_det_jacobian-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_det_jacobian","text":"mapping_det_jacobian(nodes, ::Bar2_t, ξ)\n\nAbsolute value of the determinant of the mapping Jacobian matrix for the reference 2-nodes bar [-1,1] to the local bar mapping.\n\ndet(J(xi)) = dfracx_r - x_l2\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_det_jacobian-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_det_jacobian","text":"mapping_det_jacobian(nodes, ::Tri3_t, ξ)\n\nAbsolute value of the determinant of the mapping Jacobian matrix for the the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.\n\nJ = (x_2 - x_1) (y_3 - y_1) - (x_3 - x_1) (y_2 - y_1)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_det_jacobian-Union{Tuple{T}, Tuple{AbstractArray{<:Node{2, T}}, Quad4_t, Any}} where T","page":"Mapping","title":"Bcube.mapping_det_jacobian","text":"mapping_det_jacobian(nodes, ::Quad4_t, ξ)\n\nAbsolute value of the determinant of the mapping Jacobian matrix for the the reference square [-1,1] x [-1,1] to the 4-quadrilateral mapping.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_face-Tuple{Bcube.AbstractShape, Any, Any}","page":"Mapping","title":"Bcube.mapping_face","text":"mapping_face(cshape::AbstractShape, side, permutation)\n\nBuild a mapping from the face reference element (corresponding to the side-th face of cshape) to the cell reference element (i.e the cshape), using a permutation of the face nodes.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_face-Tuple{Bcube.AbstractShape, Any}","page":"Mapping","title":"Bcube.mapping_face","text":"mapping_face(cshape::AbstractShape, side)\n\nBuild a mapping from the face reference element (corresponding to the side-th face of cshape) to the cell reference element (i.e the cshape).\n\nImplementation\n\nWe could define this function as an alias to mapping_face(cshape, side, 1:nnodes(face_shapes(cshape, side)) but for performance issue, I prefer to keep two independant functions for now.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_inv","text":"mapping_inv(nodes, ::AbstractEntityType, x)\n\nMap the local shape on the reference shape.\n\nImplementation\n\nThis function does not have to be implemented for all shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_inv","text":"mapping_inv(nodes, ::Bar2_t, x)\n\nMap the local bar on the reference 2-nodes bar [-1,1]:\n\nF^-1(x) = dfrac2x - x_r - x_lx_r - x_l\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv-Tuple{Any, Quad4_t, Any}","page":"Mapping","title":"Bcube.mapping_inv","text":"mapping_inv(nodes, ::Quad4_t, x)\n\nMap the PARALLELOGRAM quadrilateral on the reference 4-nodes square [-1,1] x [-1,1]. Warning : this mapping is only corrects for parallelogram quadrilateral, not for any quadrilateral.\n\n\n\nTODO: check this formulae with SYMPY\n\nF^-1 beginpmatrix x y endpmatrix =\nbeginpmatrix\n a_1 x + b_1 y + c_1 \n a_2 x + b_2 y + c_2\nendpmatrix\n\nwith\n\nbeginaligned\n a_1 = dfrac-2 (y_3-y_2)Delta \n b_1 = dfrac2 (x_3-x_2)Delta \n c_1 = -1 - a_1 x_1 - b_1 y_1 \n a_2 = dfrac-2 (y_1-y_2)Delta \n b_2 = dfrac2 (x_1 - x_2)Delta \n c_2 = -1 - a_2 x_1 - b_2 y_1\nendaligned\n\nwhere Delta = (x_1 - x_2)(y_3 - y_2) - (x_3 - x_2)(y_1 - y_2)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_inv","text":"mapping_inv(nodes, ::Tri3_t, x)\n\nMap the local triangle on the reference 3-nodes Triangle [0,1] x [0,1].\n\n\n\nTODO: check this formulae with SYMPY\n\nF^-1 beginpmatrix x y endpmatrix =\nfrac1x_1(y_2-y_3) + x_2(y_3-y_1) + x_3(y_1-y_2)\nbeginpmatrix\n (y_3-y_1)x + (x_1 - x_3)y + (x_3 y_1 - x_1 y_3) \n (y_1-y_2)x + (x_2 - x_1)x + (x_1 y_2 - x_2 y_1)\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv_jacobian-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_inv_jacobian","text":"mapping_inv_jacobian(nodes, etype::AbstractEntityType, x)\n\nJacobian matrix of the inverse mapping : dfracpartial F_i^-1partial x_j\n\nImplementation\n\nDefault version using LinearAlgebra to inverse the matrix, but can be specified for each shape (if it exists).\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv_jacobian-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_inv_jacobian","text":"mapping_inv_jacobian(nodes, ::Bar2_t, x)\n\nMapping's jacobian matrix for the local bar to the reference 2-nodes bar [-1, 1].\n\ndfracpartial F^-1partial x = dfrac2x_r - x_l\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv_jacobian-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_inv_jacobian","text":"mapping_inv_jacobian(nodes, ::Tri3_t, x)\n\nMapping's jacobian matrix for the local triangle to the reference 3-nodes Triangle [0,1] x [0,1] mapping.\n\n\n\nTODO: check this formulae with SYMPY\n\nfracpartial F_i^-1partial x_j =\nfrac1x_1 (y_2 - y_3) + x_2 (y_3 - y_1) + x_3 (y_1 - y_2)\nbeginpmatrix\n y_3 - y_1 x_1 - x_3 \n y_1 - y_2 x_2 - x_1\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, etype::AbstractEntityType, ξ)\n\nJacobian matrix of the mapping : dfracpartial F_ipartial xi_j.\n\nImplementation\n\nDefault version using ForwardDiff, but can be specified for each shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, ::Bar2_t, ξ)\n\nMapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.\n\ndfracpartial Fpartial xi = dfracx_r - x_l2\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, Bar3_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, ::Bar3_t, ξ)\n\nMapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.\n\n``\\dfrac{\\partial F}{\\partial \\xi} = \\frac{1}{2} \\left( (2\\xi - 1) M1 + (2\\xi + 1)M2 - 4 \\xi M_3\\right)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, Quad4_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, ::Quad4_t, ξ)\n\nMapping's jacobian matrix for the reference square [-1,1] x [-1,1] to the 4-quadrilateral\n\nfracpartial Fpartial xi = -M_1 + M_2 + M_3 - M_4 + eta (M_1 - M_2 + M_3 - M_4)\nfracpartial Fpartial eta = -M_1 - M_2 + M_3 + M_4 + xi (M_1 - M_2 + M_3 - M_4)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, ::Tri3_t, ξ)\n\nMapping's jacobian matrix for the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.\n\ndfracpartial F_ipartial xi_j =\nbeginpmatrix\n M_2 - M_1 M_3 - M_1\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian_inv(nodes, etype::AbstractEntityType, ξ)\n\nInverse of the mapping jacobian matrix. This is not exactly equivalent to the mapping_inv_jacobian since this function is evaluated in the reference element.\n\nImplementation\n\nDefault version using ForwardDiff, but can be specified for each shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian_inv(nodes, ::Bar2_t, ξ)\n\nInverse of mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.\n\ndfracpartial Fpartial xi^-1 = dfrac2x_r - x_l\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Tuple{Any, Bar3_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian_inv(nodes, ::Bar3_t, ξ)\n\nInverse of mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.\n\ndfracpartial Fpartial xi^-1 = frac2(2xi - 1) M_1 + (2xi + 1)M_2 - 4 xi M_3\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian_inv(nodes, ::Tri3_t, ξ)\n\nInverse of mapping's jacobian matrix for the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.\n\ndfracpartial F_ipartial xi_j^-1 =\nfrac1(x_1 - x_2)(y_1 - y_3) - (x_1 - x_3)(y_1 - y_2)\nbeginpmatrix\n -y_1 + y_3 x_1 - x_3 \n y_1 - y_2 -x_1 + x_2\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Union{Tuple{T}, Tuple{AbstractArray{<:Node{2, T}}, Quad4_t, Any}} where T","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian(nodes, ::Quad4_t, ξ)\n\nInverse of mapping's jacobian matrix for the reference square [-1,1] x [-1,1] to the 4-quadrilateral\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Reference-to-local","page":"Mapping","title":"Reference to local","text":"","category":"section"},{"location":"api/mapping/mapping/","page":"Mapping","title":"Mapping","text":"Modules = [Bcube]\nPages = [\"ref2loc.jl\"]","category":"page"}] +[{"location":"api/operator/operator/#Operators","page":"Operators","title":"Operators","text":"","category":"section"},{"location":"api/operator/operator/","page":"Operators","title":"Operators","text":"Modules = [Bcube]\nPages = [\"operator.jl\"]","category":"page"},{"location":"api/dof/dof/#Degree-of-freedom","page":"Degree of freedom","title":"Degree of freedom","text":"","category":"section"},{"location":"api/dof/dof/#Assembler","page":"Degree of freedom","title":"Assembler","text":"","category":"section"},{"location":"api/dof/dof/","page":"Degree of freedom","title":"Degree of freedom","text":"Modules = [Bcube]\nPages = [\"assembler.jl\"]","category":"page"},{"location":"api/dof/dof/#Bcube.AbstractFaceSidePair","page":"Degree of freedom","title":"Bcube.AbstractFaceSidePair","text":"AbstractFaceSidePair <: AbstractLazy\n\nInterface:\n\nside_n(a::AbstractFaceSidePair)\nside_p(a::AbstractFaceSidePair)\n\n\n\n\n\n","category":"type"},{"location":"api/dof/dof/#Bcube.__assemble_linear!-Tuple{Any, Any, Any, Measure}","page":"Degree of freedom","title":"Bcube.__assemble_linear!","text":"Dev notes\n\nTwo levels of \"LazyMapOver\" because first we LazyMapOver the Tuple of argument of the linear form, and the for each item of this Tuple we LazyMapOver the shape functions.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._append_contribution!-Tuple{Any, Any, Any, Any, Any, Any, CellInfo, Any}","page":"Degree of freedom","title":"Bcube._append_contribution!","text":"bilinear case\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._assemble_linear!-Tuple{Any, Any, Any, Bcube.Integration}","page":"Degree of freedom","title":"Bcube._assemble_linear!","text":"_assemble_linear!(b, l, V, integration::Integration)\n_assemble_linear!(b, l, V, integration::MultiIntegration{N}) where {N}\n\nThese functions act as a function barrier in order to:\n\nget the function corresponding to the operand in the linear form\nreshape b internally to deal with cases when V is a AbstractMultiTestFESpace\ncall __assemble_linear! to apply dispatch on the type of measure of the integration and improve type stability during the assembling loop.\n\nDev note:\n\nThe case integration::MultiIntegration{N} is treated by looping over each Integration contained in the MultiIntegration\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._blockmap_bilinear-Union{Tuple{N2}, Tuple{N1}, Tuple{Tuple{Vararg{T, N1}} where T, Tuple{Vararg{T, N2}} where T}} where {N1, N2}","page":"Degree of freedom","title":"Bcube._blockmap_bilinear","text":"From tuples a=(a_1 a_2 a_i a_m) and b=(b_1 b_2 b_j b_n), it builds A and B which correspond formally to the following two matrices :\n\nA equiv beginpmatrix\na_1 a_1 a_1\na_2 a_2 a_2\n \na_m a_m a_m\nendpmatrix\nqquad and qquad\nB equiv beginpmatrix\nb_1 b_2 b_n\nb_1 b_2 b_n\n \nb_1 b_2 b_n\nendpmatrix\n\nA and B are wrapped in LazyMapOver structures so that all operations on them are done elementwise by default (in other words, it can be considered that the operations are automatically broadcasted).\n\nDev note :\n\nBoth A and B are stored as a tuple of tuples, wrapped by LazyMapOver, where inner tuples correspond to each columns of a matrix. This hierarchical structure reduces both inference and compile times by avoiding the use of large tuples.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._count_n_elts-Union{Tuple{IND}, Tuple{M}, Tuple{TrialFESpace, TestFESpace, CellDomain{M, IND}}} where {M, IND}","page":"Degree of freedom","title":"Bcube._count_n_elts","text":"Count the (maximum) number of elements in the matrix corresponding to the bilinear assembly of U, V on a cell domain, where U and V are TrialFESpace and TestFESpace\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._count_n_elts-Union{Tuple{Tv}, Tuple{Tu}, Tuple{N}, Tuple{IND}, Tuple{M}, Tuple{Bcube.AbstractMultiFESpace{N, Tu}, Bcube.AbstractMultiFESpace{N, Tv}, CellDomain{M, IND}}} where {M, IND, N, Tu<:Tuple{Vararg{TrialFESpace}}, Tv<:Tuple{Vararg{TestFESpace}}}","page":"Degree of freedom","title":"Bcube._count_n_elts","text":"Count the (maximum) number of elements in the matrix corresponding to the bilinear assembly of U, V on a cell domain, where U and V are AbstractMultiFESpace\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._diag_tuples-Union{Tuple{N}, Tuple{Tuple{Vararg{Any, N}}, Any}} where N","page":"Degree of freedom","title":"Bcube._diag_tuples","text":"_diag_tuples(diag::Tuple{Vararg{Any,N}}, b) where N\n\nReturn N tuples of length N. For each tuple tᵢ, its values are defined so that tᵢ[k]=diag[k] if k==i, tᵢ[k]=b otherwise. The result can be seen as a dense diagonal-like array using tuple.\n\nExample for N=3:\n\n(diag[1], b, b ),\n(b, diag[2], b ),\n(b, b, diag[3]))\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._get_multi_tuple_var-Union{Tuple{Tuple{Vararg{Any, N}}}, Tuple{N}} where N","page":"Degree of freedom","title":"Bcube._get_multi_tuple_var","text":"For N=3 for example: (LazyMapOver((LazyMapOver(V[1]), NullOperator(), NullOperator())), LazyMapOver((NullOperator(), LazyMapOver(V[2]), NullOperator())), LazyMapOver((NullOperator(), NullOperator(), LazyMapOver(V[3]))))\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._may_reshape_b-Tuple{AbstractVector, TestFESpace}","page":"Degree of freedom","title":"Bcube._may_reshape_b","text":"For AbstractMultiTestFESpace, it creates a Tuple (of views) of the different \"destination\" in the vector: one for each FESpace\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_bilinear!-Tuple{Vector{Int64}, Vector{Int64}, Vector, Function, Measure{<:Bcube.AbstractFaceDomain}, TrialFESpace, TestFESpace}","page":"Degree of freedom","title":"Bcube.assemble_bilinear!","text":"assemble_bilinear!(\n I::Vector{Int},\n J::Vector{Int},\n X::Vector{T},\n f::Function,\n measure::Measure{<:AbstractFaceDomain},\n U::TrialFESpace,\n V::TestFESpace,\n)\n\nIn-place version of assemble_bilinear.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_bilinear!-Tuple{Vector{Int64}, Vector{Int64}, Vector, Function, Measure{<:CellDomain}, TrialFESpace, TestFESpace}","page":"Degree of freedom","title":"Bcube.assemble_bilinear!","text":"assemble_bilinear!(\n I::Vector{Int},\n J::Vector{Int},\n X::Vector{T},\n f::Function,\n measure::Measure{<:CellDomain},\n U::TrialFESpace,\n V::TestFESpace,\n)\n\nIn-place version of assemble_bilinear.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_bilinear-Union{Tuple{N}, Tuple{Function, Union{Bcube.AbstractMultiFESpace{N, <:Tuple{Vararg{TrialFESpace, N}}}, TrialFESpace}, Union{Bcube.AbstractMultiFESpace{N, <:Tuple{Vararg{TestFESpace, N}}}, TestFESpace}}} where N","page":"Degree of freedom","title":"Bcube.assemble_bilinear","text":"assemble_bilinear(a::Function, U, V)\n\nAssemble the (sparse) Matrix corresponding to the given bilinear form a on the trial and test finite element spaces U and V.\n\nFor the in-place version, check-out assemble_bilinear!.\n\nArguments\n\na::Function : function of two variables (u,v) representing the bilinear form\nU : trial finite element space (for u)\nV : test finite element space (for v)\n\nExamples\n\njulia> mesh = rectangle_mesh(3,3)\njulia> U = TrialFESpace(FunctionSpace(:Lagrange, 0), mesh)\njulia> V = TestFESpace(U)\njulia> dΩ = Measure(CellDomain(mesh), 3)\njulia> a(u, v) = ∫(u * v)dΩ\njulia> assemble_bilinear(a, U, V)\n4×4 SparseArrays.SparseMatrixCSC{Float64, Int64} with 4 stored entries:\n 0.25 ⋅ ⋅ ⋅\n ⋅ 0.25 ⋅ ⋅\n ⋅ ⋅ 0.25 ⋅\n ⋅ ⋅ ⋅ 0.25\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_linear!-Tuple{AbstractVector, Function, Union{Bcube.AbstractMultiFESpace{N, <:Tuple{Vararg{TestFESpace, N}}} where N, TestFESpace}}","page":"Degree of freedom","title":"Bcube.assemble_linear!","text":"assemble_linear!(b::AbstractVector, l::Function, V::Union{TestFESpace, AbstractMultiTestFESpace})\n\nIn-place version of assemble_linear.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.assemble_linear-Tuple{Function, Union{Bcube.AbstractMultiFESpace{N, <:Tuple{Vararg{TestFESpace, N}}} where N, TestFESpace}}","page":"Degree of freedom","title":"Bcube.assemble_linear","text":"assemble_linear(l::Function, V::Union{TestFESpace, AbstractMultiTestFESpace})\n\nAssemble the vector corresponding to a linear form l on the finite element space V\n\nFor the in-place version, checkout assemble_linear!.\n\nArguments\n\nl::Function : linear form to assemble, a function of one variable l(v)\nV : test finite element space\n\nExamples\n\njulia> mesh = rectangle_mesh(3,3)\njulia> U = TrialFESpace(FunctionSpace(:Lagrange, 0), mesh)\njulia> V = TestFESpace(U)\njulia> dΩ = Measure(CellDomain(mesh), 3)\njulia> l(v) = ∫(v)dΩ\njulia> assemble_linear(l, V)\n4-element Vector{Float64}:\n 0.25\n 0.25\n 0.25\n 0.25\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.blockmap_bilinear_shape_functions-Tuple{Bcube.AbstractFESpace, Bcube.AbstractFESpace, Bcube.AbstractCellInfo}","page":"Degree of freedom","title":"Bcube.blockmap_bilinear_shape_functions","text":"Dev notes:\n\nReturn blockU and blockV to be able to compute the local matrix corresponding to the bilinear form :\n\n Aij = a(λᵤj λᵥi)\n\nwhere λᵤ and λᵥ are the shape functions associated with the trial U and the test V function spaces respectively. In a \"map-over\" version, it can be written :\n\n A = a(blockU blockV)\n\nwhere blockU and blockV correspond formally to the lazy-map-over matrices :\n\n k blockUkj = λᵤj\n blockVik = λᵥi\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.blockmap_shape_functions-Tuple{Any, FaceInfo}","page":"Degree of freedom","title":"Bcube.blockmap_shape_functions","text":"Dev note :\n\nMaterialize the integrand function on all the different possible Tuples of v=(v1,0,0,...), (0,v2,0,...), ..., (..., vi, ...)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.blockmap_shape_functions-Tuple{Bcube.AbstractFESpace, Bcube.AbstractCellInfo}","page":"Degree of freedom","title":"Bcube.blockmap_shape_functions","text":"blockmap_shape_functions(fespace::AbstractFESpace, cellinfo::AbstractCellInfo)\n\nReturn all shape functions a = LazyMapOver((λ₁, λ₂, …, λₙ)) corresponding to fespace in cell cellinfo. These shape functions are wrapped by a LazyMapOver so that for a function f it gives: f(a) == map(f, a)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.blockmap_shape_functions-Tuple{Bcube.AbstractMultiFESpace, Bcube.AbstractCellInfo}","page":"Degree of freedom","title":"Bcube.blockmap_shape_functions","text":"blockmap_shape_functions(multiFESpace::AbstractMultiFESpace, cellinfo::AbstractCellInfo)\n\nReturn all shape functions corresponding to each fespace in multiFESSpace for cell cellinfo :\n\n ((v₁ ) ( v₂ ) ( vₙ))\n\nwhere:\n\nvᵢ = (λᵢ₁, λᵢ₂, …, λᵢ_ₘ) are the shapes functions of the i-th fespace in the cell.\n∅ are NullOperators\n\nNote that the LazyMapOver is used to wrap recursively the result.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.compute-Tuple{Bcube.Integration}","page":"Degree of freedom","title":"Bcube.compute","text":"compute(integration::Integration)\n\nCompute an integral, independently from a FEM/DG framework (i.e without FESpace)\n\nReturn an array of the integral evaluated over each cell (or face). To get the sum over the whole domain, simply apply the sum function.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#DofHandler","page":"Degree of freedom","title":"DofHandler","text":"","category":"section"},{"location":"api/dof/dof/","page":"Degree of freedom","title":"Degree of freedom","text":"Modules = [Bcube]\nPages = [\"dofhandler.jl\"]","category":"page"},{"location":"api/dof/dof/#Bcube.DofHandler","page":"Degree of freedom","title":"Bcube.DofHandler","text":"The DofHandler handles the degree of freedom numbering. To each degree of freedom is associated a unique integer.\n\n\n\n\n\n","category":"type"},{"location":"api/dof/dof/#Bcube.DofHandler-Tuple{Mesh, Bcube.AbstractFunctionSpace, Int64, Bool}","page":"Degree of freedom","title":"Bcube.DofHandler","text":"DofHandler(mesh::Mesh, fSpace::AbstractFunctionSpace, ncomponents::Int, isContinuous::Bool)\n\nConstructor of a DofHandler for a SingleFESpace on a Mesh.\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._deal_with_dofs_on_edges!-Tuple{Dict{Tuple{Int64, Set{Int64}}, Tuple{Int64, Vector{Int64}}}, Any, Any, Any, Any, Int64, Any, Bcube.AbstractShape, Int64, Bcube.AbstractFunctionSpace}","page":"Degree of freedom","title":"Bcube._deal_with_dofs_on_edges!","text":"deal_with_dofs_on_edges!(dict, iglob, offset, c2n, celltypes, icell::Int, inodes_g, e2n_g, s::AbstractShape, kvar::Int, fs)\n\nFunction dealing with dofs shared by different cell through an edge connection (excluding bord vertices).\n\nTODO : remove kvar\n\nArguments\n\ndict may be modified by this routine\niglob may be modified by this routine\noffset may be modified by this routine\nfs : FunctionSpace of var kvar\nicell : cell index\nkvar : var index\ns : shape of icell-th cell\ninodes_g : global indices of nodes of icell\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._deal_with_dofs_on_faces!-Tuple{Any, Any, Any, Any, Any, Int64, Vector{Vector{Int64}}, Bcube.AbstractShape, Bcube.AbstractFunctionSpace, Int64}","page":"Degree of freedom","title":"Bcube._deal_with_dofs_on_faces!","text":"TODO : remove kvar\n\nArguments\n\nf2n_g : local face index -> global nodes indices\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube._deal_with_dofs_on_vertices!-Tuple{Dict{Tuple{Int64, Int64}, Tuple{Int64, Vector{Int64}}}, Any, Any, Int64, Any, Bcube.AbstractShape, Int64, Bcube.AbstractFunctionSpace}","page":"Degree of freedom","title":"Bcube._deal_with_dofs_on_vertices!","text":"deal_with_dofs_on_vertices!(dict, iglob, offset, icell::Int, inodes_g, s::AbstractShape, kvar::Int, fs)\n\nFunction dealing with dofs shared by different cell through a vertex connection.\n\nTODO : remove kvar\n\nArguments\n\ndict may be modified by this routine\niglob may be modified by this routine\noffset may be modified by this routine\nfs : FunctionSpace of var kvar\nicell : cell index\nkvar : var index\ns : shape of icell-th cell\ninodes_g : global indices of nodes of icell\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.dof-Tuple{Bcube.DofHandler, Any, Int64, Int64}","page":"Degree of freedom","title":"Bcube.dof","text":"dof(dhl::DofHandler, icell, icomp::Int, idof::Int)\n\nGlobal index of the idof local degree of freedom of component icomp in cell icell.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show dof(dhl, 1, 1, 1)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.dof-Tuple{Bcube.DofHandler, Any, Int64}","page":"Degree of freedom","title":"Bcube.dof","text":"dof(dhl::DofHandler, icell, icomp::Int)\n\nGlobal indices of all the dofs of a given component in a given cell\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show dof(dhl, 1, 1)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.get_ncomponents-Tuple{Bcube.DofHandler}","page":"Degree of freedom","title":"Bcube.get_ncomponents","text":"Number of components handled by a DofHandler\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.max_ndofs-Tuple{Bcube.DofHandler}","page":"Degree of freedom","title":"Bcube.max_ndofs","text":"max_ndofs(dhl::DofHandler)\n\nCount maximum number of dofs per cell, all components mixed\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.ndofs-Tuple{Bcube.DofHandler, Any, AbstractVector{Int64}}","page":"Degree of freedom","title":"Bcube.ndofs","text":"ndofs(dhl, icell, icomp::Vector{Int})\n\nNumber of dofs for a given set of components in a given cell.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1); size = 2))\n@show ndofs(dhl, 1, [1, 2])\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.ndofs-Tuple{Bcube.DofHandler, Any, Int64}","page":"Degree of freedom","title":"Bcube.ndofs","text":"ndofs(dhl, icell, kvar::Int)\n\nNumber of dofs for a given variable in a given cell.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show ndofs(dhl, 1, 1)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.ndofs-Tuple{Bcube.DofHandler, Any}","page":"Degree of freedom","title":"Bcube.ndofs","text":"ndofs(dhl::DofHandler, icell)\n\nNumber of dofs for a given cell.\n\nNote that for a vector variable, the total (accross all components) number of dofs is returned.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show ndofs(dhl, 1, :u)\n\n\n\n\n\n","category":"method"},{"location":"api/dof/dof/#Bcube.ndofs-Tuple{Bcube.DofHandler}","page":"Degree of freedom","title":"Bcube.ndofs","text":"ndofs(dhl::DofHandler)\n\nTotal number of dofs. This function takes into account that dofs can be shared by multiple cells.\n\nExample\n\nmesh = one_cell_mesh(:line)\ndhl = DofHandler(mesh, Variable(:u, FunctionSpace(:Lagrange, 1)))\n@show ndofs(dhl::DofHandler)\n\n\n\n\n\n","category":"method"},{"location":"tutorial/helmholtz/#Helmholtz-equation-(FE)","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"","category":"section"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"This tutorial shows how to solve the Helmholtz eigen problem with a finite-element approach using Bcube.","category":"page"},{"location":"tutorial/helmholtz/#Theory","page":"Helmholtz equation (FE)","title":"Theory","text":"","category":"section"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"We consider the following Helmholtz equation, representing for instance the acoustic wave propagation with Neuman boundary condition(s):","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"begincases\n Delta u + omega^2 u = 0 \n dfracpartial upartial n = 0 textrm on Gamma\nendcases","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"An analytic solution of this equation can be obtained: for a rectangular domain Omega = 0L_x times 0L_y,","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"u(xy) = cos left( frack_x piL_x x right) cos left( frack_y piL_y y right) mathrmwith k_xk_y in mathbbN","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"with omega^2 = pi^2 left( dfrack_x^2L_x^2 + dfrack_y^2L_y^2 right)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Now, both the finite-element method and the discontinuous Galerkin method requires to write the weak form of the problem:","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"int_Omega (Delta u Delta v + omega^2u)v mathrmdOmega = 0","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"- int_Omega nabla u cdot nabla v mathrmdOmega\n+ underbraceleft (nabla u cdot n) v right_Gamma_=0 + omega^2 int_Omega u v mathrmd Omega = 0","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"int_Omega nabla u cdot nabla v mathrmd Omega = omega^2 int_Omega u v mathrmd Omega","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Introducing to bilinear forms a(uv) and b(uv) for respectively the left and right side terms, this equation can be written","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"a(uv) = omega^2 b(uv)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"This is actually a generalized eigenvalue problem which can be written:","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"A u = alpha B u","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"where","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"A u = int_Omega nabla u cdot nabla v mathrmd Omega B u = int_Omega u v mathrmd Omega alpha = omega^2","category":"page"},{"location":"tutorial/helmholtz/#Uncommented-code","page":"Helmholtz equation (FE)","title":"Uncommented code","text":"","category":"section"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"The code below solves the described Helmholtz eigen problem. The code with detailed comments is provided in the next section.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"using Bcube\nusing LinearAlgebra\n\nmesh = rectangle_mesh(21, 21)\n\ndegree = 1\n\nU = TrialFESpace(FunctionSpace(:Lagrange, degree), mesh)\nV = TestFESpace(U)\n\ndΩ = Measure(CellDomain(mesh), 2 * degree + 1)\n\na(u, v) = ∫(∇(u) ⋅ ∇(v))dΩ\nb(u, v) = ∫(u ⋅ v)dΩ\n\nA = assemble_bilinear(a, U, V)\nB = assemble_bilinear(b, U, V)\n\nvp, vecp = eigen(Matrix(A), Matrix(B))\n@show sqrt.(abs.(vp[3:8]))","category":"page"},{"location":"tutorial/helmholtz/#Commented-code","page":"Helmholtz equation (FE)","title":"Commented code","text":"","category":"section"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Load the necessary packages","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"using Bcube\nusing LinearAlgebra","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Mesh a 2D rectangular domain with quads.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"mesh = rectangle_mesh(21, 21)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Next, create the function space that will be used for the trial and test spaces. The Lagrange polynomial space is used here. The degree is set to 1.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"degree = 1\nfs = FunctionSpace(:Lagrange, degree)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"The trial space is created from the function space and the mesh. By default, a scalar \"continuous\" FESpace is created. For \"discontinuous\" (\"DG\") example, check out the linear transport tutorial.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"U = TrialFESpace(fs, mesh)\nV = TestFESpace(U)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Then, define the geometrical dommain on which the operators will apply. For this finite-element example, we only need a CellDomain (no FaceDomain).","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"domain = CellDomain(mesh)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Now, integrating on a domain necessitates a \"measure\", basically a quadrature of given degree.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"dΩ = Measure(domain, Quadrature(2 * degree + 1))","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"The definition of the two bilinear forms is quite natural. Note that these definitions are lazy, no computation is done at this step : the computations will be triggered by the assembly.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"a(u, v) = ∫(∇(u) ⋅ ∇(v))dΩ\nb(u, v) = ∫(u ⋅ v)dΩ","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"To obtain the two sparse matrices corresponding to the discretisation of these bilinear forms, simply call the assemble_bilinear function, providing the trial and test spaces.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"A = assemble_bilinear(a, U, V)\nB = assemble_bilinear(b, U, V)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Compute eigen-values and vectors : we convert to dense matrix to avoid importing additionnal packages, but it is quite easy to solve it in a \"sparse way\".","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"vp, vecp = eigen(Matrix(A), Matrix(B))","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Display the \"first\" five eigenvalues:","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"@show sqrt.(abs.(vp[3:8]))\nref_results = [\n 3.144823462554393,\n 4.447451992013584,\n 6.309054755690625,\n 6.309054755690786,\n 7.049403274103087,\n 7.049403274103147,","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"Now we can export the solution (the eigenvectors) at nodes of the mesh for several eigenvalues. We will restrict to the first 20 eigenvectors. To do so, we will create a FEFunction for each eigenvector. This FEFunction can then be evaluated on the mesh centers, nodes, etc.","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"ϕ = FEFunction(U)\nnvecs = min(20, get_ndofs(U))\nvalues = zeros(nnodes(mesh), nvecs)\nfor ivec in 1:nvecs\n set_dof_values!(ϕ, vecp[:, ivec])\n values[:, ivec] = var_on_vertices(ϕ, mesh)\nend","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"To write a VTK file, we need to build a dictionnary linking the variable name with its values and type","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"using WriteVTK\nout_dir = joinpath(@__DIR__, \"../myout\") # output directory\ndict_vars = Dict(\"u_$i\" => (values[:, i], VTKPointData()) for i in 1:nvecs)\nwrite_vtk(joinpath(out_dir, \"helmholtz_rectangle_mesh\"), 0, 0.0, mesh, dict_vars)","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"And here is the eigenvector corresponding to the 4th eigenvalue:","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"\"drawing\"","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"","category":"page"},{"location":"tutorial/helmholtz/","page":"Helmholtz equation (FE)","title":"Helmholtz equation (FE)","text":"This page was generated using Literate.jl.","category":"page"},{"location":"tutorial/phase_field_supercooled/#Phase-field-model-solidification-of-a-liquid-in-supercooled-state","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"","category":"section"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"In this tutorial, a coupled system of two unsteady equations is solved using finite elements and an imex time scheme. This tutorial doesn't introduce MultiFESpace, check the \"euler\" example for this. Warning : this file is currently quite long to run (a few minutes).","category":"page"},{"location":"tutorial/phase_field_supercooled/#Theory","page":"Phase field model - solidification of a liquid in supercooled state","title":"Theory","text":"","category":"section"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"This case is taken from: Kobayashi, R. (1993). Modeling and numerical simulations of dendritic crystal growth. Physica D: Nonlinear Phenomena, 63(3-4), 410-423. In particular, the variables of the problem are denoted in the same way (p for the phase indicator and T for temperature). Consider a rectangular domain Omega = 0 L_x times 0 L_y on which we wish to solve the following equations:","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":" tau partial_t p = epsilon^2 Delta p + p (1-p)(p - frac12 + m(T))","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":" partial_t T = Delta T + K partial_t p","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"where m(T) = fracalphapi atan left gamma (T_e - T) right. This set of equations represents the solidification of a liquid in a supercooled state. Here T is a dimensionless temperature and p is the solid volume fraction. Lagrange finite elements are used to discretize both equations. Time marching is performed with a forward Euler scheme for the first equation and a backward Euler scheme for the second one.","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"To initiate the solidification process, a Dirichlet boundary condition (p=1,T=1) is applied at x=0 (\"West\" boundary).","category":"page"},{"location":"tutorial/phase_field_supercooled/#Code","page":"Phase field model - solidification of a liquid in supercooled state","title":"Code","text":"","category":"section"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Load the necessary packages","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"using Bcube\nusing LinearAlgebra\nusing WriteVTK\nusing Random\n\nRandom.seed!(1234) # to obtain reproductible results","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Define some physical and numerical constants, as well as the g function appearing in the problem definition.","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"const dir = string(@__DIR__, \"/../\") # Bcube dir\nconst ε = 0.01\nconst τ = 0.0003\nconst α = 0.9\nconst γ = 10.0\nconst K = 1.6\nconst Te = 1.0\nconst β = 0.0 # noise amplitude, original value : 0.01\nconst Δt = 0.0001 # time step\nconst totalTime = 1.0 # original value : 1\nconst nout = 50 # Number of iterations to skip before writing file\nconst degree = 1 # function space degree\nconst lx = 3.0\nconst ly = 1.0\nconst nx = 100\nconst ny = 20\n\ng(T) = (α / π) * atan(γ * (Te - T))","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Read the mesh using gmsh","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"const mesh_path = dir * \"input/mesh/domainPhaseField_tri.msh\"\nconst mesh = read_msh(mesh_path)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Noise function : random between [-1/2,1/2]","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"const χ = MeshCellData(rand(ncells(mesh)) .- 0.5)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Build the function space and the FE Spaces. The two unknowns will share the same FE spaces for this tutorial. Note the way we specify the Dirichlet condition in the definition of U.","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"fs = FunctionSpace(:Lagrange, degree)\nU = TrialFESpace(fs, mesh, Dict(\"West\" => (x, t) -> 1.0))\nV = TestFESpace(U)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Build FE functions","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"ϕ = FEFunction(U)\nT = FEFunction(U)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Define measures for cell integration","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"dΩ = Measure(CellDomain(mesh), 2 * degree + 1)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Define bilinear and linear forms","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"a(u, v) = ∫(∇(u) ⋅ ∇(v))dΩ\nm(u, v) = ∫(u ⋅ v)dΩ\nl(v) = ∫(v * ϕ * (1.0 - ϕ) * (ϕ - 0.5 + g(T) + β * χ))dΩ","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Assemble the two constant matrices","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"A = assemble_bilinear(a, U, V)\nM = assemble_bilinear(m, U, V)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Create iterative matrices","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"C_ϕ = M + Δt / τ * ε^2 * A\nC_T = M + Δt * A","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Apply Dirichlet conditions. For this example, we don't use a lifting method to impose the Dirichlet, but d is used to initialize the solution.","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"d = assemble_dirichlet_vector(U, V, mesh)\napply_dirichlet_to_matrix!((C_ϕ, C_T), U, V, mesh)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Init solution and write it to a VTK file","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"set_dof_values!(ϕ, d)\nset_dof_values!(T, d)\n\ndict_vars = Dict(\n \"Temperature\" => (var_on_vertices(T, mesh), VTKPointData()),\n \"Phi\" => (var_on_vertices(ϕ, mesh), VTKPointData()),\n)\nwrite_vtk(dir * \"myout/result_phaseField_imex_1space\", 0, 0.0, mesh, dict_vars)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Factorize and allocate some vectors to increase performance","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"C_ϕ = factorize(C_ϕ)\nC_T = factorize(C_T)\nL = zero(d)\nrhs = zero(d)\nϕ_new = zero(d)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"Time loop (imex time integration)","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"t = 0.0\nitime = 0\nwhile t <= totalTime\n global t, itime\n t += Δt\n itime += 1\n @show t, totalTime\n\n # Integrate equation on ϕ\n L .= 0.0 # reset L\n assemble_linear!(L, l, V)\n rhs .= M * get_dof_values(ϕ) .+ Δt / τ .* L\n apply_dirichlet_to_vector!(rhs, U, V, mesh)\n ϕ_new .= C_ϕ \\ rhs\n\n # Integrate equation on T\n rhs .= M * (get_dof_values(T) .+ K .* (ϕ_new .- get_dof_values(ϕ)))\n apply_dirichlet_to_vector!(rhs, U, V, mesh)\n\n # Update solution\n set_dof_values!(ϕ, ϕ_new)\n set_dof_values!(T, C_T \\ rhs)\n\n # write solution in vtk format\n if itime % nout == 0\n dict_vars = Dict(\n \"Temperature\" => (var_on_vertices(T, mesh), VTKPointData()),\n \"Phi\" => (var_on_vertices(ϕ, mesh), VTKPointData()),\n )\n write_vtk(\n dir * \"myout/result_phaseField_imex_1space\",\n itime,\n t,\n mesh,\n dict_vars;\n append = true,\n )\n end\nend","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"And here is an animation of the result:","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"\"drawing\"","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"","category":"page"},{"location":"tutorial/phase_field_supercooled/","page":"Phase field model - solidification of a liquid in supercooled state","title":"Phase field model - solidification of a liquid in supercooled state","text":"This page was generated using Literate.jl.","category":"page"},{"location":"api/interpolation/fespace/#Finite-element-spaces","page":"Finite element spaces","title":"Finite element spaces","text":"","category":"section"},{"location":"api/interpolation/fespace/","page":"Finite element spaces","title":"Finite element spaces","text":"Modules = [Bcube]\nPages = [\"fespace.jl\"]","category":"page"},{"location":"api/interpolation/fespace/#Bcube.AbstractFESpace","page":"Finite element spaces","title":"Bcube.AbstractFESpace","text":"Abstract type to represent an finite-element space of size S. See SingleFESpace for more details about what looks like a finite-element space.\n\nDevs notes\n\nAll subtypes should implement the following functions:\n\nget_function_space(feSpace::AbstractFESpace)\nget_shape_functions(feSpace::AbstractFESpace, shape::AbstractShape)\nget_cell_shape_functions(feSpace::AbstractFESpace, shape::AbstractShape)\nget_ndofs(feSpace::AbstractFESpace)\nis_continuous(feSpace::AbstractFESpace)\n\nAlternatively, you may define a \"parent\" to your structure by implementing the Base.parent function. Then, all the above functions will be redirected to the \"parent\" FESpace.\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.AbstractMultiFESpace","page":"Finite element spaces","title":"Bcube.AbstractMultiFESpace","text":"Devs notes\n\nAll subtypes should implement the following functions:\n\nget_fespace(mfeSpace::AbstractMultiFESpace)\nget_mapping(mfeSpace::AbstractMultiFESpace)\nget_dofs(mfeSpace::AbstractMultiFESpace, icell::Int)\nget_shape_functions(mfeSpace::AbstractMultiFESpace, shape::AbstractShape)\nget_cell_shape_functions(mfeSpace::AbstractMultiFESpace, shape::AbstractShape)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.MultiFESpace","page":"Finite element spaces","title":"Bcube.MultiFESpace","text":"A MultiFESpace represents a \"set\" of TrialFESpace or TestFESpace. This structure provides a global dof numbering for each FESpace.\n\nN is the number of FESpace contained in this MultiFESpace.\n\nNote that the FESpace can be different from each other (one continous, one discontinuous; one scalar, one vector...)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.MultiFESpace-Union{Tuple{Tuple{Vararg{Union{TestFESpace{S, FE}, TrialFESpace{S, FE}} where {S, FE}, N}}}, Tuple{N}} where N","page":"Finite element spaces","title":"Bcube.MultiFESpace","text":"MultiFESpace(\n feSpaces::Tuple{Vararg{TrialOrTest, N}};\n arrayOfStruct::Bool = AOS_DEFAULT,\n) where {N}\nMultiFESpace(\n feSpaces::AbstractArray{FE};\n arrayOfStruct::Bool = AOS_DEFAULT,\n) where {FE <: TrialOrTest}\nMultiFESpace(feSpaces::Vararg{TrialOrTest}; arrayOfStruct::Bool = AOS_DEFAULT)\n\nBuild a finite element space representing several sub- finite element spaces.\n\nThis is particulary handy when several variables are in play since it provides a global dof numbering (for the whole system). The finite element spaces composing the MultiFESpace can be different from each other (some continuous, some discontinuous, some scalar, some vectors...).\n\nArguments\n\nfeSpaces : the finite element spaces composing the MultiFESpace. Note that they must be of type TrialFESpace or TestFESpace.\n\nKeywords\n\narrayOfStruct::Bool = AOS_DEFAULT : indicates if the dof numbering should be of type \"Array of Structs\" (AoS) or \"Struct of Arrays\" (SoA).\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.SingleFESpace","page":"Finite element spaces","title":"Bcube.SingleFESpace","text":"SingleFESpace(\n fSpace::AbstractFunctionSpace,\n mesh::AbstractMesh,\n dirichletBndNames = String[];\n size::Int = 1,\n isContinuous::Bool = true,\n kwargs...\n)\n\nBuild a finite element space (scalar or vector) from a FunctionSpace and a Mesh.\n\nArguments\n\nfSpace::AbstractFunctionSpace : the function space associated to the FESpace\nmesh::AbstractMesh : the mesh on which the FESpace is discretized\ndirichletBndNames = String[] : list of mesh boundary labels where a Dirichlet condition applies\n\nKeywords\n\nsize::Int = 1 : the number of components of the FESpace\nisContinuous::Bool = true : if true, a continuous dof numbering is created. Otherwise, dof lying\n\non cell nodes or cell faces are duplicated, not shared (discontinuous dof numbering)\n\nkwargs : for things such as parallel cache (internal/dev usage only)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.SingleFESpace-2","page":"Finite element spaces","title":"Bcube.SingleFESpace","text":"An finite-element space (FESpace) is basically a function space, associated to degrees of freedom (on a mesh).\n\nA FESpace can be either scalar (to represent a Temperature for instance) or vector (to represent a Velocity). In case of a \"vector\" SingleFESpace, all the components necessarily share the same FunctionSpace.\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.TestFESpace","page":"Finite element spaces","title":"Bcube.TestFESpace","text":"TestFESpace(trialFESpace::TrialFESpace)\nTestFESpace(\n fSpace::AbstractFunctionSpace,\n mesh::AbstractMesh,\n dirichletBndNames = String[];\n size::Int = 1,\n isContinuous::Bool = true,\n kwargs...,\n)\n\nBuild a test finite element space.\n\nA TestFESpace can be built from a TrialFESpace. See SingleFESpace for hints about the function arguments. Only arguments specific to TrialFESpace are detailed below.\n\nExamples\n\njulia> mesh = one_cell_mesh(:line)\njulia> fSpace = FunctionSpace(:Lagrange, 2)\njulia> U = TrialFESpace(fSpace, mesh)\njulia> V = TestFESpace(U)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.TestFESpace-2","page":"Finite element spaces","title":"Bcube.TestFESpace","text":"A TestFESpace is basically a SingleFESpace plus other attributes (related to boundary conditions)\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.TrialFESpace","page":"Finite element spaces","title":"Bcube.TrialFESpace","text":"TrialFESpace(feSpace, dirichletValues)\nTrialFESpace(\n fSpace::AbstractFunctionSpace,\n mesh::AbstractMesh,\n dirichlet::Dict{String} = Dict{String, Any}();\n size::Int = 1,\n isContinuous::Bool = true,\n kwargs...\n)\nTrialFESpace(\n fSpace::AbstractFunctionSpace,\n mesh::AbstractMesh,\n type::Symbol,\n dirichlet::Dict{String} = Dict{String, Any}();\n size::Int = 1,\n kwargs...\n)\n\nBuild a trial finite element space.\n\nSee SingleFESpace for hints about the function arguments. Only arguments specific to TrialFESpace are detailed below.\n\nArguments\n\ndirichlet::Dict{String} = Dict{String, Any}() : dictionnary specifying the Dirichlet valued-function (or function) associated to each mesh boundary label. The function f(x,t) to apply is expressed in the physical coordinate system. Alternatively, a constant value can be provided instead of a function.\ntype::Symbol : :continuous or :discontinuous\n\nWarning\n\nFor now the Dirichlet condition can only be applied to nodal bases.\n\nExamples\n\njulia> mesh = one_cell_mesh(:line)\njulia> fSpace = FunctionSpace(:Lagrange, 2)\njulia> U = TrialFESpace(fSpace, mesh)\njulia> V = TrialFESpace(fSpace, mesh, :discontinuous; size = 3)\njulia> W = TrialFESpace(fSpace, mesh, Dict(\"North\" => 3., \"South\" => (x,t) -> t .* x))\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube.TrialFESpace-2","page":"Finite element spaces","title":"Bcube.TrialFESpace","text":"A TrialFESpace is basically a SingleFESpace plus other attributes (related to boundary conditions)\n\nDev notes\n\nwe cannot directly store Dirichlet values on dofs because the Dirichlet values needs \"time\" to apply\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/fespace/#Bcube._MultiFESpace-Union{Tuple{Tuple{Vararg{Union{TestFESpace{S, FE}, TrialFESpace{S, FE}} where {S, FE}, N}}}, Tuple{N}} where N","page":"Finite element spaces","title":"Bcube._MultiFESpace","text":"Low-level constructor \n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube._build_mapping_AoS-Tuple{Tuple{Vararg{Union{TestFESpace{S, FE}, TrialFESpace{S, FE}} where {S, FE}}}, Int64}","page":"Finite element spaces","title":"Bcube._build_mapping_AoS","text":"Build a global numbering using an Array-Of-Struct strategy\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube._build_mapping_SoA-Tuple{Tuple{Vararg{Union{TestFESpace{S, FE}, TrialFESpace{S, FE}} where {S, FE}}}, Int64}","page":"Finite element spaces","title":"Bcube._build_mapping_SoA","text":"Build a global numbering using an Struct-Of-Array strategy \n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.allocate_dofs","page":"Finite element spaces","title":"Bcube.allocate_dofs","text":"allocate_dofs(feSpace::AbstractFESpace, T = Float64)\n\nAllocate a vector with a size equal to the number of dof of the FESpace, with the type T. For a MultiFESpace, a vector of the total size of the space is returned (and not a Tuple of vectors)\n\n\n\n\n\n","category":"function"},{"location":"api/interpolation/fespace/#Bcube.get_cell_shape_functions-Tuple{Bcube.AbstractFESpace, Bcube.AbstractShape}","page":"Finite element spaces","title":"Bcube.get_cell_shape_functions","text":"Return the shape functions associated to the AbstractFESpace in \"packed\" form: λ(x) = (λ₁(x),...,λᵢ(x),...λₙ(x)) for the n dofs.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_dirichlet_boundary_tags-Tuple{Bcube.AbstractFESpace}","page":"Finite element spaces","title":"Bcube.get_dirichlet_boundary_tags","text":"Return the boundary tags where a Dirichlet condition applies\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_dirichlet_values-Tuple{TrialFESpace}","page":"Finite element spaces","title":"Bcube.get_dirichlet_values","text":"Return the values associated to a Dirichlet condition\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_dofs-Tuple{Bcube.AbstractFESpace, Int64}","page":"Finite element spaces","title":"Bcube.get_dofs","text":"Return the dofs indices for the cell icell\n\nResult is an array of integers.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_dofs-Tuple{MultiFESpace, Int64}","page":"Finite element spaces","title":"Bcube.get_dofs","text":"get_dofs(feSpace::MultiFESpace, icell::Int)\n\nReturn the dofs indices for the cell icell for each single-feSpace. Result is a tuple of array of integers, where each array of integers are the indices relative to the numbering of each singleFESpace.\n\nWarning:\n\nCombine get_dofs with get_mapping if global dofs indices are needed.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_fespace-Tuple{Bcube.AbstractMultiFESpace}","page":"Finite element spaces","title":"Bcube.get_fespace","text":"get_fespace(mfeSpace::AbstractMultiFESpace, iSpace)\nget_fespace(mfeSpace::AbstractMultiFESpace)\n\nReturn the i-th FESpace composing this AbstractMultiFESpace. If no index is provided, the tuple of FESpace composing this AbstractMultiFESpace` is returnted.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_fespace-Tuple{MultiFESpace}","page":"Finite element spaces","title":"Bcube.get_fespace","text":"Return the tuple of FESpace composing this MultiFESpace\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_function_space-Tuple{Bcube.AbstractFESpace}","page":"Finite element spaces","title":"Bcube.get_function_space","text":"Return the FunctionSpace (eventually multiple spaces) associated to the AbstractFESpace.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_mapping-Tuple{Bcube.AbstractMultiFESpace}","page":"Finite element spaces","title":"Bcube.get_mapping","text":"get_mapping(mfeSpace::AbstractMultiFESpace, iSpace)\nget_mapping(mfeSpace::AbstractMultiFESpace)\n\nReturn the mapping for the ith FESpace composing the MultiFESpace. If no index is provided, the tuple of mapping for each FESpace` is returnted.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_n_fespace-Union{Tuple{Bcube.AbstractMultiFESpace{N}}, Tuple{N}} where N","page":"Finite element spaces","title":"Bcube.get_n_fespace","text":"Number of FESpace composing the MultiFESpace \n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_ncomponents-Tuple{Bcube.AbstractFESpace}","page":"Finite element spaces","title":"Bcube.get_ncomponents","text":"Return the size S(= number of components) associated to AbstractFESpace{S}.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_ndofs-Tuple{Bcube.AbstractFESpace}","page":"Finite element spaces","title":"Bcube.get_ndofs","text":"Return the total number of dofs of the FESpace, taking into account the continuous/discontinuous type of the space. If the FESpace contains itself several FESpace (see MultiFESpace), the sum of all dofs is returned.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_ndofs-Tuple{Bcube.AbstractMultiFESpace}","page":"Finite element spaces","title":"Bcube.get_ndofs","text":"Total number of dofs contained in this MultiFESpace \n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_shape_functions-Tuple{Bcube.AbstractFESpace, Bcube.AbstractShape}","page":"Finite element spaces","title":"Bcube.get_shape_functions","text":"Return the shape functions associated to the AbstractFESpace.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/fespace/#Bcube.get_size-Union{Tuple{Bcube.AbstractFESpace{S}}, Tuple{S}} where S","page":"Finite element spaces","title":"Bcube.get_size","text":"Return the size S associated to AbstractFESpace{S}.\n\n\n\n\n\n","category":"method"},{"location":"manual/cellfunction/#Cell-function","page":"Cell function","title":"Cell function","text":"","category":"section"},{"location":"manual/cellfunction/","page":"Cell function","title":"Cell function","text":"As explained earlier, at least two coordinates systems exist in Bcube : the \"reference\" coordinates (ReferenceDomain) and the \"physical\" coordinates (PhysicalDomain). The evaluation of a function on a point in a cell depends on the way this point has been defined. Hence the definition of CellPoints that embed the coordinate system. Given a CellPoint (or eventually a FacePoint), an AbstractCellFunction will be evaluated and the mapping between the ReferenceDomain to the PhysicalDomain (or reciprocally) will be performed internally if necessary : if an AbstractCellFunction defined in terms of reference coordinates is applied on a CellPoint expressed in the reference coordinates system, no mapping is needed.","category":"page"},{"location":"howto/howto/#How-to","page":"How to...","title":"How to","text":"","category":"section"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"To be completed to answer common user questions.","category":"page"},{"location":"howto/howto/#Comparing-manually-the-benchmarks-with-main","page":"How to...","title":"Comparing manually the benchmarks with main","text":"","category":"section"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Let's say you want to compare the performance of your current branch (named \"target\" hereafter) with the main branch (named \"baseline\" hereafter).","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Open from Bcube.jl/ a REPL and type:","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"pkg> activate --temp\npkg> add PkgBenchmark BenchmarkTools\npkg> dev .\nusing PkgBenchmark\nimport Bcube\nbenchmarkpkg(Bcube, BenchmarkConfig(; env = Dict(\"JULIA_NUM_THREADS\" => \"1\")); resultfile = joinpath(@__DIR__, \"result-target.json\"))","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"This will create a result-target.json in the current directory.","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Then checkout the main branch. Start a fresh REPL and type (almost the same):","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"pkg> activate --temp\npkg> add PkgBenchmark BenchmarkTools\npkg> dev .\nusing PkgBenchmark\nimport Bcube\nbenchmarkpkg(Bcube, BenchmarkConfig(; env = Dict(\"JULIA_NUM_THREADS\" => \"1\")); resultfile = joinpath(@__DIR__, \"result-baseline.json\"))","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"This will create a result-baseline.json in the current directory.","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"You can now \"compare\" the two files by running (watch-out for the order):","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"target = PkgBenchmark.readresults(\"result-target.json\")\nbaseline = PkgBenchmark.readresults(\"result-baseline.json\")\njudgement = judge(target, baseline)\nexport_markdown(\"judgement.md\", judgement)","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"This will create the markdown file judgement.md with the results.","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"For more details, once you've built the judgement object, you can also type the following code from https://github.com/tkf/BenchmarkCI.jl:","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"open(\"detailed-judgement.md\", \"w\") do io\n println(io, \"# Judge result\")\n export_markdown(io, judgement)\n println(io)\n println(io)\n println(io, \"---\")\n println(io, \"# Target result\")\n export_markdown(io, PkgBenchmark.target_result(judgement))\n println(io)\n println(io)\n println(io, \"---\")\n println(io, \"# Baseline result\")\n export_markdown(io, PkgBenchmark.baseline_result(judgement))\n println(io)\n println(io)\n println(io, \"---\")\nend","category":"page"},{"location":"howto/howto/#Run-the-benchmark-manually","page":"How to...","title":"Run the benchmark manually","text":"","category":"section"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Let's say you want to run the benchmarks locally (without comparing with main)","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"Open from Bcube.jl/ a REPL and type:","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"pkg> activate --temp\npkg> add PkgBenchmark\npkg> dev .\nusing PkgBenchmark\nimport Bcube\nresults = benchmarkpkg(Bcube, BenchmarkConfig(; env = Dict(\"JULIA_NUM_THREADS\" => \"1\")); resultfile = joinpath(@__DIR__, \"result.json\"))\nexport_markdown(\"results.md\", results)","category":"page"},{"location":"howto/howto/","page":"How to...","title":"How to...","text":"This will create the markdown file results.md with the results.","category":"page"},{"location":"api/mesh/gmsh_utils/#GMSH","page":"GMSH","title":"GMSH","text":"","category":"section"},{"location":"api/mesh/gmsh_utils/","page":"GMSH","title":"GMSH","text":"Modules = [Bcube]\nPages = [\"gmsh_utils.jl\"]","category":"page"},{"location":"api/mesh/gmsh_utils/#Bcube._c2n_gmsh2cgns-Tuple{Any, Any}","page":"GMSH","title":"Bcube._c2n_gmsh2cgns","text":"Convert a cell->node connectivity with gmsh numbering convention to a cell->node connectivity with CGNs numbering convention.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube._compute_space_dim-Tuple{Bool}","page":"GMSH","title":"Bcube._compute_space_dim","text":"Deduce the number of space dimensions from the mesh : if one (or more) dimension of the bounding box is way lower than the other dimensions, the number of space dimension is decreased.\n\nCurrently, having for instance (x,z) is not supported. Only (x), or (x,y), or (x,y,z).\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube._read_msh-Tuple{Int64, Bool}","page":"GMSH","title":"Bcube._read_msh","text":"_read_msh(spaceDim::Int, verbose::Bool)\n\nTo use this function, the gmsh file must have been opened already (see read_msh(path::String) for instance).\n\nThe number of topological dimensions is given by the highest dimension found in the file. The number of space dimensions is deduced from the axis dimensions if spaceDim = 0. If spaceDim is set to a positive number, this number is used as the number of space dimensions.\n\nImplementation\n\nGlobal use of gmsh module. Do not try to improve this function by passing an argument such as gmsh or gmsh.model : it leads to problems.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_cylinder_mesh-Tuple{Any, Any, Any}","page":"GMSH","title":"Bcube.gen_cylinder_mesh","text":"gen_cylinder_mesh(output, Lz; radius = 1., lc = 1e-1, order = 1, npartitions = 0, verbose = false)\n\nGenerate a 3D mesh of a cylindrical domain and length L and write the mesh to output.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_disk_mesh-Tuple{Any}","page":"GMSH","title":"Bcube.gen_disk_mesh","text":"gen_disk_mesh(output; radius = 1., lc = 1e-1, order = 1, npartitions = 0, verbose = false)\n\nGenerate a 2D mesh of a disk domain and write the mesh to output.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_hexa_mesh-Tuple{Any, Any}","page":"GMSH","title":"Bcube.gen_hexa_mesh","text":"gen_hexa_mesh(output, type; recombine = false, n = [2, 2, 2], l = [1., 1., 1.], center = [0., 0., 0.], order = 1)\n\nGenerate a 3D mesh of a hexahedral domain and write the mesh to output. Use type to specify the element types: :tetra or :hexa.\n\nImplementation\n\nNotations from https://cgns.github.io/CGNSdocscurrent/sids/conv.html We could also use extrusion.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_line_mesh-Tuple{Any}","page":"GMSH","title":"Bcube.gen_line_mesh","text":"gen_line_mesh(output; nx = 2, lx = 1., xc = 0., order = 1)\n\nGenerate a 1D mesh of a segment and write to \"output\"\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_mesh_around_disk-Tuple{Any}","page":"GMSH","title":"Bcube.gen_mesh_around_disk","text":"Mesh the domain around a disk\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_rectangle_mesh-Tuple{Any, Any}","page":"GMSH","title":"Bcube.gen_rectangle_mesh","text":"gen_rectangle_mesh(output, type; recombine = false, nx = 2, ny = 2, lx = 1., ly = 1., xc = -1., yc = -1., order = 1)\n\nGenerate a 2D mesh of a rectangle domain and write the mesh to output. Use type to specify the element types: :tri or :quad.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_rectangle_mesh_with_tri_and_quad-Tuple{Any}","page":"GMSH","title":"Bcube.gen_rectangle_mesh_with_tri_and_quad","text":"gen_rectangle_mesh_with_tri_and_quad(output; nx = 2, ny = 2, lx = 1., ly = 1., xc = -1., yc = -1., order = 1)\n\nGenerate a 2D mesh of a rectangle domain and write the mesh to output. The domain is split vertically in two parts: the upper part is composed of 'quad' cells and the lower part with 'tri'. North D –––- C | :quad | West M₁|––––-|M₂ East | :tri | A –––- B South\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.gen_star_disk_mesh-Tuple{Any, Any, Any}","page":"GMSH","title":"Bcube.gen_star_disk_mesh","text":"gen_star_disk_mesh(output, ε, m; nθ = 360, radius = 1., lc = 1e-1, order = 1, npartitions = 0, format22 = false, verbose = false)\n\nGenerate a 2D mesh of a star domain and write the mesh to output. The \"star\" wall is defined by r_wall = R left( 1 + varepsilon cos(m theta) right).\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.nodes_gmsh2cgns-Tuple{AbstractEntityType, AbstractArray}","page":"GMSH","title":"Bcube.nodes_gmsh2cgns","text":"nodes_gmsh2cgns(entity::AbstractEntityType, nodes::AbstractArray)\n\nReorder nodes of a given entity from the Gmsh format to CGNS format\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/gmsh_utils/#Bcube.read_msh","page":"GMSH","title":"Bcube.read_msh","text":"read_msh(path::String, spaceDim::Int = 0; verbose::Bool = false)\n\nRead a .msh file designated by its path.\n\nSee read_msh() for more details.\n\n\n\n\n\n","category":"function"},{"location":"api/mesh/gmsh_utils/#Bcube.read_msh_with_cell_names","page":"GMSH","title":"Bcube.read_msh_with_cell_names","text":"read_msh_with_cell_names(path::String, spaceDim = 0; verbose = false)\n\nRead a .msh file designated by its path and also return names and tags\n\n\n\n\n\n","category":"function"},{"location":"api/interpolation/spaces/#Available-spaces","page":"Available spaces","title":"Available spaces","text":"","category":"section"},{"location":"api/interpolation/spaces/#Lagrange","page":"Available spaces","title":"Lagrange","text":"","category":"section"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Modules = [Bcube]\nPages = [\"lagrange.jl\"]","category":"page"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 1}, Prism, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Prism, ξ)\n\nShape functions for Prism Lagrange element of degree 1 in a 3D space.\n\nhatlambda_1(xi eta zeta) = (1 - xi - eta)(1 - zeta)2 hspace1cm\nhatlambda_2(xi eta zeta) = xi (1 - zeta)2 hspace1cm\nhatlambda_3(xi eta zeta) = eta (1 - zeta)2 hspace1cm\nhatlambda_5(xi eta zeta) = (1 - xi - eta)(1 + zeta)2 hspace1cm\nhatlambda_6(xi eta zeta) = xi (1 + zeta)2 hspace1cm\nhatlambda_7(xi eta zeta) = eta (1 + zeta)2 hspace1cm\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 1}, Triangle, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Triangle, ξ)\n\nShape functions for Triangle Lagrange element of degree 1 in a 2D space.\n\nhatlambda_1(xi eta) = 1 - xi - eta hspace1cm\nhatlambda_2(xi eta) = xi hspace1cm\nhatlambda_3(xi eta) = eta\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 2}, Triangle, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Lagrange, 2}, ::Triangle, ξ)\n\nShape functions for Triangle Lagrange element of degree 2 in a 2D space.\n\nbeginaligned\n hatlambda_1(xi eta) = (1 - xi - eta)(1 - 2 xi - 2 eta) \n hatlambda_2(xi eta) = xi (2xi - 1) \n hatlambda_3(xi eta) = eta (2eta - 1) \n hatlambda_12(xi eta) = 4 xi (1 - xi - eta) \n hatlambda_23(xi eta) = 4 xi eta \n hatlambda_31(xi eta) = 4 eta (1 - xi - eta)\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 3}, Triangle, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Lagrange, 3}, ::Triangle, ξ)\n\nShape functions for Triangle Lagrange element of degree 3 in a 2D space.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 0}, Val{1}, Square, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Lagrange, 0}, ::Val{1}, ::Square, x)\n\nGradient of shape functions for Square Lagrange element of degree 0 in a 2D space.\n\nnabla hatlambda(xi eta) =\nbeginpmatrix\n 0 0\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 0}, Val{1}, Triangle, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Lagrange, 0}, ::Val{1}, ::Triangle, ξ)\n\nGradient of shape functions for Triangle Lagrange element of degree 0 in a 2D space.\n\nnabla hatlambda(xi eta) =\nbeginpmatrix\n 0 0\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 1}, Val{1}, Triangle, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Lagrange, 1}, ::Val{1}, ::Triangle, ξ)\n\nGradient of shape functions for Triangle Lagrange element of degree 1 in a 2D space.\n\nbeginaligned\n nabla hatlambda_1(xi eta) =\n beginpmatrix\n -1 -1\n endpmatrix \n nabla hatlambda_2(xi eta) =\n beginpmatrix\n 1 0\n endpmatrix \n nabla hatlambda_3(xi eta) =\n beginpmatrix\n 0 1\n endpmatrix \nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Lagrange, 2}, Val{1}, Triangle, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Lagrange, 2}, ::Val{1}, ::Triangle, ξ)\n\nGradient of shape functions for Triangle Lagrange element of degree 2 in a 2D space.\n\nbeginaligned\n nabla hatlambda_1(xi eta) =\n beginpmatrix\n -3 + 4 (xi + eta) -3 + 4 (xi + eta)\n endpmatrix \n nabla hatlambda_2(xi eta) =\n beginpmatrix\n -1 + 4 xi 0\n endpmatrix \n nabla hatlambda_3(xi eta) =\n beginpmatrix\n 0 -1 + 4 eta\n endpmatrix \n nabla hatlambda_12(xi eta) =\n 4 beginpmatrix\n 1 - 2 xi - eta - xi\n endpmatrix \n nabla hatlambda_23(xi eta) =\n 4 beginpmatrix\n eta xi\n endpmatrix \n nabla hatlambda_31(xi eta) =\n 4 beginpmatrix\n - eta 1 - 2 eta - xi\n endpmatrix \nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.shape_functions-Union{Tuple{N}, Tuple{D}, Tuple{FunctionSpace{<:Bcube.Lagrange, D}, Val{N}, Bcube.AbstractShape, Any}} where {D, N}","page":"Available spaces","title":"Bcube.shape_functions","text":"Default version : the shape functions are \"replicated\". If shape_functions returns the vector [λ₁; λ₂; λ₃], and if the FESpace is of size 2, then this default behaviour consists in returning the matrix [λ₁ 0; λ₂ 0; λ₃ 0; 0 λ₁; 0 λ₂; 0 λ₃].\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Taylor","page":"Available spaces","title":"Taylor","text":"","category":"section"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"The Taylor function space corresponds to a function space where functions are approximated by a Taylor series expansion of order n in each cell:","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":" forall x in Omega_ig(x) = g(x_0) + (x - x_0) g(x_0) + o(x)","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"where x_0 is the cell center.","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Note that a Taylor-P0 is strictly equivalent to a 1st-order Finite Volume discretization (beware that \"order\" can have different meaning depending on whether one refers to the order of the function space basis or the order of the discretization method).","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Recall that any function space implies that any function g is interpolated by g(x) = sum g_i lambda_i(x) where lambda_i are the shape functions. For a Taylor expansion, the definition of lambda_i is not unique. For instance for the Taylor expansion of order 1 on a 1D line above, we may be tempted to set lambda_1(x) = 1 and lambda_2(x) = (x - x_0). If you do so, what are the corresponding shape functions in the reference element, the hatlambda_i? We immediately recover hatlambda_1(hatx) = 1. For hatlambda_2:","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":" hatlambda_2(hatx) = (lambda circ F)(hatx) = (x rightarrow x - x_0) circ (hatx rightarrow fracx_r - x_l2 hatx + fracx_r + x_l2) = fracx_r - x_l2 hatx","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"So if you set lambda_2(x) = (x - x_0) then hatlambda_2 depends on the element length (Delta x = x_r-x_l), which is pointless. So lambda_2 must be proportional to the element length to obtain a universal definition for hatlambda_2. For instance, we may choose lambda_2(x) = (x - x_0) Delta x, leading to hatlambda_2(hatx) = hatx 2. But we could have chosen an other element length multiple.","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Don't forget that choosing lambda_2(x) = (x - x_0) Delta x leads to g(x) = g(x_0) + fracx - x_0Delta x g(x_0) Δx hence g_2 = g(x_0) Δx in the interpolation.","category":"page"},{"location":"api/interpolation/spaces/","page":"Available spaces","title":"Available spaces","text":"Modules = [Bcube]\nPages = [\"taylor.jl\"]","category":"page"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 0}, Bcube.AbstractShape, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Taylor, 0}, ::AbstractShape, x)\n\nShape functions for any Taylor element of degree 0 : hatlambda(xi) = 1\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 1}, Line, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Taylor, 1}, ::Line, ξ)\n\nShape functions for Line Taylor element of degree 1 in a 1D space.\n\nhatlambda_1(xi) = 1 hspace1cm hatlambda_1(xi) = fracxi2\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube._scalar_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 1}, Square, Any}","page":"Available spaces","title":"Bcube._scalar_shape_functions","text":"shape_functions(::FunctionSpace{<:Taylor, 1}, ::Square, ξ)\n\nShape functions for Square Taylor element of degree 1 in a 2D space.\n\nbeginaligned\n hatlambda_1(xi eta) = 0 \n hatlambda_2(xi eta) = fracxi2 \n hatlambda_3(xi eta) = fraceta2\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 0}, Val{1}, Line, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Taylor, 0}, ::Line, x)\n\nGradient (=derivative) of shape functions for Line Taylor element of degree 0 in a 1D space : nabla hatlambda(xi) = 0\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 0}, Val{1}, Union{Square, Triangle}, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Taylor, 0}, ::Union{Square,Triangle}, ξ)\n\nGradient of shape functions for Square or Triangle Taylor element of degree 0 in a 2D space.\n\nhatlambda_1(xi eta) = beginpmatrix 0 0 endpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 1}, Val{1}, Line, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Taylor, 1}, ::Line, ξ)\n\nGradient (=derivative) of shape functions for Line Taylor element of degree 1 in a 1D space.\n\nnabla hatlambda_1(xi) = 0 hspace1cm nabla hatlambda_1(xi) = frac12\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.grad_shape_functions-Tuple{FunctionSpace{<:Bcube.Taylor, 1}, Val{1}, Square, Any}","page":"Available spaces","title":"Bcube.grad_shape_functions","text":"grad_shape_functions(::FunctionSpace{<:Taylor, 1}, ::Square, ξ)\n\nGradient of shape functions for Square Taylor element of degree 1 in a 2D space.\n\nbeginaligned\n nabla hatlambda_1(xi eta) = beginpmatrix 0 0 endpmatrix \n nabla hatlambda_2(xi eta) = beginpmatrix frac12 0 endpmatrix \n nabla hatlambda_3(xi eta) = beginpmatrix 0 frac12 endpmatrix\nendaligned\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/spaces/#Bcube.shape_functions-Union{Tuple{N}, Tuple{FunctionSpace{<:Bcube.Taylor}, Val{N}, Bcube.AbstractShape, Any}} where N","page":"Available spaces","title":"Bcube.shape_functions","text":"Default version : the shape functions are \"replicated\". If shape_functions returns the vector [λ₁; λ₂; λ₃], and if the FESpace is of size 2, then this default behaviour consists in returning the matrix [λ₁ 0; λ₂ 0; λ₃ 0; 0 λ₁; 0 λ₂; 0 λ₃].\n\n\n\n\n\n","category":"method"},{"location":"example/linear_thermoelasticity/#Linear-thermo-elasticity","page":"Linear thermo-elasticity","title":"Linear thermo-elasticity","text":"","category":"section"},{"location":"example/linear_thermoelasticity/","page":"Linear thermo-elasticity","title":"Linear thermo-elasticity","text":"module linear_thermo_elasticity #hide\nprintln(\"Running linear thermo-elasticity API example...\") #hide\n\n# # Thermo-elasticity\n\nconst dir = string(@__DIR__, \"/\") # Bcube dir\nusing Bcube\nusing LinearAlgebra\nusing WriteVTK\nusing StaticArrays\n\n# function space (here we shall use Lagrange P1 elements) and quadrature degree.\nconst fspace = :Lagrange\nconst degree = 1 # FunctionSpace degree\nconst degquad = 2 * degree + 1\n\n# Input and output paths\nconst outputpath = joinpath(dir, \"../myout/elasticity/\")\nconst meshpath = joinpath(dir, \"../input/mesh/domainThermoElast_tri.msh\")\n\n# Time stepping scheme params\nconst α = 0.05\nconst γ = 0.5 + α\nconst β = 0.25 * (1.0 + α)^2\n\nconst totalTime = 10.0\nconst Δt = 1.0e-2\n\n# Material parameters (Young's modulus, Poisson coefficient and deduced Lamé coefficients)\nconst E = 200.0e9\nconst ν = 0.3\nconst λ = E * ν / ((1.0 + ν) * (1.0 - 2.0 * ν))\nconst μ = E / (2.0 * (1.0 + ν))\nconst Kₜ = 1.0e-6\nconst ρ = 2500.0\nconst cₚ = 1000.0\nconst k = 250.0\nconst T₀ = 280.0\n\n# Strain tensor and stress tensor (Hooke's law)\nϵ(u) = 0.5 * (∇(u) + transpose(∇(u)))\nσ(u) = λ * tr(ϵ(u)) * I + 2 * μ * (ϵ(u)) # Elastic stress\nσₜ(T) = (3 * λ + 2 * μ) * Kₜ * (T - T₀) * I # Thermal stress\n\nπ(u, v) = σ(u) ⊡ ϵ(v) # with the chosen contraction convention ϵ should be transposed, but as it is symmetric the expression remains correct\nπₜ(T, v) = σₜ(T) ⊡ ϵ(v)\n\n# materialize for identity operator\nBcube.materialize(A::LinearAlgebra.UniformScaling, B) = A\n\n# Function that performs a time step using a Newmark α-HHT scheme\n# The scheme updates the acceleration G, the velocity V and the displacement U using the following formulas:\n# ```math\n# \\begin{cases}\n# M G^{n+1} +(1-\\alpha)A U^{n+1} + \\alpha A U^{n} = (1-\\alpha) L^{n+1} + \\alpha L^n = L \\textrm{(because here $L$ is time independent)} \\\\\n# V^{n+1} = V^{n} + (1-\\gamma) \\Delta t G^n + \\gamma \\Delta t G^{n+1} \\\\\n# U^{n+1} = U^{n} + \\Delta t V^{n} + (\\frac{1}{2} - \\beta)*\\Delta t^2 G^{n} + \\beta \\Delta t^2 G^{n+1}\n# \\end{cases}\n# ```\n# where $$M$$ is the mass matrix, $$A$$ is the stiffness matrix and $$L$$ is the RHS\n# G is then computed by solving the linear system obtained by inserting the expressions for U and V in the equation for G.\nfunction Newmark_α_HHT(dt, L, A, Mat, U0, V0, G0)\n L1 = L - α * A * U0\n L2 = -(1.0 - α) * (A * U0 + dt * A * V0 + (0.5 - β) * dt * dt * A * G0)\n RHS = L1 .+ L2\n\n G = Mat \\ RHS\n U = U0 + dt * V0 + (0.5 - β) * dt * dt * G0 + β * dt * dt * G\n V = V0 + (1.0 - γ) * dt * G0 + γ * dt * G\n\n return U, V, G\nend\n\n# Function that runs the unsteady case:\nfunction run_unsteady()\n mesh = read_msh(meshpath, 2)\n\n fs = FunctionSpace(fspace, degree)\n U_scal = TrialFESpace(fs, mesh, Dict(\"West1\" => 280.0, \"East1\" => 280.0); size = 1)\n V_scal = TestFESpace(U_scal)\n U_vec = TrialFESpace(\n fs,\n mesh,\n Dict(\"West1\" => SA[0.0, 0.0], \"East1\" => SA[0.0, 0.0]);\n size = 2,\n )\n V_vec = TestFESpace(U_vec)\n\n # Initialize solution\n U = FEFunction(U_vec, 0.0)\n U0 = zeros(Bcube.get_ndofs(U_vec))\n V0 = zeros(Bcube.get_ndofs(U_vec))\n G0 = zeros(Bcube.get_ndofs(U_vec))\n\n T = FEFunction(U_scal, T₀)\n\n # Define measures for cell\n dΩ = Measure(CellDomain(mesh), degquad)\n\n # no volume force term\n f = PhysicalFunction(x -> SA[0.0, 0.0])\n\n q = PhysicalFunction(\n x -> x[1] .* (1.0 .- x[1]) .* x[2] .* (0.2 .- x[2]) .* 1500000000.0,\n )\n\n # Definition of bilinear and linear forms for the elasticity problem\n a(u, v) = ∫(π(u, v))dΩ\n m(u, v) = ∫(ρ * u ⋅ v)dΩ\n l(v) = ∫(πₜ(T, v))dΩ\n\n # An alternative way to define this linear form is to use operator composition:\n # l(v) = ∫( πₜ ∘ (T, v, ∇(v)) )dΩ\n # where πₜ(T, v, ∇v) = σₜ(T) ⊡ ϵ(v, ∇v) and ϵ(v, ∇v) = 0.5*( ∇v + transpose(∇v) )\n\n # Definition of bilinear and linear forms for the heat conduction problem\n aₜ(u, v) = ∫(k * ∇(u) ⋅ ∇(v))dΩ\n mₜ(u, v) = ∫(ρ * cₚ * u ⋅ v)dΩ\n lₜ(v) = ∫(q * v)dΩ\n\n # Assemble matrices and vector\n M = assemble_bilinear(m, U_vec, V_vec)\n A = assemble_bilinear(a, U_vec, V_vec)\n L = assemble_linear(l, V_vec)\n AT = assemble_bilinear(aₜ, U_scal, V_scal)\n MT = assemble_bilinear(mₜ, U_scal, V_scal)\n LT = assemble_linear(lₜ, V_scal)\n\n # Apply homogeneous dirichlet on A and b\n Bcube.apply_homogeneous_dirichlet_to_vector!(L, U_vec, V_vec, mesh)\n Bcube.apply_dirichlet_to_matrix!((A, M), U_vec, V_vec, mesh)\n\n # Compute a vector of dofs whose values are zeros everywhere\n # except on dofs lying on a Dirichlet boundary, where they\n # take the Dirichlet value\n Td = Bcube.assemble_dirichlet_vector(U_scal, V_scal, mesh)\n\n # Apply lift\n LT = LT - AT * Td\n\n # Apply homogeneous dirichlet condition\n Bcube.apply_homogeneous_dirichlet_to_vector!(LT, U_scal, V_scal, mesh)\n Bcube.apply_dirichlet_to_matrix!((AT, MT), U_scal, V_scal, mesh)\n\n # Write initial solution\n Un = var_on_vertices(U, mesh)\n Un = transpose(Un)\n Tn = var_on_vertices(T, mesh)\n mkpath(outputpath)\n dict_vars =\n Dict(\"Displacement\" => (Un, VTKPointData()), \"Temperature\" => (Tn, VTKPointData()))\n # Write the obtained FE solution\n write_vtk(\n outputpath * \"result_thermoelasticity\",\n 0,\n 0.0,\n mesh,\n dict_vars;\n append = false,\n )\n\n # Time loop\n itime = 0\n t = 0.0\n\n # Matrix for time stepping\n Mat = factorize(M + (1.0 - α) * (β * Δt * Δt * A))\n Miter = factorize(MT + Δt * AT)\n\n while t <= totalTime\n t += Δt\n itime = itime + 1\n @show t, itime\n\n # solve time step heat equation\n rhs = Δt * LT + MT * (get_dof_values(T) .- Td)\n set_dof_values!(T, Miter \\ rhs .+ Td)\n\n # solve time step elasticity\n U1, V1, G1 = Newmark_α_HHT(Δt, L, A, Mat, U0, V0, G0)\n\n # Update solution\n U0 .= U1\n V0 .= V1\n G0 .= G1\n\n set_dof_values!(U, U1)\n L = assemble_linear(l, V_vec)\n Bcube.apply_homogeneous_dirichlet_to_vector!(L, U_vec, V_vec, mesh)\n\n # Write solution\n if itime % 10 == 0\n Un = var_on_vertices(U, mesh)\n Un = transpose(Un)\n Tn = var_on_vertices(T, mesh)\n mkpath(outputpath)\n dict_vars = Dict(\n \"Displacement\" => (Un, VTKPointData()),\n \"Temperature\" => (Tn, VTKPointData()),\n )\n # Write the obtained FE solution\n write_vtk(\n outputpath * \"result_thermoelasticity\",\n itime,\n t,\n mesh,\n dict_vars;\n append = true,\n )\n # In order to use the warp function in paraview (solid is deformed using the displacement field)\n # the calculator filter has to be used with the following formula to reconstruct a 3D displacement field\n # with 0 z-component: Displacement_X*iHat+Displacement_Y*jHat+0.0*kHat\n end\n end\nend\n\nrun_unsteady()\n\n# Here is an animation of the obtained result:\n# ```@raw html\n# \"drawing\"\n# ```\n\nend #hide","category":"page"},{"location":"manual/function_space/#Function-and-FE-spaces","page":"Function and FE spaces","title":"Function and FE spaces","text":"","category":"section"},{"location":"manual/function_space/#AbstractFunctionSpace","page":"Function and FE spaces","title":"AbstractFunctionSpace","text":"","category":"section"},{"location":"manual/function_space/","page":"Function and FE spaces","title":"Function and FE spaces","text":"In Bcube, a FunctionSpace is defined by a type (nodal Lagrange polynomials, modal Taylor expansion, etc) and a degree. For each implemented FunctionSpace, a list of shape functions is associated on a given Shape. For instance, one can get the shape functions associated to the Lagrange polynomials or order 3 on a Square. Note that for \"tensor\" elements such as Line, Square or Cube; the Lagrange polynomials are available at any order; being computed symbolically.","category":"page"},{"location":"manual/function_space/#AbstractFESpace","page":"Function and FE spaces","title":"AbstractFESpace","text":"","category":"section"},{"location":"manual/function_space/","page":"Function and FE spaces","title":"Function and FE spaces","text":"Then, an FESpace (more precisely SingleFESpace) is a function space associated to a numbering of the degrees of freedom. Note that the numbering may depend on the continuous or discontinuous feature of the space. Hence a SingleFESpace takes basically four input to be built : a FunctionSpace, the number of components of this space (scalar or vector), an indicator of the continuous/discontinuous characteristic, and the mesh. The dof numbering is built by combining the mesh numberings (nodes, cells, faces) and the function space. Note that the degree of the FunctionSpace can differ from the \"degree\" of the mesh elements : it is possible to build a SingleFESpace with P2 polynomials on a mesh only containing straight lines (defined by only two nodes, Bar2_t). Optionaly, a SingleFESpace can also contain the tags of the boundaries where Dirichlet condition(s) applies. A MultiFESpace is simply a set of SingleFESpace, eventually of different natures. Its befenit is that it allows to build a \"global\" numbering of all the dofs represented by this space. This is especially convenient to solve systems of equations.","category":"page"},{"location":"manual/function_space/#AbstractFEFunction","page":"Function and FE spaces","title":"AbstractFEFunction","text":"","category":"section"},{"location":"manual/function_space/","page":"Function and FE spaces","title":"Function and FE spaces","text":"With a SingleFESpace, one can build the representation of a function discretized on this space: a FEFunction. This structure stores a vector of values, one for each degree of freedom of the finite element space. To set or get the values of a FEFunction, the functions set_dof_values! and get_dof_values are available respectively. A FEFunction can be projected on another FESpace; or evaluated at some specific mesh location (a coordinates, all the nodes, all the mesh centers, etc).","category":"page"},{"location":"tutorial/heat_equation/#Heat-equation-(FE)","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"","category":"section"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"In this tutorial, the heat equation (first steady and then unsteady) is solved using finite-elements.","category":"page"},{"location":"tutorial/heat_equation/#Theory","page":"Heat equation (FE)","title":"Theory","text":"","category":"section"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"This example shows how to solve the heat equation with eventually variable physical properties in steady and unsteady formulations:","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":" rho C_p partial_t u - nabla ( lambda u) = f","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"We shall assume that f rho C_p lambda in L^2(Omega). The weak form of the problem is given by: find $ u \\in \\tilde{H}^1_0(\\Omega)$ (there will be at least one Dirichlet boundary condition) such that:","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":" forall v in tildeH^1_0(Omega) underbraceint_Omega partial_t u v dx_m(partial_t uv) + underbraceint_Omega nabla u nabla v dx_a(uv) = underbraceint_Omega f v dx_l(v)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"To numerically solve this problem we seek an approximate solution using Lagrange P^1 or P^2 elements. Here we assume that the domain can be split into two domains having different material properties.","category":"page"},{"location":"tutorial/heat_equation/#Steady-case","page":"Heat equation (FE)","title":"Steady case","text":"","category":"section"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"As usual, start by importing the necessary packages.","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"using Bcube\nusing LinearAlgebra\nusing WriteVTK","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"First we define some physical and numerical constants","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"const htc = 100.0 # Heat transfer coefficient (bnd cdt)\nconst Tr = 268.0 # Recovery temperature (bnd cdt)\nconst phi = 100.0\nconst q = 1500.0\nconst λ = 100.0\nconst η = λ\nconst ρCp = 100.0 * 200.0\nconst degree = 2\nconst outputpath = joinpath(@__DIR__, \"../myout/heat_equation/\")","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Read 2D mesh","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"mesh_path = joinpath(@__DIR__, \"../input/mesh/domainSquare_tri.msh\")\nmesh = read_msh(mesh_path)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Build function space and associated Trial and Test FE spaces. We impose a Dirichlet condition with a temperature of 260K on boundary \"West\"","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"fs = FunctionSpace(:Lagrange, degree)\nU = TrialFESpace(fs, mesh, Dict(\"West\" => 260.0))\nV = TestFESpace(U)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Define measures for cell integration","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"dΩ = Measure(CellDomain(mesh), 2 * degree + 1)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Define bilinear and linear forms","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"a(u, v) = ∫(η * ∇(u) ⋅ ∇(v))dΩ\nl(v) = ∫(q * v)dΩ","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Create an affine FE system and solve it using the AffineFESystem structure. The package LinearSolve is used behind the scenes, so different solver may be used to invert the system (ex: solve(...; alg = IterativeSolversJL_GMRES())) The result is a FEFunction (ϕ). We can interpolate it on mesh centers : the result is named Tcn.","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"sys = AffineFESystem(a, l, U, V)\nϕ = solve(sys)\nTcn = var_on_centers(ϕ, mesh)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Compute analytical solution for comparison. Apply the analytical solution on mesh centers","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"T_analytical = x -> 260.0 + (q / λ) * x[1] * (1.0 - 0.5 * x[1])\nTca = map(T_analytical, get_cell_centers(mesh))","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Write both the obtained FE solution and the analytical solution to a vtk file.","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"mkpath(outputpath)\ndict_vars =\n Dict(\"Temperature\" => (Tcn, VTKCellData()), \"Temperature_a\" => (Tca, VTKCellData()))\nwrite_vtk(outputpath * \"result_steady_heat_equation\", 0, 0.0, mesh, dict_vars)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Compute and display the error","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"@show norm(Tcn .- Tca, Inf) / norm(Tca, Inf)","category":"page"},{"location":"tutorial/heat_equation/#Unsteady-case","page":"Heat equation (FE)","title":"Unsteady case","text":"","category":"section"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"The code for the unsteady case if of course very similar to the steady case, at least for the beginning. Start by defining two additional parameters:","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"totalTime = 100.0\nΔt = 0.1","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Read a slightly different mesh","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"mesh_path = joinpath(@__DIR__, \"../input/mesh/domainSquare_tri_2.msh\")\nmesh = read_msh(mesh_path)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"The rest is similar to the steady case","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"fs = FunctionSpace(:Lagrange, degree)\nU = TrialFESpace(fs, mesh, Dict(\"West\" => 260.0))\nV = TestFESpace(U)\ndΩ = Measure(CellDomain(mesh), 2 * degree + 1)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Compute matrices associated to bilinear and linear forms, and assemble","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"a(u, v) = ∫(η * ∇(u) ⋅ ∇(v))dΩ\nm(u, v) = ∫(ρCp * u ⋅ v)dΩ\nl(v) = ∫(q * v)dΩ\n\nA = assemble_bilinear(a, U, V)\nM = assemble_bilinear(m, U, V)\nL = assemble_linear(l, V)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Compute a vector of dofs whose values are zeros everywhere except on dofs lying on a Dirichlet boundary, where they take the Dirichlet value","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Ud = assemble_dirichlet_vector(U, V, mesh)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Apply lift","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"L = L - A * Ud","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Apply homogeneous dirichlet condition","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"apply_homogeneous_dirichlet_to_vector!(L, U, V, mesh)\napply_dirichlet_to_matrix!((A, M), U, V, mesh)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Form time iteration matrix (note that this is bad for performance since up to now, M and A are sparse matrices)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Miter = factorize(M + Δt * A)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Init the solution with a constant temperature of 260K","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"ϕ = FEFunction(U, 260.0)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Write initial solution to a file","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"mkpath(outputpath)\ndict_vars = Dict(\"Temperature\" => (var_on_centers(ϕ, mesh), VTKCellData()))\nwrite_vtk(outputpath * \"result_unsteady_heat_equation\", 0, 0.0, mesh, dict_vars)","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"Time loop","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"itime = 0\nt = 0.0\nwhile t <= totalTime\n global t, itime\n t += Δt\n itime = itime + 1\n @show t, itime\n\n # Compute rhs\n rhs = Δt * L + M * (get_dof_values(ϕ) .- Ud)\n\n # Invert system and apply inverse shift\n set_dof_values!(ϕ, Miter \\ rhs .+ Ud)\n\n # Write solution (every 10 iterations)\n if itime % 10 == 0\n dict_vars = Dict(\"Temperature\" => (var_on_centers(ϕ, mesh), VTKCellData()))\n write_vtk(\n outputpath * \"result_unsteady_heat_equation\",\n itime,\n t,\n mesh,\n dict_vars;\n append = true,\n )\n end\nend\n","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"","category":"page"},{"location":"tutorial/heat_equation/","page":"Heat equation (FE)","title":"Heat equation (FE)","text":"This page was generated using Literate.jl.","category":"page"},{"location":"example/covo/#Euler-equations-covo","page":"Euler equations - covo","title":"Euler equations - covo","text":"","category":"section"},{"location":"example/covo/","page":"Euler equations - covo","title":"Euler equations - covo","text":"module Covo #hide\nprintln(\"Running covo example...\") #hide\n\nconst dir = string(@__DIR__, \"/\")\nusing Bcube\nusing LinearAlgebra\nusing StaticArrays\nusing WriteVTK # only for 'VTKCellData'\nusing Profile\nusing StaticArrays\nusing InteractiveUtils\nusing BenchmarkTools\nusing UnPack\n\nfunction compute_residual(_u, V, params, cache)\n u = get_fe_functions(_u)\n\n # alias on measures\n @unpack dΩ, dΓ, dΓ_perio_x, dΓ_perio_y = params\n\n # face normals for each face domain (lazy, no computation at this step)\n nΓ = get_face_normals(dΓ)\n nΓ_perio_x = get_face_normals(dΓ_perio_x)\n nΓ_perio_y = get_face_normals(dΓ_perio_y)\n\n # flux residuals from faces for all variables\n function l(v)\n ∫(flux_Ω(u, v))dΩ +\n -∫(flux_Γ(u, v, nΓ))dΓ +\n -∫(flux_Γ(u, v, nΓ_perio_x))dΓ_perio_x +\n -∫(flux_Γ(u, v, nΓ_perio_y))dΓ_perio_y\n end\n\n rhs = assemble_linear(l, V)\n\n return cache.mass \\ rhs\nend\n\n\"\"\"\n flux_Ω(u, v)\n\nCompute volume residual using the lazy-operators approach\n\"\"\"\nflux_Ω(u, v) = _flux_Ω ∘ cellvar(u, v)\ncellvar(u, v) = (u, map(∇, v))\nfunction _flux_Ω(u, ∇v)\n ρ, ρu, ρE, ϕ = u\n ∇λ_ρ, ∇λ_ρu, ∇λ_ρE, ∇λ_ϕ = ∇v\n\n vel = ρu ./ ρ\n ρuu = ρu * transpose(vel)\n p = pressure(ρ, ρu, ρE, γ)\n\n flux_ρ = ρu\n flux_ρu = ρuu + p * I\n flux_ρE = (ρE + p) .* vel\n flux_ϕ = ϕ .* vel\n\n return ∇λ_ρ ⋅ flux_ρ + ∇λ_ρu ⊡ flux_ρu + ∇λ_ρE ⋅ flux_ρE + ∇λ_ϕ ⋅ flux_ϕ\nend\n\n\"\"\"\n flux_Γ(u,v,n)\n\nFlux at the interface is defined by a composition of two functions:\n* facevar(u,v,n) defines the input states which are needed for\n the riemann flux using operator notations\n* flux_roe(w) defines the Riemann flux (as usual)\n\"\"\"\nflux_Γ(u, v, n) = flux_roe ∘ (side⁻(u), side⁺(u), jump(v), side⁻(n))\n\n\"\"\"\n flux_roe(w)\n\"\"\"\nfunction flux_roe(ui, uj, δv, nij)\n # destructuring inputs given by `facevar` function\n\n nx, ny = nij\n ρ1, ρu1, ρE1, ϕ1 = ui\n ρ2, ρu2, ρE2, ϕ2 = uj\n δλ_ρ1, δλ_ρu1, δλ_ρE1, δλ_ϕ1 = δv\n ρux1, ρuy1 = ρu1\n ρux2, ρuy2 = ρu2\n\n # Closure\n u1 = ρux1 / ρ1\n v1 = ρuy1 / ρ1\n u2 = ρux2 / ρ2\n v2 = ρuy2 / ρ2\n p1 = pressure(ρ1, ρu1, ρE1, γ)\n p2 = pressure(ρ2, ρu2, ρE2, γ)\n\n H2 = (γ / (γ - 1)) * p2 / ρ2 + (u2 * u2 + v2 * v2) / 2.0\n H1 = (γ / (γ - 1)) * p1 / ρ1 + (u1 * u1 + v1 * v1) / 2.0\n\n R = √(ρ1 / ρ2)\n invR1 = 1.0 / (R + 1)\n uAv = (R * u1 + u2) * invR1\n vAv = (R * v1 + v2) * invR1\n Hav = (R * H1 + H2) * invR1\n cAv = √(abs((γ - 1) * (Hav - (uAv * uAv + vAv * vAv) / 2.0)))\n ecAv = (uAv * uAv + vAv * vAv) / 2.0\n\n λ1 = nx * uAv + ny * vAv\n λ3 = λ1 + cAv\n λ4 = λ1 - cAv\n\n d1 = ρ1 - ρ2\n d2 = ρ1 * u1 - ρ2 * u2\n d3 = ρ1 * v1 - ρ2 * v2\n d4 = ρE1 - ρE2\n\n # computation of the centered part of the flux\n flu11 = nx * ρ2 * u2 + ny * ρ2 * v2\n flu21 = nx * p2 + flu11 * u2\n flu31 = ny * p2 + flu11 * v2\n flu41 = H2 * flu11\n\n # Temp variables\n rc1 = (γ - 1) / cAv\n rc2 = (γ - 1) / cAv / cAv\n uq41 = ecAv / cAv + cAv / (γ - 1)\n uq42 = nx * uAv + ny * vAv\n\n fdc1 = max(λ1, 0.0) * (d1 + rc2 * (-ecAv * d1 + uAv * d2 + vAv * d3 - d4))\n fdc2 = max(λ1, 0.0) * ((nx * vAv - ny * uAv) * d1 + ny * d2 - nx * d3)\n fdc3 =\n max(λ3, 0.0) * (\n (-uq42 * d1 + nx * d2 + ny * d3) / 2.0 +\n rc1 * (ecAv * d1 - uAv * d2 - vAv * d3 + d4) / 2.0\n )\n fdc4 =\n max(λ4, 0.0) * (\n (uq42 * d1 - nx * d2 - ny * d3) / 2.0 +\n rc1 * (ecAv * d1 - uAv * d2 - vAv * d3 + d4) / 2.0\n )\n\n duv1 = fdc1 + (fdc3 + fdc4) / cAv\n duv2 = uAv * fdc1 + ny * fdc2 + (uAv / cAv + nx) * fdc3 + (uAv / cAv - nx) * fdc4\n duv3 = vAv * fdc1 - nx * fdc2 + (vAv / cAv + ny) * fdc3 + (vAv / cAv - ny) * fdc4\n duv4 =\n ecAv * fdc1 +\n (ny * uAv - nx * vAv) * fdc2 +\n (uq41 + uq42) * fdc3 +\n (uq41 - uq42) * fdc4\n\n v₁₂ = 0.5 * ((u1 + u2) * nx + (v1 + v2) * ny)\n fluxϕ = max(0.0, v₁₂) * ϕ1 + min(0.0, v₁₂) * ϕ2\n\n return (\n δλ_ρ1 * (flu11 + duv1) +\n δλ_ρu1 ⋅ (SA[flu21 + duv2, flu31 + duv3]) +\n δλ_ρE1 * (flu41 + duv4) +\n δλ_ϕ1 * (fluxϕ)\n )\nend\n\n\"\"\"\nTime integration of `f(q, t)` over a timestep `Δt`.\n\"\"\"\nforward_euler(q, f::Function, t, Δt) = get_dof_values(q) .+ Δt .* f(q, t)\n\n\"\"\"\n rk3_ssp(q, f::Function, t, Δt)\n\n`f(q, t)` is the function to integrate.\n\"\"\"\nfunction rk3_ssp(q, f::Function, t, Δt)\n stepper(q, t) = forward_euler(q, f, t, Δt)\n _q0 = get_dof_values(q)\n\n _q1 = stepper(q, Δt)\n\n set_dof_values!(q, _q1)\n _q2 = (3 / 4) .* _q0 .+ (1 / 4) .* stepper(q, t + Δt)\n\n set_dof_values!(q, _q2)\n _q1 .= (1 / 3) * _q0 .+ (2 / 3) .* stepper(q, t + Δt / 2)\n\n return _q1\nend\n\n\"\"\"\n pressure(ρ, ρu, ρE, γ)\n\nComputes pressure from perfect gaz law\n\"\"\"\nfunction pressure(ρ::Number, ρu::AbstractVector, ρE::Number, γ)\n vel = ρu ./ ρ\n ρuu = ρu * transpose(vel)\n p = (γ - 1) * (ρE - tr(ρuu) / 2)\n return p\nend\n\n\"\"\"\n Init field with a vortex (for the COVO test case)\n\"\"\"\nfunction covo!(q, dΩ)\n\n # Intermediate vars\n Cₚ = γ * r / (γ - 1)\n\n r²(x) = ((x[1] .- xvc) .^ 2 + (x[2] .- yvc) .^ 2) ./ Rc^2\n # Temperature\n T(x) = T₀ .- β^2 * U₀^2 / (2 * Cₚ) .* exp.(-r²(x))\n # Velocity\n ux(x) = U₀ .- β * U₀ / Rc .* (x[2] .- yvc) .* exp.(-r²(x) ./ 2)\n uy(x) = V₀ .+ β * U₀ / Rc .* (x[1] .- xvc) .* exp.(-r²(x) ./ 2)\n # Density\n ρ(x) = ρ₀ .* (T(x) ./ T₀) .^ (1.0 / (γ - 1))\n # momentum\n ρu(x) = SA[ρ(x) * ux(x), ρ(x) * uy(x)]\n # Energy\n ρE(x) = ρ(x) * ((Cₚ / γ) .* T(x) + (ux(x) .^ 2 + uy(x) .^ 2) ./ 2)\n # Passive scalar\n ϕ(x) = Rc^2 * r²(x) < 0.01 ? exp(-r²(x) ./ 2) : 0.0\n\n f = map(PhysicalFunction, (ρ, ρu, ρE, ϕ))\n projection_l2!(q, f, dΩ)\n return nothing\nend\n\n\"\"\"\n Tiny struct to ease the VTK output\n\"\"\"\nmutable struct VtkHandler\n basename::Any\n ite::Any\n VtkHandler(basename) = new(basename, 0)\nend\n\n\"\"\"\n Write solution to vtk\n Wrapper for `write_vtk`\n\"\"\"\nfunction append_vtk(vtk, mesh, vars, t, params)\n ρ, ρu, ρE, ϕ = vars\n\n mesh_degree = 1\n vtk_degree = maximum(x -> get_degree(Bcube.get_function_space(get_fespace(x))), vars)\n vtk_degree = max(1, mesh_degree, vtk_degree)\n\n _ρ = var_on_nodes_discontinuous(ρ, mesh, vtk_degree)\n _ρu = var_on_nodes_discontinuous(ρu, mesh, vtk_degree)\n _ρE = var_on_nodes_discontinuous(ρE, mesh, vtk_degree)\n _ϕ = var_on_nodes_discontinuous(ϕ, mesh, vtk_degree)\n\n _p = pressure.(_ρ, _ρu, _ρE, γ)\n dict_vars_dg = Dict(\n \"rho\" => (_ρ, VTKPointData()),\n \"rhou\" => (_ρu, VTKPointData()),\n \"rhoE\" => (_ρE, VTKPointData()),\n \"phi\" => (_ϕ, VTKPointData()),\n \"p\" => (_p, VTKPointData()),\n )\n Bcube.write_vtk_discontinuous(\n vtk.basename * \"_DG\",\n vtk.ite,\n t,\n mesh,\n dict_vars_dg,\n vtk_degree;\n append = vtk.ite > 0,\n )\n\n # Update counter\n vtk.ite += 1\nend\n\n# Settings\nif get(ENV, \"BenchmarkMode\", \"false\") == \"false\" #hide\n const cellfactor = 1\n const nx = 32 * cellfactor + 1\n const ny = 32 * cellfactor + 1\n const fspace = :Lagrange\n const timeScheme = :ForwardEuler\nelse #hide\n const nx = 128 + 1 #hide\n const ny = 128 + 1 #hide\n const fspace = :Lagrange\n const timeScheme = :ForwardEuler\nend #hide\nconst nperiod = 1 # number of turn\nconst CFL = 0.1\nconst degree = 1 # FunctionSpace degree\nconst degquad = 2 * degree + 1\nconst γ = 1.4\nconst β = 0.2 # vortex intensity\nconst r = 287.15 # Perfect gaz constant\nconst T₀ = 300 # mean-flow temperature\nconst P₀ = 1e5 # mean-flow pressure\nconst M₀ = 0.5 # mean-flow mach number\nconst ρ₀ = 1.0 # mean-flow density\nconst xvc = 0.0 # x-center of vortex\nconst yvc = 0.0 # y-center of vortex\nconst Rc = 0.005 # Charasteristic vortex radius\nconst c₀ = √(γ * r * T₀) # Sound velocity\nconst U₀ = M₀ * c₀ # mean-flow velocity\nconst V₀ = 0.0 # mean-flow velocity\nconst ϕ₀ = 1.0\nconst l = 0.05 # half-width of the domain\nconst Δt = CFL * 2 * l / (nx - 1) / ((1 + β) * U₀ + c₀) / (2 * degree + 1)\n#const Δt = 5.e-7\nconst nout = 100 # Number of time steps to save\nconst outputpath = \"../myout/covo/\"\nconst output = joinpath(@__DIR__, outputpath, \"covo_deg$degree\")\nconst nite = Int(floor(nperiod * 2 * l / (U₀ * Δt))) + 1\n\nfunction run_covo()\n println(\"Starting run_covo...\")\n\n # Build mesh\n meshParam = (nx = nx, ny = ny, lx = 2l, ly = 2l, xc = 0.0, yc = 0.0)\n tmp_path = \"tmp.msh\"\n if get(ENV, \"BenchmarkMode\", \"false\") == \"false\" #hide\n gen_rectangle_mesh(tmp_path, :quad; meshParam...)\n else #hide\n if get(ENV, \"MeshConfig\", \"quad\") == \"triquad\" #hide\n gen_rectangle_mesh_with_tri_and_quad(tmp_path; meshParam...) #hide\n else #hide\n gen_rectangle_mesh(tmp_path, :quad; meshParam...) #hide\n end #hide\n end #hide\n mesh = read_msh(tmp_path)\n rm(tmp_path)\n\n # Define variables and test functions\n fs = FunctionSpace(fspace, degree)\n U_sca = TrialFESpace(fs, mesh, :discontinuous; size = 1) # DG, scalar\n U_vec = TrialFESpace(fs, mesh, :discontinuous; size = 2) # DG, vectoriel\n V_sca = TestFESpace(U_sca)\n V_vec = TestFESpace(U_vec)\n U = MultiFESpace(U_sca, U_vec, U_sca, U_sca)\n V = MultiFESpace(V_sca, V_vec, V_sca, V_sca)\n u = FEFunction(U)\n\n @show Bcube.get_ndofs(U)\n\n # Define measures for cell and interior face integrations\n dΩ = Measure(CellDomain(mesh), degquad)\n dΓ = Measure(InteriorFaceDomain(mesh), degquad)\n\n # Declare periodic boundary conditions and\n # create associated domains and measures\n periodicBCType_x = PeriodicBCType(Translation(SA[-2l, 0.0]), (\"East\",), (\"West\",))\n periodicBCType_y = PeriodicBCType(Translation(SA[0.0, 2l]), (\"South\",), (\"North\",))\n Γ_perio_x = BoundaryFaceDomain(mesh, periodicBCType_x)\n Γ_perio_y = BoundaryFaceDomain(mesh, periodicBCType_y)\n dΓ_perio_x = Measure(Γ_perio_x, degquad)\n dΓ_perio_y = Measure(Γ_perio_y, degquad)\n\n params = (dΩ = dΩ, dΓ = dΓ, dΓ_perio_x = dΓ_perio_x, dΓ_perio_y = dΓ_perio_y)\n\n # Init vtk\n isdir(joinpath(@__DIR__, outputpath)) || mkpath(joinpath(@__DIR__, outputpath))\n vtk = VtkHandler(output)\n\n # Init solution\n t = 0.0\n\n covo!(u, dΩ)\n\n # cache mass matrices\n cache = (mass = factorize(Bcube.build_mass_matrix(U, V, dΩ)),)\n\n if get(ENV, \"BenchmarkMode\", \"false\") == \"true\" #hide\n return u, U, V, params, cache\n end\n\n # Write initial solution\n append_vtk(vtk, mesh, u, t, params)\n\n # Time loop\n for i in 1:nite\n println(\"\")\n println(\"\")\n println(\"Iteration \", i, \" / \", nite)\n\n ## Step forward in time\n rhs(u, t) = compute_residual(u, V, params, cache)\n if timeScheme == :ForwardEuler\n unew = forward_euler(u, rhs, time, Δt)\n elseif timeScheme == :RK3\n unew = rk3_ssp(u, rhs, time, Δt)\n else\n error(\"Unknown time scheme: $timeScheme\")\n end\n\n set_dof_values!(u, unew)\n\n t += Δt\n\n # Write solution to file\n if (i % Int(max(floor(nite / nout), 1)) == 0)\n println(\"--> VTK export\")\n append_vtk(vtk, mesh, u, t, params)\n end\n end\n\n # Summary and benchmark # ndofs total = 20480\n _rhs(u, t) = compute_residual(u, V, params, cache)\n @btime forward_euler($u, $_rhs, $time, $Δt) # 5.639 ms (1574 allocations: 2.08 MiB)\n # stepper = w -> explicit_step(w, params, cache, Δt)\n # RK3_SSP(stepper, (u, v), cache)\n # @btime RK3_SSP($stepper, ($u, $v), $cache)\n println(\"ndofs total = \", Bcube.get_ndofs(U))\n Profile.init(; n = 10^7) # returns the current settings\n Profile.clear()\n Profile.clear_malloc_data()\n @profile begin\n for i in 1:100\n forward_euler(u, _rhs, time, Δt)\n end\n end\n @show Δt, U₀, U₀ * t\n @show boundary_names(mesh)\n return nothing\nend\n\nif get(ENV, \"BenchmarkMode\", \"false\") == \"false\"\n mkpath(outputpath)\n run_covo()\nend\n\nend #hide","category":"page"},{"location":"tutorial/linear_transport/#Linear-transport-(DG)","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"","category":"section"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"In this tutorial, we show how to solve a linear transport equation using a discontinuous-Galerkin framework with Bcube.","category":"page"},{"location":"tutorial/linear_transport/#Theory","page":"Linear transport (DG)","title":"Theory","text":"","category":"section"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"In this example, we solve the following linear transport equation using discontinuous elements:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"fracpartial phipartial t + nabla cdot (c phi) = 0","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"where c is a constant velocity. Using an explicit time scheme, one obtains:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"phi^n+1 = phi^n - Delta t nabla cdot (c phi^n)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"The corresponding weak form of this equation is:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"int_Omega phi^n+1 v mathrmdOmega = int_Omega phi^n v mathrmdOmega + Delta t left\nint_Omega c phi^n cdot nabla v mathrmdOmega - oint_Gamma left( c phi cdot n right) v mathrmdGamma\nright","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"where Gamma = delta Omega. Adopting the discontinuous Galerkin framework, this equation is written in every mesh cell Omega_i. The cell boundary term involves discontinuous quantities and is replaced by a \"numerical flux\", leading to the expression:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"int_Omega_i phi^n+1 v mathrmdOmega_i = int_Omega_i phi^n v mathrmdOmega_i + Delta t left\nint_Omega_i c phi^n cdot nabla v mathrmdOmega_i - oint_Gamma_i F^*(phi) v mathrmd Gamma_i\nright","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"For this example, an upwind flux will be used for F^*. Using a matrix formulation, the above equation can be written as:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"phi^n+1 = phi^n + M^-1(f_Omega - f_Gamma)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"where M^-1 is the inverse of the mass matrix, f_Omega the volumic flux term and f_Gamma the surfacic flux term.","category":"page"},{"location":"tutorial/linear_transport/#Commented-code","page":"Linear transport (DG)","title":"Commented code","text":"","category":"section"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Start by importing the necessary packages: Load the necessary packages","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"using Bcube\nusing LinearAlgebra\nusing WriteVTK","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Before all, to ease to ease the solution VTK output we will write a structure to store the vtk filename and the number of iteration; and a function that exports the solution on demand. Note the use of var_on_nodes_discontinuous to export the solution on the mesh nodes, respecting the discontinuous feature of the solution.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"mutable struct VtkHandler\n basename::Any\n ite::Any\n mesh::Any\n VtkHandler(basename, mesh) = new(basename, 0, mesh)\nend\n\nfunction append_vtk(vtk, u::Bcube.AbstractFEFunction, t)\n # Values on center\n values = var_on_nodes_discontinuous(u, vtk.mesh)\n\n # Write\n Bcube.write_vtk_discontinuous(\n vtk.basename,\n vtk.ite,\n t,\n vtk.mesh,\n Dict(\"u\" => (values, VTKPointData())),\n 1;\n append = vtk.ite > 0,\n )\n\n # Update counter\n vtk.ite += 1\nend","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"First, we define some physical and numerical constant parameters","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"const degree = 0 # Function-space degree (Taylor(0) = first order Finite Volume)\nconst c = [1.0, 0.0] # Convection velocity (must be a vector)\nconst nite = 100 # Number of time iteration(s)\nconst CFL = 1 # 0.1 for degree 1\nconst nx = 41 # Number of nodes in the x-direction\nconst ny = 41 # Number of nodes in the y-direction\nconst lx = 2.0 # Domain width\nconst ly = 2.0 # Domain height\nconst Δt = CFL * min(lx / nx, ly / ny) / norm(c) # Time step","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Then generate the mesh of a rectangle using Gmsh and read it","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"tmp_path = \"tmp.msh\"\ngen_rectangle_mesh(tmp_path, :quad; nx = nx, ny = ny, lx = lx, ly = ly, xc = 0.0, yc = 0.0)\nmesh = read_msh(tmp_path)\nrm(tmp_path)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"We can now init our VtkHandler","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"out_dir = joinpath(@__DIR__, \"../myout\")\nvtk = VtkHandler(joinpath(out_dir, \"linear_transport\"), mesh)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"As seen in the previous tutorial, the definition of trial and test spaces needs a mesh and a function space. Here, we select Taylor space, and build discontinuous FE spaces with it. Then an FEFunction, that will represent our solution, is created.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"fs = FunctionSpace(:Taylor, degree)\nU = TrialFESpace(fs, mesh, :discontinuous)\nV = TestFESpace(U)\nu = FEFunction(U)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Define measures for cell and interior face integrations","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Γ = InteriorFaceDomain(mesh)\nΓ_in = BoundaryFaceDomain(mesh, \"West\")\nΓ_out = BoundaryFaceDomain(mesh, (\"North\", \"East\", \"South\"))\n\ndΩ = Measure(CellDomain(mesh), 2 * degree + 1)\ndΓ = Measure(Γ, 2 * degree + 1)\ndΓ_in = Measure(Γ_in, 2 * degree + 1)\ndΓ_out = Measure(Γ_out, 2 * degree + 1)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"We will also need the face normals associated to the different face domains. Note that this operation is lazy, nΓ is just an abstract representation on face normals of Γ.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"nΓ = get_face_normals(Γ)\nnΓ_in = get_face_normals(Γ_in)\nnΓ_out = get_face_normals(Γ_out)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Let's move on to the bilinear and linear forms. First, the two easiest ones:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"m(u, v) = ∫(u ⋅ v)dΩ # Mass matrix\nl_Ω(v) = ∫((c * u) ⋅ ∇(v))dΩ # Volumic convective term","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"For the flux term, we first need to define a numerical flux. It is convenient to define it separately in a dedicated function. Here is the definition of simple upwind flux.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"function upwind(ui, uj, nij)\n cij = c ⋅ nij\n if cij > zero(cij)\n flux = cij * ui\n else\n flux = cij * uj\n end\n flux\nend","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"We then define the \"flux\" as the composition of the upwind function and the needed entries: namely the solution on the negative side of the face, the solution on the positive face, and the face normal. The orientation negative/positive is arbitrary, the only convention is that the face normals are oriented from the negative side to the positive side.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"flux = upwind ∘ (side⁻(u), side⁺(u), side⁻(nΓ))\nl_Γ(v) = ∫(flux * jump(v))dΓ","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Finally, we define what to perform on the \"two\" boundaries : inlet / oulet. On the inlet, we directly impose the flux with a user defined function that depends on the time (the input is an oscillating wave). On the outlet, we keep our upwind flux but we impose the ghost cell value.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"bc_in = t -> PhysicalFunction(x -> c .* cos(3 * x[2]) * sin(4 * t)) # flux\nl_Γ_in(v, t) = ∫(side⁻(bc_in(t)) ⋅ side⁻(nΓ_in) * side⁻(v))dΓ_in\nflux_out = upwind ∘ (side⁻(u), 0.0, side⁻(nΓ_out))\nl_Γ_out(v) = ∫(flux_out * side⁻(v))dΓ_out","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Assemble the (constant) mass matrix. The returned matrix is a sparse matrix. To simplify the tutorial, we will directly compute the inverse mass matrix. But note that way more performant strategies should be employed to solve such a problem (since we don't need the inverse, only the matrix-vector product).","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"M = assemble_bilinear(m, U, V)\ninvM = inv(Matrix(M)) #WARNING : really expensive !!!","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"Let's also create three vectors to avoid allocating them at each time step","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"nd = get_ndofs(V)\nb_vol = zeros(nd)\nb_fac = similar(b_vol)\nrhs = similar(b_vol)","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"The time loop is trivial : at each time step we compute the linear forms using the assemble_ methods, we complete the rhs, perform an explicit step and write the solution.","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"t = 0.0\nfor i in 1:nite\n global t\n\n # Reset pre-allocated vectors\n b_vol .= 0.0\n b_fac .= 0.0\n\n # Compute linear forms\n assemble_linear!(b_vol, l_Ω, V)\n assemble_linear!(b_fac, l_Γ, V)\n assemble_linear!(b_fac, v -> l_Γ_in(v, t), V)\n assemble_linear!(b_fac, l_Γ_out, V)\n\n # Assemble rhs\n rhs .= Δt .* invM * (b_vol - b_fac)\n\n # Update solution\n u.dofValues .+= rhs\n\n # Update time\n t += Δt\n\n # Write to file\n append_vtk(vtk, u, t)\nend","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"And here is an animation of the result:","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"\"drawing\"","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"","category":"page"},{"location":"tutorial/linear_transport/","page":"Linear transport (DG)","title":"Linear transport (DG)","text":"This page was generated using Literate.jl.","category":"page"},{"location":"manual/operator/#LazyOperators","page":"LazyOperators","title":"LazyOperators","text":"","category":"section"},{"location":"manual/operator/","page":"LazyOperators","title":"LazyOperators","text":"WORK IN PROGRESS","category":"page"},{"location":"manual/integration/#Integration","page":"Integration","title":"Integration","text":"","category":"section"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"To compute an integral on a geometrical element, for instance a curved element, a variable substitution is used to compute the integral on the corresponding reference Shape. This variable substitution reads:","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"int_Omega g(x) mathrmd Omega = int_hatOmega J(x) left(g circ F right)(hatx) mathrmd hatOmega","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"where we recall that F is the reference to physical mapping and J is the determinant of the jacobian matrix of this mapping. Depending on the shape and element order, this determinant is either hard-coded or computed with ForwardDiff.","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"Now, to compute the right side, i.e the integral on the reference shape, quadrature rules are applied:","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"int_hatOmega g(hatx) mathrmd hatOmega = sum_i =1^N_q omega_i g(hatx_i)","category":"page"},{"location":"manual/integration/","page":"Integration","title":"Integration","text":"A specific procedure is applied to compute integrals on a face of a cell (i.e a surfacic integral on a face of a volumic element).","category":"page"},{"location":"api/interpolation/shape/#Reference-shape","page":"Reference shape","title":"Reference shape","text":"","category":"section"},{"location":"api/interpolation/shape/","page":"Reference shape","title":"Reference shape","text":"Modules = [Bcube]\nPages = [\"shape.jl\"]","category":"page"},{"location":"api/interpolation/shape/#Bcube.center-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.center","text":"center(::AbstractShape)\n\nCenter of the AbstractShape.\n\nImplementation\n\nSpecialize for better performances\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.coords-Tuple{Bcube.AbstractShape, Any}","page":"Reference shape","title":"Bcube.coords","text":"coords(shape::AbstractShape,i)\n\nReturn the coordinates of the ith shape vertices. i can be a tuple of indices, then the multiples vertices's coordinates are returned.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.coords-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.coords","text":"coords(::AbstractShape)\n\nReturn node coordinates of the shape in the reference space.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.entity-Union{Tuple{D}, Tuple{Bcube.AbstractShape, Val{D}}} where D","page":"Reference shape","title":"Bcube.entity","text":"entity(s::AbstractShape, ::Val{D}) where D\n\nReturn the geometrical Entity corresponding to the AbstractShape of a given degree D.\n\nRemark : Returned entity must be consistent with the corresponding Lagrange function space.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.face_area-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.face_area","text":"face_area(::AbstractShape)\n\nReturn the length/area of the faces of a shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.face_shapes-Tuple{Bcube.AbstractShape, Any}","page":"Reference shape","title":"Bcube.face_shapes","text":"face_shapes(shape::AbstractShape, i)\n\nShape of i-th shape of the input shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.face_shapes-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.face_shapes","text":"face_shapes(::AbstractShape)\n\nReturn a tuple of the Shape of each face of the given (cell) Shape. For instance, a Triangle has three faces, all of them are Line.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.faces2nodes-Tuple{Bcube.AbstractShape, Any}","page":"Reference shape","title":"Bcube.faces2nodes","text":"faces2nodes(shape::AbstractShape, side)\n\nReturn the index of the vertices on the iside-th face of a shape. If side is positive, the face is oriented preserving the cell normal. If side is negative, the face is returned with the opposite direction (i.e reverse node order).\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.faces2nodes-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.faces2nodes","text":"faces2nodes(::AbstractShape)\n\nReturn the index of the vertices on the faces of a shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.nedges-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.nedges","text":"nedges(::AbstractShape)\n\nGeneric function. Indicate how many edges a shape has.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.nfaces-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.nfaces","text":"nfaces(::AbstractShape)\n\nIndicate how many faces a shape has.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.normal-Tuple{Bcube.AbstractShape, Any}","page":"Reference shape","title":"Bcube.normal","text":"normal(shape::AbstractShape, i)\n\nReturn the outward normal of the ith face of the shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.normals-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.normals","text":"normals(::AbstractShape)\n\nReturn the outward normals of all the faces of the shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.nvertices-Tuple{Bcube.AbstractShape}","page":"Reference shape","title":"Bcube.nvertices","text":"nvertices(::AbstractShape)\n\nIndicate how many vertices a shape has.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/shape/#Bcube.shape-Tuple{AbstractEntityType}","page":"Reference shape","title":"Bcube.shape","text":"shape(::AbstractEntityType)\n\nReturn the reference Shape corresponding to the given AbstractEntityType.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Function-spaces","page":"Function spaces","title":"Function spaces","text":"","category":"section"},{"location":"api/interpolation/function_space/","page":"Function spaces","title":"Function spaces","text":"Modules = [Bcube]\nPages = [\"function_space.jl\", \"projection.jl\"]","category":"page"},{"location":"api/interpolation/function_space/#Bcube.AbstractFunctionSpaceType","page":"Function spaces","title":"Bcube.AbstractFunctionSpaceType","text":"Abstract structure for the different types of function space, for instance the Lagrange function space, the Taylor function space etc.\n\n\n\n\n\n","category":"type"},{"location":"api/interpolation/function_space/#Bcube.FunctionSpace-Tuple{Bcube.AbstractFunctionSpaceType, Integer}","page":"Function spaces","title":"Bcube.FunctionSpace","text":"FunctionSpace(fstype::Symbol, degree::Integer)\nFunctionSpace(fstype::AbstractFunctionSpaceType, degree::Integer)\n\nBuild a FunctionSpace of the designated FunctionSpaceType and degree.\n\nExamples\n\njulia> FunctionSpace(:Lagrange, 2)\nFunctionSpace{Bcube.Lagrange{:Uniform}, 2}()\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.basis_functions_style-Tuple{Bcube.AbstractFunctionSpace}","page":"Function spaces","title":"Bcube.basis_functions_style","text":"basis_functions_style(fs::AbstractFunctionSpace)\n\nReturn the style (modal or nodal) corresponding to the basis functions of the 'fs'.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.coords-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.coords","text":"coords(fs::AbstractFunctionSpace,::AbstractShape)\n\nReturn node coordinates in the reference space for associated function space and shape.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.get_degree-Union{Tuple{Bcube.AbstractFunctionSpace{type, degree}}, Tuple{degree}, Tuple{type}} where {type, degree}","page":"Function spaces","title":"Bcube.get_degree","text":"get_degree(::AbstractFunctionSpace{type, degree}) where{type, degree}\n\nReturn the degree associated to the AbstractFunctionSpace.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.get_type-Union{Tuple{Bcube.AbstractFunctionSpace{type}}, Tuple{type}} where type","page":"Function spaces","title":"Bcube.get_type","text":"get_type(::AbstractFunctionSpace{type})\n\nGetter for the type of the AbstractFunctionSpace\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_edge-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_edge","text":"idof_by_edge(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each edge of the Shape.\n\nDofs lying on the edge vertices are excluded.\n\nThe result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_edge_with_bounds-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_edge_with_bounds","text":"idof_by_edge_with_bounds(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each edge of the Shape.\n\nDofs lying on the edge vertices are included.\n\nThe result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_face-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_face","text":"idof_by_face(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each face of the Shape.\n\nDofs lying on the face edges are excluded, only \"face-interior\" dofs are considered.\n\nThe result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_face_with_bounds-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_face_with_bounds","text":"idof_by_face_with_bounds(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each face of the Shape.\n\nDofs lying on the face edges are included\n\nThe result is a Tuple of arrays of integers. Arrays maybe be empty. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.idof_by_vertex-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.idof_by_vertex","text":"idof_by_vertex(::AbstractFunctionSpace, ::AbstractShape)\n\nReturn the local indices of the dofs lying on each vertex of the Shape.\n\nBeware that we are talking about the Shape, not the EntityType. So 'interior' vertices of the EntityType are not taken into account for instance. See Lagrange interpolation for simple examples.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.ndofs-Tuple{Bcube.AbstractFunctionSpace, Bcube.AbstractShape}","page":"Function spaces","title":"Bcube.ndofs","text":"ndofs(fs::AbstractFunctionSpace, shape::AbstractShape)\n\nNumber of dofs associated to the given interpolation.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.shape_functions-Union{Tuple{N}, Tuple{Bcube.AbstractFunctionSpace, Val{N}, Bcube.AbstractShape, Any}} where N","page":"Function spaces","title":"Bcube.shape_functions","text":"shape_functions(::AbstractFunctionSpace, ::Val{N}, shape::AbstractShape, ξ) where N\nshape_functions(::AbstractFunctionSpace, shape::AbstractShape, ξ)\n\nReturn the list of shape functions corresponding to a FunctionSpace and a Shape. N is the size of the finite element space (default: N=1 if the argument is not provided).\n\nThe result is a vector of all the shape functions evaluated at position ξ, and not a tuple of the different shape functions. This choice is optimal for performance.\n\nNote : λ = ξ -> shape_functions(fs, shape, ξ); λ(ξ)[i] is faster than λ =shape_functions(fs, shape); λ[i](ξ)\n\nImplementation\n\nDefault version, should be overriden for each concrete FunctionSpace.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.shape_functions_vec-Union{Tuple{N}, Tuple{Bcube.AbstractFunctionSpace, Val{N}, Bcube.AbstractShape, Any}} where N","page":"Function spaces","title":"Bcube.shape_functions_vec","text":"shape_functions_vec(fs::AbstractFunctionSpace{T,D}, ::Val{N}, shape::AbstractShape, ξ) where {D,N}\n\nReturn all the shape functions of FunctionSpace on a Shape evaluated in ξ as a vector.\n\nN is the the size (number of components) of the finite element space.\n\n\n\nshape_functions_vec(fs::AbstractFunctionSpace{T,D}, n::Val{N}, shape::AbstractShape) where {T,D, N}\n\nThe shape functions are returned as a vector of functions.\n\nImplementation\n\nThis is implementation is not always valid, but it is for Lagrange and Taylor spaces (the only two spaces available up to 20/01/23).\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube._var_on_bnd_nodes_discontinuous-Tuple{Bcube.AbstractFEFunction, BoundaryFaceDomain, FunctionSpace}","page":"Function spaces","title":"Bcube._var_on_bnd_nodes_discontinuous","text":"Apply the FEFunction on the nodes of the fdomain using the FunctionSpace representation for the cells.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube._var_on_nodes_discontinuous-Tuple{Bcube.AbstractFEFunction, Mesh, FunctionSpace}","page":"Function spaces","title":"Bcube._var_on_nodes_discontinuous","text":"Apply the FEFunction on the nodes of the mesh using the FunctionSpace representation for the cells.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.var_on_bnd_nodes_discontinuous","page":"Function spaces","title":"Bcube.var_on_bnd_nodes_discontinuous","text":"var_on_bnd_nodes_discontinuous(f::AbstractFEFunction, fdomain::BoundaryFaceDomain, degree::Integer=max(1, get_degree(get_function_space(get_fespace(f)))))\n\nReturns an array containing the values of f interpolated to new DoFs on fdomain. The DoFs locations on fdomain correspond to those of a discontinuous FESpace with a :Lagrange function space of selected degree.\n\n\n\n\n\n","category":"function"},{"location":"api/interpolation/function_space/#Bcube.var_on_centers-Union{Tuple{N}, Tuple{Bcube.SingleFieldFEFunction{N}, Mesh}} where N","page":"Function spaces","title":"Bcube.var_on_centers","text":"var_on_centers(f::SingleFEFunction, mesh::Mesh)\n\nInterpolate solution on mesh vertices.\n\nThe result is a (ncells, ncomps) matrix if ncomps > 1, or a (ncells) vector otherwise.\n\n\n\n\n\n","category":"method"},{"location":"api/interpolation/function_space/#Bcube.var_on_nodes_discontinuous","page":"Function spaces","title":"Bcube.var_on_nodes_discontinuous","text":"var_on_nodes_discontinuous(f::AbstractFEFunction, mesh::Mesh, degree::Integer=max(1, get_degree(get_function_space(get_fespace(f)))))\n\nReturns an array containing the values of f interpolated to new DoFs. The DoFs correspond to those of a discontinuous cell variable with a :Lagrange function space of selected degree.\n\n\n\n\n\n","category":"function"},{"location":"api/interpolation/function_space/#Bcube.var_on_vertices-Tuple{Bcube.AbstractFEFunction, Mesh}","page":"Function spaces","title":"Bcube.var_on_vertices","text":"var_on_vertices(f::AbstractFEFunction, mesh::Mesh)\n\nInterpolate solution on mesh vertices.\n\nThe result is a (nnodes, ncomps) matrix.\n\n\n\n\n\n","category":"method"},{"location":"example/linear_elasticity/#Linear-elasticity","page":"Linear elasticity","title":"Linear elasticity","text":"","category":"section"},{"location":"example/linear_elasticity/","page":"Linear elasticity","title":"Linear elasticity","text":"module linear_elasticity #hide\nprintln(\"Running linear elasticity API example...\") #hide\n\n# # Linear elasticity\n\nconst dir = string(@__DIR__, \"/\") # bcube/example dir\nusing Bcube\nusing LinearAlgebra\nusing WriteVTK\nusing StaticArrays\n\n# function space (here we shall use Lagrange P1 elements) and quadrature degree.\nconst fspace = :Lagrange\nconst degree = 1 # FunctionSpace degree\nconst degquad = 2 * degree + 1\n\n# Input and output paths\nconst outputpath = dir * \"../myout/elasticity/\"\nconst meshpath = dir * \"../input/mesh/domainElast_tri.msh\"\n\n# Time stepping scheme params\nconst α = 0.05\nconst γ = 0.5 + α\nconst β = 0.25 * (1.0 + α)^2\n\n# Material parameters (Young's modulus, Poisson coefficient and deduced Lamé coefficients)\nconst ρ = 2500.0\nconst E = 200.0e9\nconst ν = 0.3\nconst λ = E * ν / ((1.0 + ν) * (1.0 - 2.0 * ν))\nconst μ = E / (2.0 * (1.0 + ν))\n\n# Strain tensor and stress tensor (Hooke's law)\nϵ(u) = 0.5 * (∇(u) + transpose(∇(u)))\nσ(u) = λ * tr(ϵ(u)) * I + 2 * μ * ϵ(u)\n\nπ(u, v) = σ(u) ⊡ ϵ(v) # with the chosen contraction convention ϵ should be transposed, but as it is symmetric the expression remains correct\n\n# materialize for identity operator\nBcube.materialize(A::LinearAlgebra.UniformScaling, B) = A\n\n# Function that runs the steady case:\nfunction run_steady()\n # read mesh, the second argument specifies the spatial dimension\n mesh = read_msh(meshpath, 2)\n\n fs = FunctionSpace(fspace, degree)\n U_vec = TrialFESpace(\n fs,\n mesh,\n Dict(\"West\" => SA[0.0, 0.0], \"East\" => SA[1.0, 0.0]);\n size = 2,\n )\n V_vec = TestFESpace(U_vec)\n\n # Define measures for cell\n dΩ = Measure(CellDomain(mesh), degquad)\n\n # no volume force term\n f = PhysicalFunction(x -> SA[0.0, 0.0])\n\n # definition of bilinear and linear forms\n a(u, v) = ∫(π(u, v))dΩ\n l(v) = ∫(f ⋅ v)dΩ\n\n # solve using AffineFESystem\n sys = Bcube.AffineFESystem(a, l, U_vec, V_vec)\n ϕ = Bcube.solve(sys)\n\n Un = var_on_vertices(ϕ, mesh)\n # Write the obtained FE solution\n dict_vars = Dict(\"Displacement\" => (transpose(Un), VTKPointData()))\n mkpath(outputpath)\n write_vtk(outputpath * \"result_elasticity\", itime, t, mesh, dict_vars; append = false)\nend\n\n# Function that performs a time step using a Newmark α-HHT scheme\n# The scheme updates the acceleration G, the velocity V and the displacement U using the following formulas:\n#\n# M G +(1-α)A U + αA U0 = (1-α) L + α L0 = L (because here L is time independent)\n# V = V0 + (1-γ) Δt G0 + γ Δt G\n# U = U0 + Δt V0 + (0.5-β)*Δt^2 G0 + β Δt^2 G\n#\n# G is then computed by solving the linear system obtained by inserting the expressions for U and V in the equation for G.\nfunction Newmark_α_HHT(dt, L, A, Mat, U0, V0, G0)\n L1 = L - α * A * U0\n L2 = -(1.0 - α) * (A * U0 + dt * A * V0 + (0.5 - β) * dt * dt * A * G0)\n RHS = L1 .+ L2\n\n G = Mat \\ RHS\n V = V0 + (1.0 - γ) * dt * G0 + γ * dt * G\n U = U0 + dt * V0 + (0.5 - β) * dt * dt * G0 + β * dt * dt * G\n\n return U, V, G\nend\n\n# Function that runs the unsteady case:\nfunction run_unsteady()\n # read mesh, the second argument specifies the spatial dimension\n mesh = read_msh(meshpath, 2)\n\n fs = FunctionSpace(fspace, degree)\n U_vec = TrialFESpace(fs, mesh, Dict(\"West\" => SA[0.0, 0.0]); size = 2)\n V_vec = TestFESpace(U_vec)\n\n # Define measures for cell\n dΩ = Measure(CellDomain(mesh), degquad)\n Γ = BoundaryFaceDomain(mesh, (\"East\",))\n dΓ = Measure(Γ, degquad)\n\n # surface force to be applied on East boundary\n f = PhysicalFunction(x -> SA[100000.0, 1000.0])\n\n # Definition of bilinear and linear forms\n a(u, v) = ∫(π(u, v))dΩ\n m(u, v) = ∫(ρ * u ⋅ v)dΩ\n l(v) = ∫(side⁻(f) ⋅ side⁻(v))dΓ\n\n # Assemble matrices and vector\n M = assemble_bilinear(m, U_vec, V_vec)\n A = assemble_bilinear(a, U_vec, V_vec)\n L = assemble_linear(l, V_vec)\n\n # Apply homogeneous dirichlet on A and b\n Bcube.apply_homogeneous_dirichlet_to_vector!(L, U_vec, V_vec, mesh)\n Bcube.apply_dirichlet_to_matrix!((A, M), U_vec, V_vec, mesh)\n\n # Initialize solution\n ϕ = FEFunction(U_vec, 0.0)\n U0 = zeros(Bcube.get_ndofs(U_vec))\n V0 = zeros(Bcube.get_ndofs(U_vec))\n G0 = zeros(Bcube.get_ndofs(U_vec))\n\n # Write initial solution\n Un = var_on_vertices(ϕ, mesh)\n # Write the obtained FE solution\n dict_vars = Dict(\"Displacement\" => (transpose(Un), VTKPointData()))\n mkpath(outputpath)\n write_vtk(outputpath * \"result_elasticity\", 0, 0.0, mesh, dict_vars; append = false)\n\n # Time loop\n totalTime = 1.0e-3\n Δt = 1.0e-6\n itime = 0\n t = 0.0\n\n # Matrix for time stepping\n Mat = factorize(M + (1.0 - α) * (β * Δt * Δt * A))\n\n while t <= totalTime\n t += Δt\n itime = itime + 1\n @show t, itime\n\n # solve time step\n U, V, G = Newmark_α_HHT(Δt, L, A, Mat, U0, V0, G0)\n\n # Update solution\n U0 .= U\n V0 .= V\n G0 .= G\n\n set_dof_values!(ϕ, U)\n\n # Write solution\n if itime % 10 == 0\n Un = var_on_vertices(ϕ, mesh)\n # Write the obtained FE solution\n dict_vars = Dict(\"Displacement\" => (transpose(Un), VTKPointData()))\n write_vtk(\n outputpath * \"result_elasticity\",\n itime,\n t,\n mesh,\n dict_vars;\n append = true,\n )\n # In order to use the warp function in paraview (solid is deformed using the displacement field)\n # the calculator filter has to be used with the following formula to reconstruct a 3D displacement field\n # with 0 z-component: Displacement_X*iHat+Displacement_Y*jHat+0.0*kHat\n end\n end\nend\n\n#run_steady()\nrun_unsteady()\n\nend #hide","category":"page"},{"location":"api/output/vtk/#VTK","page":"VTK","title":"VTK","text":"","category":"section"},{"location":"api/output/vtk/","page":"VTK","title":"VTK","text":"Modules = [Bcube]\nPages = [\"vtk.jl\"]","category":"page"},{"location":"api/output/vtk/#Bcube._build_fname_with_iterations-Tuple{String, Integer}","page":"VTK","title":"Bcube._build_fname_with_iterations","text":"Append the number of iteration (if positive) to the basename\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube._point_index_from_IJK-Tuple{Val{:VTK_LAGRANGE_QUADRILATERAL}, Any, Any, Any}","page":"VTK","title":"Bcube._point_index_from_IJK","text":"Return the node numbering of the node designated by its position in the x and y direction.\n\nSee https://www.kitware.com/modeling-arbitrary-order-lagrange-finite-elements-in-the-visualization-toolkit/.\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube._vtk_coords_from_lagrange-Tuple{Union{Cube, Square}, Any}","page":"VTK","title":"Bcube._vtk_coords_from_lagrange","text":"Coordinates of the nodes in the VTK cell, ordered as expected by VTK.\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube._vtk_lagrange_node_index_bcube_to_vtk-Tuple{Union{Cube, Square}, Any}","page":"VTK","title":"Bcube._vtk_lagrange_node_index_bcube_to_vtk","text":"Bcube node numbering -> VTK node numbering (in a cell)\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube._vtk_lagrange_node_index_vtk_to_bcube-Tuple{Union{Cube, Square}, Any}","page":"VTK","title":"Bcube._vtk_lagrange_node_index_vtk_to_bcube","text":"VTK node numbering (in a cell) -> Bcube node numbering\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.vtk_entity-Tuple{AbstractEntityType}","page":"VTK","title":"Bcube.vtk_entity","text":"vtk_entity(t::AbstractEntityType)\n\nConvert an AbstractEntityType into a VTKCellType. To find the correspondance, browse the WriteVTK package AND check the Doxygen (for numbering) : https://vtk.org/doc/nightly/html/classvtkTriQuadraticHexahedron.html\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.write_vtk-Union{Tuple{L}, Tuple{V}, Tuple{spaceDim}, Tuple{topoDim}, Tuple{String, Int64, Real, AbstractMesh{topoDim, spaceDim}, Dict{String, Tuple{V, L}}}} where {topoDim, spaceDim, V, L<:VTKBase.AbstractFieldData}","page":"VTK","title":"Bcube.write_vtk","text":"write_vtk(basename::String, it::Int,time::Real, mesh::AbstractMesh{topoDim,spaceDim}, vars::Dict{String,Tuple{V,L}}; append=false) where{topoDim,spaceDim,V,L<:WriteVTK.AbstractFieldData}\n\nWrite a set of variables on the mesh nodes or cell centers to a VTK file.\n\nExample\n\nmesh = basic_mesh()\nu = rand(ncells(mesh))\nv = rand(nnodes(mesh))\ndict_vars = Dict( \"u\" => (u, VTKCellData()), \"v\" => (v, VTKPointData()) )\nwrite_vtk(\"output\", 0, 0.0, mesh, dict_vars)\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.write_vtk-Union{Tuple{spaceDim}, Tuple{topoDim}, Tuple{String, AbstractMesh{topoDim, spaceDim}}} where {topoDim, spaceDim}","page":"VTK","title":"Bcube.write_vtk","text":"write_vtk(basename::String, mesh::AbstractMesh{topoDim,spaceDim}) where{topoDim,spaceDim}\n\nWrite the mesh to a VTK file.\n\nExample\n\nwrite_vtk(\"output\", basic_mesh())\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.write_vtk_discontinuous-Union{Tuple{L}, Tuple{V}, Tuple{spaceDim}, Tuple{topoDim}, Tuple{String, Int64, Real, AbstractMesh{topoDim, spaceDim}, Dict{String, Tuple{V, L}}, Int64}} where {topoDim, spaceDim, V, L<:VTKBase.AbstractFieldData}","page":"VTK","title":"Bcube.write_vtk_discontinuous","text":"VTK writer for a set of discontinuous functions. vars is a dictionnary of variable name => (values, values_location)\n\nwhere values is an array of numbers.\n\n\n\n\n\n","category":"method"},{"location":"api/output/vtk/#Bcube.write_vtk_lagrange-Union{Tuple{F}, Tuple{String, Dict{String, F}, AbstractMesh, Bcube.AbstractFESpace}, Tuple{String, Dict{String, F}, AbstractMesh, Bcube.AbstractFESpace, Integer}, Tuple{String, Dict{String, F}, AbstractMesh, Bcube.AbstractFESpace, Integer, Real}} where F<:Bcube.LazyOperators.AbstractLazy","page":"VTK","title":"Bcube.write_vtk_lagrange","text":"write_vtk_lagrange(\n basename::String,\n vars::Dict{String, F},\n mesh::AbstractMesh,\n U_export::AbstractFESpace,\n it::Integer = -1,\n time::Real = 0.0;\n collection_append = false,\n vtk_kwargs...,\n) where {F <: AbstractLazy}\n\nWrite the provided FEFunction on the mesh with the precision of the Lagrange FESpace provided.\n\nvars is a dictionnary of variable name => FEFunction to write.\n\nExample\n\nmesh = rectangle_mesh(6, 7; xmin = -1, xmax = 1.0, ymin = -1, ymax = 1.0)\nu = FEFunction(TrialFESpace(FunctionSpace(:Lagrange, 4), mesh))\nprojection_l2!(u, PhysicalFunction(x -> x[1]^2 + x[2]^2), mesh)\n\nvars = Dict(\"u\" => u, \"grad_u\" => ∇(u))\n\nfor degree_export in 1:5\n U_export = TrialFESpace(FunctionSpace(:Lagrange, degree_export), mesh)\n Bcube.write_vtk_lagrange(\n joinpath(@__DIR__, \"output\"),\n vars,\n mesh,\n U_export,\n )\nend\n\nDev notes\n\nin order to write an ASCII file, you must pass both ascii = true and append = false\ncollection_append is not named append to enable passing correct kwargs to vtk_grid\nremove (once fully validated) : write_vtk_discontinuous\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Mesh","page":"Mesh","title":"Mesh","text":"","category":"section"},{"location":"api/mesh/mesh/#Entity","page":"Mesh","title":"Entity","text":"","category":"section"},{"location":"api/mesh/mesh/","page":"Mesh","title":"Mesh","text":"Modules = [Bcube]\nPages = [\"entity.jl\"]","category":"page"},{"location":"api/mesh/mesh/#Bcube.Node","page":"Mesh","title":"Bcube.Node","text":"A Node is a point in space of dimension dim.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.topology_style-Union{Tuple{topoDim}, Tuple{T}, Tuple{spaceDim}, Tuple{Node{spaceDim, T}, AbstractEntityType{topoDim}}} where {spaceDim, T, topoDim}","page":"Mesh","title":"Bcube.topology_style","text":"topology_style(spaceDim::Int, topoDim::Int)\n\nIndicate the TopologyStyle of an entity of topology topoDim living in space of dimension spaceDim.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Connectivity","page":"Mesh","title":"Connectivity","text":"","category":"section"},{"location":"api/mesh/mesh/","page":"Mesh","title":"Mesh","text":"Modules = [Bcube]\nPages = [\"connectivity.jl\"]","category":"page"},{"location":"api/mesh/mesh/#Bcube.AbstractConnectivity","page":"Mesh","title":"Bcube.AbstractConnectivity","text":"AbstractConnectivity{T}\n\nSupertype for connectivity with indices of type T.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.Connectivity","page":"Mesh","title":"Bcube.Connectivity","text":"Connectivity{T}\n\nType for connectivity with elements of type T.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.inverse_connectivity-Union{Tuple{Connectivity{T}}, Tuple{T}} where T","page":"Mesh","title":"Bcube.inverse_connectivity","text":"inverse_connectivity(c::Connectivity{T}) where {T}\n\nReturns the \"inverse\" of the connectivity 'c' and the corresponding 'keys'. 'keys' are provided because indices in 'c' could be sparse in the general case.\n\nExample\n\nmesh = basic_mesh()\nc2n = connectivities_indices(mesh,:c2n)\nn2c, keys = inverse_connectivity(c2n)\n\nHere, 'n2c' is the node->cell graph of connectivity and, 'n2c[i]' contains the indices of the cells connected to the node of index 'keys[i]'. If 'c2n' is dense, 'keys' is not necessary (because keys[i]==i, ∀i)\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Mesh-2","page":"Mesh","title":"Mesh","text":"","category":"section"},{"location":"api/mesh/mesh/","page":"Mesh","title":"Mesh","text":"Modules = [Bcube]\nPages = [\"mesh.jl\"]","category":"page"},{"location":"api/mesh/mesh/#Bcube.AbstractMesh","page":"Mesh","title":"Bcube.AbstractMesh","text":"Implementation\n\nAll subtypes should implement the following functions:\n\nBase.parent(AbstractMesh) (default should be Base.parent(m::MyMesh) = m)\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.Mesh","page":"Mesh","title":"Bcube.Mesh","text":"bc_names : => bc_nodes : => bc_faces : => \n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.connectivity_cell2cell_by_faces-Tuple{Any}","page":"Mesh","title":"Bcube.connectivity_cell2cell_by_faces","text":"connectivity_cell2cell_by_faces(mesh)\n\nBuild the cell -> cell connectivity by looking at neighbors by faces.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.connectivity_cell2cell_by_nodes-Tuple{Any}","page":"Mesh","title":"Bcube.connectivity_cell2cell_by_nodes","text":"connectivity_cell2cell_by_nodes(mesh)\n\nBuild the cell -> cell connectivity by looking at neighbors by nodes.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.inner_faces-Tuple{Any}","page":"Mesh","title":"Bcube.inner_faces","text":"inner_faces(mesh)\n\nReturn the indices of the inner faces.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.oriented_cell_side-Tuple{Mesh, Int64, Int64}","page":"Mesh","title":"Bcube.oriented_cell_side","text":"oriented_cell_side(mesh::Mesh,icell::Int,iface::Int)\n\nReturn the side number to which the face 'iface' belongs in the cell 'icell' of the mesh. A negative side number is returned if the face is inverted. Returns '0' if the face does not belongs the cell.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.outer_faces-Tuple{Any}","page":"Mesh","title":"Bcube.outer_faces","text":"outer_faces(mesh)\n\nReturn the indices of the outer (=boundary) faces.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Domain","page":"Mesh","title":"Domain","text":"","category":"section"},{"location":"api/mesh/mesh/","page":"Mesh","title":"Mesh","text":"Modules = [Bcube]\nPages = [\"domain.jl\"]","category":"page"},{"location":"api/mesh/mesh/#Bcube.AbstractDomain","page":"Mesh","title":"Bcube.AbstractDomain","text":"An AbstractDomain designates any set of entities from a mesh. For instance a set of cells, a set of faces etc.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.BoundaryFaceDomain-Tuple{Mesh, Tuple{String, Vararg{String}}}","page":"Mesh","title":"Bcube.BoundaryFaceDomain","text":"BoundaryFaceDomain(mesh)\nBoundaryFaceDomain(mesh, label::String)\nBoundaryFaceDomain(mesh, labels::Tuple{String, Vararg{String}})\n\nBuild a BoundaryFaceDomain corresponding to the boundaries designated by one or several labels (=names).\n\nIf no label is provided, all the BoundaryFaceDomain corresponds to all the boundary faces.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.CellDomain","page":"Mesh","title":"Bcube.CellDomain","text":"A CellDomain is a representation of the cells of a mesh. It's primary purpose is to represent a domain to integrate over.\n\nExamples\n\njulia> mesh = rectangle_mesh(10, 10)\njulia> Ω_all = CellDomain(mesh)\njulia> selectedCells = [1,3,5,6]\njulia> Ω_selected = CellDomain(mesh, selectedCells)\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.CellInfo-Tuple{Any, Any, Any}","page":"Mesh","title":"Bcube.CellInfo","text":"Legacy constructor for CellInfo : no information about node indices \n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.CellInfo-Tuple{Any, Any}","page":"Mesh","title":"Bcube.CellInfo","text":"CellInfo(mesh, icell)\n\nDEBUG constructor for icell-th cell of mesh. For performance issues, don't use this version in production.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.FaceInfo","page":"Mesh","title":"Bcube.FaceInfo","text":"FaceInfo{CN<:CellInfo,CP<:CellInfo,FT,FN,F2N}\n\nType describing a face as the common side of two adjacent cells. CellInfo of cells from both sides is stored with the local side index of the face relative to each adjacent cell.\n\nRemark:\n\nFor boundary face with no periodic condition, positive cell side info\n\nare duplicate from the negative ones.\n\nFor performance reason (type stability), nodes and type of the face\n\nis stored explicitely in FaceInfo even if it could have been computed by collecting info from the side of the negative or positive cells.\n\n\n\n\n\n","category":"type"},{"location":"api/mesh/mesh/#Bcube.FaceInfo-Tuple{CellInfo, CellInfo, Any, Any, AbstractVector}","page":"Mesh","title":"Bcube.FaceInfo","text":"FaceInfo constructor\n\nCell sides are computed automatically.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.FaceInfo-Tuple{Mesh, Int64}","page":"Mesh","title":"Bcube.FaceInfo","text":"DEBUG FaceInfo constructor for kface-th cell of mesh. For performance issues, don't use this version in production.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube._compute_periodicity","page":"Mesh","title":"Bcube._compute_periodicity","text":"Find periodic face connectivities sush as :\n(faces of `labels2`) = A(faces of `labels1`)\n\n\n\n\n\n","category":"function"},{"location":"api/mesh/mesh/#Bcube.get_face_normals-Tuple{Bcube.AbstractFaceDomain}","page":"Mesh","title":"Bcube.get_face_normals","text":"Return a LazyOperator representing a face normal \n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh/#Bcube.opposite_side-Tuple{FaceInfo}","page":"Mesh","title":"Bcube.opposite_side","text":"Return the opposite side of the FaceInfo : cellside \"n\" because cellside \"p\"\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Mesh-generator","page":"Mesh generator","title":"Mesh generator","text":"","category":"section"},{"location":"api/mesh/mesh_generator/","page":"Mesh generator","title":"Mesh generator","text":"Modules = [Bcube]\nPages = [\"mesh_generator.jl\"]","category":"page"},{"location":"api/mesh/mesh_generator/#Bcube._duplicate_mesh-Tuple{AbstractMesh}","page":"Mesh generator","title":"Bcube._duplicate_mesh","text":"_duplicate_mesh(mesh::AbstractMesh)\n\nMake an exact copy of the input mesh.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.basic_mesh-Tuple{}","page":"Mesh generator","title":"Bcube.basic_mesh","text":"basic_mesh()\n\nGenerate a toy mesh of two quads and one triangle.\n\nv1 v2 v3 v4 +–-e1–>+–-e5–>+–-e8–>+ ^ | | c3 / e4 c1 e2 c2 e6 e9 | | | / +<–e3–-+<–e7–-+/ v5 v6 v7\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.circle_mesh-Tuple{Any}","page":"Mesh generator","title":"Bcube.circle_mesh","text":"circle_mesh(n; r = 1, order = 1)\n\nMesh a circle (in 2D) with n nodes on the circumference.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.line_mesh-Tuple{Any}","page":"Mesh generator","title":"Bcube.line_mesh","text":"line_mesh(n; xmin = 0., xmax = 1., order = 1, names = (\"LEFT\", \"RIGHT\"))\n\nGenerate a mesh of a line of n vertices.\n\nExample\n\njulia> mesh = line_mesh(5)\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.ncube_mesh-Tuple{Vector{Int64}}","page":"Mesh generator","title":"Bcube.ncube_mesh","text":"ncube_mesh(n::Vector{Int}; order = 1)\n\nGenerate either a line mesh, a rectangle mesh, a cubic mesh... depending on the dimension of n.\n\nArgument\n\nn number of vertices in each spatial directions\n\nExample\n\nmesh_of_a_line = ncube_mesh([10])\nmesh_of_a_square = ncube_mesh([4, 5])\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.one_cell_mesh-Tuple{Symbol}","page":"Mesh generator","title":"Bcube.one_cell_mesh","text":"one_cell_mesh(type::Symbol, order = 1)\n\nGenerate a mesh of one cell. type can be :line, :quad, :tri or :hexa.\n\nThe argument order refers to the geometry order. It has the same effect as the -order parameter in gmsh.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.rectangle_mesh-Tuple{Any, Any}","page":"Mesh generator","title":"Bcube.rectangle_mesh","text":"rectangle_mesh(\n nx,\n ny;\n type = :quad,\n xmin = 0.0,\n xmax = 1.0,\n ymin = 0.0,\n ymax = 1.0,\n order = 1,\n bnd_names = (\"north\", \"south\", \"east\", \"west\"),\n)\n\nGenerate a 2D mesh of a rectangle with nx and ny vertices in the x and y directions respectively.\n\nExample\n\njulia> mesh = rectangle_mesh(5, 4)\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.scale-Tuple{AbstractMesh, Any}","page":"Mesh generator","title":"Bcube.scale","text":"scale(mesh, factor)\n\nScale the input mesh nodes coordinates by a given factor and return the resulted mesh. The factor can be a number or a vector.\n\nUsefull for debugging.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.transform-Tuple{AbstractMesh, Any}","page":"Mesh generator","title":"Bcube.transform","text":"transform(mesh::AbstractMesh, fun)\n\nTransform the input mesh nodes coordinates by applying the given fun function and return the resulted mesh.\n\nUsefull for debugging.\n\n\n\n\n\n","category":"method"},{"location":"api/mesh/mesh_generator/#Bcube.translate-Tuple{AbstractMesh, AbstractVector{Float64}}","page":"Mesh generator","title":"Bcube.translate","text":"translate(mesh::AbstractMesh, t::Vector{Float64})\n\nTranslate the input mesh with vector t.\n\nUsefull for debugging.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Integration","page":"Integration","title":"Integration","text":"","category":"section"},{"location":"api/integration/integration/#Measure","page":"Integration","title":"Measure","text":"","category":"section"},{"location":"api/integration/integration/","page":"Integration","title":"Integration","text":"Modules = [Bcube]\nPages = [\"measure.jl\"]","category":"page"},{"location":"api/integration/integration/#Bcube.Measure","page":"Integration","title":"Bcube.Measure","text":"A Measure is geometrical domain of integration associated to a way to integrate on it (i.e a quadrature rule).\n\nQ is the quadrature type used to integrate expressions using this measure.\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.Measure-Tuple{AbstractDomain, Integer}","page":"Integration","title":"Bcube.Measure","text":"Measure(domain::AbstractDomain, degree::Integer)\nMeasure(domain::AbstractDomain, ::Val{degree}) where {degree}\n\nBuild a Measure on the designated AbstractDomain with a default quadrature of degree degree.\n\nArguments\n\ndomain::AbstractDomain : the domain to integrate over\ndegree : the degree of the quadrature rule (Legendre quadrature type by default)\n\nExamples\n\njulia> mesh = line_mesh(10)\njulia> Ω = CellDomain(mesh)\njulia> dΩ = Measure(Ω, 2)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_face_normals-Tuple{Measure{<:Bcube.AbstractFaceDomain}}","page":"Integration","title":"Bcube.get_face_normals","text":"Return a LazyOperator representing a face normal \n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Integration-methods","page":"Integration","title":"Integration methods","text":"","category":"section"},{"location":"api/integration/integration/","page":"Integration","title":"Integration","text":"Modules = [Bcube]\nPages = [\"integration.jl\"]","category":"page"},{"location":"api/integration/integration/#Base.:*-Tuple{Number, Bcube.Integration}","page":"Integration","title":"Base.:*","text":"*(a::Number, b::Integration)\n*(a::Integration, b::Number)\n\nMultiplication of an Integration is based on a rewriting rule following the linearity rules of integration : k*∫(f(x))dx => ∫(k*f(x))dx\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Base.:--Tuple{Bcube.Integrand}","page":"Integration","title":"Base.:-","text":"-(a::Integrand)\n\nSoustraction on an Integrand is treated as a multiplication by \"(-1)\" : -a ≡ ((-1)*a)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Base.:--Tuple{Bcube.Integration}","page":"Integration","title":"Base.:-","text":"-(a::Integration)\n\nSoustraction on an Integration is treated as a multiplication by \"(-1)\" : -a ≡ ((-1)*a)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.apply_quadrature-Tuple{Any, Bcube.AbstractShape, Bcube.AbstractQuadrature, Bcube.MapComputeQuadratureStyle}","page":"Integration","title":"Bcube.apply_quadrature","text":"apply_quadrature(g_ref, shape::AbstractShape, quadrature::AbstractQuadrature, ::T) where{N,T<:AbstractComputeQuadratureStyle}\n\nApply quadrature rule to function g_ref expressed on reference shape shape. Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.apply_quadrature2-Tuple{Any, Bcube.AbstractShape, Bcube.AbstractQuadrature, Bcube.MapComputeQuadratureStyle}","page":"Integration","title":"Bcube.apply_quadrature2","text":"apply_quadrature2(g_ref, shape::AbstractShape, quadrature::AbstractQuadrature, ::MapComputeQuadratureStyle) where{N}\n\nAlternative version of apply_quadrature thats seems to be more efficient for face integration (this observation is not really understood)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.getcache_∫-Tuple{AbstractEntityType, Any, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.getcache_∫","text":"getcache_∫(etype::AbstractEntityType, nodes, quadrature::AbstractQuadrature)\n\nReturn the data cache for function ∫\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate-Tuple{Any, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate","text":"integrate(g, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nIntegrate function g expressed in local element. Depending on the cell type and the space dimension, a volumic or a 'surfacic' integration is performed.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate-Tuple{Any, Int64, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate","text":"integrate(g, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nIntegrate function g on the iside-th side of the cell defined by its nodes cnodes and its type ctype. Function g(x) is expressed in the local element.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_face_ref-Tuple{Any, FaceInfo, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_face_ref","text":"Integration on a surface in a volume. We consider that we integrate on the negative side of the face.\n\nWARNING : I need this now, but I am not satisfied. We need to rethink the whole integration API\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_n-Tuple{Any, Int64, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_n","text":"integrate_n(g, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nPerform an integration over the isideth face of an element (defined by cnodes and ctype).\n\nHere g is expressed in the cell-local element : n is the normal vector in the local element, and x is in the local element as well.\n\nDev notes:\n\nThis method is DEPRECATED : never used, except in the unit tests...\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_n_ref-Tuple{Any, Int64, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_n_ref","text":"integrate_n_ref(g_ref, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nPerform an integration over the isideth face of an element (defined by cnodes and ctype).\n\nHere g_ref is expressed in the cell-reference element but n is the normal vector in the local element.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_on_ref-Tuple{Any, CellInfo, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_on_ref","text":"integrate_on_ref(g, cellinfo::CellInfo, quadrature::AbstractQuadrature, [::T]) where {N,[T<:AbstractComputeQuadratureStyle]}\n\nIntegrate a function g over a cell decribed by cellinfo. The function g can be expressed in the reference or the physical space corresponding to the cell, both cases are automatically handled by applying necessary mapping when needed.\n\nThis function is helpfull to integrate shape functions (for instance int lambda_i lambda_j) when the inverse mapping is not known explicitely (hence only hatlambda are known, not lambda).\n\nIf the last argument is given, computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Any, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(g_ref, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature, [::T]) where {[T<:AbstractComputeQuadratureStyle]}\n\nIntegrate function g_ref expressed in reference element. A variable substitution (involving Jacobian & Cie) is still applied, but the function is considered to be already mapped.\n\nThis function is helpfull to integrate shape functions (for instance int lambda_i lambda_j) when the inverse mapping is not known explicitely (hence only hatlambda are known, not lambda).\n\nIf the last argument is given, computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Any, Int64, Any, AbstractEntityType, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(g_ref, iside::Int, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature)\n\nIntegrate function g_ref on the iside-th side of the cell defined by its nodes cnodes and its type ctype. Function g_ref(x) is expressed in the cell-reference element (not the face reference).\n\nThis function is helpfull to integrate shape functions (for instance int lambda_i lambda_j) when the inverse mapping is not known explicitely (hence only hatlambda are known, not lambda).\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Bcube.isCurvilinear, Any, Any, AbstractEntityType{1}, Bcube.AbstractQuadrature, Bcube.MapComputeQuadratureStyle}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(::isCurvilinear, g_ref, cnodes, ctype::AbstractEntityType{1}, quadrature::AbstractQuadrature, ::T) where {T<:AbstractComputeQuadratureStyle}\n\nPerform an integration of the function g_ref (expressed in local element) over a line in a matbbR^n space.\n\nThe applied formulae is: int_Gamma g(x) dx = int_l F(l) g_ref(l) dl where F mathbbR rightarrow mathbbR^n is the reference segment [-1,1] to the R^n line mapping.\n\nComputation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Bcube.isNodal, Any, Any, Any, Bcube.AbstractQuadrature, Bcube.AbstractComputeQuadratureStyle}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(g_ref, cnodes, ctype, quadrature::AbstractQuadrature)\n\nIntegration on a node in a mathbbR^n space. This trivial function is only to simplify the 'side integral' expression.\n\nImplementation\n\nFor consistency reasons, g_ref is a function but it doesnt actually use its argument : the \"reference-element\" of a Node can be anything. For instance consider integrating g(x) = x on a node named node. Then g_ref(ξ) = g ∘ node.x. As you can see, g_ref doesnt actually depend on ξ\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.integrate_ref-Tuple{Bcube.isVolumic, Any, Any, AbstractEntityType, Bcube.AbstractQuadrature, Bcube.MapComputeQuadratureStyle}","page":"Integration","title":"Bcube.integrate_ref","text":"integrate_ref(::isVolumic, g_ref, cnodes, ctype::AbstractEntityType, quadrature::AbstractQuadrature, ::T) where{N, T<:AbstractComputeQuadratureStyle}\n\nIntegrate function g_ref (expressed in reference element) on mesh element of type ctype defined by its cnodes at the quadrature. Computation is optimized according to the given concrete type T<:AbstractComputeQuadratureStyle.\n\nTo do so, a variable substitution is performed to integrate on the reference element.\n\nImplementation\n\nIt has been checked that calling the apply_quadrature method within this function instead of directly applying the quadrature rule (i.e without the anonymous function) does not decrease performance nor allocation.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Quadrature-rules","page":"Integration","title":"Quadrature rules","text":"","category":"section"},{"location":"api/integration/integration/","page":"Integration","title":"Integration","text":"Modules = [Bcube]\nPages = [\"quadrature.jl\"]","category":"page"},{"location":"api/integration/integration/#Bcube.AbstractQuadrature","page":"Integration","title":"Bcube.AbstractQuadrature","text":"AbstractQuadrature{T,D}\n\nAbstract type representing quadrature of type T and degree D\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.AbstractQuadratureNode","page":"Integration","title":"Bcube.AbstractQuadratureNode","text":"AbstractQuadratureNode{S,Q}\n\nAbstract type representing a quadrature node for a shape S and a quadrature Q. This type is used to represent and identify easily a quadrature node in a quadrature rules.\n\nDerived types must implement the following method:\n\n- get_index(quadnode::AbstractQuadratureNode{S,Q})\n- get_coord(quadnode::AbstractQuadratureNode)\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.AbstractQuadratureRule","page":"Integration","title":"Bcube.AbstractQuadratureRule","text":"AbstractQuadratureRule{S,Q}\n\nAbstract type representing a quadrature rule for a shape S and quadrature Q.\n\nDerived types must implement the following method: - [get_weights(qr::AbstractQuadratureRule)] - [get_nodes(qr::AbstractQuadratureRule)] - [Base.length(qr::AbstractQuadratureRule)]\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.Quadrature","page":"Integration","title":"Bcube.Quadrature","text":"Quadrature{T,D}\n\nQuadrature of type T and degree D\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.QuadratureNode","page":"Integration","title":"Bcube.QuadratureNode","text":"QuadratureNode{S,Q}\n\nType representing a quadrature node for a shape S and a quadrature Q. This type can be used to represent and identify easily a quadrature node in the corresponding parent quadrature rule.\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.QuadratureRule","page":"Integration","title":"Bcube.QuadratureRule","text":"QuadratureRule{S,Q}\n\nAbstract type representing a quadrature rule for a shape S and quadrature Q\n\n\n\n\n\n","category":"type"},{"location":"api/integration/integration/#Bcube.QuadratureRule-Tuple{Bcube.AbstractShape, Bcube.AbstractQuadrature}","page":"Integration","title":"Bcube.QuadratureRule","text":"QuadratureRule(shape::AbstractShape, q::AbstractQuadrature)\n\nReturn the quadrature rule corresponding to the given Shape according to the selected quadrature 'q'.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Base.length-Tuple{Bcube.AbstractQuadratureRule}","page":"Integration","title":"Base.length","text":"length(qr::AbstractQuadratureRule)\n\nReturns the number of quadrature nodes of qr.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube._gausslegendre1D-Union{Tuple{Val{N}}, Tuple{N}} where N","page":"Integration","title":"Bcube._gausslegendre1D","text":"_gausslegendre1D(::Val{N}) where N\n_gausslobatto1D(::Val{N}) where N\n\nReturn N-point Gauss quadrature weights and nodes on the domain [-1:1].\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube._get_num_nodes-Union{Tuple{degree}, Tuple{Line, Val{degree}, QuadratureLegendre}} where degree","page":"Integration","title":"Bcube._get_num_nodes","text":"Gauss-Legendre formula with n nodes has degree of exactness 2n-1. Then, to obtain a given degree D, the number of nodes must satisfy: 2n-1 D or equivalently n (D+1)2\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube._get_num_nodes-Union{Tuple{degree}, Tuple{Line, Val{degree}, QuadratureLobatto}} where degree","page":"Integration","title":"Bcube._get_num_nodes","text":"Gauss-Lobatto formula with n+1 nodes has degree of exactness 2n-1, which equivalent to a degree of 2n-3 with n nodes. Then, to obtain a given degree D, the number of nodes must satisfy: 2n-3 D or equivalently n (D+3)2\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube._get_num_nodes_per_dim-Union{Tuple{Bcube.AbstractQuadratureRule{<:S}}, Tuple{S}} where S","page":"Integration","title":"Bcube._get_num_nodes_per_dim","text":"get_num_nodes_per_dim(quadrule::AbstractQuadratureRule{S}) where S<:Shape\n\nReturns the number of nodes per dimension. This function is defined for shapes for which quadratures are based on a cartesian product : Line, Square, Cube\n\nRemark : Here we assume that the same degree is used along each dimension (no anisotropy for now!)\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.evalquadnode-Tuple{Any, Bcube.AbstractQuadratureNode}","page":"Integration","title":"Bcube.evalquadnode","text":"evalquadnode(f, quadnode::AbstractQuadratureNode)\n\nEvaluate the function f at the coordinates of quadnode.\n\nBasically, it computes:\n\nf(get_coord(quadnode))\n\nRemark:\n\nOptimization could be applied if f is a function based on a nodal basis such as one of the DoF and quadnode are collocated.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_coord-Tuple{Bcube.AbstractQuadratureNode}","page":"Integration","title":"Bcube.get_coord","text":"get_coord(quadnode::AbstractQuadratureNode)\n\nReturns the coordinates of quadnode.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_index-Tuple{Bcube.AbstractQuadratureNode}","page":"Integration","title":"Bcube.get_index","text":"get_index(quadnode::AbstractQuadratureNode{S,Q})\n\nReturns the index of quadnode in the parent quadrature rule AbstractQuadRules{S,Q}\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_nodes-Tuple{Bcube.AbstractQuadratureRule}","page":"Integration","title":"Bcube.get_nodes","text":"get_nodes(qr::AbstractQuadratureRule)\n\nReturns an array containing the coordinates of all quadrature nodes of qr.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_quadnodes-Union{Tuple{QuadratureRule{S, Q, N}}, Tuple{N}, Tuple{Q}, Tuple{S}} where {S, Q, N}","page":"Integration","title":"Bcube.get_quadnodes","text":"get_quadnodes(qr::QuadratureRule{S,Q,N}) where {S,Q,N}\n\nReturns an vector containing each QuadratureNode of qr\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_quadrature_points_gausslegendre-Tuple{Type{Val{:GLTRI12}}}","page":"Integration","title":"Bcube.get_quadrature_points_gausslegendre","text":"Gauss-Legendre quadrature, 12 point rule on triangle.\n\nRef: Witherden, F. D.; Vincent, P. E. On the identification of symmetric quadrature rules for finite element methods. Comput. Math. Appl. 69 (2015), no. 10, 1232–1241\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_quadrature_points_gausslegendre-Tuple{Type{Val{:GLTRI16}}}","page":"Integration","title":"Bcube.get_quadrature_points_gausslegendre","text":"Gauss-Legendre quadrature, 16 point rule on triangle, degree 8.\n\nRef: Witherden, F. D.; Vincent, P. E. On the identification of symmetric quadrature rules for finite element methods. Comput. Math. Appl. 69 (2015), no. 10, 1232–1241\n\nNote : quadrature is rescale to match our reference triangular shape which is defined in [0:1]² instead of [-1:1]²\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_quadrature_points_gausslegendre-Tuple{Type{Val{:GLTRI7}}}","page":"Integration","title":"Bcube.get_quadrature_points_gausslegendre","text":"Gauss-Legendre quadrature, 7 point rule on triangle. \n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.get_weights-Tuple{Bcube.AbstractQuadratureRule}","page":"Integration","title":"Bcube.get_weights","text":"get_weights(qr::AbstractQuadratureRule)\n\nReturns an array containing the weights of all quadrature nodes of qr.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.quadrature_points-Tuple{Triangle, Val{4}, QuadratureLobatto}","page":"Integration","title":"Bcube.quadrature_points","text":"ref : https://www.math.umd.edu/~tadmor/references/files/Chen%20&%20Shu%20entropy%20stable%20DG%20JCP2017.pdf\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.quadrature_rule-Union{Tuple{N}, Tuple{Int64, Bcube.AbstractShape, Val{N}}} where N","page":"Integration","title":"Bcube.quadrature_rule","text":"quadrature_rule(iside::Int, shape::AbstractShape, degree::Val{N}) where N\n\nReturn the quadrature rule, computed with barycentric coefficients, corresponding to the given boundary of a shape and the given degree.\n\n\n\n\n\n","category":"method"},{"location":"api/integration/integration/#Bcube.quadrature_rule_bary-Union{Tuple{N}, Tuple{Int64, Bcube.AbstractShape, Val{N}}} where N","page":"Integration","title":"Bcube.quadrature_rule_bary","text":"quadrature_rule_bary(::Int, ::AbstractShape, degree::Val{N}) where N\n\nReturn the quadrature rule, computed with barycentric coefficients, corresponding to the given boundary of a shape and the given degree.\n\nThis function returns the quadrature weights and the barycentric weights to apply to each vertex of the reference shape. Hence, to apply the quadrature using this function, one needs to do : for (weight, l) in quadrature_rule_bary(iside, shape(etype), degree) xp = zeros(SVector{td}) for i=1:nvertices xp += l[i]*vertices[i] end # weight, xp is the quadrature couple (weight, node) end\n\n\n\n\n\n","category":"method"},{"location":"example/euler_naca_steady/#Euler-equations-on-a-NACA0012","page":"Euler equations on a NACA0012","title":"Euler equations on a NACA0012","text":"","category":"section"},{"location":"example/euler_naca_steady/","page":"Euler equations on a NACA0012","title":"Euler equations on a NACA0012","text":"module EulerNacaSteady #hide\nprintln(\"Running euler_naca_steady example...\") #hide\n# # Solve Euler equation around a NACA0012 airfoil\n\nusing Bcube\nusing LinearAlgebra\nusing WriteVTK\nusing StaticArrays\nusing BenchmarkTools\nusing Roots\nusing SparseArrays\nusing Profile\nusing InteractiveUtils\nusing WriteVTK\nusing DifferentialEquations\nusing Symbolics\nusing SparseDiffTools\n\nconst dir = string(@__DIR__, \"/\")\n\nfunction compute_residual(qdof, Q, V, params)\n q = (FEFunction(Q, qdof)...,)\n\n # alias on measures\n dΓ = params.dΓ\n dΩ = params.dΩ\n dΓ_wall = params.dΓ_wall\n dΓ_farfield = params.dΓ_farfield\n\n # Allocate rhs vectors\n b_vol = zero(qdof)\n b_fac = zero(qdof)\n\n # compute volume residuals\n l_vol(v) = ∫(flux_Ω(q, v))dΩ\n assemble_linear!(b_vol, l_vol, V)\n\n # face normals for each face domain (lazy, no computation at this step)\n nΓ = get_face_normals(dΓ)\n nΓ_wall = get_face_normals(dΓ_wall)\n nΓ_farfield = get_face_normals(dΓ_farfield)\n\n # flux residuals from interior faces for all variables\n l_Γ(v) = ∫(flux_Γ(q, v, nΓ))dΓ\n assemble_linear!(b_fac, l_Γ, V)\n\n # flux residuals from bc faces for all variables\n l_Γ_wall(v) = ∫(flux_Γ_wall(q, v, nΓ_wall))dΓ_wall\n l_Γ_farfield(v) = ∫(flux_Γ_farfield(q, v, nΓ_farfield))dΓ_farfield\n assemble_linear!(b_fac, l_Γ_wall, V)\n assemble_linear!(b_fac, l_Γ_farfield, V)\n dQ = b_vol .- b_fac\n\n return dQ\nend\n\n\"\"\"\n flux_Ω(q, v)\n\nCompute volume residual using the lazy-operators approach\n\"\"\"\nflux_Ω(q, v) = _flux_Ω ∘ (q, map(∇, v))\n\nfunction _flux_Ω(q, ∇v)\n ρ, ρu, ρE = q\n ∇λ_ρ, ∇λ_ρu, ∇λ_ρE = ∇v\n γ = stateInit.γ\n\n vel = ρu ./ ρ\n ρuu = ρu * transpose(vel)\n p = pressure(ρ, ρu, ρE, γ)\n\n flux_ρ = ρu\n flux_ρu = ρuu + p * I\n flux_ρE = (ρE + p) .* vel\n\n return return ∇λ_ρ ⋅ flux_ρ + ∇λ_ρu ⊡ flux_ρu + ∇λ_ρE ⋅ flux_ρE\nend\n\n\"\"\"\n flux_Γ(q, v, n)\n\nFlux at the interface is defined by a composition of two functions:\n* the input states at face sides which are needed for the riemann flux\n* `flux_roe` defines the Riemann flux (as usual)\n\"\"\"\nflux_Γ(q, v, n) = flux_roe ∘ (side⁻(q), side⁺(q), jump(v), side⁻(n))\n\n\"\"\"\n flux_roe(q⁻, q⁺, δv, n)\n\"\"\"\nfunction flux_roe(q⁻, q⁺, δv, n)\n γ = stateInit.γ\n nx, ny = n\n ρ1, (ρu1, ρv1), ρE1 = q⁻\n ρ2, (ρu2, ρv2), ρE2 = q⁺\n δλ_ρ1, δλ_ρu1, δλ_ρE1 = δv\n\n ρ1 = max(eps(ρ1), ρ1)\n ρ2 = max(eps(ρ2), ρ2)\n\n # Closure\n u1 = ρu1 / ρ1\n v1 = ρv1 / ρ1\n u2 = ρu2 / ρ2\n v2 = ρv2 / ρ2\n p1 = pressure(ρ1, SA[ρu1, ρv1], ρE1, γ)\n p2 = pressure(ρ2, SA[ρu2, ρv2], ρE2, γ)\n\n H2 = (γ / (γ - 1)) * p2 / ρ2 + (u2 * u2 + v2 * v2) / 2.0\n H1 = (γ / (γ - 1)) * p1 / ρ1 + (u1 * u1 + v1 * v1) / 2.0\n\n R = √(ρ1 / ρ2)\n invR1 = 1.0 / (R + 1)\n uAv = (R * u1 + u2) * invR1\n vAv = (R * v1 + v2) * invR1\n Hav = (R * H1 + H2) * invR1\n cAv = √(abs((γ - 1) * (Hav - (uAv * uAv + vAv * vAv) / 2.0)))\n ecAv = (uAv * uAv + vAv * vAv) / 2.0\n\n λ1 = nx * uAv + ny * vAv\n λ3 = λ1 + cAv\n λ4 = λ1 - cAv\n\n d1 = ρ1 - ρ2\n d2 = ρ1 * u1 - ρ2 * u2\n d3 = ρ1 * v1 - ρ2 * v2\n d4 = ρE1 - ρE2\n\n # computation of the centered part of the flux\n flux_ρ = nx * ρ2 * u2 + ny * ρ2 * v2\n flux_ρu = nx * p2 + flux_ρ * u2\n flux_ρv = ny * p2 + flux_ρ * v2\n flux_ρE = H2 * flux_ρ\n\n # Temp variables\n rc1 = (γ - 1) / cAv\n rc2 = (γ - 1) / cAv / cAv\n uq41 = ecAv / cAv + cAv / (γ - 1)\n uq42 = nx * uAv + ny * vAv\n\n fdc1 = max(λ1, 0.0) * (d1 + rc2 * (-ecAv * d1 + uAv * d2 + vAv * d3 - d4))\n fdc2 = max(λ1, 0.0) * ((nx * vAv - ny * uAv) * d1 + ny * d2 - nx * d3)\n fdc3 =\n max(λ3, 0.0) * (\n (-uq42 * d1 + nx * d2 + ny * d3) / 2.0 +\n rc1 * (ecAv * d1 - uAv * d2 - vAv * d3 + d4) / 2.0\n )\n fdc4 =\n max(λ4, 0.0) * (\n (uq42 * d1 - nx * d2 - ny * d3) / 2.0 +\n rc1 * (ecAv * d1 - uAv * d2 - vAv * d3 + d4) / 2.0\n )\n\n duv1 = fdc1 + (fdc3 + fdc4) / cAv\n duv2 = uAv * fdc1 + ny * fdc2 + (uAv / cAv + nx) * fdc3 + (uAv / cAv - nx) * fdc4\n duv3 = vAv * fdc1 - nx * fdc2 + (vAv / cAv + ny) * fdc3 + (vAv / cAv - ny) * fdc4\n duv4 =\n ecAv * fdc1 +\n (ny * uAv - nx * vAv) * fdc2 +\n (uq41 + uq42) * fdc3 +\n (uq41 - uq42) * fdc4\n\n flux_ρ += duv1\n flux_ρu += duv2\n flux_ρv += duv3\n flux_ρE += duv4\n\n return (δλ_ρ1 ⋅ flux_ρ + δλ_ρu1 ⋅ SA[flux_ρu, flux_ρv] + δλ_ρE1 ⋅ flux_ρE)\nend\n\n\"\"\"\n flux_Γ_farfield(q, v, n)\n\nCompute `Roe` flux on boundary face by imposing\n`stateBcFarfield.u_in` on `side_p`\n\"\"\"\nflux_Γ_farfield(q, v, n) = flux_roe ∘ (side⁻(q), stateBcFarfield.u_inf, side⁻(v), side⁻(n))\n\n\"\"\"\n flux_Γ_wall(q, v, n)\n\"\"\"\nflux_Γ_wall(q, v, n) = _flux_Γ_wall ∘ (side⁻(q), side⁻(v), side⁻(n))\n\nfunction _flux_Γ_wall(q⁻, v⁻, n)\n γ = stateInit.γ\n ρ1, ρu1, ρE1 = q⁻\n λ_ρ1, λ_ρu1, λ_ρE1 = v⁻\n\n p1 = pressure(ρ1, ρu1, ρE1, γ)\n\n flux_ρ = zero(ρ1)\n flux_ρu = p1 * n\n flux_ρE = zero(ρE1)\n\n return (λ_ρ1 ⋅ flux_ρ + λ_ρu1 ⋅ flux_ρu + λ_ρE1 ⋅ flux_ρE)\nend\n\nfunction sparse2vtk(\n a::AbstractSparseMatrix,\n name::String = string(@__DIR__, \"/../myout/sparse\"),\n)\n vtk_write_array(name, Array(a), \"my_property_name\")\nend\n\nmutable struct VtkHandler\n basename::String\n basename_residual::String\n ite::Int\n VtkHandler(basename) = new(basename, basename * \"_residual\", 0)\nend\n\n\"\"\"\n Write solution (at cell centers) to vtk\n Wrapper for `write_vtk`\n\"\"\"\nfunction append_vtk(vtk, mesh, vars, t, params; res = nothing)\n ρ, ρu, ρE = vars\n\n # Mean cell values\n # name2val_mean = (;zip(get_name.(vars), mean_values.(vars, degquad))...)\n # p_mean = pressure.(name2val_mean[:ρ], name2val_mean[:ρu], name2val_mean[:ρE], params.stateInit.γ)\n\n vtk_degree = maximum(x -> get_degree(Bcube.get_function_space(get_fespace(x))), vars)\n vtk_degree = max(1, mesh_degree, vtk_degree)\n _ρ = var_on_nodes_discontinuous(ρ, mesh, vtk_degree)\n _ρu = var_on_nodes_discontinuous(ρu, mesh, vtk_degree)\n _ρE = var_on_nodes_discontinuous(ρE, mesh, vtk_degree)\n\n Cp = pressure_coefficient.(_ρ, _ρu, _ρE)\n Ma = mach.(_ρ, _ρu, _ρE)\n dict_vars_dg = Dict(\n \"rho\" => (_ρ, VTKPointData()),\n \"rhou\" => (_ρu, VTKPointData()),\n \"rhoE\" => (_ρE, VTKPointData()),\n \"Cp\" => (Cp, VTKPointData()),\n \"Mach\" => (Ma, VTKPointData()),\n \"rho_mean\" => (get_values(Bcube.cell_mean(ρ, params.dΩ)), VTKCellData()),\n \"rhou_mean\" => (get_values(Bcube.cell_mean(ρu, params.dΩ)), VTKCellData()),\n \"rhoE_mean\" => (get_values(Bcube.cell_mean(ρE, params.dΩ)), VTKCellData()),\n \"lim_rho\" => (get_values(params.limρ), VTKCellData()),\n \"lim_all\" => (get_values(params.limAll), VTKCellData()),\n )\n Bcube.write_vtk_discontinuous(\n vtk.basename * \"_DG\",\n vtk.ite,\n t,\n mesh,\n dict_vars_dg,\n vtk_degree;\n append = vtk.ite > 0,\n )\n\n _ρ_wall = var_on_bnd_nodes_discontinuous(ρ, params.Γ_wall, vtk_degree)\n _ρu_wall = var_on_bnd_nodes_discontinuous(ρu, params.Γ_wall, vtk_degree)\n _ρE_wall = var_on_bnd_nodes_discontinuous(ρE, params.Γ_wall, vtk_degree)\n\n Cp_wall = pressure_coefficient.(_ρ_wall, _ρu_wall, _ρE_wall)\n Ma_wall = pressure_coefficient.(_ρ_wall, _ρu_wall, _ρE_wall)\n\n dict_vars_wall = Dict(\n \"rho\" => (_ρ_wall, VTKPointData()),\n \"rhou\" => (_ρu_wall, VTKPointData()),\n \"rhoE\" => (_ρE_wall, VTKPointData()),\n \"Cp\" => (Cp_wall, VTKPointData()),\n \"Mach\" => (Ma_wall, VTKPointData()),\n )\n Bcube.write_vtk_bnd_discontinuous(\n vtk.basename * \"_bnd_DG\",\n 1,\n 0.0,\n params.Γ_wall,\n dict_vars_wall,\n vtk_degree;\n append = false,\n )\n\n #residual:\n if !isa(res, Nothing)\n vtkfile = vtk_grid(vtk.basename_residual, Float64.(res.iter), [0.0, 1.0])\n for (k, valₖ) in enumerate(res.val)\n vtkfile[\"res_\" * string(k), VTKPointData()] = [valₖ valₖ]\n end\n vtk_save(vtkfile)\n end\n\n # Update counter\n vtk.ite += 1\n\n return nothing\nend\n\nfunction init!(q, dΩ, initstate)\n AoA = initstate.AoA\n Minf = initstate.M_inf\n Pinf = initstate.P_inf\n Tinf = initstate.T_inf\n r = initstate.r_gas\n γ = initstate.γ\n\n ρinf = Pinf / r / Tinf\n ainf = √(γ * r * Tinf)\n Vinf = Minf * ainf\n ρVxinf = ρinf * Vinf * cos(AoA)\n ρVyinf = ρinf * Vinf * sin(AoA)\n ρEinf = Pinf / (γ - 1) + 0.5 * ρinf * Vinf^2\n\n ρ0 = PhysicalFunction(x -> ρinf)\n ρu0 = PhysicalFunction(x -> SA[ρVxinf, ρVyinf])\n ρE0 = PhysicalFunction(x -> ρEinf)\n projection_l2!(q, (ρ0, ρu0, ρE0), dΩ)\n return nothing\nend\n\nfunction main(stateInit, stateBcFarfield, degree)\n @show degree, degquad\n\n mesh = read_msh(dir * \"../input/mesh/naca0012_o\" * string(mesh_degree) * \".msh\", 2)\n scale!(mesh, 1.0 / 0.5334)\n\n dimcar = compute_dimcar(mesh)\n\n DMPrelax = DMPcurv₀ .* dimcar .^ 2\n\n # Then we create a `NamedTuple` to hold the simulation parameters.\n params = (\n degquad = degquad,\n stateInit = stateInit,\n stateBcFarfield = stateBcFarfield,\n DMPrelax = DMPrelax,\n )\n\n # Define measures for cell and interior face integrations\n dΩ = Measure(CellDomain(mesh), degquad)\n dΓ = Measure(InteriorFaceDomain(mesh), degquad)\n\n # Declare boundary conditions and\n # create associated domains and measures\n Γ_wall = BoundaryFaceDomain(mesh, (\"NACA\",))\n Γ_farfield = BoundaryFaceDomain(mesh, (\"FARFIELD\",))\n dΓ_wall = Measure(Γ_wall, degquad)\n dΓ_farfield = Measure(Γ_farfield, degquad)\n\n params = (\n params...,\n Γ_wall = Γ_wall,\n dΓ = dΓ,\n dΩ = dΩ,\n dΓ_wall = dΓ_wall,\n dΓ_farfield = dΓ_farfield,\n )\n\n qLowOrder = nothing\n\n for deg in 0:degree\n params = (params..., degree = deg)\n\n fs = FunctionSpace(fspace, deg)\n Q_sca = TrialFESpace(fs, mesh, :discontinuous; size = 1) # DG, scalar\n Q_vec = TrialFESpace(fs, mesh, :discontinuous; size = 2) # DG, vectoriel\n V_sca = TestFESpace(Q_sca)\n V_vec = TestFESpace(Q_vec)\n Q = MultiFESpace(Q_sca, Q_vec, Q_sca)\n V = MultiFESpace(V_sca, V_vec, V_sca)\n\n q = FEFunction(Q)\n\n # select an initial configurations:\n if deg == 0\n init!(q, mesh, stateInit)\n else\n println(\"Start projection\")\n projection_l2!(q, qLowOrder, dΩ)\n println(\"End projection\")\n end\n\n # create CellData to store limiter values\n limρ = Bcube.MeshCellData(ones(ncells(mesh)))\n limAll = Bcube.MeshCellData(ones(ncells(mesh)))\n params = (params..., limρ = limρ, limAll = limAll)\n\n # Init vtk handler\n mkpath(outputpath)\n vtk = VtkHandler(\n outputpath * \"euler_naca_mdeg\" * string(mesh_degree) * \"_deg\" * string(deg),\n )\n\n # Init time\n time = 0.0\n\n # Save initial solution\n append_vtk(vtk, mesh, q, time, params)\n\n # Build the cache and store everything you want to compute only once (such as the mass matrice inverse...)\n\n cache = ()\n # Allocate buffer for compute_residual\n b_vol = zeros(Bcube.get_ndofs(Q))\n b_fac = zeros(Bcube.get_ndofs(Q))\n cache = (cache..., b_vol = b_vol, b_fac = b_fac)\n\n cache = (\n cache...,\n cacheCellMean = Bcube.build_cell_mean_cache(q, dΩ),\n mass = factorize(Bcube.build_mass_matrix(Q, V, dΩ)),\n mass_sca = factorize(Bcube.build_mass_matrix(Q_sca, V_sca, dΩ)),\n mass_vec = factorize(Bcube.build_mass_matrix(Q_vec, V_vec, dΩ)),\n )\n\n time, q = steady_solve!(Q, V, q, mesh, params, cache, vtk, deg)\n append_vtk(vtk, mesh, q, time, params)\n println(\"end steady_solve for deg=\", deg, \" !\")\n\n deg < degree && (qLowOrder = deepcopy(q))\n end\n return nothing\nend\n\nfunction steady_solve!(Q, V, q, mesh, params, cache, vtk, deg)\n counter = [0]\n q0 = deepcopy(get_dof_values(q))\n ode_params =\n (Q = Q, V = V, params = params, cache = cache, counter = counter, vtk = vtk)\n\n rhs!(dq, q, p, t) = dq .= compute_residual(q, p.Q, p.V, p.params)\n\n # compute sparsity pattern and coloring\n println(\"computing jacobian cache...\")\n if withbench\n _rhs!(dq, q) = rhs!(dq, q, ode_params, 0.0)\n @btime $_rhs!(similar($q0), $q0)\n q_bench = FEFunction(Q, q0)\n @btime $apply_limitation!($q_bench, $ode_params)\n @show length(q0)\n end\n\n #sparsity_pattern = Symbolics.jacobian_sparsity(_rhs!, similar(Q0), Q0)\n #tjac = @elapsed Symbolics.jacobian_sparsity(_rhs!, similar(Q0), Q0)\n #@show tjac\n sparsity_pattern = Bcube.build_jacobian_sparsity_pattern(Q, mesh)\n println(\"sparsity pattern computed !\")\n display(sparsity_pattern)\n colors = matrix_colors(sparsity_pattern)\n println(\"coloring done!\")\n @show maximum(colors)\n\n ode = ODEFunction(\n rhs!;\n mass_matrix = Bcube.build_mass_matrix(Q, V, params.dΩ),\n jac_prototype = sparsity_pattern,\n colorvec = colors,\n )\n\n Tfinal = Inf\n problem = ODEProblem(ode, q0, (0.0, Tfinal), ode_params)\n timestepper = ImplicitEuler(; nlsolve = NLNewton(; max_iter = 20))\n\n cb_cache = DiscreteCallback(always_true, update_cache!; save_positions = (false, false))\n cb_vtk = DiscreteCallback(always_true, output_vtk; save_positions = (false, false))\n cb_steady = TerminateSteadyState(1e-6, 1e-6, condition_steadystate)\n\n error = 1e-1\n\n sol = solve(\n problem,\n timestepper;\n initializealg = NoInit(),\n adaptive = true,\n abstol = error,\n reltol = error,\n progress = false,\n progress_steps = 1000,\n save_everystep = false,\n save_start = false,\n save_end = false,\n isoutofdomain = isoutofdomain,\n callback = CallbackSet(cb_cache, cb_vtk, cb_steady),\n )\n\n set_dof_values!(q, sol.u[end])\n return sol.t[end], q\nend\n\nalways_true(args...) = true\n\nfunction isoutofdomain(dof, p, t)\n any(isnan, dof) && return true\n\n q = FEFunction(p.Q, dof)\n q_mean = map(get_values, Bcube.cell_mean(q, p.cache.cacheCellMean))\n p_mean = pressure.(q_mean..., stateInit.γ)\n\n negative_ρ = any(x -> x < 0, q_mean[1])\n negative_p = any(x -> x < 0, p_mean)\n isout = negative_ρ || negative_p\n isout && @show negative_ρ, negative_p\n return isout\nend\n\nfunction update_cache!(integrator)\n Q = integrator.p.Q\n Q1, = Q\n deg = get_degree(Bcube.get_function_space(Q1))\n println(\n \"deg=\",\n deg,\n \" update_cache! : iter=\",\n integrator.p.counter[1],\n \" dt=\",\n integrator.dt,\n )\n\n q = FEFunction(integrator.p.Q, integrator.u)\n limiter_projection && apply_limitation!(q, integrator.p)\n return nothing\nend\n\nfunction output_vtk(integrator)\n u_modified!(integrator, false)\n mesh = get_mesh(get_domain(integrator.p.params.dΩ))\n q = FEFunction(integrator.p.Q, integrator.u)\n counter = integrator.p.counter\n counter .+= 1\n if (counter[1] % nout == 0)\n println(\"output_vtk \", counter[1])\n append_vtk(integrator.p.vtk, mesh, q, integrator.t, integrator.p.params)\n end\n return nothing\nend\n\nfunction condition_steadystate(integrator, abstol, reltol, min_t)\n u_modified!(integrator, false)\n if DiffEqBase.isinplace(integrator.sol.prob)\n testval = first(get_tmp_cache(integrator))\n @. testval = (integrator.u - integrator.uprev) / (integrator.t - integrator.tprev)\n else\n testval = (integrator.u - integrator.uprev) / (integrator.t - integrator.tprev)\n end\n\n if typeof(integrator.u) <: Array\n any(\n abs(d) > abstol && abs(d) > reltol * abs(u) for (d, abstol, reltol, u) in\n zip(testval, Iterators.cycle(abstol), Iterators.cycle(reltol), integrator.u)\n ) && (return false)\n else\n any((abs.(testval) .> abstol) .& (abs.(testval) .> reltol .* abs.(integrator.u))) &&\n (return false)\n end\n\n if min_t === nothing\n return true\n else\n return integrator.t >= min_t\n end\nend\n\n\"\"\"\nCompute the characteristic dimension of each cell of `mesh`:\ndimcar = (cell volume) / (cell surface)\n\n# TODO :\nto be moved to Bcube\n\"\"\"\nfunction compute_dimcar(mesh)\n fs = FunctionSpace(:Lagrange, 0)\n V = TestFESpace(fs, mesh; size = 1, isContinuous = false)\n\n # Define measures for cell and interior face integrations\n dΩ = Measure(CellDomain(mesh), degquad)\n dΓ = Measure(InteriorFaceDomain(mesh), degquad)\n dΓ_bc = Measure(BoundaryFaceDomain(mesh), degquad)\n\n f1 = PhysicalFunction(x -> 1.0)\n l(v) = ∫(f1 ⋅ v)dΩ\n l_face(v, dω) = ∫(side⁻(f1) ⋅ side⁻(v) + side⁺(f1) ⋅ side⁺(v))dω\n\n vol = assemble_linear(l, V)\n surf = assemble_linear(Base.Fix2(l_face, dΓ), V)\n surf += assemble_linear(Base.Fix2(l_face, dΓ_bc), V)\n return vol ./ surf\nend\n\n\"\"\"\nReferences:\n* Xiangxiong Zhang, Chi-Wang Shu, On positivity-preserving high order discontinuous\n Galerkin schemes for compressible Euler equations on rectangular meshes,\n Journal of Computational Physics, Volume 229, Issue 23, 2010.\n https://doi.org/10.1016/j.jcp.2010.08.016\n* Zhang, X., Xia, Y. & Shu, CW. Maximum-Principle-Satisfying and Positivity-Preserving\n High Order Discontinuous Galerkin Schemes for Conservation Laws on Triangular Meshes.\n J Sci Comput 50, 29–62 (2012). https://doi.org/10.1007/s10915-011-9472-8\n\"\"\"\nfunction apply_limitation!(q::Bcube.AbstractFEFunction, ode_params)\n params = ode_params.params\n cache = ode_params.cache\n mesh = get_mesh(get_domain(params.dΩ))\n ρ, ρu, ρE = q\n\n ρ_mean, ρu_mean, ρE_mean = Bcube.cell_mean(q, cache.cacheCellMean)\n\n _limρ, ρ_proj = linear_scaling_limiter(\n ρ,\n params.dΩ;\n bounds = (ρmin₀, ρmax₀),\n DMPrelax = params.DMPrelax,\n mass = cache.mass_sca,\n )\n\n op_t = limiter_param_p ∘ (ρ_proj, ρu, ρE, ρ_mean, ρu_mean, ρE_mean)\n t = Bcube._minmax_cells(op_t, mesh, Val(params.degquad))\n tmin = Bcube.MeshCellData(getindex.(t, 1))\n\n if eltype(_limρ) == eltype(params.limρ) # skip Dual number case\n set_values!(params.limρ, get_values(_limρ))\n set_values!(params.limAll, get_values(tmin))\n end\n\n limited_var(u, ū, lim_u) = ū + lim_u * (u - ū)\n projection_l2!(ρ, limited_var(ρ_proj, ρ_mean, tmin), params.dΩ; mass = cache.mass_sca)\n projection_l2!(ρu, limited_var(ρu, ρu_mean, tmin), params.dΩ; mass = cache.mass_vec)\n projection_l2!(ρE, limited_var(ρE, ρE_mean, tmin), params.dΩ; mass = cache.mass_sca)\n return nothing\nend\n\nfunction limiter_param_p(ρ̂, ρu, ρE, ρ_mean, ρu_mean, ρE_mean)\n γ = stateInit.γ\n p = pressure(ρ̂, ρu, ρE, γ)\n\n if p ≥ pmin₀\n t = 1.0\n else\n @show p, ρ̂, ρu, ρE\n @show ρ_mean, ρu_mean, ρE_mean\n @show pressure(ρ_mean, ρu_mean, ρE_mean, γ)\n if pressure(ρ_mean, ρu_mean, ρE_mean, γ) > pmin₀\n fₜ =\n t ->\n pressure(\n t * ρ̂ + (1 - t) * ρ_mean,\n t * ρu + (1 - t) * ρu_mean,\n t * ρE + (1 - t) * ρE_mean,\n γ,\n ) - pmin₀\n bounds = (0.0, 1.0)\n t = find_zero(fₜ, bounds, Bisection())\n else\n t = NaN\n println(\"t = NaN\")\n end\n end\n\n return t\nend\n\nfunction pressure(ρ::Number, ρu::AbstractVector, ρE::Number, γ)\n vel = ρu ./ ρ\n ρuu = ρu * transpose(vel)\n p = (γ - 1) * (ρE - tr(ρuu) / 2)\n return p\nend\n\ncompute_Pᵢ(P, γ, M) = P * (1 + 0.5 * (γ - 1) * M^2)^(γ / (γ - 1))\ncompute_Tᵢ(T, γ, M) = T * (1 + 0.5 * (γ - 1) * M^2)\n\nfunction bc_state_farfield(AoA, M, P, T, r, γ)\n a = √(γ * r * T)\n vn = M * a\n ρ = P / r / T\n ρu = SA[ρ * vn * cos(AoA), ρ * vn * sin(AoA)]\n ρE = P / (γ - 1) + 0.5 * ρ * vn^2\n return (ρ, ρu, ρE)\nend\n\nfunction pressure_coefficient(ρ, ρu, ρE)\n (pressure(ρ, ρu, ρE, stateInit.γ) - stateInit.P_inf) /\n (stateBcFarfield.Pᵢ_inf - stateInit.P_inf)\nend\nfunction mach(ρ, ρu, ρE)\n norm(ρu ./ ρ) / √(stateInit.γ * max(0.0, pressure(ρ, ρu, ρE, stateInit.γ) / ρ))\nend\n\nconst degreemax = 2 # Function-space degree\nconst mesh_degree = 2\nconst fspace = :Lagrange\nconst limiter_projection = true\nconst ρmin₀ = 1.0e-8\nconst ρmax₀ = 1.0e+10\nconst pmin₀ = 1.0e-8\nconst pmax₀ = 1.0e+10\nconst DMPcurv₀ = 10.0e3\nconst withbench = false\n\nconst stateInit = (\n AoA = deg2rad(1.25),\n M_inf = 0.8,\n P_inf = 101325.0,\n T_inf = 275.0,\n r_gas = 287.0,\n γ = 1.4,\n)\nconst nite_max = 300 #300000 # Number of time iteration(s)\nconst nout = 1 # number of step between two vtk outputs\nconst mass_matrix_in_solve = true\nconst degquad = 6\nconst outputpath = string(@__DIR__, \"/../myout/euler_naca_steady/\")\n\nconst stateBcFarfield = (\n AoA = stateInit.AoA,\n M_inf = stateInit.M_inf,\n Pᵢ_inf = compute_Pᵢ(stateInit.P_inf, stateInit.γ, stateInit.M_inf),\n Tᵢ_inf = compute_Tᵢ(stateInit.T_inf, stateInit.γ, stateInit.M_inf),\n u_inf = bc_state_farfield(\n stateInit.AoA,\n stateInit.M_inf,\n stateInit.P_inf,\n stateInit.T_inf,\n stateInit.r_gas,\n stateInit.γ,\n ),\n r_gas = stateInit.r_gas,\n γ = stateInit.γ,\n)\n\nmain(stateInit, stateBcFarfield, degreemax)\n\nend #hide","category":"page"},{"location":"manual/geometry/#Geometry-and-mesh","page":"Geometry and mesh","title":"Geometry and mesh","text":"","category":"section"},{"location":"manual/geometry/","page":"Geometry and mesh","title":"Geometry and mesh","text":"A Mesh is a set basically of nodes (Node), a set of entities (the mesh elements) and a list of connectivies that link the entities between themselves and with the nodes.","category":"page"},{"location":"manual/geometry/","page":"Geometry and mesh","title":"Geometry and mesh","text":"In Bcube every mesh entity has corresponding reference Shape, a simplified or canonical representation of this element. A 1D line is mapped on the [-1,1] segment, and a rectangle is mapped on a square for instance. On these reference shapes, (almost) everything is known : the vertices location, the area, the quadrature points... Hence in Bcube we always compute things in the reference shape. For \"Lagrange\" elements (such as Bar*_t, Tri*_t, Quad*_t, Tetra*_t, Hexa*_t, Penta*_t etc), the mapping from the reference shape to a geometrical element is directly obtained from the corresponding Lagrange polynomials and the element node coordinates. Given a geometrical element with n nodes M_i, the mapping reads:","category":"page"},{"location":"manual/geometry/","page":"Geometry and mesh","title":"Geometry and mesh","text":"F(xi) = sum_i=1^n hatlambda_i(xi)M_i","category":"page"},{"location":"manual/geometry/","page":"Geometry and mesh","title":"Geometry and mesh","text":"where (lambda)_i are the Lagrange polynomials whose order matches the element order.","category":"page"},{"location":"","page":"Home","title":"Home","text":"CurrentModule = Bcube","category":"page"},{"location":"#Bcube","page":"Home","title":"Bcube","text":"","category":"section"},{"location":"#Purpose-of-Bcube","page":"Home","title":"Purpose of Bcube","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"Bcube is a Julia library providing tools for the spatial discretization of partial differential equation(s) (PDE). The main objectives are:","category":"page"},{"location":"","page":"Home","title":"Home","text":"to provide a set of tools to quickly assemble an algorithm solving partial differential equation(s) (so the main objective is to help building prototypes without thinking about the numerical core)\nto be completed : efficient/performant PDE resolution?","category":"page"},{"location":"","page":"Home","title":"Home","text":"This documentation is organised as follow. Checkout the tutorials to see what Bcube is capable of and/or quickly learn how to use it. Then, some more elaborated examples are provided to demonstrate the library capabilities. The \"Manual\" part explains how the core is organized. Finally, the \"API\" section is the low level code documentation.","category":"page"},{"location":"#Writing-documentation","page":"Home","title":"Writing documentation","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"To write documentation for Bcube, Julia's guidelines should be followed : https://docs.julialang.org/en/v1/manual/documentation/. Moreover, this project tries to apply the SciML Style Guide.","category":"page"},{"location":"#Conventions","page":"Home","title":"Conventions","text":"","category":"section"},{"location":"","page":"Home","title":"Home","text":"This documentation follows the following notation or naming conventions:","category":"page"},{"location":"","page":"Home","title":"Home","text":"coordinates inside a reference frame are noted hatx haty or xi eta while coordinates in the physical frame are noted xy\nwhen talking about a mapping, F or sometimes F_rp designates the mapping from the reference element to the physical element. On the other side, F^-1 or sometimes F_pr designates the physical element to the reference element mapping.\n\"dof\" means \"degree of freedom\"","category":"page"},{"location":"api/mapping/mapping/#Mapping","page":"Mapping","title":"Mapping","text":"","category":"section"},{"location":"api/mapping/mapping/#Mappings","page":"Mapping","title":"Mappings","text":"","category":"section"},{"location":"api/mapping/mapping/","page":"Mapping","title":"Mapping","text":"Modules = [Bcube]\nPages = [\"mapping.jl\"]","category":"page"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::AbstractEntityType, ξ)\n\nMap the reference shape on the local shape.\n\nImplementation\n\nThis function must be implemented for all shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Bar2_t, ξ)\n\nMap the reference 2-nodes bar [-1,1] on the local bar:\n\nF(xi) = dfracx_r - x_l2 xi + dfracx_r + x_l2\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bar3_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Bar3_t, ξ)\n\nMap the reference 3-nodes bar on the local bar (using Lagrange)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bcube.AbstractShape, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, cshape::AbstractShape, ξ)\n\nReturns the mapping of the an abstract shape (=ref element) to a target element defined by its nodes.\n\nFor instance, if cshape == Line, then the mapping is the same wether the input is the Shape or a Bar2_t. However if the cell is of type Bar3_t, it is still the Bar2_t mapping that is returned.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bcube.Hexa27_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Hexa27_t, ξ)\n\nMap the reference 8-nodes cube [-1,1] x [-1,1] x [-1,1] on the 27-hexa.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bcube.Penta6_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Penta6_t, ξ)\n\nMap the reference 6-nodes prism [0,1] x [0,1] x [-1,1] on the 6-penta (prism).\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Bcube.Tri6_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Tri6_t, ξ)\n\nMap the reference 6-nodes triangle [0,1] x [0,1] on the P2 curved-triangle.\n\nF(xi) = sum lambda_i(xi) x_i where lambda_i are the Lagrange P2 shape functions and x_i are the local curved-triangle vertices' coordinates.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Hexa8_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Hexa8_t, ξ)\n\nMap the reference 8-nodes cube [-1,1] x [-1,1] x [-1,1] on the 8-hexa.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Quad4_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Quad4_t, ξ)\n\nMap the reference 4-nodes square [-1,1] x [-1,1] on the 4-quadrilateral.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Quad9_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Quad9_t, ξ)\n\nMap the reference 4-nodes square [-1,1] x [-1,1] on the P2 curved-quadrilateral.\n\nF(xi) = sum lambda_i(xi) x_i where lambda_i are the Lagrange P2 shape functions and x_i are the local curved-quadrilateral vertices' coordinates.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping","text":"mapping(nodes, ::Tri3_t, ξ)\n\nMap the reference 3-nodes Triangle [0,1] x [0,1] on the local triangle.\n\nF(xi eta) = (1 - xi - eta) M_1 + x M_2 + y M_3\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_det_jacobian-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_det_jacobian","text":"mapping_det_jacobian(nodes, etype::AbstractEntityType, ξ)\n\nAbsolute value of the determinant of the mapping Jacobian matrix, expressed in the reference element.\n\nImplementation\n\nDefault version using mapping_jacobian, but can be specified for each shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_det_jacobian-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_det_jacobian","text":"mapping_det_jacobian(nodes, ::Bar2_t, ξ)\n\nAbsolute value of the determinant of the mapping Jacobian matrix for the reference 2-nodes bar [-1,1] to the local bar mapping.\n\ndet(J(xi)) = dfracx_r - x_l2\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_det_jacobian-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_det_jacobian","text":"mapping_det_jacobian(nodes, ::Tri3_t, ξ)\n\nAbsolute value of the determinant of the mapping Jacobian matrix for the the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.\n\nJ = (x_2 - x_1) (y_3 - y_1) - (x_3 - x_1) (y_2 - y_1)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_det_jacobian-Union{Tuple{T}, Tuple{AbstractArray{<:Node{2, T}}, Quad4_t, Any}} where T","page":"Mapping","title":"Bcube.mapping_det_jacobian","text":"mapping_det_jacobian(nodes, ::Quad4_t, ξ)\n\nAbsolute value of the determinant of the mapping Jacobian matrix for the the reference square [-1,1] x [-1,1] to the 4-quadrilateral mapping.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_face-Tuple{Bcube.AbstractShape, Any, Any}","page":"Mapping","title":"Bcube.mapping_face","text":"mapping_face(cshape::AbstractShape, side, permutation)\n\nBuild a mapping from the face reference element (corresponding to the side-th face of cshape) to the cell reference element (i.e the cshape), using a permutation of the face nodes.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_face-Tuple{Bcube.AbstractShape, Any}","page":"Mapping","title":"Bcube.mapping_face","text":"mapping_face(cshape::AbstractShape, side)\n\nBuild a mapping from the face reference element (corresponding to the side-th face of cshape) to the cell reference element (i.e the cshape).\n\nImplementation\n\nWe could define this function as an alias to mapping_face(cshape, side, 1:nnodes(face_shapes(cshape, side)) but for performance issue, I prefer to keep two independant functions for now.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_inv","text":"mapping_inv(nodes, ::AbstractEntityType, x)\n\nMap the local shape on the reference shape.\n\nImplementation\n\nThis function does not have to be implemented for all shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_inv","text":"mapping_inv(nodes, ::Bar2_t, x)\n\nMap the local bar on the reference 2-nodes bar [-1,1]:\n\nF^-1(x) = dfrac2x - x_r - x_lx_r - x_l\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv-Tuple{Any, Quad4_t, Any}","page":"Mapping","title":"Bcube.mapping_inv","text":"mapping_inv(nodes, ::Quad4_t, x)\n\nMap the PARALLELOGRAM quadrilateral on the reference 4-nodes square [-1,1] x [-1,1]. Warning : this mapping is only corrects for parallelogram quadrilateral, not for any quadrilateral.\n\n\n\nTODO: check this formulae with SYMPY\n\nF^-1 beginpmatrix x y endpmatrix =\nbeginpmatrix\n a_1 x + b_1 y + c_1 \n a_2 x + b_2 y + c_2\nendpmatrix\n\nwith\n\nbeginaligned\n a_1 = dfrac-2 (y_3-y_2)Delta \n b_1 = dfrac2 (x_3-x_2)Delta \n c_1 = -1 - a_1 x_1 - b_1 y_1 \n a_2 = dfrac-2 (y_1-y_2)Delta \n b_2 = dfrac2 (x_1 - x_2)Delta \n c_2 = -1 - a_2 x_1 - b_2 y_1\nendaligned\n\nwhere Delta = (x_1 - x_2)(y_3 - y_2) - (x_3 - x_2)(y_1 - y_2)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_inv","text":"mapping_inv(nodes, ::Tri3_t, x)\n\nMap the local triangle on the reference 3-nodes Triangle [0,1] x [0,1].\n\n\n\nTODO: check this formulae with SYMPY\n\nF^-1 beginpmatrix x y endpmatrix =\nfrac1x_1(y_2-y_3) + x_2(y_3-y_1) + x_3(y_1-y_2)\nbeginpmatrix\n (y_3-y_1)x + (x_1 - x_3)y + (x_3 y_1 - x_1 y_3) \n (y_1-y_2)x + (x_2 - x_1)x + (x_1 y_2 - x_2 y_1)\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv_jacobian-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_inv_jacobian","text":"mapping_inv_jacobian(nodes, etype::AbstractEntityType, x)\n\nJacobian matrix of the inverse mapping : dfracpartial F_i^-1partial x_j\n\nImplementation\n\nDefault version using LinearAlgebra to inverse the matrix, but can be specified for each shape (if it exists).\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv_jacobian-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_inv_jacobian","text":"mapping_inv_jacobian(nodes, ::Bar2_t, x)\n\nMapping's jacobian matrix for the local bar to the reference 2-nodes bar [-1, 1].\n\ndfracpartial F^-1partial x = dfrac2x_r - x_l\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_inv_jacobian-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_inv_jacobian","text":"mapping_inv_jacobian(nodes, ::Tri3_t, x)\n\nMapping's jacobian matrix for the local triangle to the reference 3-nodes Triangle [0,1] x [0,1] mapping.\n\n\n\nTODO: check this formulae with SYMPY\n\nfracpartial F_i^-1partial x_j =\nfrac1x_1 (y_2 - y_3) + x_2 (y_3 - y_1) + x_3 (y_1 - y_2)\nbeginpmatrix\n y_3 - y_1 x_1 - x_3 \n y_1 - y_2 x_2 - x_1\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, etype::AbstractEntityType, ξ)\n\nJacobian matrix of the mapping : dfracpartial F_ipartial xi_j.\n\nImplementation\n\nDefault version using ForwardDiff, but can be specified for each shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, ::Bar2_t, ξ)\n\nMapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.\n\ndfracpartial Fpartial xi = dfracx_r - x_l2\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, Bar3_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, ::Bar3_t, ξ)\n\nMapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.\n\n``\\dfrac{\\partial F}{\\partial \\xi} = \\frac{1}{2} \\left( (2\\xi - 1) M1 + (2\\xi + 1)M2 - 4 \\xi M_3\\right)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, Quad4_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, ::Quad4_t, ξ)\n\nMapping's jacobian matrix for the reference square [-1,1] x [-1,1] to the 4-quadrilateral\n\nfracpartial Fpartial xi = -M_1 + M_2 + M_3 - M_4 + eta (M_1 - M_2 + M_3 - M_4)\nfracpartial Fpartial eta = -M_1 - M_2 + M_3 + M_4 + xi (M_1 - M_2 + M_3 - M_4)\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian","text":"mapping_jacobian(nodes, ::Tri3_t, ξ)\n\nMapping's jacobian matrix for the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.\n\ndfracpartial F_ipartial xi_j =\nbeginpmatrix\n M_2 - M_1 M_3 - M_1\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Tuple{Any, AbstractEntityType, Any}","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian_inv(nodes, etype::AbstractEntityType, ξ)\n\nInverse of the mapping jacobian matrix. This is not exactly equivalent to the mapping_inv_jacobian since this function is evaluated in the reference element.\n\nImplementation\n\nDefault version using ForwardDiff, but can be specified for each shape.\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Tuple{Any, Bar2_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian_inv(nodes, ::Bar2_t, ξ)\n\nInverse of mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.\n\ndfracpartial Fpartial xi^-1 = dfrac2x_r - x_l\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Tuple{Any, Bar3_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian_inv(nodes, ::Bar3_t, ξ)\n\nInverse of mapping's jacobian matrix for the reference 2-nodes bar [-1, 1] to the local bar.\n\ndfracpartial Fpartial xi^-1 = frac2(2xi - 1) M_1 + (2xi + 1)M_2 - 4 xi M_3\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Tuple{Any, Tri3_t, Any}","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian_inv(nodes, ::Tri3_t, ξ)\n\nInverse of mapping's jacobian matrix for the reference 3-nodes Triangle [0,1] x [0,1] to the local triangle mapping.\n\ndfracpartial F_ipartial xi_j^-1 =\nfrac1(x_1 - x_2)(y_1 - y_3) - (x_1 - x_3)(y_1 - y_2)\nbeginpmatrix\n -y_1 + y_3 x_1 - x_3 \n y_1 - y_2 -x_1 + x_2\nendpmatrix\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Bcube.mapping_jacobian_inv-Union{Tuple{T}, Tuple{AbstractArray{<:Node{2, T}}, Quad4_t, Any}} where T","page":"Mapping","title":"Bcube.mapping_jacobian_inv","text":"mapping_jacobian(nodes, ::Quad4_t, ξ)\n\nInverse of mapping's jacobian matrix for the reference square [-1,1] x [-1,1] to the 4-quadrilateral\n\n\n\n\n\n","category":"method"},{"location":"api/mapping/mapping/#Reference-to-local","page":"Mapping","title":"Reference to local","text":"","category":"section"},{"location":"api/mapping/mapping/","page":"Mapping","title":"Mapping","text":"Modules = [Bcube]\nPages = [\"ref2loc.jl\"]","category":"page"}] } diff --git a/previews/PR2/tutorial/heat_equation/index.html b/previews/PR2/tutorial/heat_equation/index.html index 6f3ea85b..f7a0419c 100644 --- a/previews/PR2/tutorial/heat_equation/index.html +++ b/previews/PR2/tutorial/heat_equation/index.html @@ -60,4 +60,4 @@ ) end end -

This page was generated using Literate.jl.

+

This page was generated using Literate.jl.

diff --git a/previews/PR2/tutorial/helmholtz/index.html b/previews/PR2/tutorial/helmholtz/index.html index c708ebd5..a3f286d8 100644 --- a/previews/PR2/tutorial/helmholtz/index.html +++ b/previews/PR2/tutorial/helmholtz/index.html @@ -43,4 +43,4 @@ end

To write a VTK file, we need to build a dictionnary linking the variable name with its values and type

using WriteVTK
 out_dir = joinpath(@__DIR__, "../myout") # output directory
 dict_vars = Dict("u_$i" => (values[:, i], VTKPointData()) for i in 1:nvecs)
-write_vtk(joinpath(out_dir, "helmholtz_rectangle_mesh"), 0, 0.0, mesh, dict_vars)

And here is the eigenvector corresponding to the 4th eigenvalue:

drawing

This page was generated using Literate.jl.

+write_vtk(joinpath(out_dir, "helmholtz_rectangle_mesh"), 0, 0.0, mesh, dict_vars)

And here is the eigenvector corresponding to the 4th eigenvalue:

drawing

This page was generated using Literate.jl.

diff --git a/previews/PR2/tutorial/linear_transport/index.html b/previews/PR2/tutorial/linear_transport/index.html index 0e467a29..6ea3b3e1 100644 --- a/previews/PR2/tutorial/linear_transport/index.html +++ b/previews/PR2/tutorial/linear_transport/index.html @@ -95,4 +95,4 @@ # Write to file append_vtk(vtk, u, t) -end

And here is an animation of the result:

drawing

This page was generated using Literate.jl.

+end

And here is an animation of the result:

drawing

This page was generated using Literate.jl.

diff --git a/previews/PR2/tutorial/phase_field_supercooled/index.html b/previews/PR2/tutorial/phase_field_supercooled/index.html index 88887c87..767c465e 100644 --- a/previews/PR2/tutorial/phase_field_supercooled/index.html +++ b/previews/PR2/tutorial/phase_field_supercooled/index.html @@ -79,4 +79,4 @@ append = true, ) end -end

And here is an animation of the result:

drawing

This page was generated using Literate.jl.

+end

And here is an animation of the result:

drawing

This page was generated using Literate.jl.