Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split values into geometric mapping and function values #764

Merged
merged 175 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
175 commits
Select commit Hold shift + click to select a range
c44c02d
Introduce FunctionValues and GeometryValues
KnutAM Jul 12, 2023
1d1f7c6
Add benchmark and temporarily support renamed old types
KnutAM Jul 12, 2023
92b9779
Fix inline annotation for julia 1.6 ?
KnutAM Jul 12, 2023
8fef34d
Move callsite inline to function definitions
KnutAM Jul 12, 2023
506a6f7
Fix shell example, used internals of cellvalues
KnutAM Jul 12, 2023
d2eda0f
Use FunctionValues in FaceValues too
KnutAM Jul 12, 2023
744ba44
Use get_x_values for facevalues
KnutAM Jul 18, 2023
5cb7052
Initial work - some ex works, not all tests
KnutAM Aug 11, 2023
bb47cdb
Fix construction of FaceValues
KnutAM Aug 12, 2023
7ae714e
Trying out to get RT working
KnutAM Aug 28, 2023
7f484eb
Add definition of positive faces and edges
KnutAM Aug 28, 2023
ec6e21a
Finish merge
KnutAM Sep 16, 2023
6daaf65
Fix show to old values
KnutAM Sep 16, 2023
2a6aee0
Seemingly working triangle and nedelec
KnutAM Sep 18, 2023
ac04724
Add notes for new iterator
KnutAM Sep 19, 2023
4994e6e
Generalize and support 2nd order Nedelec on triangle
KnutAM Sep 20, 2023
f62961c
Add citation from master
KnutAM Sep 20, 2023
eeb1245
Empty cell_values.jl
KnutAM Sep 20, 2023
d89b268
Merge master
KnutAM Sep 20, 2023
6f7f988
Use mapping requirement info in GeometryValues
KnutAM Sep 20, 2023
f1020f3
Add test for gradient and continuity of Nedelec
KnutAM Sep 21, 2023
02051ee
Basic RaviartThomas implementation, gradient mapping seems to have an…
KnutAM Sep 21, 2023
df83ae8
Fix error in ContravariantPiolaMapping gradient calculation
KnutAM Sep 22, 2023
c4e1d63
Reenable tests, setup tmp ci, add mapping desc to devdocs
KnutAM Sep 23, 2023
562041a
bijective to diffeomorphic in theory section
KnutAM Sep 25, 2023
cf44f6c
Work on maxwell eigenproblem, but doesn't give correct results
KnutAM Sep 27, 2023
bafd9ce
Remove unintended comments
KnutAM Oct 3, 2023
eed2740
Create mixed formulation, RaviartThomas example
KnutAM Oct 7, 2023
026c753
Update docs manifest
KnutAM Oct 7, 2023
25ddd17
Merge master
KnutAM Oct 7, 2023
4df280e
Instantiate new Manifest
KnutAM Oct 7, 2023
2557b3e
Correct Manifest update oopsi
KnutAM Oct 7, 2023
27a22cc
Update examples to calculate flux
KnutAM Oct 7, 2023
3facc07
Change parameterization and fix test tolerances
KnutAM Oct 7, 2023
a6e4505
Relax type-constraints in GeometryValues and FunctionValues
KnutAM Oct 8, 2023
85bf3f7
Create extra titles for heat eq modifications
KnutAM Oct 8, 2023
06a097d
Use RequiresHessian in CellValues, and comment out unused future func…
KnutAM Oct 8, 2023
bcb25d3
Fix copy for CellValues and FaceValues
KnutAM Oct 8, 2023
5c33c5b
Fix show of values
KnutAM Oct 8, 2023
8b16b97
Fix test on julia 1.6
KnutAM Oct 8, 2023
ab28d25
Relax tolerance for gradient check a bit
KnutAM Oct 8, 2023
d5f7191
Move to old files
KnutAM Oct 8, 2023
7f17ffe
Rename files
KnutAM Oct 8, 2023
fbed8e5
Move includes to top level
KnutAM Oct 8, 2023
7bbc5e4
Remove unused example files and notes
KnutAM Oct 8, 2023
d322caf
Rename back and re-add docstrings
KnutAM Oct 8, 2023
8384d01
Remove CairoMakie from docs
KnutAM Oct 8, 2023
97eebbe
Add better error message if sdim don't match during reinit
KnutAM Oct 8, 2023
0cee936
Docfixes
KnutAM Oct 8, 2023
90ccab1
Show check for triangle mesh for the heat equation
KnutAM Oct 8, 2023
3f6cd9b
Remove benchmark script
KnutAM Oct 8, 2023
e5c80d7
Remove new interpolation related things
KnutAM Oct 8, 2023
a650a55
Remove unused doc things and examples
KnutAM Oct 8, 2023
066b13e
Remove tests for new interpolations
KnutAM Oct 8, 2023
c3e1574
Remove tests for new interpolations
KnutAM Oct 8, 2023
72f1ea2
Reduce git diff
KnutAM Oct 8, 2023
3aad963
Generalize example to try with 2nd order Lagrange
KnutAM Oct 8, 2023
6767160
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 9, 2023
0668d46
Rename GeometryValues -> GeometryMapping
KnutAM Oct 13, 2023
cf5d398
Correct i to alpha in mapping documentation
KnutAM Oct 13, 2023
2c67048
Add white background to make visible in dark mode
KnutAM Oct 13, 2023
6141453
Add error if cell===nothing for non-identity mappings
KnutAM Oct 13, 2023
35e8790
Move mapping docs to topics and add walkthrough of SimpleCellValues
KnutAM Oct 13, 2023
ff4133a
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 13, 2023
c76c0af
Add performance annotations and rename checkface to boundscheck_face
KnutAM Oct 13, 2023
b5e4121
Improve PointValues constructor from CellValues
KnutAM Oct 13, 2023
089c42a
Use internal functions for geometric ip when testing cellvalues
KnutAM Oct 13, 2023
07e3851
Add devdocs, other docfixes, and fallback for shape value and gradien…
KnutAM Oct 13, 2023
f3e6564
Fix so that API docs for FEValues is ok again
KnutAM Oct 13, 2023
6380914
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 13, 2023
f5c662c
Rename xx_values.jl to XxValues.jl
KnutAM Oct 13, 2023
917fef7
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 13, 2023
f9e9aa5
Rename at include too
KnutAM Oct 13, 2023
5916f8a
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 13, 2023
c418594
Merge docs/Manifest from master
KnutAM Oct 13, 2023
294475f
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 13, 2023
d47ae33
Minor formatting fixes according to review
KnutAM Oct 13, 2023
88b4cf0
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 13, 2023
b508556
Forgot rename of type param
KnutAM Oct 13, 2023
085278b
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 13, 2023
3805c6c
Merge master
KnutAM Oct 16, 2023
4451fac
Use new functions
KnutAM Oct 16, 2023
72e4404
Update docs manifest
KnutAM Oct 16, 2023
8ae23a8
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 16, 2023
3049dc4
Move svg to gh-pages
KnutAM Oct 21, 2023
24591b5
Use shape_x_x_and_x instead of precompute_values
KnutAM Oct 21, 2023
9dfceeb
Reintroduce precompute_values
KnutAM Oct 21, 2023
ea7e33e
Fix test of show
KnutAM Oct 21, 2023
94a2893
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 21, 2023
1a7e9c9
Remove unused internal methods
KnutAM Oct 21, 2023
41ae092
Test error paths
KnutAM Oct 21, 2023
cc32d03
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 21, 2023
13a5845
Remove tests for Nedelec
KnutAM Oct 21, 2023
9b020da
Remove unused test-code
KnutAM Oct 21, 2023
00e2e4f
Test show(::PointValues)
KnutAM Oct 21, 2023
09cf607
Fix test of show(::PointValues)
KnutAM Oct 21, 2023
ac8ebbf
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 21, 2023
43970f3
Remove unused methods
KnutAM Oct 21, 2023
ba3ac8f
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 21, 2023
d4da8a2
Comment out unused stuff from PR798
KnutAM Oct 21, 2023
d8cca13
Comment more unused methods/functions and mark with PR798 for ref
KnutAM Oct 21, 2023
005659a
Grammar and stylistic fixes
KnutAM Oct 23, 2023
69b50b4
Add further devdoc explanations
KnutAM Oct 23, 2023
c505036
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Oct 23, 2023
f829e88
Describe FEValues interface
KnutAM Nov 4, 2023
d4c36c2
Delete checkquadpoint method that causes illegal (at)inbounds
KnutAM Nov 4, 2023
667b193
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Nov 4, 2023
2550a75
Fix typo in devdocs
KnutAM Nov 4, 2023
00e67f8
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Nov 4, 2023
acefcde
Add type specification to shape_value and shape_gradient docstring spec
KnutAM Nov 5, 2023
dfea1ec
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Nov 5, 2023
94c174f
Testing it out
KnutAM Nov 10, 2023
c36ffda
Passing tests
KnutAM Nov 11, 2023
4ab9ba2
Fix performance annotations to come on par with master
KnutAM Nov 11, 2023
cc0c806
Move utils to common_values
KnutAM Nov 21, 2023
e109c9b
Remove PointValuesInternal
KnutAM Nov 21, 2023
34beb70
Fix test
KnutAM Nov 21, 2023
05fab53
Add custom values instructions to devdocs
KnutAM Nov 22, 2023
be6daf8
Add test that check instructions in devdocs for custom FEValues
KnutAM Nov 22, 2023
fbd367e
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Nov 22, 2023
66bf56d
Address Dennis' comments on SimpleCellValues
KnutAM Nov 24, 2023
b31e821
Address Dennis' comments on common values
KnutAM Nov 24, 2023
e1131c5
Merge FVG
KnutAM Nov 24, 2023
a417b1a
Add empty line bottom of commonvalues
KnutAM Nov 25, 2023
0bbc09d
Simplifications
KnutAM Dec 1, 2023
ae80cfb
Fix PointValues usage in PointEvalHandler
KnutAM Dec 3, 2023
810e5d8
Merge master
KnutAM Dec 3, 2023
1d5b9f1
Fix tests after merge
KnutAM Dec 3, 2023
7ea7fbf
Merge branch 'kam/dev/FVG' into kam/FunctionValuesGeneralization
KnutAM Dec 3, 2023
76a9312
Fix missing double-comment for literate
KnutAM Dec 3, 2023
be6e832
Merge 798
KnutAM Dec 3, 2023
679a4ac
Improved naming/interfaces
KnutAM Dec 3, 2023
a913c9b
Fix formatting of SimpleCellValues example
KnutAM Dec 3, 2023
8b6c097
Simplify text in SimpleCellValues example
KnutAM Dec 3, 2023
96a9766
Consistent code formatting and minimize diff
KnutAM Dec 3, 2023
a807738
Removed wrong whitespace
KnutAM Dec 3, 2023
4e83a1b
Merge PR798
KnutAM Dec 3, 2023
28464b9
Rename to old naming convention for easier review
KnutAM Dec 3, 2023
9e389bb
Try git mv for minimizing diff
KnutAM Dec 4, 2023
664abae
Redo rename, git mv didn't help
KnutAM Dec 4, 2023
9833fe8
Use sprint(show, ...) instead of helper fun for testing
KnutAM Dec 4, 2023
c76b57f
Use (at)eval instead of eval(quote
KnutAM Dec 4, 2023
946deef
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 4, 2023
0e71d03
Comment out GeometryMapping{2} related functions
KnutAM Dec 4, 2023
6fe3fc6
Include missed code from master merge
KnutAM Dec 4, 2023
2bd5f14
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 4, 2023
7d497d0
Change order or args for reinit
KnutAM Dec 4, 2023
86655d9
Fix errors due to changed order
KnutAM Dec 4, 2023
0453c15
Merge PR798
KnutAM Dec 4, 2023
8f16066
Update docstrings to new order in reinit
KnutAM Dec 4, 2023
2c11172
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 4, 2023
08a67af
Change input kwargs
KnutAM Dec 4, 2023
8563824
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 4, 2023
be5d910
Simplify code for FunctionValues construction
KnutAM Dec 4, 2023
894a141
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 4, 2023
00a5eec
Use branching in FunctionValues constructor
KnutAM Dec 4, 2023
41c92c4
Fix order of args
KnutAM Dec 4, 2023
6b16028
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 4, 2023
36c018e
More logic if in FunctionValues
KnutAM Dec 4, 2023
f0264b8
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 4, 2023
c7d7a0e
Remove use of (at)eval and be explicit instead
KnutAM Dec 5, 2023
e48b878
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 5, 2023
65e916e
Remove credit from SimpleCellValues literate
KnutAM Dec 5, 2023
6f020f4
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 5, 2023
8faecd4
Parse the generated file and return the MD string to show it
KnutAM Dec 5, 2023
1c95441
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 5, 2023
5c75770
Apply review suggestions
KnutAM Dec 6, 2023
b3ce313
Fix type instability in point eval
KnutAM Dec 6, 2023
7c308a1
Merge FunctionValuesGeneralization
KnutAM Dec 6, 2023
bcbf26f
Fix minor typo during merging
KnutAM Dec 6, 2023
2cbd2b9
Include cell in interface reinits
KnutAM Dec 6, 2023
74dafaa
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 6, 2023
6407b11
Merge branch 'master' into kam/FunctionValues
KnutAM Dec 6, 2023
8df8d52
Merge branch 'master' into kam/FunctionValuesGeneralization
KnutAM Dec 6, 2023
a255614
Merge branch 'kam/FunctionValuesGeneralization' into kam/FunctionValues
KnutAM Dec 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions benchmark/helper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,17 @@ function _generalized_ritz_galerkin_assemble_local_matrix(grid::Ferrite.Abstract
end

# Minimal Petrov-Galerkin type local assembly loop. We assume that both function spaces share the same integration rule. Test is applied from the left.
function _generalized_petrov_galerkin_assemble_local_matrix(grid::Ferrite.AbstractGrid, cellvalues_shape::CellValues{<: Ferrite.InterpolationByDim{dim}}, f_shape, cellvalues_test::CellValues{<: Ferrite.InterpolationByDim{dim}}, f_test, op) where {dim}
function _generalized_petrov_galerkin_assemble_local_matrix(grid::Ferrite.AbstractGrid, cellvalues_shape::CellValues, f_shape, cellvalues_test::CellValues, f_test, op)
n_basefuncs_shape = getnbasefunctions(cellvalues_shape)
n_basefuncs_test = getnbasefunctions(cellvalues_test)
Ke = zeros(n_basefuncs_test, n_basefuncs_shape)

#implicit assumption: Same geometry!
X_shape = zeros(Vec{dim,Float64}, Ferrite.getngeobasefunctions(cellvalues_shape))
X_shape = zeros(get_coordinate_type(grid), Ferrite.getngeobasefunctions(cellvalues_shape))
getcoordinates!(X_shape, grid, 1)
reinit!(cellvalues_shape, X_shape)

X_test = zeros(Vec{dim,Float64}, Ferrite.getngeobasefunctions(cellvalues_test))
X_test = zeros(get_coordinate_type(grid), Ferrite.getngeobasefunctions(cellvalues_test))
getcoordinates!(X_test, grid, 1)
reinit!(cellvalues_test, X_test)

Expand Down
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Optim = "429524aa-4258-5aef-a3af-852621145aeb"
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Tensors = "48a634ad-e948-5137-8d70-aa71f2a747f4"
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
3,089 changes: 3,089 additions & 0 deletions docs/src/assets/fe_mapping.svg
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/src/devdocs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ developing the library.

```@contents
Depth = 1
Pages = ["reference_cells.md", "interpolations.md", "elements.md", "dofhandler.md", "performance.md"]
Pages = ["reference_cells.md", "interpolations.md", "elements.md", "mapping.md", "dofhandler.md", "performance.md"]
```
103 changes: 103 additions & 0 deletions docs/src/devdocs/mapping.md
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Mapping of finite elements
The shape functions and gradients stored in an `FEValues` object, is reinitialized for each cell by calling the `reinit!` function. The main part of this calculation, considers how to map the functions described on the reference cell, to the actual cell.
KnutAM marked this conversation as resolved.
Show resolved Hide resolved

The geometric mapping of a finite element from the reference coordinates to the real coordinates is shown in the following illustration.

![mapping_figure](../assets/fe_mapping.svg)

This mapping is given by the geometric shape functions, $\hat{N}_i^g(\boldsymbol{\xi})$, such that
```math
\begin{align*}
\boldsymbol{x}(\boldsymbol{\xi}) =& \sum_{i}^N \hat{\boldsymbol{x}}_i \hat{N}_i^g(\boldsymbol{\xi}) \\
\boldsymbol{J} :=& \frac{\mathrm{d}\boldsymbol{x}}{\mathrm{d}\boldsymbol{\xi}} = \sum_{i}^N \hat{\boldsymbol{x}}_i \otimes \frac{\mathrm{d} \hat{N}_i^g}{\mathrm{d}\boldsymbol{\xi}}\\
\boldsymbol{\mathcal{H}} :=&
\frac{\mathrm{d} \boldsymbol{J}}{\mathrm{d} \boldsymbol{\xi}} = \sum_{\alpha=1}^N \hat{\boldsymbol{x}}_\alpha \otimes \frac{\mathrm{d}^2 \hat{N}^g_\alpha}{\mathrm{d} \boldsymbol{\xi}^2}
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
\end{align*}
```
where the defined $\boldsymbol{J}$ is the jacobian of the mapping, and in some cases we will also need the corresponding hessian, $\boldsymbol{\mathcal{H}}$ (3rd order tensor).

We require that the mapping from reference coordinates to real coordinates is [diffeomorphic](https://en.wikipedia.org/wiki/Diffeomorphism), meaning that we can express $\boldsymbol{x} = \boldsymbol{x}(\boldsymbol{\xi}(\boldsymbol{x}))$, such that
```math
\begin{align*}
\frac{\mathrm{d}\boldsymbol{x}}{\mathrm{d}\boldsymbol{x}} = \boldsymbol{I} &= \frac{\mathrm{d}\boldsymbol{x}}{\mathrm{d}\boldsymbol{\xi}} \cdot \frac{\mathrm{d}\boldsymbol{\xi}}{\mathrm{d}\boldsymbol{x}}
\quad\Rightarrow\quad
\frac{\mathrm{d}\boldsymbol{\xi}}{\mathrm{d}\boldsymbol{x}} = \left[\frac{\mathrm{d}\boldsymbol{x}}{\mathrm{d}\boldsymbol{\xi}}\right]^{-1} = \boldsymbol{J}^{-1}
\end{align*}
```
Depending on the function interpolation, we may want different types of mappings to conserve certain properties of the fields. This results in the different mapping types described below.

## Identity mapping
`Ferrite.IdentityMapping`

For scalar fields, we always use scalar base functions. For tensorial fields (non-scalar, e.g. vector-fields), the base functions can be constructed from scalar base functions, by using e.g. `VectorizedInterpolation`. From the perspective of the mapping, however, each component is mapped as an individual scalar base function. And for scalar base functions, we only require that the value of the base function is invariant to the element shape (real coordinate), and only depends on the reference coordinate, i.e.
```math
\begin{align*}
N(\boldsymbol{x}) &= \hat{N}(\boldsymbol{\xi}(\boldsymbol{x}))\nonumber \\
\mathrm{grad}(N(\boldsymbol{x})) &= \frac{\mathrm{d}\hat{N}}{\mathrm{d}\boldsymbol{\xi}} \cdot \boldsymbol{J}^{-1}
\end{align*}
```

## Covariant Piola mapping, H(curl)
`Ferrite.CovariantPiolaMapping`

The covariant Piola mapping of a vectorial base function preserves the tangential components. For the value, the mapping is defined as
```math
\begin{align*}
\boldsymbol{N}(\boldsymbol{x}) = \boldsymbol{J}^{-\mathrm{T}} \cdot \hat{\boldsymbol{N}}(\boldsymbol{\xi}(\boldsymbol{x}))
\end{align*}
```
which yields the gradient,
```math
\begin{align*}
\mathrm{grad}(\boldsymbol{N}(\boldsymbol{x})) &= \boldsymbol{J}^{-T} \cdot \frac{\mathrm{d} \hat{\boldsymbol{N}}}{\mathrm{d} \boldsymbol{\xi}} \cdot \boldsymbol{J}^{-1} - \boldsymbol{J}^{-T} \cdot \left[\hat{\boldsymbol{N}}(\boldsymbol{\xi}(\boldsymbol{x}))\cdot \boldsymbol{J}^{-1} \cdot \boldsymbol{\mathcal{H}}\cdot \boldsymbol{J}^{-1}\right]
\end{align*}
```

!!! details "Derivation"
Expressing the gradient, $\mathrm{grad}(\boldsymbol{N})$, in index notation,
```math
\begin{align*}
\frac{\mathrm{d} N_i}{\mathrm{d} x_j} &= \frac{\mathrm{d}}{\mathrm{d} x_j} \left[J^{-\mathrm{T}}_{ik} \hat{N}_k\right] = \frac{\mathrm{d} J^{-\mathrm{T}}_{ik}}{\mathrm{d} x_j} \hat{N}_k + J^{-\mathrm{T}}_{ik} \frac{\mathrm{d} \hat{N}_k}{\mathrm{d} \xi_l} J_{lj}^{-1}
\end{align*}
```

Except for a few elements, $\boldsymbol{J}$ varies as a function of $\boldsymbol{x}$. The derivative can be calculated as
```math
\begin{align*}
\frac{\mathrm{d} J^{-\mathrm{T}}_{ik}}{\mathrm{d} x_j} &= \frac{\mathrm{d} J^{-\mathrm{T}}_{ik}}{\mathrm{d} J_{mn}} \frac{\mathrm{d} J_{mn}}{\mathrm{d} x_j} = - J_{km}^{-1} J_{in}^{-T} \frac{\mathrm{d} J_{mn}}{\mathrm{d} x_j} \nonumber \\
\frac{\mathrm{d} J_{mn}}{\mathrm{d} x_j} &= \mathcal{H}_{mno} J_{oj}^{-1}
\end{align*}
```

## Contravariant Piola mapping, H(div)
`Ferrite.ContravariantPiolaMapping`

The covariant Piola mapping of a vectorial base function preserves the normal components. For the value, the mapping is defined as
```math
\begin{align*}
\boldsymbol{N}(\boldsymbol{x}) = \frac{\boldsymbol{J}}{\det(\boldsymbol{J})} \cdot \hat{\boldsymbol{N}}(\boldsymbol{\xi}(\boldsymbol{x}))
\end{align*}
```
This gives the gradient
```math
\begin{align*}
\mathrm{grad}(\boldsymbol{N}(\boldsymbol{x})) = [\boldsymbol{\mathcal{H}}\cdot\boldsymbol{J}^{-1}] : \frac{[\boldsymbol{I} \underline{\otimes} \boldsymbol{I}] \cdot \hat{\boldsymbol{N}}}{\det(\boldsymbol{J})}
- \left[\frac{\boldsymbol{J} \cdot \hat{\boldsymbol{N}}}{\det(\boldsymbol{J})}\right] \otimes \left[\boldsymbol{J}^{-T} : \boldsymbol{\mathcal{H}} \cdot \boldsymbol{J}^{-1}\right]
+ \boldsymbol{J} \cdot \frac{\mathrm{d} \hat{\boldsymbol{N}}}{\mathrm{d} \boldsymbol{\xi}} \cdot \frac{\boldsymbol{J}^{-1}}{\det(\boldsymbol{J})}
\end{align*}
```

!!! details "Derivation"
Expressing the gradient, $\mathrm{grad}(\boldsymbol{N})$, in index notation,
```math
\begin{align*}
\frac{\mathrm{d} N_i}{\mathrm{d} x_j} &= \frac{\mathrm{d}}{\mathrm{d} x_j} \left[\frac{J_{ik}}{\det(\boldsymbol{J})} \hat{N}_k\right] =\nonumber\\
&= \frac{\mathrm{d} J_{ik}}{\mathrm{d} x_j} \frac{\hat{N}_k}{\det(\boldsymbol{J})}
- \frac{\mathrm{d} \det(\boldsymbol{J})}{\mathrm{d} x_j} \frac{J_{ik} \hat{N}_k}{\det(\boldsymbol{J})^2}
+ \frac{J_{ik}}{\det(\boldsymbol{J})} \frac{\mathrm{d} \hat{N}_k}{\mathrm{d} \xi_l} J_{lj}^{-1} \\
&= \mathcal{H}_{ikl} J^{-1}_{lj} \frac{\hat{N}_k}{\det(\boldsymbol{J})}
- J^{-T}_{mn} \mathcal{H}_{mnl} J^{-1}_{lj} \frac{J_{ik} \hat{N}_k}{\det(\boldsymbol{J})}
+ \frac{J_{ik}}{\det(\boldsymbol{J})} \frac{\mathrm{d} \hat{N}_k}{\mathrm{d} \xi_l} J_{lj}^{-1}
\end{align*}
```

2 changes: 1 addition & 1 deletion docs/src/literate-howto/postprocessing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ include("../tutorials/heat_equation.jl");
# Next we define a function that computes the heat flux for each integration point in the domain.
# Fourier's law is adopted, where the conductivity tensor is assumed to be isotropic with unit
# conductivity ``\lambda = 1 ⇒ q = - \nabla u``, where ``u`` is the temperature.
function compute_heat_fluxes(cellvalues::CellValues{<:ScalarInterpolation}, dh::DofHandler, a::AbstractVector{T}) where T
function compute_heat_fluxes(cellvalues::CellValues, dh::DofHandler, a::AbstractVector{T}) where T
KnutAM marked this conversation as resolved.
Show resolved Hide resolved

n = getnbasefunctions(cellvalues)
cell_dofs = zeros(Int, n)
Expand Down
6 changes: 3 additions & 3 deletions docs/src/literate-tutorials/incompressible_elasticity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ end
# use a `PseudoBlockArray` from `BlockArrays.jl`.

function doassemble(
cellvalues_u::CellValues{<:VectorInterpolation},
cellvalues_p::CellValues{<:ScalarInterpolation},
facevalues_u::FaceValues{<:VectorInterpolation},
cellvalues_u::CellValues,
cellvalues_p::CellValues,
facevalues_u::FaceValues,
K::SparseMatrixCSC, grid::Grid, dh::DofHandler, mp::LinearElasticity
)
f = zeros(ndofs(dh))
Expand Down
8 changes: 5 additions & 3 deletions docs/src/literate-tutorials/linear_shell.jl
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ end;
# ##### Main element routine
# Below is the main routine that calculates the stiffness matrix of the shell element.
# Since it is a so called degenerate shell element, the code is similar to that for an standard continuum element.
shape_reference_gradient(cv::CellValues, q_point, i) = cv.fun_values.dNdξ[i, q_point]

function integrate_shell!(ke, cv, qr_ooplane, X, data)
nnodes = getnbasefunctions(cv)
ndofs = nnodes*5
Expand All @@ -281,9 +283,9 @@ function integrate_shell!(ke, cv, qr_ooplane, X, data)
ef1, ef2, ef3 = fiber_coordsys(p)

for iqp in 1:getnquadpoints(cv)
N = cv.N[:,iqp]
dNdξ = cv.dNdξ[:,iqp]
dNdx = cv.dNdx[:,iqp]
N = [shape_value(cv, iqp, i) for i in 1:nnodes]
dNdξ = [shape_reference_gradient(cv, iqp, i) for i in 1:nnodes]
dNdx = [shape_gradient(cv, iqp, i) for i in 1:nnodes]
termi-official marked this conversation as resolved.
Show resolved Hide resolved

for oqp in 1:length(qr_ooplane.weights)
ζ = qr_ooplane.points[oqp][1]
Expand Down
2 changes: 1 addition & 1 deletion src/Dofs/DofHandler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ function _evaluate_at_grid_nodes!(data::Union{Vector,Matrix}, sdh::SubDofHandler
u::Vector{T}, cv::CellValues, drange::UnitRange, ::Type{RT}) where {T, RT}
ue = zeros(T, length(drange))
# TODO: Remove this hack when embedding works...
if RT <: Vec && cv isa CellValues{<:ScalarInterpolation}
if RT <: Vec && get_function_interpolation(cv) isa ScalarInterpolation
uer = reinterpret(RT, ue)
else
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
uer = ue
Expand Down
172 changes: 172 additions & 0 deletions src/FEValues/FunctionValues.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#################################################################
# Note on dimensions: #
# sdim = spatial dimension (dimension of the grid nodes) #
# rdim = reference dimension (dimension in isoparametric space) #
# vdim = vector dimension (dimension of the field) #
#################################################################

# Helpers to get the correct types for FunctionValues for the given function and, if needed, geometric interpolations.
struct SInterpolationDims{rdim,sdim} end
struct VInterpolationDims{rdim,sdim,vdim} end
function InterpolationDims(::ScalarInterpolation, ip_geo::VectorizedInterpolation{sdim}) where sdim
return SInterpolationDims{getdim(ip_geo),sdim}()
end
function InterpolationDims(::VectorInterpolation{vdim}, ip_geo::VectorizedInterpolation{sdim}) where {vdim,sdim}
return VInterpolationDims{getdim(ip_geo),sdim,vdim}()
end

typeof_N(::Type{T}, ::SInterpolationDims) where T = T
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
typeof_N(::Type{T}, ::VInterpolationDims{<:Any,dim,dim}) where {T,dim} = Vec{dim,T}
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
typeof_N(::Type{T}, ::VInterpolationDims{<:Any,<:Any,vdim}) where {T,vdim} = SVector{vdim,T} # Why not ::Vec here?

typeof_dNdx(::Type{T}, ::SInterpolationDims{dim,dim}) where {T,dim} = Vec{dim,T}
typeof_dNdx(::Type{T}, ::SInterpolationDims{<:Any,sdim}) where {T,sdim} = SVector{sdim,T} # Why not ::Vec here?
typeof_dNdx(::Type{T}, ::VInterpolationDims{dim,dim,dim}) where {T,dim} = Tensor{2,dim,T}
typeof_dNdx(::Type{T}, ::VInterpolationDims{<:Any,sdim,vdim}) where {T,sdim,vdim} = SMatrix{vdim,sdim,T} # If vdim=sdim!=rdim Tensor would be possible...

typeof_dNdξ(::Type{T}, ::SInterpolationDims{dim,dim}) where {T,dim} = Vec{dim,T}
typeof_dNdξ(::Type{T}, ::SInterpolationDims{rdim}) where {T,rdim} = SVector{rdim,T} # Why not ::Vec here?
typeof_dNdξ(::Type{T}, ::VInterpolationDims{dim,dim,dim}) where {T,dim} = Tensor{2,dim,T}
typeof_dNdξ(::Type{T}, ::VInterpolationDims{rdim,<:Any,vdim}) where {T,rdim,vdim} = SMatrix{vdim,rdim,T} # If vdim=rdim!=sdim Tensor would be possible...
termi-official marked this conversation as resolved.
Show resolved Hide resolved

struct FunctionValues{IP, N_t, dNdx_t, dNdξ_t}
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
ip::IP # ::Interpolation
N_x::N_t # ::AbstractMatrix{Union{<:Tensor,<:Number}}
N_ξ::N_t # ::AbstractMatrix{Union{<:Tensor,<:Number}}
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
dNdx::dNdx_t # ::AbstractMatrix{Union{<:Tensor,<:StaticArray}}
dNdξ::dNdξ_t # ::AbstractMatrix{Union{<:Tensor,<:StaticArray}}
end
function FunctionValues(::Type{T}, ip::Interpolation, qr::QuadratureRule, ip_geo::VectorizedInterpolation) where T
ip_dims = InterpolationDims(ip, ip_geo)
N_t = typeof_N(T, ip_dims)
dNdx_t = typeof_dNdx(T, ip_dims)
dNdξ_t = typeof_dNdξ(T, ip_dims)
n_shape = getnbasefunctions(ip)
n_qpoints = getnquadpoints(qr)

N_ξ = zeros(N_t, n_shape, n_qpoints)
if isa(get_mapping_type(ip), IdentityMapping)
N_x = N_ξ
else
N_x = zeros(N_t, n_shape, n_qpoints)
end
dNdξ = zeros(dNdξ_t, n_shape, n_qpoints)
dNdx = fill(zero(dNdx_t) * T(NaN), n_shape, n_qpoints)
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
fv = FunctionValues(ip, N_x, N_ξ, dNdx, dNdξ)
precompute_values!(fv, qr) # Precompute N and dNdξ
return fv
end
function Base.copy(v::FunctionValues)
N_ξ_copy = copy(v.N_ξ)
N_x_copy = v.N_ξ === v.N_x ? N_ξ_copy : copy(v.N_x) # Preserve aliasing
return FunctionValues(copy(v.ip), N_x_copy, N_ξ_copy, copy(v.dNdx), copy(v.dNdξ))
end

function precompute_values!(fv::FunctionValues, qr::QuadratureRule)
n_shape = getnbasefunctions(fv.ip)
for (qp, ξ) in pairs(getpoints(qr))
for i in 1:n_shape
fv.dNdξ[i, qp], fv.N_ξ[i, qp] = shape_gradient_and_value(fv.ip, ξ, i)
end
end
end

getnbasefunctions(funvals::FunctionValues) = size(funvals.N_x, 1)
@propagate_inbounds shape_value(funvals::FunctionValues, q_point::Int, base_func::Int) = funvals.N_x[base_func, q_point]
@propagate_inbounds shape_gradient(funvals::FunctionValues, q_point::Int, base_func::Int) = funvals.dNdx[base_func, q_point]
@propagate_inbounds shape_symmetric_gradient(funvals::FunctionValues, q_point::Int, base_func::Int) = symmetric(shape_gradient(funvals, q_point, base_func))

get_function_interpolation(funvals::FunctionValues) = funvals.ip

shape_value_type(funvals::FunctionValues) = eltype(funvals.N_x)
shape_gradient_type(funvals::FunctionValues) = eltype(funvals.dNdx)


# Checks that the user provides the right dimension of coordinates to reinit! methods to ensure good error messages if not
sdim_from_gradtype(::Type{<:AbstractTensor{<:Any,sdim}}) where sdim = sdim
sdim_from_gradtype(::Type{<:SVector{sdim}}) where sdim = sdim
sdim_from_gradtype(::Type{<:SMatrix{<:Any,sdim}}) where sdim = sdim

# For performance, these must be fully inferrable for the compiler.
# args: valname (:CellValues or :FaceValues), shape_gradient_type, eltype(x)
function check_reinit_sdim_consistency(valname, gradtype, ::Type{<:Vec{sdim}}) where {sdim}
check_reinit_sdim_consistency(valname, Val(sdim_from_gradtype(gradtype)), Val(sdim))
end
check_reinit_sdim_consistency(_, ::Val{sdim}, ::Val{sdim}) where sdim = nothing
function check_reinit_sdim_consistency(valname, ::Val{sdim_val}, ::Val{sdim_x}) where {sdim_val, sdim_x}
error("""The $valname and coordinates have different spatial dimensions, $sdim_val and $sdim_x.
Could it be that you forgot to vectorize the geometric interpolation when constructing the $valname?""")
end

# Mapping types
struct IdentityMapping end
struct CovariantPiolaMapping end
struct ContravariantPiolaMapping end
# Not yet implemented:
# struct DoubleCovariantPiolaMapping end
# struct DoubleContravariantPiolaMapping end

get_mapping_type(fv::FunctionValues) = get_mapping_type(fv.ip)
KnutAM marked this conversation as resolved.
Show resolved Hide resolved

requires_hessian(::IdentityMapping) = false
requires_hessian(::ContravariantPiolaMapping) = true
requires_hessian(::CovariantPiolaMapping) = true

# Support for embedded elements
calculate_Jinv(J::Tensor{2}) = inv(J)
calculate_Jinv(J::SMatrix) = pinv(J)

# Hotfix to get the dots right for embedded elements until mixed tensors are merged.
# Scalar/Vector interpolations with sdim == rdim (== vdim)
@inline dothelper(A, B) = A ⋅ B
# Vector interpolations with sdim == rdim != vdim
@inline dothelper(A::SMatrix{vdim, dim}, B::Tensor{2, dim}) where {vdim, dim} = A * SMatrix{dim, dim}(B)
# Scalar interpolations with sdim > rdim
@inline dothelper(A::SVector{rdim}, B::SMatrix{rdim, sdim}) where {rdim, sdim} = B' * A
# Vector interpolations with sdim > rdim
@inline dothelper(B::SMatrix{vdim, rdim}, A::SMatrix{rdim, sdim}) where {vdim, rdim, sdim} = B * A

@inline function apply_mapping!(funvals::FunctionValues, args...)
return apply_mapping!(funvals, get_mapping_type(funvals), args...)
end

@inline function apply_mapping!(funvals::FunctionValues, ::IdentityMapping, q_point::Int, mapping_values, args...)
Jinv = calculate_Jinv(getjacobian(mapping_values))
@inbounds for j in 1:getnbasefunctions(funvals)
#funvals.dNdx[j, q_point] = funvals.dNdξ[j, q_point] ⋅ Jinv # TODO via Tensors.jl
funvals.dNdx[j, q_point] = dothelper(funvals.dNdξ[j, q_point], Jinv)
end
return nothing
end

@inline function apply_mapping!(funvals::FunctionValues, ::CovariantPiolaMapping, q_point::Int, mapping_values, cell)
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
H = gethessian(mapping_values)
Jinv = inv(getjacobian(mapping_values))
@inbounds for j in 1:getnbasefunctions(funvals)
d = get_direction(funvals.ip, j, cell)
dNdξ = funvals.dNdξ[j, q_point]
N_ξ = funvals.N_ξ[j, q_point]
funvals.N_x[j, q_point] = d*(N_ξ ⋅ Jinv)
funvals.dNdx[j, q_point] = d*(Jinv' ⋅ dNdξ ⋅ Jinv - Jinv' ⋅ (N_ξ ⋅ Jinv ⋅ H ⋅ Jinv))
end
return nothing
end

@inline function apply_mapping!(funvals::FunctionValues, ::ContravariantPiolaMapping, q_point::Int, mapping_values, cell)
KnutAM marked this conversation as resolved.
Show resolved Hide resolved
H = gethessian(mapping_values)
J = getjacobian(mapping_values)
Jinv = inv(J)
detJ = det(J)
I2 = one(J)
H_Jinv = H⋅Jinv
A1 = (H_Jinv ⊡ (otimesl(I2,I2))) / detJ
A2 = (Jinv' ⊡ H_Jinv) / detJ
@inbounds for j in 1:getnbasefunctions(funvals)
d = get_direction(funvals.ip, j, cell)
dNdξ = funvals.dNdξ[j, q_point]
N_ξ = funvals.N_ξ[j, q_point]
funvals.N_x[j, q_point] = d*(J ⋅ N_ξ)/detJ
funvals.dNdx[j, q_point] = d*(J ⋅ dNdξ ⋅ Jinv/detJ + A1 ⋅ N_ξ - (J ⋅ N_ξ) ⊗ A2)
end
return nothing
end
Loading