Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Core Modules
dune-localfunctions
Commits
e41bccc6
Commit
e41bccc6
authored
May 11, 2021
by
Henrik Stolzmann
Browse files
Added high order Nedelec elements in 2d and 3d.
parent
9b7cf76c
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
CHANGELOG.md
View file @
e41bccc6
...
...
@@ -31,6 +31,8 @@
Tagged the old versions of:
`numLagrangePoints`
,
`equidistantLagrangePoints`
,
`RTL2InterpolationBuilder::topologyId()`
,
`VirtualMonomialBasis(topologyId)`
,
`VirtualMonomialBasis::topologyId()`
as deprecated.
*
Add a construction algorithm for high order Nédélec elements on triangles and tetrahedra.
# Release 2.7
*
The header
`lagrange.hh`
now includes all headers of all Lagrange implementations,
...
...
dune/localfunctions/nedelec/nedelecsimplex/CMakeLists.txt
0 → 100644
View file @
e41bccc6
install
(
FILES
nedelecsimplexbasis.hh
nedelecsimplexinterpolation.hh
nedelecsimplexprebasis.hh
DESTINATION
${
CMAKE_INSTALL_INCLUDEDIR
}
/dune/localfunctions/nedelec/nedelecsimplex
)
dune/localfunctions/nedelec/nedelecsimplex/nedelecsimplexbasis.hh
0 → 100644
View file @
e41bccc6
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_LOCALFUNCTIONS_NEDELEC_NEDELECSIMPLEX_NEDELECSIMPLEXBASIS_HH
#define DUNE_LOCALFUNCTIONS_NEDELEC_NEDELECSIMPLEX_NEDELECSIMPLEXBASIS_HH
#include <fstream>
#include <dune/common/exceptions.hh>
#include <dune/localfunctions/utility/defaultbasisfactory.hh>
#include "nedelecsimplexinterpolation.hh"
#include "nedelecsimplexprebasis.hh"
namespace
Dune
{
/*
* `NedelecPreBasisFactory` provides a basis for the Nedelec function space.
* `NedelecL2InterpolationFactory` provides the linear functionals.
*
* `Defaultbasisfactory::create` first builds the function space and the linear functionals.
* Then the constructor of `BasisMatrix` gets called. There the matrix
*
* \begin{equation}
* A_{i,j} := N_j(\phi_i)
* \end{equation}
*
* with linear functionals $N_j$ and basisfunctions $\phi_i$ gets assembled.
* Then the matrix gets inverted and is then used as a coefficent matrix for the standard monomial basis.
*
* For more details on the theory see the first chapter "Construction of Local Finite Element Spaces Using the Generic Reference Elements"
* of the book "Advances in Dune" by Dedner, Flemisch and Klöfkorn published in 2012.
*/
template
<
unsigned
int
dim
,
class
SF
,
class
CF
>
struct
NedelecBasisFactory
:
public
DefaultBasisFactory
<
NedelecPreBasisFactory
<
dim
,
CF
>
,
NedelecL2InterpolationFactory
<
dim
,
CF
>
,
dim
,
dim
,
SF
,
CF
>
{};
}
#endif // #ifndef DUNE_LOCALFUNCTIONS_NEDELEC_NEDELECSIMPLEX_NEDELECSIMPLEXBASIS_HH
dune/localfunctions/nedelec/nedelecsimplex/nedelecsimplexinterpolation.hh
0 → 100644
View file @
e41bccc6
This diff is collapsed.
Click to expand it.
dune/localfunctions/nedelec/nedelecsimplex/nedelecsimplexprebasis.hh
0 → 100644
View file @
e41bccc6
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_LOCALFUNCTIONS_NEDELEC_NEDELECSIMPLEX_NEDELECSIMPLEXPREBASIS_HH
#define DUNE_LOCALFUNCTIONS_NEDELEC_NEDELECSIMPLEX_NEDELECSIMPLEXPREBASIS_HH
#include <fstream>
#include <utility>
#include <dune/geometry/type.hh>
#include <dune/localfunctions/utility/polynomialbasis.hh>
namespace
Dune
{
template
<
GeometryType
::
Id
geometryId
,
class
Field
>
struct
NedelecVecMatrix
;
template
<
unsigned
int
dim
,
class
Field
>
struct
NedelecPreBasisFactory
{
typedef
MonomialBasisProvider
<
dim
,
Field
>
MBasisFactory
;
typedef
typename
MBasisFactory
::
Object
MBasis
;
typedef
StandardEvaluator
<
MBasis
>
EvalMBasis
;
typedef
PolynomialBasisWithMatrix
<
EvalMBasis
,
SparseCoeffMatrix
<
Field
,
dim
>
>
Basis
;
typedef
const
Basis
Object
;
typedef
std
::
size_t
Key
;
template
<
unsigned
int
dd
,
class
FF
>
struct
EvaluationBasisFactory
{
typedef
MonomialBasisProvider
<
dd
,
FF
>
Type
;
};
template
<
GeometryType
::
Id
geometryId
>
static
Object
*
create
(
Key
order
)
{
/*
* The nedelec parameter begins at 1.
* This is the numbering used by J.C. Nedelec himself.
* See "Mixed Finite Elements in \R^3" published in 1980.
*
* This construction is based on the construction of Raviart-Thomas elements.
* There the numbering starts at 0.
* Because of this we reduce the order internally by 1.
*/
order
--
;
NedelecVecMatrix
<
geometryId
,
Field
>
vecMatrix
(
order
);
MBasis
*
mbasis
=
MBasisFactory
::
template
create
<
geometryId
>(
order
+
1
);
std
::
remove_const_t
<
Object
>*
tmBasis
=
new
std
::
remove_const_t
<
Object
>
(
*
mbasis
);
tmBasis
->
fill
(
vecMatrix
);
return
tmBasis
;
}
static
void
release
(
Object
*
object
)
{
delete
object
;
}
};
template
<
GeometryType
::
Id
geometryId
,
class
Field
>
struct
NedelecVecMatrix
{
static
constexpr
GeometryType
geometry
=
geometryId
;
static
const
unsigned
int
dim
=
geometry
.
dim
();
typedef
MultiIndex
<
dim
,
Field
>
MI
;
typedef
MonomialBasis
<
geometryId
,
MI
>
MIBasis
;
NedelecVecMatrix
(
std
::
size_t
order
)
{
/*
* Construction of Nedelec elements see "Mixed Finite Elements in \R^3" by Nedelec, 1980.
*
* Let $\P_{n,k}$ be the space of polynomials in $n$ variables with degree $\leq k$.
* The space of Nedelec functions in $n$ dimensions with index $k$ is defined as
*
* \begin{equation*}
* Ned_k := (\P_{n,k-1})^n \oplus \{p \in (\P_{n,k})^n: <p,x>=0 \}
* \end{equation*}
* with $x=(x,y)$ in two dimensions and $x=(x,y,z)$ in three dimensions.
*
* For $Ned_k$ holds
* \begin{equation*}
* (\P_{n,k-1})^n \subset Ned_k \subset (\P_{n,k})^n.
* \end{equation*}
*
* We construct $(\P_{n,k})^n$ and and only use the monomials contained in $Ned$.
*
*/
if
(
dim
!=
2
&&
dim
!=
3
||
!
geometry
.
isSimplex
())
DUNE_THROW
(
Dune
::
NotImplemented
,
"High order nedelec elements are only supported by simplices in 2d and 3d"
);
MIBasis
basis
(
order
+
1
);
FieldVector
<
MI
,
dim
>
x
;
/*
* Init MultiIndices
* x[0]=(1,0,0) x
* x[1]=(0,1,0) y
* x[2]=(0,0,1) z
*/
for
(
unsigned
int
i
=
0
;
i
<
dim
;
++
i
)
x
[
i
].
set
(
i
,
1
);
std
::
vector
<
MI
>
val
(
basis
.
size
()
);
// val now contains all monomials in $n$ dimensions with degree $\leq order+1$
basis
.
evaluate
(
x
,
val
);
col_
=
basis
.
size
();
// get $\dim (\P_{n,order-1})$
unsigned
int
notHomogen
=
0
;
if
(
order
>
0
)
notHomogen
=
basis
.
sizes
()[
order
-
1
];
// the number of basis functions for the set of homogeneous polynomials with degree $order$
unsigned
int
homogen
=
basis
.
sizes
()[
order
]
-
notHomogen
;
/*
* 2D:
* \begin{equation*}
* Ned_{order} = (\P_{order-1})^2 \oplus (-y,x)^T \widetilde \P_{order-1}
* \end{equation*}
*
* It gets more complicated in higher dimensions.
*
* 3D:
* \begin{equation*}
* Ned_{order} = (\P_{n,order-1})^3 \oplus (z,0,-x)^T \widetilde \P_{n,order-1} \oplus (-y,x,0)^T \widetilde \P_{n,order-1} \oplus (0,-z,y)^T \widetilde \P_{n-1,order-1}
* \end{equation*}
*
* Note the last term. The index $n-1$ is on purpose.
* Else i.e. k=2
*
* (0,z,-y)^T x = (z,0,-x)^T y - (y,-x,0)^T z.
*
*/
/*
* compute the number of rows for the coefficient matrix
*
* row_ = dim* \dim Ned_{order}
*/
if
(
dim
==
2
)
row_
=
(
notHomogen
*
dim
+
homogen
*
(
dim
+
1
))
*
dim
;
else
if
(
dim
==
3
)
{
// get dim \P_{n-1,order-1}
int
homogenTwoVariables
=
0
;
for
(
int
w
=
notHomogen
;
w
<
notHomogen
+
homogen
;
w
++
)
if
(
val
[
w
].
z
(
0
)
==
0
)
homogenTwoVariables
++
;
row_
=
(
notHomogen
*
dim
+
homogen
*
(
dim
+
2
)
+
homogenTwoVariables
)
*
dim
;
}
mat_
=
new
Field
*
[
row_
];
int
row
=
0
;
/* Assign the correct values for the nonhomogeneous polymonials $p\in (\P_{n,order-1})^dim$
* A basis function is represented by $dim$ rows.
*/
for
(
unsigned
int
i
=
0
;
i
<
notHomogen
+
homogen
;
++
i
)
{
for
(
unsigned
int
r
=
0
;
r
<
dim
;
++
r
)
{
for
(
unsigned
int
rr
=
0
;
rr
<
dim
;
++
rr
)
{
// init row to zero
mat_
[
row
]
=
new
Field
[
col_
];
for
(
unsigned
int
j
=
0
;
j
<
col_
;
++
j
)
mat_
[
row
][
j
]
=
0.
;
if
(
r
==
rr
)
mat_
[
row
][
i
]
=
1.
;
++
row
;
}
}
}
/* Assign the correct values for the homogeneous polymonials $p\in Ned_{order} \backslash (\P_{n,order-1})^dim$
* A basis function is represented by $dim$ rows.
*/
for
(
unsigned
int
i
=
0
;
i
<
homogen
;
++
i
)
{
// get a monomial $ p \in \P_{n,order}\backslash \P_{n,order-1}$
MI
xval
=
val
[
notHomogen
+
i
];
if
(
dim
==
2
)
{
for
(
unsigned
int
r
=
0
;
r
<
dim
;
++
r
)
{
// init rows to zero
mat_
[
row
+
r
]
=
new
Field
[
col_
];
for
(
unsigned
int
j
=
0
;
j
<
col_
;
++
j
)
mat_
[
row
+
r
][
j
]
=
0.
;
}
/* set $(-y,x)^T p$ with a homogeneous monomial $p$
*
* The loop over the monomials is needed to obtain the corresponding column index.
*/
for
(
int
w
=
homogen
+
notHomogen
;
w
<
val
.
size
();
++
w
)
{
if
(
val
[
w
]
==
xval
*
x
[
0
])
mat_
[
row
+
1
][
w
]
=
1.
;
if
(
val
[
w
]
==
xval
*
x
[
1
])
mat_
[
row
][
w
]
=
-
1.
;
}
row
+=
dim
;
}
else
if
(
dim
==
3
)
{
int
skipLastDim
=
xval
.
z
(
0
)
>
0
;
/*
* Init 9 rows to zero.
* If the homogeneous monomial has a positive x-exponent (0,-z,y) gets skipped ( see example for the Nedelec space in 3D )
* In this case only 6 rows get initialised.
*/
for
(
unsigned
int
r
=
0
;
r
<
dim
*
(
dim
-
skipLastDim
);
++
r
)
{
// init rows to zero
mat_
[
row
+
r
]
=
new
Field
[
col_
];
for
(
unsigned
int
j
=
0
;
j
<
col_
;
++
j
)
mat_
[
row
+
r
][
j
]
=
0.
;
}
/*
* first $dim$ rows are for (z,0,-x)
*
* second $dim$ rows are for (-y,x,0)
*
* third $dim$ rows are for (0,-z,y)
*
*/
for
(
unsigned
int
r
=
0
;
r
<
dim
-
skipLastDim
;
++
r
)
{
int
index
=
(
r
+
dim
-
1
)
%
dim
;
for
(
int
w
=
homogen
+
notHomogen
;
w
<
val
.
size
();
++
w
)
{
if
(
val
[
w
]
==
xval
*
x
[
index
])
mat_
[
row
+
r
][
w
]
=
1.
;
if
(
val
[
w
]
==
xval
*
x
[
r
])
mat_
[
row
+
index
][
w
]
=
-
1.
;
}
row
+=
dim
;
}
}
}
}
~
NedelecVecMatrix
()
{
for
(
unsigned
int
i
=
0
;
i
<
rows
();
++
i
)
{
delete
[]
mat_
[
i
];
}
delete
[]
mat_
;
}
unsigned
int
cols
()
const
{
return
col_
;
}
unsigned
int
rows
()
const
{
return
row_
;
}
template
<
class
Vector
>
void
row
(
const
unsigned
int
row
,
Vector
&
vec
)
const
{
const
unsigned
int
N
=
cols
();
assert
(
vec
.
size
()
==
N
);
for
(
unsigned
int
i
=
0
;
i
<
N
;
++
i
)
field_cast
(
mat_
[
row
][
i
],
vec
[
i
]);
}
unsigned
int
row_
,
col_
;
Field
**
mat_
;
};
}
#endif // #ifndef DUNE_LOCALFUNCTIONS_NEDELEC_NEDELECSIMPLEX_NEDELECSIMPLEXPREBASIS_HH
dune/localfunctions/test/CMakeLists.txt
View file @
e41bccc6
...
...
@@ -88,3 +88,11 @@ dune_add_test(NAME test-raviartthomassimplex3
dune_add_test
(
NAME test-raviartthomassimplex4
SOURCES test-raviartthomassimplex.cc
COMPILE_DEFINITIONS
"CHECKDIM=4"
)
dune_add_test
(
NAME test-nedelecsimplex2
SOURCES test-nedelecsimplex.cc
COMPILE_DEFINITIONS
"CHECKDIM=2"
)
dune_add_test
(
NAME test-nedelecsimplex3
SOURCES test-nedelecsimplex.cc
COMPILE_DEFINITIONS
"CHECKDIM=3"
)
dune/localfunctions/test/test-nedelecsimplex.cc
0 → 100644
View file @
e41bccc6
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#include <config.h>
#include <dune/localfunctions/nedelec/nedelecsimplex/nedelecsimplexbasis.hh>
#include <dune/localfunctions/utility/field.hh>
#include <dune/localfunctions/utility/basisprint.hh>
/**
* \file
* \brief Performs some tests for the generic Nedelec
* shape functions on simplices.
*
* The topology can be chosen at compile time by setting TOPOLOGY
* to a Dune::GeometryType like
* \code
* GeometryTypes::simplex(2)
* \endcode
* which generates a 2d simplex. If TOPOLOGY is not set, triangles and tetrahedra
* are tested. Note, this may lead to prolonged compiler runs.
*
* For debugging purpuse the functions and the derivatives can be
* printed. You have to define the macro TEST_OUTPUT_FUNCTIONS to
* activate this function.
*/
#if HAVE_GMP
typedef
Dune
::
GMPField
<
128
>
StorageField
;
typedef
Dune
::
GMPField
<
512
>
ComputeField
;
#else
typedef
double
StorageField
;
typedef
double
ComputeField
;
#endif
template
<
Dune
::
GeometryType
::
Id
geometryId
>
bool
test
(
unsigned
int
order
)
{
bool
ret
=
true
;
constexpr
Dune
::
GeometryType
geometry
=
geometryId
;
for
(
unsigned
int
o
=
1
;
o
<=
order
;
++
o
)
{
std
::
cout
<<
"Testing "
<<
geometry
<<
" of the "
<<
o
<<
"-th kind"
<<
std
::
endl
;
typedef
Dune
::
NedelecBasisFactory
<
geometry
.
dim
(),
StorageField
,
ComputeField
>
BasisFactory
;
const
typename
BasisFactory
::
Object
&
basis
=
*
BasisFactory
::
template
create
<
geometry
>(
o
);
// define the macro TEST_OUTPUT_FUNCTIONS to output files containing functions and
// derivatives in a human readabible form (aka LaTeX source)
#ifdef TEST_OUTPUT_FUNCTIONS
std
::
stringstream
name
;
name
<<
"ned_"
<<
geometry
<<
"_p"
<<
o
<<
".basis"
;
std
::
ofstream
out
(
name
.
str
().
c_str
());
Dune
::
basisPrint
<
0
,
BasisFactory
,
typename
BasisFactory
::
StorageField
,
geometry
>
(
out
,
basis
);
Dune
::
basisPrint
<
1
,
BasisFactory
,
typename
BasisFactory
::
StorageField
,
geometry
>
(
out
,
basis
);
#endif // TEST_OUTPUT_FUNCTIONS
// test interpolation
typedef
Dune
::
NedelecL2InterpolationFactory
<
geometry
.
dim
(),
StorageField
>
InterpolationFactory
;
const
typename
InterpolationFactory
::
Object
&
interpol
=
*
InterpolationFactory
::
template
create
<
geometry
>(
o
);
Dune
::
LFEMatrix
<
StorageField
>
matrix
;
interpol
.
interpolate
(
basis
,
matrix
);
for
(
unsigned
int
i
=
0
;
i
<
matrix
.
rows
();
++
i
)
matrix
(
i
,
i
)
-=
1
;
for
(
unsigned
int
i
=
0
;
i
<
matrix
.
rows
();
++
i
)
for
(
unsigned
int
j
=
0
;
j
<
matrix
.
cols
();
++
j
)
if
(
std
::
abs
(
matrix
(
i
,
j
)
)
>
1000.
*
Dune
::
Zero
<
double
>::
epsilon
()
)
std
::
cout
<<
" non-zero entry in interpolation matrix: "
<<
"("
<<
i
<<
","
<<
j
<<
") = "
<<
Dune
::
field_cast
<
double
>
(
matrix
(
i
,
j
))
<<
std
::
endl
;
BasisFactory
::
release
(
&
basis
);
std
::
cout
<<
"----------------------------------------------------------------------------------------------------------------
\n
"
;
}
if
(
!
ret
)
{
std
::
cout
<<
" FAILED !"
<<
std
::
endl
;
}
return
ret
;
}
#ifdef CHECKDIM
#if CHECKDIM==2
#define CHECKDIM2
#elif CHECKDIM==3
#define CHECKDIM3
#endif
#else
#define CHECKDIM2
#define CHECKDIM3
#endif
int
main
(
int
argc
,
char
**
argv
)
{
using
namespace
Dune
;
using
namespace
Impl
;
unsigned
int
order
=
(
argc
<
2
)
?
5
:
atoi
(
argv
[
1
]);
if
(
argc
<
2
)
{
std
::
cerr
<<
"Usage: "
<<
argv
[
0
]
<<
" <p>"
<<
std
::
endl
<<
"Using default kind of "
<<
order
<<
std
::
endl
;
}
#ifdef TOPOLOGY
return
(
test
<
TOPOLOGY
>
(
order
)
?
0
:
1
);
#else
bool
tests
=
true
;
#ifdef CHECKDIM2
tests
&=
test
<
GeometryTypes
::
simplex
(
2
)
>
(
order
);
#endif
#ifdef CHECKDIM3
tests
&=
test
<
GeometryTypes
::
simplex
(
3
)
>
(
order
);
#endif
return
(
tests
?
0
:
1
);
#endif // TOPOLOGY
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment