2818 lines
86 KiB
C++
2818 lines
86 KiB
C++
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#include "fem.hpp"
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <cstdio>
|
|
#ifdef _WIN32
|
|
#define snprintf _snprintf_s
|
|
#endif
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
using namespace std;
|
|
|
|
int FiniteElementCollection::HasFaceDofs(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TETRAHEDRON: return DofForGeometry (Geometry::TRIANGLE);
|
|
case Geometry::CUBE: return DofForGeometry (Geometry::SQUARE);
|
|
case Geometry::PRISM:
|
|
return max(DofForGeometry (Geometry::TRIANGLE),
|
|
DofForGeometry (Geometry::SQUARE));
|
|
default:
|
|
mfem_error ("FiniteElementCollection::HasFaceDofs:"
|
|
" unknown geometry type.");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
FiniteElementCollection *FiniteElementCollection::GetTraceCollection() const
|
|
{
|
|
MFEM_ABORT("this method is not implemented in this derived class!");
|
|
return NULL;
|
|
}
|
|
|
|
FiniteElementCollection *FiniteElementCollection::New(const char *name)
|
|
{
|
|
FiniteElementCollection *fec = NULL;
|
|
|
|
if (!strcmp(name, "Linear"))
|
|
{
|
|
fec = new LinearFECollection;
|
|
}
|
|
else if (!strcmp(name, "Quadratic"))
|
|
{
|
|
fec = new QuadraticFECollection;
|
|
}
|
|
else if (!strcmp(name, "QuadraticPos"))
|
|
{
|
|
fec = new QuadraticPosFECollection;
|
|
}
|
|
else if (!strcmp(name, "Cubic"))
|
|
{
|
|
fec = new CubicFECollection;
|
|
}
|
|
else if (!strcmp(name, "Const3D"))
|
|
{
|
|
fec = new Const3DFECollection;
|
|
}
|
|
else if (!strcmp(name, "Const2D"))
|
|
{
|
|
fec = new Const2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "LinearDiscont2D"))
|
|
{
|
|
fec = new LinearDiscont2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "GaussLinearDiscont2D"))
|
|
{
|
|
fec = new GaussLinearDiscont2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "P1OnQuad"))
|
|
{
|
|
fec = new P1OnQuadFECollection;
|
|
}
|
|
else if (!strcmp(name, "QuadraticDiscont2D"))
|
|
{
|
|
fec = new QuadraticDiscont2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "QuadraticPosDiscont2D"))
|
|
{
|
|
fec = new QuadraticPosDiscont2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "GaussQuadraticDiscont2D"))
|
|
{
|
|
fec = new GaussQuadraticDiscont2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "CubicDiscont2D"))
|
|
{
|
|
fec = new CubicDiscont2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "LinearDiscont3D"))
|
|
{
|
|
fec = new LinearDiscont3DFECollection;
|
|
}
|
|
else if (!strcmp(name, "QuadraticDiscont3D"))
|
|
{
|
|
fec = new QuadraticDiscont3DFECollection;
|
|
}
|
|
else if (!strcmp(name, "LinearNonConf3D"))
|
|
{
|
|
fec = new LinearNonConf3DFECollection;
|
|
}
|
|
else if (!strcmp(name, "CrouzeixRaviart"))
|
|
{
|
|
fec = new CrouzeixRaviartFECollection;
|
|
}
|
|
else if (!strcmp(name, "ND1_3D"))
|
|
{
|
|
fec = new ND1_3DFECollection;
|
|
}
|
|
else if (!strcmp(name, "RT0_2D"))
|
|
{
|
|
fec = new RT0_2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "RT1_2D"))
|
|
{
|
|
fec = new RT1_2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "RT2_2D"))
|
|
{
|
|
fec = new RT2_2DFECollection;
|
|
}
|
|
else if (!strcmp(name, "RT0_3D"))
|
|
{
|
|
fec = new RT0_3DFECollection;
|
|
}
|
|
else if (!strcmp(name, "RT1_3D"))
|
|
{
|
|
fec = new RT1_3DFECollection;
|
|
}
|
|
else if (!strncmp(name, "H1_Trace_", 9))
|
|
{
|
|
fec = new H1_Trace_FECollection(atoi(name + 13), atoi(name + 9));
|
|
}
|
|
else if (!strncmp(name, "H1_Trace@", 9))
|
|
{
|
|
fec = new H1_Trace_FECollection(atoi(name + 15), atoi(name + 11),
|
|
BasisType::GetType(name[9]));
|
|
}
|
|
else if (!strncmp(name, "H1_", 3))
|
|
{
|
|
fec = new H1_FECollection(atoi(name + 7), atoi(name + 3));
|
|
}
|
|
else if (!strncmp(name, "H1Pos_Trace_", 12))
|
|
{
|
|
fec = new H1_Trace_FECollection(atoi(name + 16), atoi(name + 12),
|
|
BasisType::Positive);
|
|
}
|
|
else if (!strncmp(name, "H1Pos_", 6))
|
|
{
|
|
fec = new H1Pos_FECollection(atoi(name + 10), atoi(name + 6));
|
|
}
|
|
else if (!strncmp(name, "H1Ser_", 6))
|
|
{
|
|
fec = new H1Ser_FECollection(atoi(name + 10), atoi(name + 6));
|
|
}
|
|
else if (!strncmp(name, "H1@", 3))
|
|
{
|
|
fec = new H1_FECollection(atoi(name + 9), atoi(name + 5),
|
|
BasisType::GetType(name[3]));
|
|
}
|
|
else if (!strncmp(name, "L2_T", 4))
|
|
fec = new L2_FECollection(atoi(name + 10), atoi(name + 6),
|
|
atoi(name + 4));
|
|
else if (!strncmp(name, "L2_", 3))
|
|
{
|
|
fec = new L2_FECollection(atoi(name + 7), atoi(name + 3));
|
|
}
|
|
else if (!strncmp(name, "L2Int_T", 7))
|
|
{
|
|
fec = new L2_FECollection(atoi(name + 13), atoi(name + 9),
|
|
atoi(name + 7), FiniteElement::INTEGRAL);
|
|
}
|
|
else if (!strncmp(name, "L2Int_", 6))
|
|
{
|
|
fec = new L2_FECollection(atoi(name + 10), atoi(name + 6),
|
|
BasisType::GaussLegendre,
|
|
FiniteElement::INTEGRAL);
|
|
}
|
|
else if (!strncmp(name, "RT_Trace_", 9))
|
|
{
|
|
fec = new RT_Trace_FECollection(atoi(name + 13), atoi(name + 9));
|
|
}
|
|
else if (!strncmp(name, "RT_ValTrace_", 12))
|
|
{
|
|
fec = new RT_Trace_FECollection(atoi(name + 16), atoi(name + 12),
|
|
FiniteElement::VALUE);
|
|
}
|
|
else if (!strncmp(name, "RT_Trace@", 9))
|
|
{
|
|
fec = new RT_Trace_FECollection(atoi(name + 15), atoi(name + 11),
|
|
FiniteElement::INTEGRAL,
|
|
BasisType::GetType(name[9]));
|
|
}
|
|
else if (!strncmp(name, "RT_ValTrace@", 12))
|
|
{
|
|
fec = new RT_Trace_FECollection(atoi(name + 18), atoi(name + 14),
|
|
FiniteElement::VALUE,
|
|
BasisType::GetType(name[12]));
|
|
}
|
|
else if (!strncmp(name, "DG_Iface_", 9))
|
|
{
|
|
fec = new DG_Interface_FECollection(atoi(name + 13), atoi(name + 9));
|
|
}
|
|
else if (!strncmp(name, "DG_Iface@", 9))
|
|
{
|
|
fec = new DG_Interface_FECollection(atoi(name + 15), atoi(name + 11),
|
|
FiniteElement::VALUE,
|
|
BasisType::GetType(name[9]));
|
|
}
|
|
else if (!strncmp(name, "DG_IntIface_", 12))
|
|
{
|
|
fec = new DG_Interface_FECollection(atoi(name + 16), atoi(name + 12),
|
|
FiniteElement::INTEGRAL);
|
|
}
|
|
else if (!strncmp(name, "DG_IntIface@", 12))
|
|
{
|
|
fec = new DG_Interface_FECollection(atoi(name + 18), atoi(name + 14),
|
|
FiniteElement::INTEGRAL,
|
|
BasisType::GetType(name[12]));
|
|
}
|
|
else if (!strncmp(name, "RT_", 3))
|
|
{
|
|
fec = new RT_FECollection(atoi(name + 7), atoi(name + 3));
|
|
}
|
|
else if (!strncmp(name, "RT@", 3))
|
|
{
|
|
fec = new RT_FECollection(atoi(name + 10), atoi(name + 6),
|
|
BasisType::GetType(name[3]),
|
|
BasisType::GetType(name[4]));
|
|
}
|
|
else if (!strncmp(name, "ND_Trace_", 9))
|
|
{
|
|
fec = new ND_Trace_FECollection(atoi(name + 13), atoi(name + 9));
|
|
}
|
|
else if (!strncmp(name, "ND_Trace@", 9))
|
|
{
|
|
fec = new ND_Trace_FECollection(atoi(name + 16), atoi(name + 12),
|
|
BasisType::GetType(name[9]),
|
|
BasisType::GetType(name[10]));
|
|
}
|
|
else if (!strncmp(name, "ND_", 3))
|
|
{
|
|
fec = new ND_FECollection(atoi(name + 7), atoi(name + 3));
|
|
}
|
|
else if (!strncmp(name, "ND@", 3))
|
|
{
|
|
fec = new ND_FECollection(atoi(name + 10), atoi(name + 6),
|
|
BasisType::GetType(name[3]),
|
|
BasisType::GetType(name[4]));
|
|
}
|
|
else if (!strncmp(name, "Local_", 6))
|
|
{
|
|
fec = new Local_FECollection(name + 6);
|
|
}
|
|
else if (!strncmp(name, "NURBS", 5))
|
|
{
|
|
if (name[5] != '\0')
|
|
{
|
|
// "NURBS" + "number" --> fixed order nurbs collection
|
|
fec = new NURBSFECollection(atoi(name + 5));
|
|
}
|
|
else
|
|
{
|
|
// "NURBS" --> variable order nurbs collection
|
|
fec = new NURBSFECollection();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("unknown FiniteElementCollection: " << name);
|
|
}
|
|
MFEM_VERIFY(!strcmp(fec->Name(), name), "input name: \"" << name
|
|
<< "\" does not match the created collection name: \""
|
|
<< fec->Name() << '"');
|
|
|
|
return fec;
|
|
}
|
|
|
|
template <Geometry::Type geom>
|
|
inline void FiniteElementCollection::GetNVE(int &nv, int &ne)
|
|
{
|
|
typedef typename Geometry::Constants<geom> g_consts;
|
|
|
|
nv = g_consts::NumVert;
|
|
ne = g_consts::NumEdges;
|
|
}
|
|
|
|
template <Geometry::Type geom, typename v_t>
|
|
inline void FiniteElementCollection::
|
|
GetEdge(int &nv, v_t &v, int &ne, int &e, int &eo, const int edge_info)
|
|
{
|
|
typedef typename Geometry::Constants<Geometry::SEGMENT> e_consts;
|
|
typedef typename Geometry::Constants<geom> g_consts;
|
|
|
|
nv = e_consts::NumVert;
|
|
ne = 1;
|
|
e = edge_info/64;
|
|
eo = edge_info%64;
|
|
MFEM_ASSERT(0 <= e && e < g_consts::NumEdges, "");
|
|
MFEM_ASSERT(0 <= eo && eo < e_consts::NumOrient, "");
|
|
v[0] = e_consts::Orient[eo][0];
|
|
v[1] = e_consts::Orient[eo][1];
|
|
v[0] = g_consts::Edges[e][v[0]];
|
|
v[1] = g_consts::Edges[e][v[1]];
|
|
}
|
|
|
|
template <Geometry::Type geom, Geometry::Type f_geom,
|
|
typename v_t, typename e_t, typename eo_t>
|
|
inline void FiniteElementCollection::
|
|
GetFace(int &nv, v_t &v, int &ne, e_t &e, eo_t &eo,
|
|
int &nf, int &f, Geometry::Type &fg, int &fo, const int face_info)
|
|
{
|
|
typedef typename Geometry::Constants< geom> g_consts;
|
|
typedef typename Geometry::Constants<f_geom> f_consts;
|
|
|
|
nv = f_consts::NumVert;
|
|
nf = 1;
|
|
f = face_info/64;
|
|
fg = f_geom;
|
|
fo = face_info%64;
|
|
MFEM_ASSERT(0 <= f && f < g_consts::NumFaces, "");
|
|
MFEM_ASSERT(0 <= fo && fo < f_consts::NumOrient, "");
|
|
for (int i = 0; i < f_consts::NumVert; i++)
|
|
{
|
|
v[i] = f_consts::Orient[fo][i];
|
|
v[i] = g_consts::FaceVert[f][v[i]];
|
|
}
|
|
ne = f_consts::NumEdges;
|
|
for (int i = 0; i < f_consts::NumEdges; i++)
|
|
{
|
|
int v0 = v[f_consts::Edges[i][0]];
|
|
int v1 = v[f_consts::Edges[i][1]];
|
|
int eor = 0;
|
|
if (v0 > v1) { swap(v0, v1); eor = 1; }
|
|
for (int j = g_consts::VertToVert::I[v0]; true; j++)
|
|
{
|
|
MFEM_ASSERT(j < g_consts::VertToVert::I[v0+1],
|
|
"internal error, edge not found");
|
|
if (v1 == g_consts::VertToVert::J[j][0])
|
|
{
|
|
int en = g_consts::VertToVert::J[j][1];
|
|
if (en < 0)
|
|
{
|
|
en = -1-en;
|
|
eor = 1-eor;
|
|
}
|
|
e[i] = en;
|
|
eo[i] = eor;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FiniteElementCollection::SubDofOrder(Geometry::Type Geom, int SDim,
|
|
int Info,
|
|
Array<int> &dofs) const
|
|
{
|
|
// Info = 64 * SubIndex + SubOrientation
|
|
MFEM_ASSERT(0 <= Geom && Geom < Geometry::NumGeom,
|
|
"invalid Geom = " << Geom);
|
|
MFEM_ASSERT(0 <= SDim && SDim <= Geometry::Dimension[Geom],
|
|
"invalid SDim = " << SDim <<
|
|
" for Geom = " << Geometry::Name[Geom]);
|
|
|
|
const int nvd = DofForGeometry(Geometry::POINT);
|
|
if (SDim == 0) // vertex
|
|
{
|
|
const int off = nvd*(Info/64);
|
|
dofs.SetSize(nvd);
|
|
for (int i = 0; i < nvd; i++)
|
|
{
|
|
dofs[i] = off + i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int v[4], e[4], eo[4], f[1], fo[1];
|
|
int av = 0, nv = 0, ae = 0, ne = 0, nf = 0;
|
|
Geometry::Type fg[1];
|
|
|
|
switch (Geom)
|
|
{
|
|
case Geometry::SEGMENT:
|
|
{
|
|
GetNVE<Geometry::SEGMENT>(av, ae);
|
|
GetEdge<Geometry::SEGMENT>(nv, v, ne, e[0], eo[0], Info);
|
|
break;
|
|
}
|
|
|
|
case Geometry::TRIANGLE:
|
|
{
|
|
GetNVE<Geometry::TRIANGLE>(av, ae);
|
|
switch (SDim)
|
|
{
|
|
case 1:
|
|
GetEdge<Geometry::TRIANGLE>(nv, v, ne, e[0], eo[0], Info);
|
|
break;
|
|
case 2:
|
|
GetFace<Geometry::TRIANGLE,Geometry::TRIANGLE>(
|
|
nv, v, ne, e, eo, nf, f[0], fg[0], fo[0], Info);
|
|
break;
|
|
default:
|
|
goto not_supp;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Geometry::SQUARE:
|
|
{
|
|
GetNVE<Geometry::SQUARE>(av, ae);
|
|
switch (SDim)
|
|
{
|
|
case 1:
|
|
GetEdge<Geometry::SQUARE>(nv, v, ne, e[0], eo[0], Info);
|
|
break;
|
|
case 2:
|
|
GetFace<Geometry::SQUARE,Geometry::SQUARE>(
|
|
nv, v, ne, e, eo, nf, f[0], fg[0], fo[0], Info);
|
|
break;
|
|
default:
|
|
goto not_supp;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Geometry::TETRAHEDRON:
|
|
{
|
|
GetNVE<Geometry::TETRAHEDRON>(av, ae);
|
|
switch (SDim)
|
|
{
|
|
case 1:
|
|
GetEdge<Geometry::TETRAHEDRON>(nv, v, ne, e[0], eo[0], Info);
|
|
break;
|
|
case 2:
|
|
GetFace<Geometry::TETRAHEDRON,Geometry::TRIANGLE>(
|
|
nv, v, ne, e, eo, nf, f[0], fg[0], fo[0], Info);
|
|
break;
|
|
default:
|
|
goto not_supp;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Geometry::CUBE:
|
|
{
|
|
GetNVE<Geometry::CUBE>(av, ae);
|
|
switch (SDim)
|
|
{
|
|
case 1:
|
|
GetEdge<Geometry::CUBE>(nv, v, ne, e[0], eo[0], Info);
|
|
break;
|
|
case 2:
|
|
GetFace<Geometry::CUBE,Geometry::SQUARE>(
|
|
nv, v, ne, e, eo, nf, f[0], fg[0], fo[0], Info);
|
|
break;
|
|
default:
|
|
goto not_supp;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
MFEM_ABORT("invalid Geom = " << Geom);
|
|
}
|
|
|
|
int ned = (ne > 0) ? DofForGeometry(Geometry::SEGMENT) : 0;
|
|
|
|
// add vertex dofs
|
|
dofs.SetSize(nv*nvd+ne*ned);
|
|
for (int i = 0; i < nv; i++)
|
|
{
|
|
for (int j = 0; j < nvd; j++)
|
|
{
|
|
dofs[i*nvd+j] = v[i]*nvd+j;
|
|
}
|
|
}
|
|
int l_off = nv*nvd, g_off = av*nvd;
|
|
|
|
// add edge dofs
|
|
if (ned > 0)
|
|
{
|
|
for (int i = 0; i < ne; i++)
|
|
{
|
|
const int *ed = DofOrderForOrientation(Geometry::SEGMENT,
|
|
eo[i] ? -1 : 1);
|
|
for (int j = 0; j < ned; j++)
|
|
{
|
|
dofs[l_off+i*ned+j] =
|
|
ed[j] >= 0 ?
|
|
g_off+e[i]*ned+ed[j] :
|
|
-1-(g_off+e[i]*ned+(-1-ed[j]));
|
|
}
|
|
}
|
|
l_off += ne*ned;
|
|
g_off += ae*ned;
|
|
}
|
|
|
|
// add face dofs
|
|
if (nf > 0)
|
|
{
|
|
const int nfd = DofForGeometry(fg[0]); // assume same face geometry
|
|
dofs.SetSize(dofs.Size()+nf*nfd);
|
|
for (int i = 0; i < nf; i++)
|
|
{
|
|
const int *fd = DofOrderForOrientation(fg[i], fo[i]);
|
|
for (int j = 0; j < nfd; j++)
|
|
{
|
|
dofs[l_off+i*nfd+j] =
|
|
fd[j] >= 0 ?
|
|
g_off+f[i]*nfd+fd[j] :
|
|
-1-(g_off+f[i]*nfd+(-1-fd[j]));
|
|
}
|
|
}
|
|
}
|
|
|
|
// add volume dofs ...
|
|
}
|
|
return;
|
|
|
|
not_supp:
|
|
MFEM_ABORT("Geom = " << Geometry::Name[Geom] <<
|
|
", SDim = " << SDim << " is not supported");
|
|
}
|
|
|
|
const FiniteElement *
|
|
LinearFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return &PointFE;
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
case Geometry::CUBE: return &ParallelepipedFE;
|
|
case Geometry::PRISM: return &WedgeFE;
|
|
default:
|
|
mfem_error ("LinearFECollection: unknown geometry type.");
|
|
}
|
|
return &SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int LinearFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 1;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 0;
|
|
case Geometry::TETRAHEDRON: return 0;
|
|
case Geometry::CUBE: return 0;
|
|
case Geometry::PRISM: return 0;
|
|
default:
|
|
mfem_error ("LinearFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *LinearFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
QuadraticFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return &PointFE;
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
case Geometry::CUBE: return &ParallelepipedFE;
|
|
case Geometry::PRISM: return &WedgeFE;
|
|
default:
|
|
mfem_error ("QuadraticFECollection: unknown geometry type.");
|
|
}
|
|
return &SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int QuadraticFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 1;
|
|
case Geometry::SEGMENT: return 1;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 1;
|
|
case Geometry::TETRAHEDRON: return 0;
|
|
case Geometry::CUBE: return 1;
|
|
case Geometry::PRISM: return 0;
|
|
default:
|
|
mfem_error ("QuadraticFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *QuadraticFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
static int indexes[] = { 0 };
|
|
|
|
return indexes;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
QuadraticPosFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("QuadraticPosFECollection: unknown geometry type.");
|
|
}
|
|
return NULL; // Make some compilers happy
|
|
}
|
|
|
|
int QuadraticPosFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 1;
|
|
case Geometry::SEGMENT: return 1;
|
|
case Geometry::SQUARE: return 1;
|
|
default:
|
|
mfem_error ("QuadraticPosFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *QuadraticPosFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
static int indexes[] = { 0 };
|
|
|
|
return indexes;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
CubicFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return &PointFE;
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
case Geometry::CUBE: return &ParallelepipedFE;
|
|
case Geometry::PRISM: return &WedgeFE;
|
|
default:
|
|
mfem_error ("CubicFECollection: unknown geometry type.");
|
|
}
|
|
return &SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int CubicFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 1;
|
|
case Geometry::SEGMENT: return 2;
|
|
case Geometry::TRIANGLE: return 1;
|
|
case Geometry::SQUARE: return 4;
|
|
case Geometry::TETRAHEDRON: return 0;
|
|
case Geometry::CUBE: return 8;
|
|
case Geometry::PRISM: return 2;
|
|
default:
|
|
mfem_error ("CubicFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *CubicFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
if (GeomType == Geometry::SEGMENT)
|
|
{
|
|
static int ind_pos[] = { 0, 1 };
|
|
static int ind_neg[] = { 1, 0 };
|
|
|
|
if (Or < 0)
|
|
{
|
|
return ind_neg;
|
|
}
|
|
return ind_pos;
|
|
}
|
|
else if (GeomType == Geometry::TRIANGLE)
|
|
{
|
|
static int indexes[] = { 0 };
|
|
|
|
return indexes;
|
|
}
|
|
else if (GeomType == Geometry::SQUARE)
|
|
{
|
|
static int sq_ind[8][4] = {{0, 1, 2, 3}, {0, 2, 1, 3},
|
|
{2, 0, 3, 1}, {1, 0, 3, 2},
|
|
{3, 2, 1, 0}, {3, 1, 2, 0},
|
|
{1, 3, 0, 2}, {2, 3, 0, 1}
|
|
};
|
|
return sq_ind[Or];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
CrouzeixRaviartFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("CrouzeixRaviartFECollection: unknown geometry type.");
|
|
}
|
|
return &SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int CrouzeixRaviartFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 1;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 0;
|
|
default:
|
|
mfem_error ("CrouzeixRaviartFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *CrouzeixRaviartFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
static int indexes[] = { 0 };
|
|
|
|
return indexes;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
RT0_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("RT0_2DFECollection: unknown geometry type.");
|
|
}
|
|
return &SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int RT0_2DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 1;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 0;
|
|
default:
|
|
mfem_error ("RT0_2DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int * RT0_2DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
static int ind_pos[] = { 0 };
|
|
static int ind_neg[] = { -1 };
|
|
|
|
if (Or > 0)
|
|
{
|
|
return ind_pos;
|
|
}
|
|
return ind_neg;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
RT1_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("RT1_2DFECollection: unknown geometry type.");
|
|
}
|
|
return &SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int RT1_2DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 2;
|
|
case Geometry::TRIANGLE: return 2;
|
|
case Geometry::SQUARE: return 4;
|
|
default:
|
|
mfem_error ("RT1_2DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *RT1_2DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
static int ind_pos[] = { 0, 1 };
|
|
static int ind_neg[] = { -2, -1 };
|
|
|
|
if (Or > 0)
|
|
{
|
|
return ind_pos;
|
|
}
|
|
return ind_neg;
|
|
}
|
|
|
|
const FiniteElement *
|
|
RT2_2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("RT2_2DFECollection: unknown geometry type.");
|
|
}
|
|
return &SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int RT2_2DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 3;
|
|
case Geometry::TRIANGLE: return 6;
|
|
case Geometry::SQUARE: return 12;
|
|
default:
|
|
mfem_error ("RT2_2DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *RT2_2DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
static int ind_pos[] = { 0, 1, 2 };
|
|
static int ind_neg[] = { -3, -2, -1 };
|
|
|
|
if (Or > 0)
|
|
{
|
|
return ind_pos;
|
|
}
|
|
return ind_neg;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
Const2DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("Const2DFECollection: unknown geometry type.");
|
|
}
|
|
return &TriangleFE; // Make some compilers happy
|
|
}
|
|
|
|
int Const2DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 1;
|
|
case Geometry::SQUARE: return 1;
|
|
default:
|
|
mfem_error ("Const2DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *Const2DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
LinearDiscont2DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("LinearDiscont2DFECollection: unknown geometry type.");
|
|
}
|
|
return &TriangleFE; // Make some compilers happy
|
|
}
|
|
|
|
int LinearDiscont2DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 3;
|
|
case Geometry::SQUARE: return 4;
|
|
default:
|
|
mfem_error ("LinearDiscont2DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int * LinearDiscont2DFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
GaussLinearDiscont2DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("GaussLinearDiscont2DFECollection:"
|
|
" unknown geometry type.");
|
|
}
|
|
return &TriangleFE; // Make some compilers happy
|
|
}
|
|
|
|
int GaussLinearDiscont2DFECollection::DofForGeometry(Geometry::Type GeomType)
|
|
const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 3;
|
|
case Geometry::SQUARE: return 4;
|
|
default:
|
|
mfem_error ("GaussLinearDiscont2DFECollection:"
|
|
" unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *GaussLinearDiscont2DFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
P1OnQuadFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
if (GeomType != Geometry::SQUARE)
|
|
{
|
|
mfem_error ("P1OnQuadFECollection: unknown geometry type.");
|
|
}
|
|
return &QuadrilateralFE;
|
|
}
|
|
|
|
int P1OnQuadFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::SQUARE: return 3;
|
|
default:
|
|
mfem_error ("P1OnQuadFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *P1OnQuadFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
QuadraticDiscont2DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("QuadraticDiscont2DFECollection: unknown geometry type.");
|
|
}
|
|
return &TriangleFE; // Make some compilers happy
|
|
}
|
|
|
|
int QuadraticDiscont2DFECollection::DofForGeometry(Geometry::Type GeomType)
|
|
const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 6;
|
|
case Geometry::SQUARE: return 9;
|
|
default:
|
|
mfem_error ("QuadraticDiscont2DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *QuadraticDiscont2DFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
QuadraticPosDiscont2DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("QuadraticPosDiscont2DFECollection: unknown geometry type.");
|
|
}
|
|
return NULL; // Make some compilers happy
|
|
}
|
|
|
|
int QuadraticPosDiscont2DFECollection::DofForGeometry(Geometry::Type GeomType)
|
|
const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::SQUARE: return 9;
|
|
default:
|
|
mfem_error ("QuadraticPosDiscont2DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
GaussQuadraticDiscont2DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType)
|
|
const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("GaussQuadraticDiscont2DFECollection:"
|
|
" unknown geometry type.");
|
|
}
|
|
return &QuadrilateralFE; // Make some compilers happy
|
|
}
|
|
|
|
int GaussQuadraticDiscont2DFECollection::DofForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 6;
|
|
case Geometry::SQUARE: return 9;
|
|
default:
|
|
mfem_error ("GaussQuadraticDiscont2DFECollection:"
|
|
" unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *GaussQuadraticDiscont2DFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
CubicDiscont2DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
default:
|
|
mfem_error ("CubicDiscont2DFECollection: unknown geometry type.");
|
|
}
|
|
return &TriangleFE; // Make some compilers happy
|
|
}
|
|
|
|
int CubicDiscont2DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 10;
|
|
case Geometry::SQUARE: return 16;
|
|
default:
|
|
mfem_error ("CubicDiscont2DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *CubicDiscont2DFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
LinearNonConf3DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
case Geometry::CUBE: return &ParallelepipedFE;
|
|
default:
|
|
mfem_error ("LinearNonConf3DFECollection: unknown geometry type.");
|
|
}
|
|
return &TriangleFE; // Make some compilers happy
|
|
}
|
|
|
|
int LinearNonConf3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 1;
|
|
case Geometry::SQUARE: return 1;
|
|
case Geometry::TETRAHEDRON: return 0;
|
|
case Geometry::CUBE: return 0;
|
|
default:
|
|
mfem_error ("LinearNonConf3DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *LinearNonConf3DFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
static int indexes[] = { 0 };
|
|
|
|
return indexes;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
Const3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
case Geometry::CUBE: return &ParallelepipedFE;
|
|
case Geometry::PRISM: return &WedgeFE;
|
|
default:
|
|
mfem_error ("Const3DFECollection: unknown geometry type.");
|
|
}
|
|
return &TetrahedronFE; // Make some compilers happy
|
|
}
|
|
|
|
int Const3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 0;
|
|
case Geometry::TETRAHEDRON: return 1;
|
|
case Geometry::CUBE: return 1;
|
|
case Geometry::PRISM: return 1;
|
|
default:
|
|
mfem_error ("Const3DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *Const3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
LinearDiscont3DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
case Geometry::CUBE: return &ParallelepipedFE;
|
|
default:
|
|
mfem_error ("LinearDiscont3DFECollection: unknown geometry type.");
|
|
}
|
|
return &TetrahedronFE; // Make some compilers happy
|
|
}
|
|
|
|
int LinearDiscont3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 0;
|
|
case Geometry::TETRAHEDRON: return 4;
|
|
case Geometry::CUBE: return 8;
|
|
default:
|
|
mfem_error ("LinearDiscont3DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *LinearDiscont3DFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
QuadraticDiscont3DFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
case Geometry::CUBE: return &ParallelepipedFE;
|
|
default:
|
|
mfem_error ("QuadraticDiscont3DFECollection: unknown geometry type.");
|
|
}
|
|
return &TetrahedronFE; // Make some compilers happy
|
|
}
|
|
|
|
int QuadraticDiscont3DFECollection::DofForGeometry(Geometry::Type GeomType)
|
|
const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 0;
|
|
case Geometry::TETRAHEDRON: return 10;
|
|
case Geometry::CUBE: return 27;
|
|
default:
|
|
mfem_error ("QuadraticDiscont3DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *QuadraticDiscont3DFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
const FiniteElement *
|
|
RefinedLinearFECollection::FiniteElementForGeometry(
|
|
Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return &PointFE;
|
|
case Geometry::SEGMENT: return &SegmentFE;
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
case Geometry::CUBE: return &ParallelepipedFE;
|
|
default:
|
|
mfem_error ("RefinedLinearFECollection: unknown geometry type.");
|
|
}
|
|
return &SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int RefinedLinearFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 1;
|
|
case Geometry::SEGMENT: return 1;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 1;
|
|
case Geometry::TETRAHEDRON: return 0;
|
|
case Geometry::CUBE: return 1;
|
|
default:
|
|
mfem_error ("RefinedLinearFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *RefinedLinearFECollection::DofOrderForOrientation(
|
|
Geometry::Type GeomType, int Or) const
|
|
{
|
|
static int indexes[] = { 0 };
|
|
|
|
return indexes;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
ND1_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::CUBE: return &HexahedronFE;
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
default:
|
|
mfem_error ("ND1_3DFECollection: unknown geometry type.");
|
|
}
|
|
return &HexahedronFE; // Make some compilers happy
|
|
}
|
|
|
|
int ND1_3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 1;
|
|
case Geometry::TRIANGLE: return 0;
|
|
case Geometry::SQUARE: return 0;
|
|
case Geometry::TETRAHEDRON: return 0;
|
|
case Geometry::CUBE: return 0;
|
|
default:
|
|
mfem_error ("ND1_3DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *ND1_3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
static int ind_pos[] = { 0 };
|
|
static int ind_neg[] = { -1 };
|
|
|
|
if (Or > 0)
|
|
{
|
|
return ind_pos;
|
|
}
|
|
return ind_neg;
|
|
}
|
|
|
|
|
|
const FiniteElement *
|
|
RT0_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
case Geometry::CUBE: return &HexahedronFE;
|
|
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
|
default:
|
|
mfem_error ("RT0_3DFECollection: unknown geometry type.");
|
|
}
|
|
return &HexahedronFE; // Make some compilers happy
|
|
}
|
|
|
|
int RT0_3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 1;
|
|
case Geometry::SQUARE: return 1;
|
|
case Geometry::TETRAHEDRON: return 0;
|
|
case Geometry::CUBE: return 0;
|
|
default:
|
|
mfem_error ("RT0_3DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *RT0_3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
static int ind_pos[] = { 0 };
|
|
static int ind_neg[] = { -1 };
|
|
|
|
if ((GeomType == Geometry::TRIANGLE) || (GeomType == Geometry::SQUARE))
|
|
{
|
|
if (Or % 2 == 0)
|
|
{
|
|
return ind_pos;
|
|
}
|
|
return ind_neg;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const FiniteElement *
|
|
RT1_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::TRIANGLE: return &TriangleFE;
|
|
case Geometry::SQUARE: return &QuadrilateralFE;
|
|
case Geometry::CUBE: return &HexahedronFE;
|
|
default:
|
|
mfem_error ("RT1_3DFECollection: unknown geometry type.");
|
|
}
|
|
return &HexahedronFE; // Make some compilers happy
|
|
}
|
|
|
|
int RT1_3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::POINT: return 0;
|
|
case Geometry::SEGMENT: return 0;
|
|
case Geometry::TRIANGLE: return 2;
|
|
case Geometry::SQUARE: return 4;
|
|
case Geometry::CUBE: return 12;
|
|
default:
|
|
mfem_error ("RT1_3DFECollection: unknown geometry type.");
|
|
}
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *RT1_3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
if (GeomType == Geometry::SQUARE)
|
|
{
|
|
static int sq_ind[8][4] =
|
|
{
|
|
{0, 1, 2, 3}, {-1, -3, -2, -4},
|
|
{2, 0, 3, 1}, {-2, -1, -4, -3},
|
|
{3, 2, 1, 0}, {-4, -2, -3, -1},
|
|
{1, 3, 0, 2}, {-3, -4, -1, -2}
|
|
};
|
|
|
|
return sq_ind[Or];
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
|
{
|
|
MFEM_VERIFY(p >= 1, "H1_FECollection requires order >= 1.");
|
|
MFEM_VERIFY(dim >= 0 && dim <= 3, "H1_FECollection requires 0 <= dim <= 3.");
|
|
|
|
const int pm1 = p - 1, pm2 = pm1 - 1, pm3 = pm2 - 1, pm4 = pm3 - 1;
|
|
|
|
int pt_type = BasisType::GetQuadrature1D(btype);
|
|
b_type = BasisType::Check(btype);
|
|
switch (btype)
|
|
{
|
|
case BasisType::GaussLobatto:
|
|
{
|
|
snprintf(h1_name, 32, "H1_%dD_P%d", dim, p);
|
|
break;
|
|
}
|
|
case BasisType::Positive:
|
|
{
|
|
snprintf(h1_name, 32, "H1Pos_%dD_P%d", dim, p);
|
|
break;
|
|
}
|
|
case BasisType::Serendipity:
|
|
{
|
|
snprintf(h1_name, 32, "H1Ser_%dD_P%d", dim, p);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
MFEM_VERIFY(Quadrature1D::CheckClosed(pt_type) !=
|
|
Quadrature1D::Invalid,
|
|
"unsupported BasisType: " << BasisType::Name(btype));
|
|
|
|
snprintf(h1_name, 32, "H1@%c_%dD_P%d",
|
|
(int)BasisType::GetChar(btype), dim, p);
|
|
}
|
|
}
|
|
|
|
for (int g = 0; g < Geometry::NumGeom; g++)
|
|
{
|
|
H1_dof[g] = 0;
|
|
H1_Elements[g] = NULL;
|
|
}
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
SegDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
TriDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
QuadDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 24; i++)
|
|
{
|
|
TetDofOrd[i] = NULL;
|
|
}
|
|
|
|
H1_dof[Geometry::POINT] = 1;
|
|
H1_Elements[Geometry::POINT] = new PointFiniteElement;
|
|
|
|
if (dim >= 1)
|
|
{
|
|
H1_dof[Geometry::SEGMENT] = pm1;
|
|
if (b_type == BasisType::Positive)
|
|
{
|
|
H1_Elements[Geometry::SEGMENT] = new H1Pos_SegmentElement(p);
|
|
}
|
|
else
|
|
{
|
|
H1_Elements[Geometry::SEGMENT] = new H1_SegmentElement(p, btype);
|
|
}
|
|
|
|
SegDofOrd[0] = new int[2*pm1];
|
|
SegDofOrd[1] = SegDofOrd[0] + pm1;
|
|
for (int i = 0; i < pm1; i++)
|
|
{
|
|
SegDofOrd[0][i] = i;
|
|
SegDofOrd[1][i] = pm2 - i;
|
|
}
|
|
}
|
|
|
|
if (dim >= 2)
|
|
{
|
|
H1_dof[Geometry::TRIANGLE] = (pm1*pm2)/2;
|
|
H1_dof[Geometry::SQUARE] = pm1*pm1;
|
|
if (b_type == BasisType::Positive)
|
|
{
|
|
H1_Elements[Geometry::TRIANGLE] = new H1Pos_TriangleElement(p);
|
|
H1_Elements[Geometry::SQUARE] = new H1Pos_QuadrilateralElement(p);
|
|
}
|
|
else if (b_type == BasisType::Serendipity)
|
|
{
|
|
// Note: in fe_coll.hpp the DofForGeometry(Geometry::Type) method
|
|
// returns H1_dof[GeomType], so we need to fix the value of H1_dof here
|
|
// for the serendipity case.
|
|
|
|
// formula for number of interior serendipity DoFs (when p>1)
|
|
H1_dof[Geometry::SQUARE] = (pm3*pm2)/2;
|
|
H1_Elements[Geometry::SQUARE] = new H1Ser_QuadrilateralElement(p);
|
|
// allows for mixed tri/quad meshes
|
|
H1_Elements[Geometry::TRIANGLE] = new H1Pos_TriangleElement(p);
|
|
}
|
|
else
|
|
{
|
|
H1_Elements[Geometry::TRIANGLE] = new H1_TriangleElement(p, btype);
|
|
H1_Elements[Geometry::SQUARE] = new H1_QuadrilateralElement(p, btype);
|
|
}
|
|
|
|
const int &TriDof = H1_dof[Geometry::TRIANGLE];
|
|
const int &QuadDof = H1_dof[Geometry::SQUARE];
|
|
TriDofOrd[0] = new int[6*TriDof];
|
|
for (int i = 1; i < 6; i++)
|
|
{
|
|
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
|
|
}
|
|
// see Mesh::GetTriOrientation in mesh/mesh.cpp
|
|
for (int j = 0; j < pm2; j++)
|
|
{
|
|
for (int i = 0; i + j < pm2; i++)
|
|
{
|
|
int o = TriDof - ((pm1 - j)*(pm2 - j))/2 + i;
|
|
int k = pm3 - j - i;
|
|
TriDofOrd[0][o] = o; // (0,1,2)
|
|
TriDofOrd[1][o] = TriDof - ((pm1-j)*(pm2-j))/2 + k; // (1,0,2)
|
|
TriDofOrd[2][o] = TriDof - ((pm1-i)*(pm2-i))/2 + k; // (2,0,1)
|
|
TriDofOrd[3][o] = TriDof - ((pm1-k)*(pm2-k))/2 + i; // (2,1,0)
|
|
TriDofOrd[4][o] = TriDof - ((pm1-k)*(pm2-k))/2 + j; // (1,2,0)
|
|
TriDofOrd[5][o] = TriDof - ((pm1-i)*(pm2-i))/2 + j; // (0,2,1)
|
|
}
|
|
}
|
|
|
|
QuadDofOrd[0] = new int[8*QuadDof];
|
|
for (int i = 1; i < 8; i++)
|
|
{
|
|
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
|
|
}
|
|
|
|
// For serendipity order >=4, the QuadDofOrd array must be re-defined. We
|
|
// do this by computing the corresponding tensor product QuadDofOrd array
|
|
// or two orders less, which contains enough DoFs for their serendipity
|
|
// basis. This could be optimized.
|
|
if (b_type == BasisType::Serendipity)
|
|
{
|
|
if (p < 4)
|
|
{
|
|
// no face dofs --> don't need to adjust QuadDofOrd
|
|
}
|
|
else // p >= 4 --> have face dofs
|
|
{
|
|
// Exactly the same as tensor product case, but with all orders
|
|
// reduced by 2 e.g. in case p=5 it builds a 2x2 array, even though
|
|
// there are only 3 serendipity dofs.
|
|
// In the tensor product case, the i and j index tensor directions,
|
|
// and o index from 0 to (pm1)^2,
|
|
|
|
for (int j = 0; j < pm3; j++) // pm3 instead of pm1, etc
|
|
{
|
|
for (int i = 0; i < pm3; i++)
|
|
{
|
|
int o = i + j*pm3;
|
|
QuadDofOrd[0][o] = i + j*pm3; // (0,1,2,3)
|
|
QuadDofOrd[1][o] = j + i*pm3; // (0,3,2,1)
|
|
QuadDofOrd[2][o] = j + (pm4 - i)*pm3; // (1,2,3,0)
|
|
QuadDofOrd[3][o] = (pm4 - i) + j*pm3; // (1,0,3,2)
|
|
QuadDofOrd[4][o] = (pm4 - i) + (pm4 - j)*pm3; // (2,3,0,1)
|
|
QuadDofOrd[5][o] = (pm4 - j) + (pm4 - i)*pm3; // (2,1,0,3)
|
|
QuadDofOrd[6][o] = (pm4 - j) + i*pm3; // (3,0,1,2)
|
|
QuadDofOrd[7][o] = i + (pm4 - j)*pm3; // (3,2,1,0)
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
else // not serendipity
|
|
{
|
|
for (int j = 0; j < pm1; j++)
|
|
{
|
|
for (int i = 0; i < pm1; i++)
|
|
{
|
|
int o = i + j*pm1;
|
|
QuadDofOrd[0][o] = i + j*pm1; // (0,1,2,3)
|
|
QuadDofOrd[1][o] = j + i*pm1; // (0,3,2,1)
|
|
QuadDofOrd[2][o] = j + (pm2 - i)*pm1; // (1,2,3,0)
|
|
QuadDofOrd[3][o] = (pm2 - i) + j*pm1; // (1,0,3,2)
|
|
QuadDofOrd[4][o] = (pm2 - i) + (pm2 - j)*pm1; // (2,3,0,1)
|
|
QuadDofOrd[5][o] = (pm2 - j) + (pm2 - i)*pm1; // (2,1,0,3)
|
|
QuadDofOrd[6][o] = (pm2 - j) + i*pm1; // (3,0,1,2)
|
|
QuadDofOrd[7][o] = i + (pm2 - j)*pm1; // (3,2,1,0)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dim >= 3)
|
|
{
|
|
H1_dof[Geometry::TETRAHEDRON] = (TriDof*pm3)/3;
|
|
H1_dof[Geometry::CUBE] = QuadDof*pm1;
|
|
H1_dof[Geometry::PRISM] = TriDof*pm1;
|
|
if (b_type == BasisType::Positive)
|
|
{
|
|
H1_Elements[Geometry::TETRAHEDRON] = new H1Pos_TetrahedronElement(p);
|
|
H1_Elements[Geometry::CUBE] = new H1Pos_HexahedronElement(p);
|
|
H1_Elements[Geometry::PRISM] = new H1Pos_WedgeElement(p);
|
|
}
|
|
else
|
|
{
|
|
H1_Elements[Geometry::TETRAHEDRON] =
|
|
new H1_TetrahedronElement(p, btype);
|
|
H1_Elements[Geometry::CUBE] = new H1_HexahedronElement(p, btype);
|
|
H1_Elements[Geometry::PRISM] = new H1_WedgeElement(p, btype);
|
|
}
|
|
|
|
const int &TetDof = H1_dof[Geometry::TETRAHEDRON];
|
|
TetDofOrd[0] = new int[24*TetDof];
|
|
for (int i = 1; i < 24; i++)
|
|
{
|
|
TetDofOrd[i] = TetDofOrd[i-1] + TetDof;
|
|
}
|
|
// see Mesh::GetTetOrientation in mesh/mesh.cpp
|
|
for (int k = 0; k < pm3; k++)
|
|
{
|
|
for (int j = 0; j + k < pm3; j++)
|
|
{
|
|
for (int i = 0; i + j + k < pm3; i++)
|
|
{
|
|
int l = pm4 - k - j - i;
|
|
int o = TetDof - ((pm1 - k) * (pm2 - k) * (pm3 - k)) / 6
|
|
+ (j * (2 * p - 5 - j - 2 * k)) / 2 + i;
|
|
int o1 = TetDof - ((pm1 - j) * (pm2 - j) * (pm3 - j)) / 6
|
|
+ (k * (2 * p - 5 - k - 2 * j)) / 2 + i;
|
|
int o2 = TetDof - ((pm1 - i) * (pm2 - i) * (pm3 - i)) / 6
|
|
+ (k * (2 * p - 5 - k - 2 * i)) / 2 + j;
|
|
int o3 = TetDof - ((pm1 - k) * (pm2 - k) * (pm3 - k)) / 6
|
|
+ (i * (2 * p - 5 - i - 2 * k)) / 2 + j;
|
|
int o4 = TetDof - ((pm1 - j) * (pm2 - j) * (pm3 - j)) / 6
|
|
+ (i * (2 * p - 5 - i - 2 * j)) / 2 + k;
|
|
int o5 = TetDof - ((pm1 - i) * (pm2 - i) * (pm3 - i)) / 6
|
|
+ (j * (2 * p - 5 - j - 2 * i)) / 2 + k;
|
|
int o6 = TetDof - ((pm1 - k) * (pm2 - k) * (pm3 - k)) / 6
|
|
+ (l * (2 * p - 5 - l - 2 * k)) / 2 + j;
|
|
int o7 = TetDof - ((pm1 - l) * (pm2 - l) * (pm3 - l)) / 6
|
|
+ (k * (2 * p - 5 - k - 2 * l)) / 2 + j;
|
|
int o8 = TetDof - ((pm1 - l) * (pm2 - l) * (pm3 - l)) / 6
|
|
+ (j * (2 * p - 5 - j - 2 * l)) / 2 + k;
|
|
int o9 = TetDof - ((pm1 - j) * (pm2 - j) * (pm3 - j)) / 6
|
|
+ (l * (2 * p - 5 - l - 2 * j)) / 2 + k;
|
|
int o10 = TetDof - ((pm1 - j) * (pm2 - j) * (pm3 - j)) / 6
|
|
+ (k * (2 * p - 5 - k - 2 * j)) / 2 + l;
|
|
int o11 = TetDof - ((pm1 - k) * (pm2 - k) * (pm3 - k)) / 6
|
|
+ (j * (2 * p - 5 - j - 2 * k)) / 2 + l;
|
|
int o12 = TetDof - ((pm1 - i) * (pm2 - i) * (pm3 - i)) / 6
|
|
+ (l * (2 * p - 5 - l - 2 * i)) / 2 + k;
|
|
int o13 = TetDof - ((pm1 - l) * (pm2 - l) * (pm3 - l)) / 6
|
|
+ (i * (2 * p - 5 - i - 2 * l)) / 2 + k;
|
|
int o14 = TetDof - ((pm1 - k) * (pm2 - k) * (pm3 - k)) / 6
|
|
+ (i * (2 * p - 5 - i - 2 * k)) / 2 + l;
|
|
int o15 = TetDof - ((pm1 - i) * (pm2 - i) * (pm3 - i)) / 6
|
|
+ (k * (2 * p - 5 - k - 2 * i)) / 2 + l;
|
|
int o16 = TetDof - ((pm1 - l) * (pm2 - l) * (pm3 - l)) / 6
|
|
+ (k * (2 * p - 5 - k - 2 * l)) / 2 + i;
|
|
int o17 = TetDof - ((pm1 - k) * (pm2 - k) * (pm3 - k)) / 6
|
|
+ (l * (2 * p - 5 - l - 2 * k)) / 2 + i;
|
|
int o18 = TetDof - ((pm1 - i) * (pm2 - i) * (pm3 - i)) / 6
|
|
+ (j * (2 * p - 5 - j - 2 * i)) / 2 + l;
|
|
int o19 = TetDof - ((pm1 - j) * (pm2 - j) * (pm3 - j)) / 6
|
|
+ (i * (2 * p - 5 - i - 2 * j)) / 2 + l;
|
|
int o20 = TetDof - ((pm1 - j) * (pm2 - j) * (pm3 - j)) / 6
|
|
+ (l * (2 * p - 5 - l - 2 * j)) / 2 + i;
|
|
int o21 = TetDof - ((pm1 - l) * (pm2 - l) * (pm3 - l)) / 6
|
|
+ (j * (2 * p - 5 - j - 2 * l)) / 2 + i;
|
|
int o22 = TetDof - ((pm1 - l) * (pm2 - l) * (pm3 - l)) / 6
|
|
+ (i * (2 * p - 5 - i - 2 * l)) / 2 + j;
|
|
int o23 = TetDof - ((pm1 - i) * (pm2 - i) * (pm3 - i)) / 6
|
|
+ (l * (2 * p - 5 - l - 2 * i)) / 2 + j;
|
|
TetDofOrd[ 0][o] = o; // (0,1,2,3)
|
|
TetDofOrd[ 1][o] = o1; // (0,1,3,2)
|
|
TetDofOrd[ 2][o] = o2; // (0,2,3,1)
|
|
TetDofOrd[ 3][o] = o3; // (0,2,1,3)
|
|
TetDofOrd[ 4][o] = o4; // (0,3,1,2)
|
|
TetDofOrd[ 5][o] = o5; // (0,3,2,1)
|
|
TetDofOrd[ 6][o] = o6; // (1,2,0,3)
|
|
TetDofOrd[ 7][o] = o7; // (1,2,3,0)
|
|
TetDofOrd[ 8][o] = o8; // (1,3,2,0)
|
|
TetDofOrd[ 9][o] = o9; // (1,3,0,2)
|
|
TetDofOrd[10][o] = o10; // (1,0,3,2)
|
|
TetDofOrd[11][o] = o11; // (1,0,2,3)
|
|
TetDofOrd[12][o] = o12; // (2,3,0,1)
|
|
TetDofOrd[13][o] = o13; // (2,3,1,0)
|
|
TetDofOrd[14][o] = o14; // (2,0,1,3)
|
|
TetDofOrd[15][o] = o15; // (2,0,3,1)
|
|
TetDofOrd[16][o] = o16; // (2,1,3,0)
|
|
TetDofOrd[17][o] = o17; // (2,1,0,3)
|
|
TetDofOrd[18][o] = o18; // (3,0,2,1)
|
|
TetDofOrd[19][o] = o19; // (3,0,1,2)
|
|
TetDofOrd[20][o] = o20; // (3,1,0,2)
|
|
TetDofOrd[21][o] = o21; // (3,1,2,0)
|
|
TetDofOrd[22][o] = o22; // (3,2,1,0)
|
|
TetDofOrd[23][o] = o23; // (3,2,0,1)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const int *H1_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
if (GeomType == Geometry::SEGMENT)
|
|
{
|
|
return (Or > 0) ? SegDofOrd[0] : SegDofOrd[1];
|
|
}
|
|
else if (GeomType == Geometry::TRIANGLE)
|
|
{
|
|
return TriDofOrd[Or%6];
|
|
}
|
|
else if (GeomType == Geometry::SQUARE)
|
|
{
|
|
return QuadDofOrd[Or%8];
|
|
}
|
|
else if (GeomType == Geometry::TETRAHEDRON)
|
|
{
|
|
return TetDofOrd[Or%24];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
FiniteElementCollection *H1_FECollection::GetTraceCollection() const
|
|
{
|
|
int p = H1_dof[Geometry::SEGMENT] + 1;
|
|
int dim = -1;
|
|
if (!strncmp(h1_name, "H1_", 3))
|
|
{
|
|
dim = atoi(h1_name + 3);
|
|
}
|
|
else if (!strncmp(h1_name, "H1Pos_", 6))
|
|
{
|
|
dim = atoi(h1_name + 6);
|
|
}
|
|
else if (!strncmp(h1_name, "H1@", 3))
|
|
{
|
|
dim = atoi(h1_name + 5);
|
|
}
|
|
return (dim < 0) ? NULL : new H1_Trace_FECollection(p, dim, b_type);
|
|
}
|
|
|
|
const int *H1_FECollection::GetDofMap(Geometry::Type GeomType) const
|
|
{
|
|
const int *dof_map = NULL;
|
|
const FiniteElement *fe = H1_Elements[GeomType];
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SEGMENT:
|
|
case Geometry::SQUARE:
|
|
case Geometry::CUBE:
|
|
dof_map = dynamic_cast<const TensorBasisElement *>(fe)
|
|
->GetDofMap().GetData();
|
|
break;
|
|
default:
|
|
MFEM_ABORT("Geometry type " << Geometry::Name[GeomType] << " is not "
|
|
"implemented");
|
|
// The "Cartesian" ordering for other geometries is defined by the
|
|
// class GeometryRefiner.
|
|
}
|
|
return dof_map;
|
|
}
|
|
|
|
H1_FECollection::~H1_FECollection()
|
|
{
|
|
delete [] SegDofOrd[0];
|
|
delete [] TriDofOrd[0];
|
|
delete [] QuadDofOrd[0];
|
|
delete [] TetDofOrd[0];
|
|
for (int g = 0; g < Geometry::NumGeom; g++)
|
|
{
|
|
delete H1_Elements[g];
|
|
}
|
|
}
|
|
|
|
|
|
H1_Trace_FECollection::H1_Trace_FECollection(const int p, const int dim,
|
|
const int btype)
|
|
: H1_FECollection(p, dim-1, btype)
|
|
{
|
|
if (btype == BasisType::GaussLobatto)
|
|
{
|
|
snprintf(h1_name, 32, "H1_Trace_%dD_P%d", dim, p);
|
|
}
|
|
else if (btype == BasisType::Positive)
|
|
{
|
|
snprintf(h1_name, 32, "H1Pos_Trace_%dD_P%d", dim, p);
|
|
}
|
|
else // base class checks that type is closed
|
|
{
|
|
snprintf(h1_name, 32, "H1_Trace@%c_%dD_P%d",
|
|
(int)BasisType::GetChar(btype), dim, p);
|
|
}
|
|
}
|
|
|
|
|
|
L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
|
const int map_type)
|
|
{
|
|
MFEM_VERIFY(p >= 0, "L2_FECollection requires order >= 0.");
|
|
|
|
b_type = BasisType::Check(btype);
|
|
const char *prefix = NULL;
|
|
switch (map_type)
|
|
{
|
|
case FiniteElement::VALUE: prefix = "L2"; break;
|
|
case FiniteElement::INTEGRAL: prefix = "L2Int"; break;
|
|
default:
|
|
MFEM_ABORT("invalid map_type: " << map_type);
|
|
}
|
|
switch (btype)
|
|
{
|
|
case BasisType::GaussLegendre:
|
|
snprintf(d_name, 32, "%s_%dD_P%d", prefix, dim, p);
|
|
break;
|
|
default:
|
|
snprintf(d_name, 32, "%s_T%d_%dD_P%d", prefix, btype, dim, p);
|
|
}
|
|
|
|
for (int g = 0; g < Geometry::NumGeom; g++)
|
|
{
|
|
L2_Elements[g] = NULL;
|
|
Tr_Elements[g] = NULL;
|
|
}
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
SegDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
TriDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 24; i++)
|
|
{
|
|
TetDofOrd[i] = NULL;
|
|
}
|
|
OtherDofOrd = NULL;
|
|
|
|
if (dim == 0)
|
|
{
|
|
L2_Elements[Geometry::POINT] = new PointFiniteElement;
|
|
}
|
|
else if (dim == 1)
|
|
{
|
|
if (b_type == BasisType::Positive)
|
|
{
|
|
L2_Elements[Geometry::SEGMENT] = new L2Pos_SegmentElement(p);
|
|
}
|
|
else
|
|
{
|
|
L2_Elements[Geometry::SEGMENT] = new L2_SegmentElement(p, btype);
|
|
}
|
|
L2_Elements[Geometry::SEGMENT]->SetMapType(map_type);
|
|
|
|
Tr_Elements[Geometry::POINT] = new PointFiniteElement;
|
|
// No need to set the map_type for Tr_Elements.
|
|
|
|
const int pp1 = p + 1;
|
|
SegDofOrd[0] = new int[2*pp1];
|
|
SegDofOrd[1] = SegDofOrd[0] + pp1;
|
|
for (int i = 0; i <= p; i++)
|
|
{
|
|
SegDofOrd[0][i] = i;
|
|
SegDofOrd[1][i] = p - i;
|
|
}
|
|
}
|
|
else if (dim == 2)
|
|
{
|
|
if (b_type == BasisType::Positive)
|
|
{
|
|
L2_Elements[Geometry::TRIANGLE] = new L2Pos_TriangleElement(p);
|
|
L2_Elements[Geometry::SQUARE] = new L2Pos_QuadrilateralElement(p);
|
|
}
|
|
else
|
|
{
|
|
L2_Elements[Geometry::TRIANGLE] = new L2_TriangleElement(p, btype);
|
|
L2_Elements[Geometry::SQUARE] = new L2_QuadrilateralElement(p, btype);
|
|
}
|
|
L2_Elements[Geometry::TRIANGLE]->SetMapType(map_type);
|
|
L2_Elements[Geometry::SQUARE]->SetMapType(map_type);
|
|
// Trace element use the default Gauss-Legendre nodal points for positive basis
|
|
if (b_type == BasisType::Positive)
|
|
{
|
|
Tr_Elements[Geometry::SEGMENT] = new L2_SegmentElement(p);
|
|
}
|
|
else
|
|
{
|
|
Tr_Elements[Geometry::SEGMENT] = new L2_SegmentElement(p, btype);
|
|
}
|
|
|
|
const int TriDof = L2_Elements[Geometry::TRIANGLE]->GetDof();
|
|
TriDofOrd[0] = new int[6*TriDof];
|
|
for (int i = 1; i < 6; i++)
|
|
{
|
|
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
|
|
}
|
|
const int pp1 = p + 1, pp2 = pp1 + 1;
|
|
for (int j = 0; j <= p; j++)
|
|
{
|
|
for (int i = 0; i + j <= p; i++)
|
|
{
|
|
int o = TriDof - ((pp2 - j)*(pp1 - j))/2 + i;
|
|
int k = p - j - i;
|
|
TriDofOrd[0][o] = o; // (0,1,2)
|
|
TriDofOrd[1][o] = TriDof - ((pp2-j)*(pp1-j))/2 + k; // (1,0,2)
|
|
TriDofOrd[2][o] = TriDof - ((pp2-i)*(pp1-i))/2 + k; // (2,0,1)
|
|
TriDofOrd[3][o] = TriDof - ((pp2-k)*(pp1-k))/2 + i; // (2,1,0)
|
|
TriDofOrd[4][o] = TriDof - ((pp2-k)*(pp1-k))/2 + j; // (1,2,0)
|
|
TriDofOrd[5][o] = TriDof - ((pp2-i)*(pp1-i))/2 + j; // (0,2,1)
|
|
}
|
|
}
|
|
const int QuadDof = L2_Elements[Geometry::SQUARE]->GetDof();
|
|
OtherDofOrd = new int[QuadDof];
|
|
for (int j = 0; j < QuadDof; j++)
|
|
{
|
|
OtherDofOrd[j] = j; // for Or == 0
|
|
}
|
|
}
|
|
else if (dim == 3)
|
|
{
|
|
if (b_type == BasisType::Positive)
|
|
{
|
|
L2_Elements[Geometry::TETRAHEDRON] = new L2Pos_TetrahedronElement(p);
|
|
L2_Elements[Geometry::CUBE] = new L2Pos_HexahedronElement(p);
|
|
L2_Elements[Geometry::PRISM] = new L2Pos_WedgeElement(p);
|
|
}
|
|
else
|
|
{
|
|
L2_Elements[Geometry::TETRAHEDRON] =
|
|
new L2_TetrahedronElement(p, btype);
|
|
L2_Elements[Geometry::CUBE] = new L2_HexahedronElement(p, btype);
|
|
L2_Elements[Geometry::PRISM] = new L2_WedgeElement(p, btype);
|
|
}
|
|
L2_Elements[Geometry::TETRAHEDRON]->SetMapType(map_type);
|
|
L2_Elements[Geometry::CUBE]->SetMapType(map_type);
|
|
L2_Elements[Geometry::PRISM]->SetMapType(map_type);
|
|
// Trace element use the default Gauss-Legendre nodal points for positive basis
|
|
if (b_type == BasisType::Positive)
|
|
{
|
|
Tr_Elements[Geometry::TRIANGLE] = new L2_TriangleElement(p);
|
|
Tr_Elements[Geometry::SQUARE] = new L2_QuadrilateralElement(p);
|
|
}
|
|
else
|
|
{
|
|
Tr_Elements[Geometry::TRIANGLE] = new L2_TriangleElement(p, btype);
|
|
Tr_Elements[Geometry::SQUARE] = new L2_QuadrilateralElement(p, btype);
|
|
}
|
|
|
|
const int TetDof = L2_Elements[Geometry::TETRAHEDRON]->GetDof();
|
|
const int HexDof = L2_Elements[Geometry::CUBE]->GetDof();
|
|
const int PriDof = L2_Elements[Geometry::PRISM]->GetDof();
|
|
const int MaxDof = std::max(TetDof, std::max(PriDof, HexDof));
|
|
|
|
TetDofOrd[0] = new int[24*TetDof];
|
|
for (int i = 1; i < 24; i++)
|
|
{
|
|
TetDofOrd[i] = TetDofOrd[i-1] + TetDof;
|
|
}
|
|
// see Mesh::GetTetOrientation in mesh/mesh.cpp
|
|
const int pp1 = p + 1, pp2 = pp1 + 1, pp3 = pp2 + 1;
|
|
for (int k = 0; k <= p; k++)
|
|
{
|
|
for (int j = 0; j + k <= p; j++)
|
|
{
|
|
for (int i = 0; i + j + k <= p; i++)
|
|
{
|
|
int l = p - k - j - i;
|
|
int o = TetDof - ((pp1 - k) * (pp2 - k) * (pp3 - k)) / 6
|
|
+ (j * (2 * p + 3 - j - 2 * k)) / 2 + i;
|
|
int o1 = TetDof - ((pp1 - j) * (pp2 - j) * (pp3 - j)) / 6
|
|
+ (k * (2 * p + 3 - k - 2 * j)) / 2 + i;
|
|
int o2 = TetDof - ((pp1 - i) * (pp2 - i) * (pp3 - i)) / 6
|
|
+ (k * (2 * p + 3 - k - 2 * i)) / 2 + j;
|
|
int o3 = TetDof - ((pp1 - k) * (pp2 - k) * (pp3 - k)) / 6
|
|
+ (i * (2 * p + 3 - i - 2 * k)) / 2 + j;
|
|
int o4 = TetDof - ((pp1 - j) * (pp2 - j) * (pp3 - j)) / 6
|
|
+ (i * (2 * p + 3 - i - 2 * j)) / 2 + k;
|
|
int o5 = TetDof - ((pp1 - i) * (pp2 - i) * (pp3 - i)) / 6
|
|
+ (j * (2 * p + 3 - j - 2 * i)) / 2 + k;
|
|
int o6 = TetDof - ((pp1 - k) * (pp2 - k) * (pp3 - k)) / 6
|
|
+ (l * (2 * p + 3 - l - 2 * k)) / 2 + j;
|
|
int o7 = TetDof - ((pp1 - l) * (pp2 - l) * (pp3 - l)) / 6
|
|
+ (k * (2 * p + 3 - k - 2 * l)) / 2 + j;
|
|
int o8 = TetDof - ((pp1 - l) * (pp2 - l) * (pp3 - l)) / 6
|
|
+ (j * (2 * p + 3 - j - 2 * l)) / 2 + k;
|
|
int o9 = TetDof - ((pp1 - j) * (pp2 - j) * (pp3 - j)) / 6
|
|
+ (l * (2 * p + 3 - l - 2 * j)) / 2 + k;
|
|
int o10 = TetDof - ((pp1 - j) * (pp2 - j) * (pp3 - j)) / 6
|
|
+ (k * (2 * p + 3 - k - 2 * j)) / 2 + l;
|
|
int o11 = TetDof - ((pp1 - k) * (pp2 - k) * (pp3 - k)) / 6
|
|
+ (j * (2 * p + 3 - j - 2 * k)) / 2 + l;
|
|
int o12 = TetDof - ((pp1 - i) * (pp2 - i) * (pp3 - i)) / 6
|
|
+ (l * (2 * p + 3 - l - 2 * i)) / 2 + k;
|
|
int o13 = TetDof - ((pp1 - l) * (pp2 - l) * (pp3 - l)) / 6
|
|
+ (i * (2 * p + 3 - i - 2 * l)) / 2 + k;
|
|
int o14 = TetDof - ((pp1 - k) * (pp2 - k) * (pp3 - k)) / 6
|
|
+ (i * (2 * p + 3 - i - 2 * k)) / 2 + l;
|
|
int o15 = TetDof - ((pp1 - i) * (pp2 - i) * (pp3 - i)) / 6
|
|
+ (k * (2 * p + 3 - k - 2 * i)) / 2 + l;
|
|
int o16 = TetDof - ((pp1 - l) * (pp2 - l) * (pp3 - l)) / 6
|
|
+ (k * (2 * p + 3 - k - 2 * l)) / 2 + i;
|
|
int o17 = TetDof - ((pp1 - k) * (pp2 - k) * (pp3 - k)) / 6
|
|
+ (l * (2 * p + 3 - l - 2 * k)) / 2 + i;
|
|
int o18 = TetDof - ((pp1 - i) * (pp2 - i) * (pp3 - i)) / 6
|
|
+ (j * (2 * p + 3 - j - 2 * i)) / 2 + l;
|
|
int o19 = TetDof - ((pp1 - j) * (pp2 - j) * (pp3 - j)) / 6
|
|
+ (i * (2 * p + 3 - i - 2 * j)) / 2 + l;
|
|
int o20 = TetDof - ((pp1 - j) * (pp2 - j) * (pp3 - j)) / 6
|
|
+ (l * (2 * p + 3 - l - 2 * j)) / 2 + i;
|
|
int o21 = TetDof - ((pp1 - l) * (pp2 - l) * (pp3 - l)) / 6
|
|
+ (j * (2 * p + 3 - j - 2 * l)) / 2 + i;
|
|
int o22 = TetDof - ((pp1 - l) * (pp2 - l) * (pp3 - l)) / 6
|
|
+ (i * (2 * p + 3 - i - 2 * l)) / 2 + j;
|
|
int o23 = TetDof - ((pp1 - i) * (pp2 - i) * (pp3 - i)) / 6
|
|
+ (l * (2 * p + 3 - l - 2 * i)) / 2 + j;
|
|
TetDofOrd[ 0][o] = o; // (0,1,2,3)
|
|
TetDofOrd[ 1][o] = o1; // (0,1,3,2)
|
|
TetDofOrd[ 2][o] = o2; // (0,2,3,1)
|
|
TetDofOrd[ 3][o] = o3; // (0,2,1,3)
|
|
TetDofOrd[ 4][o] = o4; // (0,3,1,2)
|
|
TetDofOrd[ 5][o] = o5; // (0,3,2,1)
|
|
TetDofOrd[ 6][o] = o6; // (1,2,0,3)
|
|
TetDofOrd[ 7][o] = o7; // (1,2,3,0)
|
|
TetDofOrd[ 8][o] = o8; // (1,3,2,0)
|
|
TetDofOrd[ 9][o] = o9; // (1,3,0,2)
|
|
TetDofOrd[10][o] = o10; // (1,0,3,2)
|
|
TetDofOrd[11][o] = o11; // (1,0,2,3)
|
|
TetDofOrd[12][o] = o12; // (2,3,0,1)
|
|
TetDofOrd[13][o] = o13; // (2,3,1,0)
|
|
TetDofOrd[14][o] = o14; // (2,0,1,3)
|
|
TetDofOrd[15][o] = o15; // (2,0,3,1)
|
|
TetDofOrd[16][o] = o16; // (2,1,3,0)
|
|
TetDofOrd[17][o] = o17; // (2,1,0,3)
|
|
TetDofOrd[18][o] = o18; // (3,0,2,1)
|
|
TetDofOrd[19][o] = o19; // (3,0,1,2)
|
|
TetDofOrd[20][o] = o20; // (3,1,0,2)
|
|
TetDofOrd[21][o] = o21; // (3,1,2,0)
|
|
TetDofOrd[22][o] = o22; // (3,2,1,0)
|
|
TetDofOrd[23][o] = o23; // (3,2,0,1)
|
|
}
|
|
}
|
|
}
|
|
OtherDofOrd = new int[MaxDof];
|
|
for (int j = 0; j < MaxDof; j++)
|
|
{
|
|
OtherDofOrd[j] = j; // for Or == 0
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mfem::err << "L2_FECollection::L2_FECollection : dim = "
|
|
<< dim << endl;
|
|
mfem_error();
|
|
}
|
|
}
|
|
|
|
const int *L2_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SEGMENT:
|
|
return (Or > 0) ? SegDofOrd[0] : SegDofOrd[1];
|
|
|
|
case Geometry::TRIANGLE:
|
|
return TriDofOrd[Or%6];
|
|
|
|
case Geometry::TETRAHEDRON:
|
|
return TetDofOrd[Or%24];
|
|
|
|
default:
|
|
return (Or == 0) ? OtherDofOrd : NULL;
|
|
}
|
|
}
|
|
|
|
L2_FECollection::~L2_FECollection()
|
|
{
|
|
delete [] OtherDofOrd;
|
|
delete [] SegDofOrd[0];
|
|
delete [] TriDofOrd[0];
|
|
delete [] TetDofOrd[0];
|
|
for (int i = 0; i < Geometry::NumGeom; i++)
|
|
{
|
|
delete L2_Elements[i];
|
|
delete Tr_Elements[i];
|
|
}
|
|
}
|
|
|
|
|
|
RT_FECollection::RT_FECollection(const int p, const int dim,
|
|
const int cb_type, const int ob_type)
|
|
: ob_type(ob_type)
|
|
{
|
|
MFEM_VERIFY(p >= 0, "RT_FECollection requires order >= 0.");
|
|
|
|
int cp_type = BasisType::GetQuadrature1D(cb_type);
|
|
int op_type = BasisType::GetQuadrature1D(ob_type);
|
|
|
|
if (Quadrature1D::CheckClosed(cp_type) == Quadrature1D::Invalid)
|
|
{
|
|
const char *cb_name = BasisType::Name(cb_type); // this may abort
|
|
MFEM_ABORT("unknown closed BasisType: " << cb_name);
|
|
}
|
|
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid)
|
|
{
|
|
const char *ob_name = BasisType::Name(ob_type); // this may abort
|
|
MFEM_ABORT("unknown open BasisType: " << ob_name);
|
|
}
|
|
|
|
InitFaces(p, dim, FiniteElement::INTEGRAL, true);
|
|
|
|
if (cb_type == BasisType::GaussLobatto &&
|
|
ob_type == BasisType::GaussLegendre)
|
|
{
|
|
snprintf(rt_name, 32, "RT_%dD_P%d", dim, p);
|
|
}
|
|
else
|
|
{
|
|
snprintf(rt_name, 32, "RT@%c%c_%dD_P%d", (int)BasisType::GetChar(cb_type),
|
|
(int)BasisType::GetChar(ob_type), dim, p);
|
|
}
|
|
|
|
const int pp1 = p + 1;
|
|
if (dim == 2)
|
|
{
|
|
// TODO: cb_type, ob_type for triangles
|
|
RT_Elements[Geometry::TRIANGLE] = new RT_TriangleElement(p);
|
|
RT_dof[Geometry::TRIANGLE] = p*pp1;
|
|
|
|
RT_Elements[Geometry::SQUARE] = new RT_QuadrilateralElement(p, cb_type,
|
|
ob_type);
|
|
// two vector components * n_unk_face *
|
|
RT_dof[Geometry::SQUARE] = 2*p*pp1;
|
|
}
|
|
else if (dim == 3)
|
|
{
|
|
// TODO: cb_type, ob_type for tets
|
|
RT_Elements[Geometry::TETRAHEDRON] = new RT_TetrahedronElement(p);
|
|
RT_dof[Geometry::TETRAHEDRON] = p*pp1*(p + 2)/2;
|
|
|
|
RT_Elements[Geometry::CUBE] = new RT_HexahedronElement(p, cb_type, ob_type);
|
|
RT_dof[Geometry::CUBE] = 3*p*pp1*pp1;
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("invalid dim = " << dim);
|
|
}
|
|
}
|
|
|
|
// This is a special protected constructor only used by RT_Trace_FECollection
|
|
// and DG_Interface_FECollection
|
|
RT_FECollection::RT_FECollection(const int p, const int dim, const int map_type,
|
|
const bool signs, const int ob_type)
|
|
: ob_type(ob_type)
|
|
{
|
|
if (Quadrature1D::CheckOpen(BasisType::GetQuadrature1D(ob_type)) ==
|
|
Quadrature1D::Invalid)
|
|
{
|
|
const char *ob_name = BasisType::Name(ob_type); // this may abort
|
|
MFEM_ABORT("Invalid open basis type: " << ob_name);
|
|
}
|
|
InitFaces(p, dim, map_type, signs);
|
|
}
|
|
|
|
void RT_FECollection::InitFaces(const int p, const int dim, const int map_type,
|
|
const bool signs)
|
|
{
|
|
int op_type = BasisType::GetQuadrature1D(ob_type);
|
|
|
|
MFEM_VERIFY(Quadrature1D::CheckOpen(op_type) != Quadrature1D::Invalid,
|
|
"invalid open point type");
|
|
|
|
const int pp1 = p + 1, pp2 = p + 2;
|
|
|
|
for (int g = 0; g < Geometry::NumGeom; g++)
|
|
{
|
|
RT_Elements[g] = NULL;
|
|
RT_dof[g] = 0;
|
|
}
|
|
// Degree of Freedom orderings
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
SegDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
TriDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
QuadDofOrd[i] = NULL;
|
|
}
|
|
|
|
if (dim == 2)
|
|
{
|
|
L2_SegmentElement *l2_seg = new L2_SegmentElement(p, ob_type);
|
|
l2_seg->SetMapType(map_type);
|
|
RT_Elements[Geometry::SEGMENT] = l2_seg;
|
|
RT_dof[Geometry::SEGMENT] = pp1;
|
|
|
|
SegDofOrd[0] = new int[2*pp1];
|
|
SegDofOrd[1] = SegDofOrd[0] + pp1;
|
|
for (int i = 0; i <= p; i++)
|
|
{
|
|
SegDofOrd[0][i] = i;
|
|
SegDofOrd[1][i] = signs ? (-1 - (p - i)) : (p - i);
|
|
}
|
|
}
|
|
else if (dim == 3)
|
|
{
|
|
L2_TriangleElement *l2_tri = new L2_TriangleElement(p, ob_type);
|
|
l2_tri->SetMapType(map_type);
|
|
RT_Elements[Geometry::TRIANGLE] = l2_tri;
|
|
RT_dof[Geometry::TRIANGLE] = pp1*pp2/2;
|
|
|
|
L2_QuadrilateralElement *l2_quad = new L2_QuadrilateralElement(p, ob_type);
|
|
l2_quad->SetMapType(map_type);
|
|
RT_Elements[Geometry::SQUARE] = l2_quad;
|
|
RT_dof[Geometry::SQUARE] = pp1*pp1;
|
|
|
|
int TriDof = RT_dof[Geometry::TRIANGLE];
|
|
TriDofOrd[0] = new int[6*TriDof];
|
|
for (int i = 1; i < 6; i++)
|
|
{
|
|
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
|
|
}
|
|
// see Mesh::GetTriOrientation in mesh/mesh.cpp,
|
|
// the constructor of H1_FECollection
|
|
for (int j = 0; j <= p; j++)
|
|
{
|
|
for (int i = 0; i + j <= p; i++)
|
|
{
|
|
int o = TriDof - ((pp2 - j)*(pp1 - j))/2 + i;
|
|
int k = p - j - i;
|
|
TriDofOrd[0][o] = o; // (0,1,2)
|
|
TriDofOrd[1][o] = -1-(TriDof-((pp2-j)*(pp1-j))/2+k); // (1,0,2)
|
|
TriDofOrd[2][o] = TriDof-((pp2-i)*(pp1-i))/2+k; // (2,0,1)
|
|
TriDofOrd[3][o] = -1-(TriDof-((pp2-k)*(pp1-k))/2+i); // (2,1,0)
|
|
TriDofOrd[4][o] = TriDof-((pp2-k)*(pp1-k))/2+j; // (1,2,0)
|
|
TriDofOrd[5][o] = -1-(TriDof-((pp2-i)*(pp1-i))/2+j); // (0,2,1)
|
|
if (!signs)
|
|
{
|
|
for (int k = 1; k < 6; k += 2)
|
|
{
|
|
TriDofOrd[k][o] = -1 - TriDofOrd[k][o];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int QuadDof = RT_dof[Geometry::SQUARE];
|
|
QuadDofOrd[0] = new int[8*QuadDof];
|
|
for (int i = 1; i < 8; i++)
|
|
{
|
|
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
|
|
}
|
|
// see Mesh::GetQuadOrientation in mesh/mesh.cpp
|
|
for (int j = 0; j <= p; j++)
|
|
{
|
|
for (int i = 0; i <= p; i++)
|
|
{
|
|
int o = i + j*pp1;
|
|
QuadDofOrd[0][o] = i + j*pp1; // (0,1,2,3)
|
|
QuadDofOrd[1][o] = -1 - (j + i*pp1); // (0,3,2,1)
|
|
QuadDofOrd[2][o] = j + (p - i)*pp1; // (1,2,3,0)
|
|
QuadDofOrd[3][o] = -1 - ((p - i) + j*pp1); // (1,0,3,2)
|
|
QuadDofOrd[4][o] = (p - i) + (p - j)*pp1; // (2,3,0,1)
|
|
QuadDofOrd[5][o] = -1 - ((p - j) + (p - i)*pp1); // (2,1,0,3)
|
|
QuadDofOrd[6][o] = (p - j) + i*pp1; // (3,0,1,2)
|
|
QuadDofOrd[7][o] = -1 - (i + (p - j)*pp1); // (3,2,1,0)
|
|
if (!signs)
|
|
{
|
|
for (int k = 1; k < 8; k += 2)
|
|
{
|
|
QuadDofOrd[k][o] = -1 - QuadDofOrd[k][o];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const int *RT_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
if (GeomType == Geometry::SEGMENT)
|
|
{
|
|
return (Or > 0) ? SegDofOrd[0] : SegDofOrd[1];
|
|
}
|
|
else if (GeomType == Geometry::TRIANGLE)
|
|
{
|
|
return TriDofOrd[Or%6];
|
|
}
|
|
else if (GeomType == Geometry::SQUARE)
|
|
{
|
|
return QuadDofOrd[Or%8];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
FiniteElementCollection *RT_FECollection::GetTraceCollection() const
|
|
{
|
|
int dim, p;
|
|
if (!strncmp(rt_name, "RT_", 3))
|
|
{
|
|
dim = atoi(rt_name + 3);
|
|
p = atoi(rt_name + 7);
|
|
}
|
|
else // rt_name = RT@.._.D_P*
|
|
{
|
|
dim = atoi(rt_name + 6);
|
|
p = atoi(rt_name + 10);
|
|
}
|
|
return new RT_Trace_FECollection(p, dim, FiniteElement::INTEGRAL, ob_type);
|
|
}
|
|
|
|
RT_FECollection::~RT_FECollection()
|
|
{
|
|
delete [] SegDofOrd[0];
|
|
delete [] TriDofOrd[0];
|
|
delete [] QuadDofOrd[0];
|
|
for (int g = 0; g < Geometry::NumGeom; g++)
|
|
{
|
|
delete RT_Elements[g];
|
|
}
|
|
}
|
|
|
|
|
|
RT_Trace_FECollection::RT_Trace_FECollection(const int p, const int dim,
|
|
const int map_type,
|
|
const int ob_type)
|
|
: RT_FECollection(p, dim, map_type, true, ob_type)
|
|
{
|
|
const char *prefix =
|
|
(map_type == FiniteElement::INTEGRAL) ? "RT_Trace" : "RT_ValTrace";
|
|
char ob_str[3] = { '\0', '\0', '\0' };
|
|
|
|
if (ob_type != BasisType::GaussLegendre)
|
|
{
|
|
ob_str[0] = '@';
|
|
ob_str[1] = BasisType::GetChar(ob_type);
|
|
}
|
|
snprintf(rt_name, 32, "%s%s_%dD_P%d", prefix, ob_str, dim, p);
|
|
|
|
MFEM_VERIFY(dim == 2 || dim == 3, "Wrong dimension, dim = " << dim);
|
|
}
|
|
|
|
|
|
DG_Interface_FECollection::DG_Interface_FECollection(const int p, const int dim,
|
|
const int map_type,
|
|
const int ob_type)
|
|
: RT_FECollection(p, dim, map_type, false, ob_type)
|
|
{
|
|
MFEM_VERIFY(dim == 2 || dim == 3, "Wrong dimension, dim = " << dim);
|
|
|
|
const char *prefix =
|
|
(map_type == FiniteElement::VALUE) ? "DG_Iface" : "DG_IntIface";
|
|
if (ob_type == BasisType::GaussLegendre)
|
|
{
|
|
snprintf(rt_name, 32, "%s_%dD_P%d", prefix, dim, p);
|
|
}
|
|
else
|
|
{
|
|
snprintf(rt_name, 32, "%s@%c_%dD_P%d", prefix,
|
|
(int)BasisType::GetChar(ob_type), dim, p);
|
|
}
|
|
}
|
|
|
|
ND_FECollection::ND_FECollection(const int p, const int dim,
|
|
const int cb_type, const int ob_type)
|
|
{
|
|
MFEM_VERIFY(p >= 1, "ND_FECollection requires order >= 1.");
|
|
MFEM_VERIFY(dim >= 1 && dim <= 3, "ND_FECollection requires 1 <= dim <= 3.");
|
|
|
|
const int pm1 = p - 1, pm2 = p - 2;
|
|
|
|
if (cb_type == BasisType::GaussLobatto &&
|
|
ob_type == BasisType::GaussLegendre)
|
|
{
|
|
snprintf(nd_name, 32, "ND_%dD_P%d", dim, p);
|
|
}
|
|
else
|
|
{
|
|
snprintf(nd_name, 32, "ND@%c%c_%dD_P%d", (int)BasisType::GetChar(cb_type),
|
|
(int)BasisType::GetChar(ob_type), dim, p);
|
|
}
|
|
|
|
for (int g = 0; g < Geometry::NumGeom; g++)
|
|
{
|
|
ND_Elements[g] = NULL;
|
|
ND_dof[g] = 0;
|
|
}
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
SegDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
TriDofOrd[i] = NULL;
|
|
}
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
QuadDofOrd[i] = NULL;
|
|
}
|
|
|
|
int op_type = BasisType::GetQuadrature1D(ob_type);
|
|
int cp_type = BasisType::GetQuadrature1D(cb_type);
|
|
|
|
// Error checking
|
|
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid)
|
|
{
|
|
const char *ob_name = BasisType::Name(ob_type);
|
|
MFEM_ABORT("Invalid open basis point type: " << ob_name);
|
|
}
|
|
if (Quadrature1D::CheckClosed(cp_type) == Quadrature1D::Invalid)
|
|
{
|
|
const char *cb_name = BasisType::Name(cb_type);
|
|
MFEM_ABORT("Invalid closed basis point type: " << cb_name);
|
|
}
|
|
|
|
if (dim >= 1)
|
|
{
|
|
ND_Elements[Geometry::SEGMENT] = new ND_SegmentElement(p, ob_type);
|
|
ND_dof[Geometry::SEGMENT] = p;
|
|
|
|
SegDofOrd[0] = new int[2*p];
|
|
SegDofOrd[1] = SegDofOrd[0] + p;
|
|
for (int i = 0; i < p; i++)
|
|
{
|
|
SegDofOrd[0][i] = i;
|
|
SegDofOrd[1][i] = -1 - (pm1 - i);
|
|
}
|
|
}
|
|
|
|
if (dim >= 2)
|
|
{
|
|
ND_Elements[Geometry::SQUARE] = new ND_QuadrilateralElement(p, cb_type,
|
|
ob_type);
|
|
ND_dof[Geometry::SQUARE] = 2*p*pm1;
|
|
|
|
// TODO: cb_type and ob_type for triangles
|
|
ND_Elements[Geometry::TRIANGLE] = new ND_TriangleElement(p);
|
|
ND_dof[Geometry::TRIANGLE] = p*pm1;
|
|
|
|
int QuadDof = ND_dof[Geometry::SQUARE];
|
|
QuadDofOrd[0] = new int[8*QuadDof];
|
|
for (int i = 1; i < 8; i++)
|
|
{
|
|
QuadDofOrd[i] = QuadDofOrd[i-1] + QuadDof;
|
|
}
|
|
// see Mesh::GetQuadOrientation in mesh/mesh.cpp
|
|
for (int j = 0; j < pm1; j++)
|
|
{
|
|
for (int i = 0; i < p; i++)
|
|
{
|
|
int d1 = i + j*p; // x-component
|
|
int d2 = p*pm1 + j + i*pm1; // y-component
|
|
// (0,1,2,3)
|
|
QuadDofOrd[0][d1] = d1;
|
|
QuadDofOrd[0][d2] = d2;
|
|
// (0,3,2,1)
|
|
QuadDofOrd[1][d1] = d2;
|
|
QuadDofOrd[1][d2] = d1;
|
|
// (1,2,3,0)
|
|
// QuadDofOrd[2][d1] = p*pm1 + (pm2 - j) + i*pm1;
|
|
// QuadDofOrd[2][d2] = -1 - ((pm1 - i) + j*p);
|
|
QuadDofOrd[2][d1] = -1 - (p*pm1 + j + (pm1 - i)*pm1);
|
|
QuadDofOrd[2][d2] = i + (pm2 - j)*p;
|
|
// (1,0,3,2)
|
|
QuadDofOrd[3][d1] = -1 - ((pm1 - i) + j*p);
|
|
QuadDofOrd[3][d2] = p*pm1 + (pm2 - j) + i*pm1;
|
|
// (2,3,0,1)
|
|
QuadDofOrd[4][d1] = -1 - ((pm1 - i) + (pm2 - j)*p);
|
|
QuadDofOrd[4][d2] = -1 - (p*pm1 + (pm2 - j) + (pm1 - i)*pm1);
|
|
// (2,1,0,3)
|
|
QuadDofOrd[5][d1] = -1 - (p*pm1 + (pm2 - j) + (pm1 - i)*pm1);
|
|
QuadDofOrd[5][d2] = -1 - ((pm1 - i) + (pm2 - j)*p);
|
|
// (3,0,1,2)
|
|
// QuadDofOrd[6][d1] = -1 - (p*pm1 + j + (pm1 - i)*pm1);
|
|
// QuadDofOrd[6][d2] = i + (pm2 - j)*p;
|
|
QuadDofOrd[6][d1] = p*pm1 + (pm2 - j) + i*pm1;
|
|
QuadDofOrd[6][d2] = -1 - ((pm1 - i) + j*p);
|
|
// (3,2,1,0)
|
|
QuadDofOrd[7][d1] = i + (pm2 - j)*p;
|
|
QuadDofOrd[7][d2] = -1 - (p*pm1 + j + (pm1 - i)*pm1);
|
|
}
|
|
}
|
|
|
|
int TriDof = ND_dof[Geometry::TRIANGLE];
|
|
TriDofOrd[0] = new int[6*TriDof];
|
|
for (int i = 1; i < 6; i++)
|
|
{
|
|
TriDofOrd[i] = TriDofOrd[i-1] + TriDof;
|
|
}
|
|
// see Mesh::GetTriOrientation in mesh/mesh.cpp,
|
|
// the constructor of H1_FECollection
|
|
for (int j = 0; j <= pm2; j++)
|
|
{
|
|
for (int i = 0; i + j <= pm2; i++)
|
|
{
|
|
int k1 = p*pm1 - (p - j)*(pm1 - j) + 2*i;
|
|
int k2 = p*pm1 - (p - i)*(pm1 - i) + 2*j;
|
|
// (0,1,2)
|
|
TriDofOrd[0][k1 ] = k1;
|
|
TriDofOrd[0][k1+1] = k1 + 1;
|
|
// (0,2,1)
|
|
TriDofOrd[5][k1 ] = k2 + 1;
|
|
TriDofOrd[5][k1+1] = k2;
|
|
|
|
// The other orientations can not be supported with the current
|
|
// interface. The method Mesh::ReorientTetMesh will ensure that
|
|
// only orientations 0 and 5 are generated.
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dim >= 3)
|
|
{
|
|
ND_Elements[Geometry::CUBE] = new ND_HexahedronElement(p, cb_type, ob_type);
|
|
ND_dof[Geometry::CUBE] = 3*p*pm1*pm1;
|
|
|
|
// TODO: cb_type and ob_type for tets
|
|
ND_Elements[Geometry::TETRAHEDRON] = new ND_TetrahedronElement(p);
|
|
ND_dof[Geometry::TETRAHEDRON] = p*pm1*pm2/2;
|
|
}
|
|
}
|
|
|
|
const int *ND_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
if (GeomType == Geometry::SEGMENT)
|
|
{
|
|
return (Or > 0) ? SegDofOrd[0] : SegDofOrd[1];
|
|
}
|
|
else if (GeomType == Geometry::TRIANGLE)
|
|
{
|
|
if (Or != 0 && Or != 5)
|
|
{
|
|
MFEM_ABORT("triangle face orientation " << Or << " is not supported! "
|
|
"Use Mesh::ReorientTetMesh to fix it.");
|
|
}
|
|
return TriDofOrd[Or%6];
|
|
}
|
|
else if (GeomType == Geometry::SQUARE)
|
|
{
|
|
return QuadDofOrd[Or%8];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
FiniteElementCollection *ND_FECollection::GetTraceCollection() const
|
|
{
|
|
int p, dim, cb_type, ob_type;
|
|
|
|
p = ND_dof[Geometry::SEGMENT];
|
|
if (nd_name[2] == '_') // ND_
|
|
{
|
|
dim = atoi(nd_name + 3);
|
|
cb_type = BasisType::GaussLobatto;
|
|
ob_type = BasisType::GaussLegendre;
|
|
}
|
|
else // ND@
|
|
{
|
|
dim = atoi(nd_name + 6);
|
|
cb_type = BasisType::GetType(nd_name[3]);
|
|
ob_type = BasisType::GetType(nd_name[4]);
|
|
}
|
|
return new ND_Trace_FECollection(p, dim, cb_type, ob_type);
|
|
}
|
|
|
|
ND_FECollection::~ND_FECollection()
|
|
{
|
|
delete [] SegDofOrd[0];
|
|
delete [] TriDofOrd[0];
|
|
delete [] QuadDofOrd[0];
|
|
for (int g = 0; g < Geometry::NumGeom; g++)
|
|
{
|
|
delete ND_Elements[g];
|
|
}
|
|
}
|
|
|
|
|
|
ND_Trace_FECollection::ND_Trace_FECollection(const int p, const int dim,
|
|
const int cb_type,
|
|
const int ob_type)
|
|
: ND_FECollection(p, dim-1, cb_type, ob_type)
|
|
{
|
|
if (cb_type == BasisType::GaussLobatto &&
|
|
ob_type == BasisType::GaussLegendre)
|
|
{
|
|
snprintf(nd_name, 32, "ND_Trace_%dD_P%d", dim, p);
|
|
}
|
|
else
|
|
{
|
|
snprintf(nd_name, 32, "ND_Trace@%c%c_%dD_P%d",
|
|
(int)BasisType::GetChar(cb_type),
|
|
(int)BasisType::GetChar(ob_type), dim, p);
|
|
}
|
|
}
|
|
|
|
|
|
Local_FECollection::Local_FECollection(const char *fe_name)
|
|
{
|
|
snprintf(d_name, 32, "Local_%s", fe_name);
|
|
|
|
Local_Element = NULL;
|
|
|
|
if (!strcmp(fe_name, "BiCubic2DFiniteElement") ||
|
|
!strcmp(fe_name, "Quad_Q3"))
|
|
{
|
|
GeomType = Geometry::SQUARE;
|
|
Local_Element = new BiCubic2DFiniteElement;
|
|
}
|
|
else if (!strcmp(fe_name, "Nedelec1HexFiniteElement") ||
|
|
!strcmp(fe_name, "Hex_ND1"))
|
|
{
|
|
GeomType = Geometry::CUBE;
|
|
Local_Element = new Nedelec1HexFiniteElement;
|
|
}
|
|
else if (!strncmp(fe_name, "H1_", 3))
|
|
{
|
|
GeomType = Geometry::SQUARE;
|
|
Local_Element = new H1_QuadrilateralElement(atoi(fe_name + 7));
|
|
}
|
|
else if (!strncmp(fe_name, "H1Pos_", 6))
|
|
{
|
|
GeomType = Geometry::SQUARE;
|
|
Local_Element = new H1Pos_QuadrilateralElement(atoi(fe_name + 10));
|
|
}
|
|
else if (!strncmp(fe_name, "L2_", 3))
|
|
{
|
|
GeomType = Geometry::SQUARE;
|
|
Local_Element = new L2_QuadrilateralElement(atoi(fe_name + 7));
|
|
}
|
|
else
|
|
{
|
|
mfem::err << "Local_FECollection::Local_FECollection : fe_name = "
|
|
<< fe_name << endl;
|
|
mfem_error();
|
|
}
|
|
}
|
|
|
|
|
|
NURBSFECollection::NURBSFECollection(int Order)
|
|
{
|
|
const int order = (Order == VariableOrder) ? 1 : Order;
|
|
SegmentFE = new NURBS1DFiniteElement(order);
|
|
QuadrilateralFE = new NURBS2DFiniteElement(order);
|
|
ParallelepipedFE = new NURBS3DFiniteElement(order);
|
|
|
|
SetOrder(Order);
|
|
}
|
|
|
|
void NURBSFECollection::SetOrder(int Order) const
|
|
{
|
|
mOrder = Order;
|
|
if (Order != VariableOrder)
|
|
{
|
|
snprintf(name, 16, "NURBS%i", Order);
|
|
}
|
|
else
|
|
{
|
|
snprintf(name, 16, "NURBS");
|
|
}
|
|
}
|
|
|
|
NURBSFECollection::~NURBSFECollection()
|
|
{
|
|
delete ParallelepipedFE;
|
|
delete QuadrilateralFE;
|
|
delete SegmentFE;
|
|
}
|
|
|
|
const FiniteElement *
|
|
NURBSFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
switch (GeomType)
|
|
{
|
|
case Geometry::SEGMENT: return SegmentFE;
|
|
case Geometry::SQUARE: return QuadrilateralFE;
|
|
case Geometry::CUBE: return ParallelepipedFE;
|
|
default:
|
|
mfem_error ("NURBSFECollection: unknown geometry type.");
|
|
}
|
|
return SegmentFE; // Make some compilers happy
|
|
}
|
|
|
|
int NURBSFECollection::DofForGeometry(Geometry::Type GeomType) const
|
|
{
|
|
mfem_error("NURBSFECollection::DofForGeometry");
|
|
return 0; // Make some compilers happy
|
|
}
|
|
|
|
const int *NURBSFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
|
int Or) const
|
|
{
|
|
mfem_error("NURBSFECollection::DofOrderForOrientation");
|
|
return NULL;
|
|
}
|
|
|
|
FiniteElementCollection *NURBSFECollection::GetTraceCollection() const
|
|
{
|
|
MFEM_ABORT("NURBS finite elements can not be statically condensed!");
|
|
return NULL;
|
|
}
|
|
|
|
}
|