Files
mfem/fem/geom.cpp
T

1415 lines
43 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 "../mesh/wedge.hpp"
namespace mfem
{
const char *Geometry::Name[NumGeom] =
{ "Point", "Segment", "Triangle", "Square", "Tetrahedron", "Cube", "Prism" };
const double Geometry::Volume[NumGeom] =
{ 1.0, 1.0, 0.5, 1.0, 1./6, 1.0, 0.5 };
Geometry::Geometry()
{
// Vertices for Geometry::POINT
GeomVert[0] = new IntegrationRule(1);
GeomVert[0]->IntPoint(0).x = 0.0;
// Vertices for Geometry::SEGMENT
GeomVert[1] = new IntegrationRule(2);
GeomVert[1]->IntPoint(0).x = 0.0;
GeomVert[1]->IntPoint(1).x = 1.0;
// Vertices for Geometry::TRIANGLE
GeomVert[2] = new IntegrationRule(3);
GeomVert[2]->IntPoint(0).x = 0.0;
GeomVert[2]->IntPoint(0).y = 0.0;
GeomVert[2]->IntPoint(1).x = 1.0;
GeomVert[2]->IntPoint(1).y = 0.0;
GeomVert[2]->IntPoint(2).x = 0.0;
GeomVert[2]->IntPoint(2).y = 1.0;
// Vertices for Geometry::SQUARE
GeomVert[3] = new IntegrationRule(4);
GeomVert[3]->IntPoint(0).x = 0.0;
GeomVert[3]->IntPoint(0).y = 0.0;
GeomVert[3]->IntPoint(1).x = 1.0;
GeomVert[3]->IntPoint(1).y = 0.0;
GeomVert[3]->IntPoint(2).x = 1.0;
GeomVert[3]->IntPoint(2).y = 1.0;
GeomVert[3]->IntPoint(3).x = 0.0;
GeomVert[3]->IntPoint(3).y = 1.0;
// Vertices for Geometry::TETRAHEDRON
GeomVert[4] = new IntegrationRule(4);
GeomVert[4]->IntPoint(0).x = 0.0;
GeomVert[4]->IntPoint(0).y = 0.0;
GeomVert[4]->IntPoint(0).z = 0.0;
GeomVert[4]->IntPoint(1).x = 1.0;
GeomVert[4]->IntPoint(1).y = 0.0;
GeomVert[4]->IntPoint(1).z = 0.0;
GeomVert[4]->IntPoint(2).x = 0.0;
GeomVert[4]->IntPoint(2).y = 1.0;
GeomVert[4]->IntPoint(2).z = 0.0;
GeomVert[4]->IntPoint(3).x = 0.0;
GeomVert[4]->IntPoint(3).y = 0.0;
GeomVert[4]->IntPoint(3).z = 1.0;
// Vertices for Geometry::CUBE
GeomVert[5] = new IntegrationRule(8);
GeomVert[5]->IntPoint(0).x = 0.0;
GeomVert[5]->IntPoint(0).y = 0.0;
GeomVert[5]->IntPoint(0).z = 0.0;
GeomVert[5]->IntPoint(1).x = 1.0;
GeomVert[5]->IntPoint(1).y = 0.0;
GeomVert[5]->IntPoint(1).z = 0.0;
GeomVert[5]->IntPoint(2).x = 1.0;
GeomVert[5]->IntPoint(2).y = 1.0;
GeomVert[5]->IntPoint(2).z = 0.0;
GeomVert[5]->IntPoint(3).x = 0.0;
GeomVert[5]->IntPoint(3).y = 1.0;
GeomVert[5]->IntPoint(3).z = 0.0;
GeomVert[5]->IntPoint(4).x = 0.0;
GeomVert[5]->IntPoint(4).y = 0.0;
GeomVert[5]->IntPoint(4).z = 1.0;
GeomVert[5]->IntPoint(5).x = 1.0;
GeomVert[5]->IntPoint(5).y = 0.0;
GeomVert[5]->IntPoint(5).z = 1.0;
GeomVert[5]->IntPoint(6).x = 1.0;
GeomVert[5]->IntPoint(6).y = 1.0;
GeomVert[5]->IntPoint(6).z = 1.0;
GeomVert[5]->IntPoint(7).x = 0.0;
GeomVert[5]->IntPoint(7).y = 1.0;
GeomVert[5]->IntPoint(7).z = 1.0;
// Vertices for Geometry::PRISM
GeomVert[6] = new IntegrationRule(6);
GeomVert[6]->IntPoint(0).x = 0.0;
GeomVert[6]->IntPoint(0).y = 0.0;
GeomVert[6]->IntPoint(0).z = 0.0;
GeomVert[6]->IntPoint(1).x = 1.0;
GeomVert[6]->IntPoint(1).y = 0.0;
GeomVert[6]->IntPoint(1).z = 0.0;
GeomVert[6]->IntPoint(2).x = 0.0;
GeomVert[6]->IntPoint(2).y = 1.0;
GeomVert[6]->IntPoint(2).z = 0.0;
GeomVert[6]->IntPoint(3).x = 0.0;
GeomVert[6]->IntPoint(3).y = 0.0;
GeomVert[6]->IntPoint(3).z = 1.0;
GeomVert[6]->IntPoint(4).x = 1.0;
GeomVert[6]->IntPoint(4).y = 0.0;
GeomVert[6]->IntPoint(4).z = 1.0;
GeomVert[6]->IntPoint(5).x = 0.0;
GeomVert[6]->IntPoint(5).y = 1.0;
GeomVert[6]->IntPoint(5).z = 1.0;
GeomCenter[POINT].x = 0.0;
GeomCenter[POINT].y = 0.0;
GeomCenter[POINT].z = 0.0;
GeomCenter[SEGMENT].x = 0.5;
GeomCenter[SEGMENT].y = 0.0;
GeomCenter[SEGMENT].z = 0.0;
GeomCenter[TRIANGLE].x = 1.0 / 3.0;
GeomCenter[TRIANGLE].y = 1.0 / 3.0;
GeomCenter[TRIANGLE].z = 0.0;
GeomCenter[SQUARE].x = 0.5;
GeomCenter[SQUARE].y = 0.5;
GeomCenter[SQUARE].z = 0.0;
GeomCenter[TETRAHEDRON].x = 0.25;
GeomCenter[TETRAHEDRON].y = 0.25;
GeomCenter[TETRAHEDRON].z = 0.25;
GeomCenter[CUBE].x = 0.5;
GeomCenter[CUBE].y = 0.5;
GeomCenter[CUBE].z = 0.5;
GeomCenter[PRISM].x = 1.0 / 3.0;
GeomCenter[PRISM].y = 1.0 / 3.0;
GeomCenter[PRISM].z = 0.5;
GeomToPerfGeomJac[POINT] = NULL;
GeomToPerfGeomJac[SEGMENT] = new DenseMatrix(1);
GeomToPerfGeomJac[TRIANGLE] = new DenseMatrix(2);
GeomToPerfGeomJac[SQUARE] = new DenseMatrix(2);
GeomToPerfGeomJac[TETRAHEDRON] = new DenseMatrix(3);
GeomToPerfGeomJac[CUBE] = new DenseMatrix(3);
GeomToPerfGeomJac[PRISM] = new DenseMatrix(3);
PerfGeomToGeomJac[POINT] = NULL;
PerfGeomToGeomJac[SEGMENT] = NULL;
PerfGeomToGeomJac[TRIANGLE] = new DenseMatrix(2);
PerfGeomToGeomJac[SQUARE] = NULL;
PerfGeomToGeomJac[TETRAHEDRON] = new DenseMatrix(3);
PerfGeomToGeomJac[CUBE] = NULL;
PerfGeomToGeomJac[PRISM] = new DenseMatrix(3);
GeomToPerfGeomJac[SEGMENT]->Diag(1.0, 1);
{
IsoparametricTransformation tri_T;
tri_T.SetFE(&TriangleFE);
GetPerfPointMat (TRIANGLE, tri_T.GetPointMat());
tri_T.SetIntPoint(&GeomCenter[TRIANGLE]);
*GeomToPerfGeomJac[TRIANGLE] = tri_T.Jacobian();
CalcInverse(tri_T.Jacobian(), *PerfGeomToGeomJac[TRIANGLE]);
}
GeomToPerfGeomJac[SQUARE]->Diag(1.0, 2);
{
IsoparametricTransformation tet_T;
tet_T.SetFE(&TetrahedronFE);
GetPerfPointMat (TETRAHEDRON, tet_T.GetPointMat());
tet_T.SetIntPoint(&GeomCenter[TETRAHEDRON]);
*GeomToPerfGeomJac[TETRAHEDRON] = tet_T.Jacobian();
CalcInverse(tet_T.Jacobian(), *PerfGeomToGeomJac[TETRAHEDRON]);
}
GeomToPerfGeomJac[CUBE]->Diag(1.0, 3);
{
IsoparametricTransformation pri_T;
pri_T.SetFE(&WedgeFE);
GetPerfPointMat (PRISM, pri_T.GetPointMat());
pri_T.SetIntPoint(&GeomCenter[PRISM]);
*GeomToPerfGeomJac[PRISM] = pri_T.Jacobian();
CalcInverse(pri_T.Jacobian(), *PerfGeomToGeomJac[PRISM]);
}
}
Geometry::~Geometry()
{
for (int i = 0; i < NumGeom; i++)
{
delete PerfGeomToGeomJac[i];
delete GeomToPerfGeomJac[i];
delete GeomVert[i];
}
}
const IntegrationRule * Geometry::GetVertices(int GeomType)
{
switch (GeomType)
{
case Geometry::POINT: return GeomVert[0];
case Geometry::SEGMENT: return GeomVert[1];
case Geometry::TRIANGLE: return GeomVert[2];
case Geometry::SQUARE: return GeomVert[3];
case Geometry::TETRAHEDRON: return GeomVert[4];
case Geometry::CUBE: return GeomVert[5];
case Geometry::PRISM: return GeomVert[6];
default:
mfem_error ("Geometry::GetVertices(...)");
}
// make some compilers happy.
return GeomVert[0];
}
// static method
void Geometry::GetRandomPoint(int GeomType, IntegrationPoint &ip)
{
switch (GeomType)
{
case Geometry::POINT:
ip.x = 0.0;
break;
case Geometry::SEGMENT:
ip.x = double(rand()) / RAND_MAX;
break;
case Geometry::TRIANGLE:
ip.x = double(rand()) / RAND_MAX;
ip.y = double(rand()) / RAND_MAX;
if (ip.x + ip.y > 1.0)
{
ip.x = 1.0 - ip.x;
ip.y = 1.0 - ip.y;
}
break;
case Geometry::SQUARE:
ip.x = double(rand()) / RAND_MAX;
ip.y = double(rand()) / RAND_MAX;
break;
case Geometry::TETRAHEDRON:
ip.x = double(rand()) / RAND_MAX;
ip.y = double(rand()) / RAND_MAX;
ip.z = double(rand()) / RAND_MAX;
// map to the triangular prism obtained by extruding the reference
// triangle in z direction
if (ip.x + ip.y > 1.0)
{
ip.x = 1.0 - ip.x;
ip.y = 1.0 - ip.y;
}
// split the prism into 3 parts: 1 is the reference tet, and the
// other two tets (as given below) are mapped to the reference tet
if (ip.x + ip.z > 1.0)
{
// tet with vertices: (0,0,1),(1,0,1),(0,1,1),(1,0,0)
ip.x = ip.x + ip.z - 1.0;
// ip.y = ip.y;
ip.z = 1.0 - ip.z;
// mapped to: (0,0,0),(1,0,0),(0,1,0),(0,0,1)
}
else if (ip.x + ip.y + ip.z > 1.0)
{
// tet with vertices: (0,1,1),(0,1,0),(0,0,1),(1,0,0)
double x = ip.x;
ip.x = 1.0 - x - ip.z;
ip.y = 1.0 - x - ip.y;
ip.z = x;
// mapped to: (0,0,0),(1,0,0),(0,1,0),(0,0,1)
}
break;
case Geometry::CUBE:
ip.x = double(rand()) / RAND_MAX;
ip.y = double(rand()) / RAND_MAX;
ip.z = double(rand()) / RAND_MAX;
break;
case Geometry::PRISM:
ip.x = double(rand()) / RAND_MAX;
ip.y = double(rand()) / RAND_MAX;
ip.z = double(rand()) / RAND_MAX;
if (ip.x + ip.y > 1.0)
{
ip.x = 1.0 - ip.x;
ip.y = 1.0 - ip.y;
}
break;
default:
MFEM_ABORT("Unknown type of reference element!");
}
}
namespace internal
{
// Fuzzy equality operator with absolute tolerance eps.
inline bool NearlyEqual(double x, double y, double eps)
{
return std::abs(x-y) <= eps;
}
// Fuzzy greater than comparison operator with absolute tolerance eps.
// Returns true when x is greater than y by at least eps.
inline bool FuzzyGT(double x, double y, double eps)
{
return (x > y + eps);
}
// Fuzzy less than comparison operator with absolute tolerance eps.
// Returns true when x is less than y by at least eps.
inline bool FuzzyLT(double x, double y, double eps)
{
return (x < y - eps);
}
}
// static method
bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip)
{
switch (GeomType)
{
case Geometry::POINT:
if (ip.x != 0.0) { return false; }
break;
case Geometry::SEGMENT:
if (ip.x < 0.0 || ip.x > 1.0) { return false; }
break;
case Geometry::TRIANGLE:
if (ip.x < 0.0 || ip.y < 0.0 || ip.x+ip.y > 1.0) { return false; }
break;
case Geometry::SQUARE:
if (ip.x < 0.0 || ip.x > 1.0 || ip.y < 0.0 || ip.y > 1.0)
{ return false; }
break;
case Geometry::TETRAHEDRON:
if (ip.x < 0.0 || ip.y < 0.0 || ip.z < 0.0 ||
ip.x+ip.y+ip.z > 1.0) { return false; }
break;
case Geometry::CUBE:
if (ip.x < 0.0 || ip.x > 1.0 || ip.y < 0.0 || ip.y > 1.0 ||
ip.z < 0.0 || ip.z > 1.0) { return false; }
break;
case Geometry::PRISM:
if (ip.x < 0.0 || ip.y < 0.0 || ip.x+ip.y > 1.0 ||
ip.z < 0.0 || ip.z > 1.0) { return false; }
break;
default:
MFEM_ABORT("Unknown type of reference element!");
}
return true;
}
bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip, double eps)
{
switch (GeomType)
{
case Geometry::POINT:
if (! internal::NearlyEqual(ip.x, 0.0, eps))
{
return false;
}
break;
case Geometry::SEGMENT:
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|| internal::FuzzyGT(ip.x, 1.0, eps) )
{
return false;
}
break;
case Geometry::TRIANGLE:
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|| internal::FuzzyLT(ip.y, 0.0, eps)
|| internal::FuzzyGT(ip.x+ip.y, 1.0, eps) )
{
return false;
}
break;
case Geometry::SQUARE:
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|| internal::FuzzyGT(ip.x, 1.0, eps)
|| internal::FuzzyLT(ip.y, 0.0, eps)
|| internal::FuzzyGT(ip.y, 1.0, eps) )
{
return false;
}
break;
case Geometry::TETRAHEDRON:
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|| internal::FuzzyLT(ip.y, 0.0, eps)
|| internal::FuzzyLT(ip.z, 0.0, eps)
|| internal::FuzzyGT(ip.x+ip.y+ip.z, 1.0, eps) )
{
return false;
}
break;
case Geometry::CUBE:
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|| internal::FuzzyGT(ip.x, 1.0, eps)
|| internal::FuzzyLT(ip.y, 0.0, eps)
|| internal::FuzzyGT(ip.y, 1.0, eps)
|| internal::FuzzyLT(ip.z, 0.0, eps)
|| internal::FuzzyGT(ip.z, 1.0, eps) )
{
return false;
}
break;
case Geometry::PRISM:
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|| internal::FuzzyLT(ip.y, 0.0, eps)
|| internal::FuzzyGT(ip.x+ip.y, 1.0, eps)
|| internal::FuzzyLT(ip.z, 0.0, eps)
|| internal::FuzzyGT(ip.z, 1.0, eps) )
{
return false;
}
break;
default:
MFEM_ABORT("Unknown type of reference element!");
}
return true;
}
namespace internal
{
template <int N, int dim>
inline bool IntersectSegment(double lbeg[N], double lend[N],
IntegrationPoint &end)
{
double t = 1.0;
bool out = false;
for (int i = 0; i < N; i++)
{
lbeg[i] = std::max(lbeg[i], 0.0); // remove round-off
if (lend[i] < 0.0)
{
out = true;
t = std::min(t, lbeg[i]/(lbeg[i]-lend[i]));
}
}
if (out)
{
if (dim >= 1) { end.x = t*lend[0] + (1.0-t)*lbeg[0]; }
if (dim >= 2) { end.y = t*lend[1] + (1.0-t)*lbeg[1]; }
if (dim >= 3) { end.z = t*lend[2] + (1.0-t)*lbeg[2]; }
return false;
}
return true;
}
inline bool ProjectTriangle(double &x, double &y)
{
if (x < 0.0)
{
x = 0.0;
if (y < 0.0) { y = 0.0; }
else if (y > 1.0) { y = 1.0; }
return false;
}
if (y < 0.0)
{
if (x > 1.0) { x = 1.0; }
y = 0.0;
return false;
}
const double l3 = 1.0-x-y;
if (l3 < 0.0)
{
if (y - x > 1.0) { x = 0.0; y = 1.0; }
else if (y - x < -1.0) { x = 1.0; y = 0.0; }
else { x += l3/2; y += l3/2; }
return false;
}
return true;
}
}
// static method
bool Geometry::ProjectPoint(int GeomType, const IntegrationPoint &beg,
IntegrationPoint &end)
{
switch (GeomType)
{
case Geometry::POINT:
{
if (end.x != 0.0) { end.x = 0.0; return false; }
break;
}
case Geometry::SEGMENT:
{
if (end.x < 0.0) { end.x = 0.0; return false; }
if (end.x > 1.0) { end.x = 1.0; return false; }
break;
}
case Geometry::TRIANGLE:
{
double lend[3] = { end.x, end.y, 1.0-end.x-end.y };
double lbeg[3] = { beg.x, beg.y, 1.0-beg.x-beg.y };
return internal::IntersectSegment<3,2>(lbeg, lend, end);
}
case Geometry::SQUARE:
{
double lend[4] = { end.x, end.y, 1.0-end.x, 1.0-end.y };
double lbeg[4] = { beg.x, beg.y, 1.0-beg.x, 1.0-beg.y };
return internal::IntersectSegment<4,2>(lbeg, lend, end);
}
case Geometry::TETRAHEDRON:
{
double lend[4] = { end.x, end.y, end.z, 1.0-end.x-end.y-end.z };
double lbeg[4] = { beg.x, beg.y, beg.z, 1.0-beg.x-beg.y-beg.z };
return internal::IntersectSegment<4,3>(lbeg, lend, end);
}
case Geometry::CUBE:
{
double lend[6] = { end.x, end.y, end.z,
1.0-end.x, 1.0-end.y, 1.0-end.z
};
double lbeg[6] = { beg.x, beg.y, beg.z,
1.0-beg.x, 1.0-beg.y, 1.0-beg.z
};
return internal::IntersectSegment<6,3>(lbeg, lend, end);
}
case Geometry::PRISM:
{
double lend[5] = { end.x, end.y, end.z, 1.0-end.x-end.y, 1.0-end.z };
double lbeg[5] = { beg.x, beg.y, beg.z, 1.0-beg.x-beg.y, 1.0-beg.z };
return internal::IntersectSegment<5,3>(lbeg, lend, end);
}
default:
MFEM_ABORT("Unknown type of reference element!");
}
return true;
}
// static method
bool Geometry::ProjectPoint(int GeomType, IntegrationPoint &ip)
{
// If ip is outside the element, replace it with the point on the boundary
// that is closest to the original ip and return false; otherwise, return
// true without changing ip.
switch (GeomType)
{
case SEGMENT:
{
if (ip.x < 0.0) { ip.x = 0.0; return false; }
else if (ip.x > 1.0) { ip.x = 1.0; return false; }
return true;
}
case TRIANGLE:
{
return internal::ProjectTriangle(ip.x, ip.y);
}
case SQUARE:
{
bool in_x, in_y;
if (ip.x < 0.0) { in_x = false; ip.x = 0.0; }
else if (ip.x > 1.0) { in_x = false; ip.x = 1.0; }
else { in_x = true; }
if (ip.y < 0.0) { in_y = false; ip.y = 0.0; }
else if (ip.y > 1.0) { in_y = false; ip.y = 1.0; }
else { in_y = true; }
return in_x && in_y;
}
case TETRAHEDRON:
{
if (ip.z < 0.0)
{
ip.z = 0.0;
internal::ProjectTriangle(ip.x, ip.y);
return false;
}
if (ip.y < 0.0)
{
ip.y = 0.0;
internal::ProjectTriangle(ip.x, ip.z);
return false;
}
if (ip.x < 0.0)
{
ip.x = 0.0;
internal::ProjectTriangle(ip.y, ip.z);
return false;
}
const double l4 = 1.0-ip.x-ip.y-ip.z;
if (l4 < 0.0)
{
const double l4_3 = l4/3;
ip.x += l4_3;
ip.y += l4_3;
internal::ProjectTriangle(ip.x, ip.y);
ip.z = 1.0-ip.x-ip.y;
return false;
}
return true;
}
case CUBE:
{
bool in_x, in_y, in_z;
if (ip.x < 0.0) { in_x = false; ip.x = 0.0; }
else if (ip.x > 1.0) { in_x = false; ip.x = 1.0; }
else { in_x = true; }
if (ip.y < 0.0) { in_y = false; ip.y = 0.0; }
else if (ip.y > 1.0) { in_y = false; ip.y = 1.0; }
else { in_y = true; }
if (ip.z < 0.0) { in_z = false; ip.z = 0.0; }
else if (ip.z > 1.0) { in_z = false; ip.z = 1.0; }
else { in_z = true; }
return in_x && in_y && in_z;
}
case PRISM:
{
bool in_tri, in_z;
in_tri = internal::ProjectTriangle(ip.x, ip.y);
if (ip.z < 0.0) { in_z = false; ip.z = 0.0; }
else if (ip.z > 1.0) { in_z = false; ip.z = 1.0; }
else { in_z = true; }
return in_tri && in_z;
}
default:
MFEM_ABORT("Reference element type is not supported!");
}
return true;
}
void Geometry::GetPerfPointMat(int GeomType, DenseMatrix &pm)
{
switch (GeomType)
{
case Geometry::SEGMENT:
{
pm.SetSize (1, 2);
pm(0,0) = 0.0;
pm(0,1) = 1.0;
}
break;
case Geometry::TRIANGLE:
{
pm.SetSize (2, 3);
pm(0,0) = 0.0; pm(1,0) = 0.0;
pm(0,1) = 1.0; pm(1,1) = 0.0;
pm(0,2) = 0.5; pm(1,2) = 0.86602540378443864676;
}
break;
case Geometry::SQUARE:
{
pm.SetSize (2, 4);
pm(0,0) = 0.0; pm(1,0) = 0.0;
pm(0,1) = 1.0; pm(1,1) = 0.0;
pm(0,2) = 1.0; pm(1,2) = 1.0;
pm(0,3) = 0.0; pm(1,3) = 1.0;
}
break;
case Geometry::TETRAHEDRON:
{
pm.SetSize (3, 4);
pm(0,0) = 0.0; pm(1,0) = 0.0; pm(2,0) = 0.0;
pm(0,1) = 1.0; pm(1,1) = 0.0; pm(2,1) = 0.0;
pm(0,2) = 0.5; pm(1,2) = 0.86602540378443864676; pm(2,2) = 0.0;
pm(0,3) = 0.5; pm(1,3) = 0.28867513459481288225;
pm(2,3) = 0.81649658092772603273;
}
break;
case Geometry::CUBE:
{
pm.SetSize (3, 8);
pm(0,0) = 0.0; pm(1,0) = 0.0; pm(2,0) = 0.0;
pm(0,1) = 1.0; pm(1,1) = 0.0; pm(2,1) = 0.0;
pm(0,2) = 1.0; pm(1,2) = 1.0; pm(2,2) = 0.0;
pm(0,3) = 0.0; pm(1,3) = 1.0; pm(2,3) = 0.0;
pm(0,4) = 0.0; pm(1,4) = 0.0; pm(2,4) = 1.0;
pm(0,5) = 1.0; pm(1,5) = 0.0; pm(2,5) = 1.0;
pm(0,6) = 1.0; pm(1,6) = 1.0; pm(2,6) = 1.0;
pm(0,7) = 0.0; pm(1,7) = 1.0; pm(2,7) = 1.0;
}
break;
case Geometry::PRISM:
{
pm.SetSize (3, 6);
pm(0,0) = 0.0; pm(1,0) = 0.0; pm(2,0) = 0.0;
pm(0,1) = 1.0; pm(1,1) = 0.0; pm(2,1) = 0.0;
pm(0,2) = 0.5; pm(1,2) = 0.86602540378443864676; pm(2,2) = 0.0;
pm(0,3) = 0.0; pm(1,3) = 0.0; pm(2,3) = 1.0;
pm(0,4) = 1.0; pm(1,4) = 0.0; pm(2,4) = 1.0;
pm(0,5) = 0.5; pm(1,5) = 0.86602540378443864676; pm(2,5) = 1.0;
}
break;
default:
mfem_error ("Geometry::GetPerfPointMat (...)");
}
}
void Geometry::JacToPerfJac(int GeomType, const DenseMatrix &J,
DenseMatrix &PJ) const
{
if (PerfGeomToGeomJac[GeomType])
{
Mult(J, *PerfGeomToGeomJac[GeomType], PJ);
}
else
{
PJ = J;
}
}
const int Geometry::NumBdrArray[NumGeom] = { 0, 2, 3, 4, 4, 6, 5 };
const int Geometry::Dimension[NumGeom] = { 0, 1, 2, 2, 3, 3, 3 };
const int Geometry::DimStart[MaxDim+2] =
{ POINT, SEGMENT, TRIANGLE, TETRAHEDRON, NUM_GEOMETRIES };
const int Geometry::NumVerts[NumGeom] = { 1, 2, 3, 4, 4, 8, 6 };
const int Geometry::NumEdges[NumGeom] = { 0, 1, 3, 4, 6, 12, 9 };
const int Geometry::NumFaces[NumGeom] = { 0, 0, 1, 1, 4, 6, 5 };
const int Geometry::
Constants<Geometry::POINT>::Orient[1][1] = {{0}};
const int Geometry::
Constants<Geometry::POINT>::InvOrient[1] = {0};
const int Geometry::
Constants<Geometry::SEGMENT>::Edges[1][2] = { {0, 1} };
const int Geometry::
Constants<Geometry::SEGMENT>::Orient[2][2] = { {0, 1}, {1, 0} };
const int Geometry::
Constants<Geometry::SEGMENT>::InvOrient[2] = { 0, 1 };
const int Geometry::
Constants<Geometry::TRIANGLE>::Edges[3][2] = {{0, 1}, {1, 2}, {2, 0}};
const int Geometry::
Constants<Geometry::TRIANGLE>::VertToVert::I[3] = {0, 2, 3};
const int Geometry::
Constants<Geometry::TRIANGLE>::VertToVert::J[3][2] = {{1, 0}, {2, -3}, {2, 1}};
const int Geometry::
Constants<Geometry::TRIANGLE>::FaceVert[1][3] = {{0, 1, 2}};
const int Geometry::
Constants<Geometry::TRIANGLE>::Orient[6][3] =
{
{0, 1, 2}, {1, 0, 2}, {2, 0, 1},
{2, 1, 0}, {1, 2, 0}, {0, 2, 1}
};
const int Geometry::
Constants<Geometry::TRIANGLE>::InvOrient[6] = { 0, 1, 4, 3, 2, 5 };
const int Geometry::
Constants<Geometry::SQUARE>::Edges[4][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}};
const int Geometry::
Constants<Geometry::SQUARE>::VertToVert::I[4] = {0, 2, 3, 4};
const int Geometry::
Constants<Geometry::SQUARE>::VertToVert::J[4][2] =
{{1, 0}, {3, -4}, {2, 1}, {3, 2}};
const int Geometry::
Constants<Geometry::SQUARE>::FaceVert[1][4] = {{0, 1, 2, 3}};
const int Geometry::
Constants<Geometry::SQUARE>::Orient[8][4] =
{
{0, 1, 2, 3}, {0, 3, 2, 1}, {1, 2, 3, 0}, {1, 0, 3, 2},
{2, 3, 0, 1}, {2, 1, 0, 3}, {3, 0, 1, 2}, {3, 2, 1, 0}
};
const int Geometry::
Constants<Geometry::SQUARE>::InvOrient[8] = { 0, 1, 6, 3, 4, 5, 2, 7 };
const int Geometry::
Constants<Geometry::TETRAHEDRON>::Edges[6][2] =
{{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
const int Geometry::
Constants<Geometry::TETRAHEDRON>::FaceTypes[4] =
{
Geometry::TRIANGLE, Geometry::TRIANGLE,
Geometry::TRIANGLE, Geometry::TRIANGLE
};
const int Geometry::
Constants<Geometry::TETRAHEDRON>::FaceVert[4][3] =
{{1, 2, 3}, {0, 3, 2}, {0, 1, 3}, {0, 2, 1}};
const int Geometry::
Constants<Geometry::TETRAHEDRON>::VertToVert::I[4] = {0, 3, 5, 6};
const int Geometry::
Constants<Geometry::TETRAHEDRON>::VertToVert::J[6][2] =
{
{1, 0}, {2, 1}, {3, 2}, // 0,1:0 0,2:1 0,3:2
{2, 3}, {3, 4}, // 1,2:3 1,3:4
{3, 5} // 2,3:5
};
const int Geometry::
Constants<Geometry::TETRAHEDRON>::Orient[24][4] =
{
{0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 3, 1}, {0, 2, 1, 3},
{0, 3, 1, 2}, {0, 3, 2, 1},
{1, 2, 0, 3}, {1, 2, 3, 0}, {1, 3, 2, 0}, {1, 3, 0, 2},
{1, 0, 3, 2}, {1, 0, 2, 3},
{2, 3, 0, 1}, {2, 3, 1, 0}, {2, 0, 1, 3}, {2, 0, 3, 1},
{2, 1, 3, 0}, {2, 1, 0, 3},
{3, 0, 2, 1}, {3, 0, 1, 2}, {3, 1, 0, 2}, {3, 1, 2, 0},
{3, 2, 1, 0}, {3, 2, 0, 1}
};
const int Geometry::
Constants<Geometry::TETRAHEDRON>::InvOrient[24] =
{
0, 1, 4, 3, 2, 5,
14, 19, 18, 15, 10, 11,
12, 23, 6, 9, 20, 17,
8, 7, 16, 21, 22, 13
};
const int Geometry::
Constants<Geometry::CUBE>::Edges[12][2] =
{
{0, 1}, {1, 2}, {3, 2}, {0, 3}, {4, 5}, {5, 6},
{7, 6}, {4, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}
};
const int Geometry::
Constants<Geometry::CUBE>::FaceTypes[6] =
{
Geometry::SQUARE, Geometry::SQUARE, Geometry::SQUARE,
Geometry::SQUARE, Geometry::SQUARE, Geometry::SQUARE
};
const int Geometry::
Constants<Geometry::CUBE>::FaceVert[6][4] =
{
{3, 2, 1, 0}, {0, 1, 5, 4}, {1, 2, 6, 5},
{2, 3, 7, 6}, {3, 0, 4, 7}, {4, 5, 6, 7}
};
const int Geometry::
Constants<Geometry::CUBE>::VertToVert::I[8] = {0, 3, 5, 7, 8, 10, 11, 12};
const int Geometry::
Constants<Geometry::CUBE>::VertToVert::J[12][2] =
{
{1, 0}, {3, 3}, {4, 8}, // 0,1:0 0,3:3 0,4:8
{2, 1}, {5, 9}, // 1,2:1 1,5:9
{3,-3}, {6,10}, // 2,3:-3 2,6:10
{7,11}, // 3,7:11
{5, 4}, {7, 7}, // 4,5:4 4,7:7
{6, 5}, // 5,6:5
{7,-7} // 6,7:-7
};
const int Geometry::
Constants<Geometry::PRISM>::Edges[9][2] =
{{0, 1}, {1, 2}, {2, 0}, {3, 4}, {4, 5}, {5, 3}, {0, 3}, {1, 4}, {2, 5}};
const int Geometry::
Constants<Geometry::PRISM>::FaceTypes[5] =
{
Geometry::TRIANGLE, Geometry::TRIANGLE,
Geometry::SQUARE, Geometry::SQUARE, Geometry::SQUARE
};
const int Geometry::
Constants<Geometry::PRISM>::FaceVert[5][4] =
{{0, 2, 1, -1}, {3, 4, 5, -1}, {0, 1, 4, 3}, {1, 2, 5, 4}, {2, 0, 3, 5}};
const int Geometry::
Constants<Geometry::PRISM>::VertToVert::I[6] = {0, 3, 5, 6, 8, 9};
const int Geometry::
Constants<Geometry::PRISM>::VertToVert::J[9][2] =
{
{1, 0}, {2, -3}, {3, 6}, // 0,1:0 0,2:-3 0,3:6
{2, 1}, {4, 7}, // 1,2:1 1,4:7
{5, 8}, // 2,5:8
{4, 3}, {5, -6}, // 3,4:3 3,5:-6
{5, 4} // 4,5:4
};
GeometryRefiner::GeometryRefiner()
{
type = Quadrature1D::ClosedUniform;
}
GeometryRefiner::~GeometryRefiner()
{
for (int i = 0; i < Geometry::NumGeom; i++)
{
for (int j = 0; j < RGeom[i].Size(); j++) { delete RGeom[i][j]; }
for (int j = 0; j < IntPts[i].Size(); j++) { delete IntPts[i][j]; }
}
}
RefinedGeometry *GeometryRefiner::FindInRGeom(Geometry::Type Geom,
int Times, int ETimes,
int Type)
{
Array<RefinedGeometry *> &RGA = RGeom[Geom];
for (int i = 0; i < RGA.Size(); i++)
{
RefinedGeometry &RG = *RGA[i];
if (RG.Times == Times && RG.ETimes == ETimes && RG.Type == Type)
{
return &RG;
}
}
return NULL;
}
IntegrationRule *GeometryRefiner::FindInIntPts(Geometry::Type Geom, int NPts)
{
Array<IntegrationRule *> &IPA = IntPts[Geom];
for (int i = 0; i < IPA.Size(); i++)
{
IntegrationRule &ir = *IPA[i];
if (ir.GetNPoints() == NPts) { return &ir; }
}
return NULL;
}
RefinedGeometry * GeometryRefiner::Refine(Geometry::Type Geom,
int Times, int ETimes)
{
int i, j, k, l, m;
Times = std::max(Times, 1);
ETimes = std::max(ETimes, 1);
const double *cp = poly1d.GetPoints(Times, BasisType::GetNodalBasis(type));
RefinedGeometry *RG = FindInRGeom(Geom, Times, ETimes, type);
if (RG) { return RG; }
switch (Geom)
{
case Geometry::POINT:
{
RG = new RefinedGeometry(1, 1, 0);
RG->Times = 1;
RG->ETimes = 0;
RG->Type = type;
RG->RefPts.IntPoint(0).x = cp[0];
RG->RefGeoms[0] = 0;
RGeom[Geometry::POINT].Append(RG);
return RG;
}
case Geometry::SEGMENT:
{
RG = new RefinedGeometry(Times+1, 2*Times, 0);
RG->Times = Times;
RG->ETimes = 0;
RG->Type = type;
for (i = 0; i <= Times; i++)
{
IntegrationPoint &ip = RG->RefPts.IntPoint(i);
ip.x = cp[i];
}
Array<int> &G = RG->RefGeoms;
for (i = 0; i < Times; i++)
{
G[2*i+0] = i;
G[2*i+1] = i+1;
}
RGeom[Geometry::SEGMENT].Append(RG);
return RG;
}
case Geometry::TRIANGLE:
{
RG = new RefinedGeometry((Times+1)*(Times+2)/2, 3*Times*Times,
3*Times*(ETimes+1), 3*Times);
RG->Times = Times;
RG->ETimes = ETimes;
RG->Type = type;
for (k = j = 0; j <= Times; j++)
for (i = 0; i <= Times-j; i++, k++)
{
IntegrationPoint &ip = RG->RefPts.IntPoint(k);
ip.x = cp[i]/(cp[i] + cp[j] + cp[Times-i-j]);
ip.y = cp[j]/(cp[i] + cp[j] + cp[Times-i-j]);
}
Array<int> &G = RG->RefGeoms;
for (l = k = j = 0; j < Times; j++, k++)
for (i = 0; i < Times-j; i++, k++)
{
G[l++] = k;
G[l++] = k+1;
G[l++] = k+Times-j+1;
if (i+j+1 < Times)
{
G[l++] = k+1;
G[l++] = k+Times-j+2;
G[l++] = k+Times-j+1;
}
}
Array<int> &E = RG->RefEdges;
int lb = 0, li = 2*RG->NumBdrEdges;
// horizontal edges
for (k = 0; k < Times; k += Times/ETimes)
{
int &lt = (k == 0) ? lb : li;
j = k*(Times+1)-((k-1)*k)/2;
for (i = 0; i < Times-k; i++)
{
E[lt++] = j; j++;
E[lt++] = j;
}
}
// diagonal edges
for (k = Times; k > 0; k -= Times/ETimes)
{
int &lt = (k == Times) ? lb : li;
j = k;
for (i = 0; i < k; i++)
{
E[lt++] = j; j += Times-i;
E[lt++] = j;
}
}
// vertical edges
for (k = 0; k < Times; k += Times/ETimes)
{
int &lt = (k == 0) ? lb : li;
j = k;
for (i = 0; i < Times-k; i++)
{
E[lt++] = j; j += Times-i+1;
E[lt++] = j;
}
}
RGeom[Geometry::TRIANGLE].Append(RG);
return RG;
}
case Geometry::SQUARE:
{
RG = new RefinedGeometry((Times+1)*(Times+1), 4*Times*Times,
4*(ETimes+1)*Times, 4*Times);
RG->Times = Times;
RG->ETimes = ETimes;
RG->Type = type;
for (k = j = 0; j <= Times; j++)
for (i = 0; i <= Times; i++, k++)
{
IntegrationPoint &ip = RG->RefPts.IntPoint(k);
ip.x = cp[i];
ip.y = cp[j];
}
Array<int> &G = RG->RefGeoms;
for (l = k = j = 0; j < Times; j++, k++)
for (i = 0; i < Times; i++, k++)
{
G[l++] = k;
G[l++] = k+1;
G[l++] = k+Times+2;
G[l++] = k+Times+1;
}
Array<int> &E = RG->RefEdges;
int lb = 0, li = 2*RG->NumBdrEdges;
// horizontal edges
for (k = 0; k <= Times; k += Times/ETimes)
{
int &lt = (k == 0 || k == Times) ? lb : li;
for (i = 0, j = k*(Times+1); i < Times; i++)
{
E[lt++] = j; j++;
E[lt++] = j;
}
}
// vertical edges (in right-to-left order)
for (k = Times; k >= 0; k -= Times/ETimes)
{
int &lt = (k == Times || k == 0) ? lb : li;
for (i = 0, j = k; i < Times; i++)
{
E[lt++] = j; j += Times+1;
E[lt++] = j;
}
}
RGeom[Geometry::SQUARE].Append(RG);
return RG;
}
case Geometry::CUBE:
{
RG = new RefinedGeometry ((Times+1)*(Times+1)*(Times+1),
8*Times*Times*Times, 0);
RG->Times = Times;
RG->ETimes = ETimes;
RG->Type = type;
for (l = k = 0; k <= Times; k++)
for (j = 0; j <= Times; j++)
for (i = 0; i <= Times; i++, l++)
{
IntegrationPoint &ip = RG->RefPts.IntPoint(l);
ip.x = cp[i];
ip.y = cp[j];
ip.z = cp[k];
}
Array<int> &G = RG->RefGeoms;
for (l = k = 0; k < Times; k++)
for (j = 0; j < Times; j++)
for (i = 0; i < Times; i++)
{
G[l++] = i+0 + (j+0 + (k+0) * (Times+1)) * (Times+1);
G[l++] = i+1 + (j+0 + (k+0) * (Times+1)) * (Times+1);
G[l++] = i+1 + (j+1 + (k+0) * (Times+1)) * (Times+1);
G[l++] = i+0 + (j+1 + (k+0) * (Times+1)) * (Times+1);
G[l++] = i+0 + (j+0 + (k+1) * (Times+1)) * (Times+1);
G[l++] = i+1 + (j+0 + (k+1) * (Times+1)) * (Times+1);
G[l++] = i+1 + (j+1 + (k+1) * (Times+1)) * (Times+1);
G[l++] = i+0 + (j+1 + (k+1) * (Times+1)) * (Times+1);
}
RGeom[Geometry::CUBE].Append(RG);
return RG;
}
case Geometry::TETRAHEDRON:
{
// subdivide the tetrahedron with vertices
// (0,0,0), (0,0,1), (1,1,1), (0,1,1)
// vertices: 0 <= i <= j <= k <= Times
// (3-combination with repetitions)
// number of vertices: (n+3)*(n+2)*(n+1)/6, n = Times
// elements: the vertices are: v1=(i,j,k), v2=v1+u1, v3=v2+u2, v4=v3+u3
// where 0 <= i <= j <= k <= n-1 and
// u1,u2,u3 is a permutation of (1,0,0),(0,1,0),(0,0,1)
// such that all v2,v3,v4 have non-decreasing components
// number of elements: n^3
const int n = Times;
RG = new RefinedGeometry((n+3)*(n+2)*(n+1)/6, 4*n*n*n, 0);
RG->Times = Times;
RG->ETimes = ETimes;
RG->Type = type;
// enumerate and define the vertices
Array<int> vi((n+1)*(n+1)*(n+1));
vi = -1;
m = 0;
for (k = 0; k <= n; k++)
for (j = 0; j <= k; j++)
for (i = 0; i <= j; i++)
{
IntegrationPoint &ip = RG->RefPts.IntPoint(m);
// map the coordinates to the reference tetrahedron
// (0,0,0) -> (0,0,0)
// (0,0,1) -> (1,0,0)
// (1,1,1) -> (0,1,0)
// (0,1,1) -> (0,0,1)
double w = cp[k-j] + cp[i] + cp[j-i] + cp[Times-k];
ip.x = cp[k-j]/w;
ip.y = cp[i]/w;
ip.z = cp[j-i]/w;
l = i + (j + k * (n+1)) * (n+1);
vi[l] = m;
m++;
}
if (m != (n+3)*(n+2)*(n+1)/6)
{
mfem_error("GeometryRefiner::Refine() for TETRAHEDRON #1");
}
// elements
Array<int> &G = RG->RefGeoms;
m = 0;
for (k = 0; k < n; k++)
for (j = 0; j <= k; j++)
for (i = 0; i <= j; i++)
{
// the ordering of the vertices is chosen to ensure:
// 1) correct orientation
// 2) the x,y,z edges are in the set of edges
// {(0,1),(2,3), (0,2),(1,3)}
// (goal is to ensure that subsequent refinement using
// this procedure preserves the six tetrahedral shapes)
// zyx: (i,j,k)-(i,j,k+1)-(i+1,j+1,k+1)-(i,j+1,k+1)
G[m++] = vi[i+0 + (j+0 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+0 + (j+0 + (k+1) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+1 + (k+1) * (n+1)) * (n+1)];
G[m++] = vi[i+0 + (j+1 + (k+1) * (n+1)) * (n+1)];
if (j < k)
{
// yzx: (i,j,k)-(i+1,j+1,k+1)-(i,j+1,k)-(i,j+1,k+1)
G[m++] = vi[i+0 + (j+0 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+1 + (k+1) * (n+1)) * (n+1)];
G[m++] = vi[i+0 + (j+1 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+0 + (j+1 + (k+1) * (n+1)) * (n+1)];
// yxz: (i,j,k)-(i,j+1,k)-(i+1,j+1,k+1)-(i+1,j+1,k)
G[m++] = vi[i+0 + (j+0 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+0 + (j+1 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+1 + (k+1) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+1 + (k+0) * (n+1)) * (n+1)];
}
if (i < j)
{
// xzy: (i,j,k)-(i+1,j,k)-(i+1,j+1,k+1)-(i+1,j,k+1)
G[m++] = vi[i+0 + (j+0 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+0 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+1 + (k+1) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+0 + (k+1) * (n+1)) * (n+1)];
if (j < k)
{
// xyz: (i,j,k)-(i+1,j+1,k+1)-(i+1,j,k)-(i+1,j+1,k)
G[m++] = vi[i+0 + (j+0 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+1 + (k+1) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+0 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+1 + (k+0) * (n+1)) * (n+1)];
}
// zxy: (i,j,k)-(i+1,j+1,k+1)-(i,j,k+1)-(i+1,j,k+1)
G[m++] = vi[i+0 + (j+0 + (k+0) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+1 + (k+1) * (n+1)) * (n+1)];
G[m++] = vi[i+0 + (j+0 + (k+1) * (n+1)) * (n+1)];
G[m++] = vi[i+1 + (j+0 + (k+1) * (n+1)) * (n+1)];
}
}
if (m != 4*n*n*n)
{
mfem_error("GeometryRefiner::Refine() for TETRAHEDRON #2");
}
for (i = 0; i < m; i++)
if (G[i] < 0)
{
mfem_error("GeometryRefiner::Refine() for TETRAHEDRON #3");
}
RGeom[Geometry::TETRAHEDRON].Append(RG);
return RG;
}
case Geometry::PRISM:
{
const int n = Times;
RG = new RefinedGeometry ((n+1)*(n+1)*(n+2)/2, 6*n*n*n, 0);
RG->Times = Times;
RG->ETimes = ETimes;
RG->Type = type;
// enumerate and define the vertices
m = 0;
for (l = k = 0; k <= n; k++)
for (j = 0; j <= n; j++)
for (i = 0; i <= n-j; i++, l++)
{
IntegrationPoint &ip = RG->RefPts.IntPoint(l);
if (type == 0)
{
ip.x = double(i) / n;
ip.y = double(j) / n;
ip.z = double(k) / n;
}
else
{
ip.x = cp[i]/(cp[i] + cp[j] + cp[n-i-j]);
ip.y = cp[j]/(cp[i] + cp[j] + cp[n-i-j]);
ip.z = cp[k];
}
m++;
}
if (m != (n+1)*(n+1)*(n+2)/2)
{
mfem_error("GeometryRefiner::Refine() for PRISM #1");
}
// elements
Array<int> &G = RG->RefGeoms;
m = 0;
for (m = k = 0; k < n; k++)
for (l = j = 0; j < n; j++, l++)
for (i = 0; i < n-j; i++, l++)
{
G[m++] = l + (k+0) * (n+1) * (n+2) / 2;
G[m++] = l + 1 + (k+0) * (n+1) * (n+2) / 2;
G[m++] = l - j + (2 + (k+0) * (n+2)) * (n+1) / 2;
G[m++] = l + (k+1) * (n+1) * (n+2) / 2;
G[m++] = l + 1 + (k+1) * (n+1) * (Times+2) / 2;
G[m++] = l - j + (2 + (k+1) * (n+2)) * (n+1) / 2;
if (i+j+1 < n)
{
G[m++] = l + 1 + (k+0) * (n+1) * (n+2)/2;
G[m++] = l - j + (2 + (k+0) * (n+1)) * (n+2) / 2;
G[m++] = l - j + (2 + (k+0) * (n+2)) * (n+1) / 2;
G[m++] = l + 1 + (k+1) * (n+1) * (n+2) / 2;
G[m++] = l - j + (2 + (k+1) * (n+1)) * (n+2) / 2;
G[m++] = l - j + (2 + (k+1) * (n+2)) * (n+1) / 2;
}
}
if (m != 6*n*n*n)
{
mfem_error("GeometryRefiner::Refine() for PRISM #2");
}
for (i = 0; i < m; i++)
if (G[i] < 0)
{
mfem_error("GeometryRefiner::Refine() for PRISM #3");
}
RGeom[Geometry::PRISM].Append(RG);
return RG;
}
default:
return NULL;
}
}
const IntegrationRule *GeometryRefiner::RefineInterior(Geometry::Type Geom,
int Times)
{
IntegrationRule *ir = NULL;
switch (Geom)
{
case Geometry::SEGMENT:
{
if (Times < 2)
{
return NULL;
}
ir = FindInIntPts(Geom, Times-1);
if (ir == NULL)
{
ir = new IntegrationRule(Times-1);
for (int i = 1; i < Times; i++)
{
IntegrationPoint &ip = ir->IntPoint(i-1);
ip.x = double(i) / Times;
ip.y = ip.z = 0.0;
}
}
}
break;
case Geometry::TRIANGLE:
{
if (Times < 3)
{
return NULL;
}
ir = FindInIntPts(Geom, ((Times-1)*(Times-2))/2);
if (ir == NULL)
{
ir = new IntegrationRule(((Times-1)*(Times-2))/2);
for (int k = 0, j = 1; j < Times-1; j++)
for (int i = 1; i < Times-j; i++, k++)
{
IntegrationPoint &ip = ir->IntPoint(k);
ip.x = double(i) / Times;
ip.y = double(j) / Times;
ip.z = 0.0;
}
}
}
break;
case Geometry::SQUARE:
{
if (Times < 2)
{
return NULL;
}
ir = FindInIntPts(Geom, (Times-1)*(Times-1));
if (ir == NULL)
{
ir = new IntegrationRule((Times-1)*(Times-1));
for (int k = 0, j = 1; j < Times; j++)
for (int i = 1; i < Times; i++, k++)
{
IntegrationPoint &ip = ir->IntPoint(k);
ip.x = double(i) / Times;
ip.y = double(j) / Times;
ip.z = 0.0;
}
}
}
break;
default:
mfem_error("GeometryRefiner::RefineInterior(...)");
}
if (ir) { IntPts[Geom].Append(ir); }
return ir;
}
GeometryRefiner GlobGeometryRefiner;
}