Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8501138bc | ||
|
|
c679c99b35 | ||
|
|
3f9a3658a6 |
+1
-15
@@ -145,14 +145,6 @@ examples/petsc/velocity.*
|
||||
examples/petsc/elastic_energy.*
|
||||
examples/petsc/mode_*
|
||||
|
||||
examples/arpack/ex11
|
||||
examples/arpack/mode_*
|
||||
examples/arpack/ex11.mesh
|
||||
|
||||
examples/spectra/ex11
|
||||
examples/spectra/mode_*
|
||||
examples/spectra/ex11.mesh
|
||||
|
||||
examples/pumi/ex1
|
||||
examples/pumi/ex[126]p
|
||||
examples/pumi/refined.mesh
|
||||
@@ -318,13 +310,7 @@ tests/convergence/prates
|
||||
tests/par-mesh-format/ex1p
|
||||
|
||||
# VPATH builds
|
||||
build-*/
|
||||
|
||||
# User config
|
||||
user-*
|
||||

|
||||
# VSCode
|
||||
.vscode
|
||||
build-*/*
|
||||
|
||||
# PETSc automated build
|
||||
petsc-build/*
|
||||
|
||||
@@ -50,7 +50,6 @@ variables:
|
||||
AUTOTEST_REPO: ssh://git@mybitbucket.llnl.gov:7999/mfem/autotest.git
|
||||
MFEM_DATA_REPO: https://github.com/mfem/data.git
|
||||
ARTIFACTS_DIR: artifacts
|
||||
SLURM_OVERLAP: 1
|
||||
|
||||
# The pipeline is divided into stages. Usually, jobs in a given stage wait for
|
||||
# the preceding stages to complete before to start. However, we sometimes use
|
||||
|
||||
@@ -12,24 +12,6 @@ Version 4.3.1 (development)
|
||||
===========================
|
||||
- Added support for hr-adaptivity using TMOP-based error estimator.
|
||||
|
||||
- Adding lowest order Nedelec and Raviart-Thomas basis functions on wedge
|
||||
shaped elements.
|
||||
|
||||
- Added initial support for meshes with pyramidal elements, including several
|
||||
pyramidal meshes in the data/ directory and support for the lowest order H1,
|
||||
Nedelec, Raviart-Thomas, and L2 basis functions on pyramids.
|
||||
|
||||
- Updated the hypre interface according to changes in hypre-2.22.1. The ADS
|
||||
solver is now fully working on GPUs.
|
||||
|
||||
- Tetrahedral meshes no longer need to be reordered to support high order
|
||||
Nedelec basis functions. This will allow future support for Nedelec basis
|
||||
functions on wedges and pyramids which are not amenable to reordering. The
|
||||
ReorientTetMesh method of the Mesh and ParMesh classes has been deprecated.
|
||||
|
||||
- Gmsh meshes where all elements have zero physical tag (the default Gmsh
|
||||
output format if no physical groups are defined) are now successfully loaded,
|
||||
and elements are reassigned attribute number 1.
|
||||
|
||||
Version 4.3, released on July 29, 2021
|
||||
======================================
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
cff-version: 1.2.0
|
||||
message: "If you use MFEM, please cite it as follows."
|
||||
authors:
|
||||
- family-names: "MFEM Team"
|
||||
title: "MFEM: Modular Finite Element Methods [Software]"
|
||||
doi: 10.11578/dc.20171025.1248
|
||||
url: "https://mfem.org"
|
||||
preferred-citation:
|
||||
type: article
|
||||
authors:
|
||||
- family-names: "Anderson"
|
||||
given-names: "Robert"
|
||||
orcid: "https://orcid.org/0000-0002-3508-9944"
|
||||
- family-names: "Andrej"
|
||||
given-names: "Julian"
|
||||
orcid: "https://orcid.org/0000-0001-7661-4840"
|
||||
- family-names: "Barker"
|
||||
given-names: "Andrew"
|
||||
orcid: "https://orcid.org/0000-0003-3572-911X"
|
||||
- family-names: "Bramwell"
|
||||
given-names: "Jamie"
|
||||
- family-names: "Camier"
|
||||
given-names: "Jean-Sylvain"
|
||||
orcid: "https://orcid.org/0000-0003-2421-1999"
|
||||
- family-names: "Cerveny"
|
||||
given-names: "Jakub"
|
||||
orcid: "https://orcid.org/0000-0003-4231-2531"
|
||||
- family-names: "Dobrev"
|
||||
given-names: "Veselin"
|
||||
orcid: "https://orcid.org/0000-0003-1793-5622"
|
||||
- family-names: "Dudouit"
|
||||
given-names: "Yohann"
|
||||
orcid: "https://orcid.org/0000-0001-5831-561X"
|
||||
- family-names: "Fisher"
|
||||
given-names: "Aaron"
|
||||
- family-names: "Kolev"
|
||||
given-names: "Tzanio"
|
||||
orcid: "https://orcid.org/0000-0002-2810-3090"
|
||||
- family-names: "Pazner"
|
||||
given-names: "Will"
|
||||
orcid: "https://orcid.org/0000-0003-4885-2934"
|
||||
- family-names: "Stowell"
|
||||
given-names: "Mark"
|
||||
orcid: "https://orcid.org/0000-0002-5389-7435"
|
||||
- family-names: "Tomov"
|
||||
given-names: "Vladimir"
|
||||
orcid: "https://orcid.org/0000-0002-1846-6816"
|
||||
- family-names: "Akkerman"
|
||||
given-names: "Ido"
|
||||
orcid: "https://orcid.org/0000-0002-5937-0300"
|
||||
- family-names: "Dahm"
|
||||
given-names: "Johann"
|
||||
orcid: "https://orcid.org/0000-0001-9657-3564"
|
||||
- family-names: "Medina"
|
||||
given-names: "David"
|
||||
- family-names: "Zampini"
|
||||
given-names: "Stefano"
|
||||
orcid: "https://orcid.org/0000-0002-0435-0433"
|
||||
doi: "10.1016/j.camwa.2020.06.009"
|
||||
journal: "Computers \\& Mathematics with Applications"
|
||||
month: 1
|
||||
start: 42 # First page number
|
||||
end: 74 # Last page number
|
||||
title: "MFEM: A Modular Finite Element Methods Library"
|
||||
volume: 81
|
||||
year: 2021
|
||||
@@ -549,7 +549,7 @@ The specific libraries and their options are:
|
||||
Options: HYPRE_OPT, HYPRE_LIB.
|
||||
Versions: HYPRE >= 2.10.0b (HYPRE built without CUDA)
|
||||
HYPRE >= 2.20.0 (HYPRE built with '--enable-mixedint')
|
||||
HYPRE >= 2.22.1 (HYPRE built with CUDA)
|
||||
HYPRE >= 2.22.0 (HYPRE built with CUDA)
|
||||
|
||||
- METIS, used when MFEM_USE_METIS = YES. If using METIS 5, set
|
||||
MFEM_USE_METIS_5 = YES (default is to use METIS 4).
|
||||
|
||||
@@ -91,12 +91,6 @@
|
||||
// Enable MFEM functionality based on the SuiteSparse library.
|
||||
// #define MFEM_USE_SUITESPARSE
|
||||
|
||||
// Enable MFEM functionality based on the ARPACK library.
|
||||
// #define MFEM_USE_ARPACK
|
||||
|
||||
// Enable MFEM functionality based on the SPECTRA library.
|
||||
// #define MFEM_USE_SPECTRA
|
||||
|
||||
// Enable MFEM functionality based on the SuperLU library.
|
||||
// #define MFEM_USE_SUPERLU
|
||||
// #define MFEM_USE_SUPERLU5
|
||||
|
||||
@@ -31,8 +31,6 @@ MFEM_TIMER_TYPE = @MFEM_TIMER_TYPE@
|
||||
MFEM_USE_SUNDIALS = @MFEM_USE_SUNDIALS@
|
||||
MFEM_USE_MESQUITE = @MFEM_USE_MESQUITE@
|
||||
MFEM_USE_SUITESPARSE = @MFEM_USE_SUITESPARSE@
|
||||
MFEM_USE_ARPACK = @MFEM_USE_ARPACK@
|
||||
MFEM_USE_SPECTRA = @MFEM_USE_SPECTRA@
|
||||
MFEM_USE_SUPERLU = @MFEM_USE_SUPERLU@
|
||||
MFEM_USE_SUPERLU5 = @MFEM_USE_SUPERLU5@
|
||||
MFEM_USE_MUMPS = @MFEM_USE_MUMPS@
|
||||
|
||||
@@ -151,8 +151,6 @@ MFEM_USE_UMPIRE = NO
|
||||
MFEM_USE_SIMD = NO
|
||||
MFEM_USE_ADIOS2 = NO
|
||||
MFEM_USE_MKL_CPARDISO = NO
|
||||
MFEM_USE_ARPACK = NO
|
||||
MFEM_USE_SPECTRA = NO
|
||||
|
||||
# MPI library compile and link flags
|
||||
# These settings are used only when building MFEM with MPI + HIP
|
||||
@@ -330,19 +328,6 @@ NETCDF_LIB = $(XLINKER)-rpath,$(NETCDF_DIR)/lib -L$(NETCDF_DIR)/lib\
|
||||
$(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib\
|
||||
-lnetcdf -lhdf5_hl -lhdf5 $(ZLIB_LIB)
|
||||
|
||||
# ARPACK library configuration
|
||||
ARPACK_DIR = @MFEM_DIR@/../ARPACK
|
||||
ARPACK_OPT = -I$(ARPACK_DIR)
|
||||
ARPACK_LIB = -L$(ARPACK_DIR) -lparpack -larpack
|
||||
|
||||
# EIGEN library configuration
|
||||
EIGEN_DIR = @MFEM_DIR@/../eigen
|
||||
EIGEN_OPT = -I$(EIGEN_DIR)
|
||||
|
||||
# SPECTRA library configuration
|
||||
SPECTRA_DIR = @MFEM_DIR@/../spectra/include
|
||||
SPECTRA_OPT = -I$(SPECTRA_DIR) $(EIGEN_OPT)
|
||||
|
||||
# PETSc library configuration (version greater or equal to 3.8 or the dev branch)
|
||||
PETSC_ARCH := arch-linux2-c-debug
|
||||
PETSC_DIR := $(MFEM_DIR)/../petsc/$(PETSC_ARCH)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
MFEM INLINE mesh v1.0
|
||||
|
||||
type = pyramid
|
||||
nx = 4
|
||||
ny = 4
|
||||
nz = 4
|
||||
sx = 1.0
|
||||
sy = 1.0
|
||||
sz = 1.0
|
||||
@@ -1,43 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
2
|
||||
1 7 4 3 2 1 0
|
||||
1 7 1 2 3 4 5
|
||||
|
||||
boundary
|
||||
8
|
||||
1 2 0 2 1
|
||||
2 2 0 3 2
|
||||
3 2 0 4 3
|
||||
4 2 0 1 4
|
||||
5 2 1 2 5
|
||||
6 2 2 3 5
|
||||
7 2 3 4 5
|
||||
8 2 4 1 5
|
||||
|
||||
vertices
|
||||
6
|
||||
3
|
||||
0 0 -1
|
||||
1 0 0
|
||||
0 1 0
|
||||
-1 0 0
|
||||
0 -1 0
|
||||
0 0 1
|
||||
@@ -1,38 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
1
|
||||
1 7 0 1 2 3 4
|
||||
|
||||
boundary
|
||||
5
|
||||
1 3 3 2 1 0
|
||||
2 2 0 1 4
|
||||
3 2 1 2 4
|
||||
4 2 2 3 4
|
||||
5 2 3 0 4
|
||||
|
||||
vertices
|
||||
5
|
||||
3
|
||||
0 0 0
|
||||
1 0 0
|
||||
1 1 0
|
||||
0 1 0
|
||||
0 0 1
|
||||
@@ -1,47 +0,0 @@
|
||||
Mesh.Algorithm = 6;
|
||||
|
||||
lc = 0.1;
|
||||
Point(1) = {0.0,0.0,0.0,lc};
|
||||
Point(2) = {1,0.0,0.0,lc};
|
||||
Point(3) = {0,1,0.0,lc};
|
||||
Circle(1) = {2,1,3};
|
||||
Point(4) = {-1,0,0.0,lc};
|
||||
Point(5) = {0,-1,0.0,lc};
|
||||
Circle(2) = {3,1,4};
|
||||
Circle(3) = {4,1,5};
|
||||
Circle(4) = {5,1,2};
|
||||
Point(6) = {0,0,-1,lc};
|
||||
Point(7) = {0,0,1,lc};
|
||||
Circle(5) = {3,1,6};
|
||||
Circle(6) = {6,1,5};
|
||||
Circle(7) = {5,1,7};
|
||||
Circle(8) = {7,1,3};
|
||||
Circle(9) = {2,1,7};
|
||||
Circle(10) = {7,1,4};
|
||||
Circle(11) = {4,1,6};
|
||||
Circle(12) = {6,1,2};
|
||||
Curve Loop(13) = {2,8,-10};
|
||||
Surface(14) = {13};
|
||||
Curve Loop(15) = {10,3,7};
|
||||
Surface(16) = {15};
|
||||
Curve Loop(17) = {-8,-9,1};
|
||||
Surface(18) = {17};
|
||||
Curve Loop(19) = {-11,-2,5};
|
||||
Surface(20) = {19};
|
||||
Curve Loop(21) = {-5,-12,-1};
|
||||
Surface(22) = {21};
|
||||
Curve Loop(23) = {-3,11,6};
|
||||
Surface(24) = {23};
|
||||
Curve Loop(25) = {-7,4,9};
|
||||
Surface(26) = {25};
|
||||
Curve Loop(27) = {-4,12,-6};
|
||||
Surface(28) = {27};
|
||||
Surface Loop(29) = {28,26,16,14,20,24,22,18};
|
||||
Volume(30) = {29};
|
||||
|
||||
Physical Surface(1) = {28,26,16,14,20,24,22,18};
|
||||
Physical Volume(2) = 30;
|
||||
|
||||
// Generate 2D mesh
|
||||
Mesh 2;
|
||||
Mesh.MshFileVersion = 2.2;
|
||||
-4793
File diff suppressed because it is too large
Load Diff
@@ -1,286 +0,0 @@
|
||||
// MFEM Example 11 - Serial Version
|
||||
//
|
||||
// Compile with: make ex11
|
||||
//
|
||||
// Sample runs: ex11 -m ../data/square-disc.mesh
|
||||
// ex11 -m ../data/star.mesh
|
||||
// ex11 -m ../data/star-mixed.mesh
|
||||
// ex11 -m ../data/periodic-annulus-sector.msh
|
||||
// ex11 -m ../data/square-disc-p2.vtk -o 2
|
||||
// ex11 -m ../data/square-disc-p3.mesh -o 3
|
||||
// ex11 -m ../data/square-disc-nurbs.mesh -o -1
|
||||
// ex11 -m ../data/disc-nurbs.mesh -o -1 -n 20
|
||||
// ex11 -m ../data/star-surf.mesh
|
||||
// ex11 -m ../data/square-disc-surf.mesh
|
||||
// ex11 -m ../data/inline-segment.mesh
|
||||
// ex11 -m ../data/inline-quad.mesh
|
||||
// ex11 -m ../data/inline-tri.mesh
|
||||
// ex11 -m ../data/amr-quad.mesh
|
||||
// ex11 -m ../data/amr-hex.mesh
|
||||
// ex11 -m ../data/mobius-strip.mesh -n 8
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to solve the
|
||||
// eigenvalue problem -Delta u = lambda u with homogeneous
|
||||
// Dirichlet boundary conditions.
|
||||
//
|
||||
// We compute a number of the lowest eigenmodes by discretizing
|
||||
// the Laplacian and Mass operators using a FE space of the
|
||||
// specified order, or an isoparametric/isogeometric space if
|
||||
// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for
|
||||
// NURBS mesh, etc.)
|
||||
//
|
||||
// The example highlights the use of the ARPACK eigenvalue solver
|
||||
// (regular inverse mode). Reusing a single GLVis visualization
|
||||
// window for multiple eigenfunctions is also illustrated.
|
||||
//
|
||||
// We recommend viewing Example 1 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/star.mesh";
|
||||
int ser_ref_levels = 3;
|
||||
int order = 1;
|
||||
int nev = 5;
|
||||
double dbc_eig = 1e3;
|
||||
bool visualization = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&nev, "-n", "--num-eigs",
|
||||
"Number of desired eigenmodes.");
|
||||
args.AddOption(&dbc_eig, "-d", "--dbc-eig",
|
||||
"Eigenvalues associated with Dirichlet BC "
|
||||
"(should be larger than the maximum desired eigenvalue).");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// 2. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh *mesh;
|
||||
ifstream imesh(mesh_file);
|
||||
if (!imesh)
|
||||
{
|
||||
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
|
||||
return 2;
|
||||
}
|
||||
mesh = new Mesh(imesh, 1, 1);
|
||||
imesh.close();
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement (2 by default, or
|
||||
// specified on the command line with -rs).
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 4. Define a finite element space on the mesh. Here we
|
||||
// use continuous Lagrange finite elements of the specified order. If
|
||||
// order < 1, we instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec;
|
||||
if (order > 0)
|
||||
{
|
||||
fec = new H1_FECollection(order, dim);
|
||||
}
|
||||
else if (mesh->GetNodes())
|
||||
{
|
||||
fec = mesh->GetNodes()->OwnFEC();
|
||||
}
|
||||
else
|
||||
{
|
||||
fec = new H1_FECollection(order = 1, dim);
|
||||
}
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
|
||||
int size = fespace->GetVSize();
|
||||
|
||||
cout << "Number of unknowns: " << size << endl;
|
||||
|
||||
// 5. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite
|
||||
// element space. The first corresponds to the Laplacian operator -Delta,
|
||||
// while the second is a simple mass matrix needed on the right hand side
|
||||
// of the generalized eigenvalue problem below. The boundary conditions
|
||||
// are implemented by elimination with special values on the diagonal to
|
||||
// shift the Dirichlet eigenvalues out of the computational range. After
|
||||
// serial and parallel assembly we extract the corresponding parallel
|
||||
// matrices A and M.
|
||||
ConstantCoefficient one(1.0);
|
||||
Array<int> ess_bdr;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
}
|
||||
|
||||
BilinearForm *a = new BilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
if (mesh->bdr_attributes.Size() == 0)
|
||||
{
|
||||
// Add a mass term if the mesh has no boundary, e.g. periodic mesh or
|
||||
// closed surface.
|
||||
a->AddDomainIntegrator(new MassIntegrator(one));
|
||||
}
|
||||
a->Assemble();
|
||||
if (mesh->bdr_attributes.Size() != 0)
|
||||
{
|
||||
a->EliminateEssentialBCDiag(ess_bdr, dbc_eig);
|
||||
}
|
||||
a->Finalize();
|
||||
|
||||
BilinearForm *m = new BilinearForm(fespace);
|
||||
m->AddDomainIntegrator(new MassIntegrator(one));
|
||||
m->Assemble();
|
||||
if (mesh->bdr_attributes.Size() != 0)
|
||||
{
|
||||
// shift the eigenvalue corresponding to eliminated dofs to a large value
|
||||
m->EliminateEssentialBCDiag(ess_bdr, 1.0);
|
||||
}
|
||||
m->Finalize();
|
||||
|
||||
// 6. Define and configure the ARPACK eigensolver
|
||||
ArPackSym * arpack = new ArPackSym();
|
||||
Solver * solver = NULL;
|
||||
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// 7. Define a simple symmetric Gauss-Seidel preconditioner and use it to
|
||||
// solve the system A X = B with PCG.
|
||||
cout << "Building CGSolver" << endl;
|
||||
GSSmoother M(m->SpMat());
|
||||
CGSolver * cg_solver = new CGSolver;
|
||||
cg_solver->SetPreconditioner(M);
|
||||
cg_solver->SetRelTol(1.0e-12);
|
||||
solver = cg_solver;
|
||||
#else
|
||||
// 7. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
cout << "Building UMFPackSolver" << endl;
|
||||
UMFPackSolver * umf_solver = new UMFPackSolver;
|
||||
umf_solver->Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
|
||||
solver = umf_solver;
|
||||
#endif
|
||||
solver->SetOperator(m->SpMat());
|
||||
|
||||
arpack->SetNumModes(nev);
|
||||
arpack->SetMaxIter(400);
|
||||
arpack->SetTol(1e-8);
|
||||
arpack->SetMode(2);
|
||||
arpack->SetPrintLevel(2);
|
||||
|
||||
arpack->SetOperator(*a);
|
||||
arpack->SetMassMatrix(*m);
|
||||
arpack->SetSolver(*solver);
|
||||
|
||||
// 8. Compute the eigenmodes and extract the array of eigenvalues. Define a
|
||||
// parallel grid function to represent each of the eigenmodes returned by
|
||||
// the solver.
|
||||
Array<double> eigenvalues;
|
||||
arpack->Solve();
|
||||
arpack->GetEigenvalues(eigenvalues);
|
||||
|
||||
cout << endl;
|
||||
std::ios::fmtflags old_fmt = cout.flags();
|
||||
cout.setf(std::ios::scientific);
|
||||
std::streamsize old_prec = cout.precision(14);
|
||||
for (int i=0; i<nev; i++)
|
||||
{
|
||||
cout << "Eigenvalue lambda " << eigenvalues[i] << endl;
|
||||
}
|
||||
cout.precision(old_prec);
|
||||
cout.flags(old_fmt);
|
||||
cout << endl;
|
||||
|
||||
GridFunction x(fespace);
|
||||
|
||||
// 9. Save the refined mesh and the modes in parallel. This output can be
|
||||
// viewed later using GLVis: "glvis -np <np> -m mesh -g mode".
|
||||
{
|
||||
ostringstream mesh_name, mode_name;
|
||||
mesh_name << "ex11.mesh";
|
||||
|
||||
ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
|
||||
for (int i=0; i<nev; i++)
|
||||
{
|
||||
// convert eigenvector from HypreParVector to ParGridFunction
|
||||
x = arpack->GetEigenvector(i);
|
||||
|
||||
mode_name << "mode_" << setfill('0') << setw(2) << i;
|
||||
|
||||
ofstream mode_ofs(mode_name.str().c_str());
|
||||
mode_ofs.precision(8);
|
||||
x.Save(mode_ofs);
|
||||
mode_name.str("");
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream mode_sock(vishost, visport);
|
||||
mode_sock.precision(8);
|
||||
|
||||
for (int i=0; i<nev; i++)
|
||||
{
|
||||
cout << "Eigenmode " << i+1 << '/' << nev
|
||||
<< ", Lambda = " << eigenvalues[i] << endl;
|
||||
|
||||
// convert eigenvector from HypreParVector to ParGridFunction
|
||||
x = arpack->GetEigenvector(i);
|
||||
|
||||
mode_sock << "solution\n" << *mesh << x << flush
|
||||
<< "window_title 'Eigenmode " << i+1 << '/' << nev
|
||||
<< ", Lambda = " << eigenvalues[i] << "'" << endl;
|
||||
|
||||
char c;
|
||||
cout << "press (q)uit or (c)ontinue --> " << flush;
|
||||
cin >> c;
|
||||
|
||||
if (c != 'c')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
mode_sock.close();
|
||||
}
|
||||
|
||||
// 11. Free the used memory.
|
||||
delete arpack;
|
||||
delete solver;
|
||||
delete m;
|
||||
delete a;
|
||||
|
||||
delete fespace;
|
||||
if (order > 0)
|
||||
{
|
||||
delete fec;
|
||||
}
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
# Copyright (c) 2010-2021, 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.
|
||||
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/arpack/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_EXAMPLES = ex11
|
||||
PAR_EXAMPLES =
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
EXAMPLES = $(SEQ_EXAMPLES)
|
||||
else
|
||||
EXAMPLES = $(PAR_EXAMPLES)
|
||||
endif
|
||||
RC_FILES = $(patsubst $(SRC)%,%,$(wildcard $(SRC)rc_*))
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all clean clean-build clean-exec
|
||||
|
||||
# Remove built-in rule
|
||||
%: %.cpp
|
||||
|
||||
# Replace the default implicit rule for *.cpp files
|
||||
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
|
||||
|
||||
all: $(EXAMPLES)
|
||||
|
||||
# Examples depend on their corresponding rc_* files:
|
||||
make-rc-rule = $(1): | $(filter rc_$(1)%,$(RC_FILES))
|
||||
$(foreach ex,$(EXAMPLES),$(eval $(call make-rc-rule,$(ex))))
|
||||
|
||||
# Rules to copy the rc_* files when building out-of-source:
|
||||
ifneq ($(SRC),)
|
||||
$(RC_FILES): %: $(SRC)%
|
||||
cp -pf $(<) .
|
||||
endif
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
$(error The MFEM library is not built)
|
||||
|
||||
clean: clean-build clean-exec
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -rf mesh.* sol.* sol_p.* sol_u.* Example5*
|
||||
@rm -f ex9-mesh.* ex9-init.* ex9-final.* Example9*
|
||||
@rm -f deformed.* velocity.* elastic_energy.*
|
||||
@@ -206,9 +206,9 @@ int main(int argc, char *argv[])
|
||||
cout << "Size of linear system: " << A->Height() << endl;
|
||||
|
||||
// 11. Solve the linear system A X = B.
|
||||
MFEM_PERF_BEGIN("Solve A X=B");
|
||||
if (!pa)
|
||||
{
|
||||
MFEM_PERF_SCOPE("Solve A X=B (FA)");
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
|
||||
GSSmoother M((SparseMatrix&)(*A));
|
||||
@@ -223,7 +223,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else // Jacobi preconditioning in partial assembly mode
|
||||
{
|
||||
MFEM_PERF_SCOPE("Solve A X=B (PA)");
|
||||
if (UsesTensorBasis(fespace))
|
||||
{
|
||||
OperatorJacobiSmoother M(a, ess_tdof_list);
|
||||
@@ -234,6 +233,7 @@ int main(int argc, char *argv[])
|
||||
CG(*A, B, X, 1, 400, 1e-12, 0.0);
|
||||
}
|
||||
}
|
||||
MFEM_PERF_END("Solve A X=B");
|
||||
// 12. Recover the solution as a finite element grid function.
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
|
||||
+18
-19
@@ -231,29 +231,28 @@ int main(int argc, char *argv[])
|
||||
// 13. Solve the linear system A X = B.
|
||||
// * With full assembly, use the BoomerAMG preconditioner from hypre.
|
||||
// * With partial assembly, use Jacobi smoothing, for now.
|
||||
MFEM_PERF_BEGIN("Solve A X = B");
|
||||
Solver *prec = NULL;
|
||||
if (pa)
|
||||
{
|
||||
MFEM_PERF_SCOPE("Solve A X=B");
|
||||
Solver *prec = NULL;
|
||||
if (pa)
|
||||
if (UsesTensorBasis(fespace))
|
||||
{
|
||||
if (UsesTensorBasis(fespace))
|
||||
{
|
||||
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
|
||||
}
|
||||
prec = new OperatorJacobiSmoother(a, ess_tdof_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
prec = new HypreBoomerAMG;
|
||||
}
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(2000);
|
||||
cg.SetPrintLevel(1);
|
||||
if (prec) { cg.SetPreconditioner(*prec); }
|
||||
cg.SetOperator(*A);
|
||||
cg.Mult(B, X);
|
||||
delete prec;
|
||||
}
|
||||
else
|
||||
{
|
||||
prec = new HypreBoomerAMG;
|
||||
}
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-12);
|
||||
cg.SetMaxIter(2000);
|
||||
cg.SetPrintLevel(1);
|
||||
if (prec) { cg.SetPreconditioner(*prec); }
|
||||
cg.SetOperator(*A);
|
||||
cg.Mult(B, X);
|
||||
delete prec;
|
||||
MFEM_PERF_END("Solve A X = B");
|
||||
// 14. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
// ex1 -m ../data/fichera.mesh
|
||||
// ex1 -m ../data/fichera-mixed.mesh
|
||||
// ex1 -m ../data/toroid-wedge.mesh
|
||||
// ex1 -m ../data/octahedron.mesh -o 1
|
||||
// ex1 -m ../data/periodic-annulus-sector.msh
|
||||
// ex1 -m ../data/periodic-torus-sector.msh
|
||||
// ex1 -m ../data/square-disc-p2.vtk -o 2
|
||||
|
||||
@@ -118,6 +118,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
|
||||
+4
-7
@@ -24,10 +24,7 @@
|
||||
// class ConductionOperator defining C(u)), as well as their
|
||||
// implicit time integration. Note that implementing the method
|
||||
// ConductionOperator::ImplicitSolve is the only requirement for
|
||||
// high-order implicit (SDIRK) time integration. In this example,
|
||||
// the diffusion operator is linearized by evaluating with the
|
||||
// lagged solution from the previous timestep, so there is only
|
||||
// a linear solve.
|
||||
// high-order implicit (SDIRK) time integration.
|
||||
//
|
||||
// We recommend viewing examples 2, 9 and 10 before viewing this
|
||||
// example.
|
||||
@@ -329,8 +326,8 @@ ConductionOperator::ConductionOperator(FiniteElementSpace &f, double al,
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
|
||||
{
|
||||
// Compute:
|
||||
// du_dt = M^{-1}*-Ku
|
||||
// for du_dt, where K is linearized by using u from the previous timestep
|
||||
// du_dt = M^{-1}*-K(u)
|
||||
// for du_dt
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg(); // z = -z
|
||||
M_solver.Mult(z, du_dt);
|
||||
@@ -341,7 +338,7 @@ void ConductionOperator::ImplicitSolve(const double dt,
|
||||
{
|
||||
// Solve the equation:
|
||||
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
|
||||
// for du_dt, where K is linearized by using u from the previous timestep
|
||||
// for du_dt
|
||||
if (!T)
|
||||
{
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
|
||||
+5
-8
@@ -24,11 +24,8 @@
|
||||
// class ConductionOperator defining C(u)), as well as their
|
||||
// implicit time integration. Note that implementing the method
|
||||
// ConductionOperator::ImplicitSolve is the only requirement for
|
||||
// high-order implicit (SDIRK) time integration. In this example,
|
||||
// the diffusion operator is linearized by evaluating with the
|
||||
// lagged solution from the previous timestep, so there is only
|
||||
// a linear solve. Optional saving with ADIOS2
|
||||
// (adios2.readthedocs.io) is also illustrated.
|
||||
// high-order implicit (SDIRK) time integration. Optional saving
|
||||
// with ADIOS2 (adios2.readthedocs.io) is also illustrated.
|
||||
//
|
||||
// We recommend viewing examples 2, 9 and 10 before viewing this
|
||||
// example.
|
||||
@@ -423,8 +420,8 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &f, double al,
|
||||
void ConductionOperator::Mult(const Vector &u, Vector &du_dt) const
|
||||
{
|
||||
// Compute:
|
||||
// du_dt = M^{-1}*-Ku
|
||||
// for du_dt, where K is linearized by using u from the previous timestep
|
||||
// du_dt = M^{-1}*-K(u)
|
||||
// for du_dt
|
||||
Kmat.Mult(u, z);
|
||||
z.Neg(); // z = -z
|
||||
M_solver.Mult(z, du_dt);
|
||||
@@ -435,7 +432,7 @@ void ConductionOperator::ImplicitSolve(const double dt,
|
||||
{
|
||||
// Solve the equation:
|
||||
// du_dt = M^{-1}*[-K(u + dt*du_dt)]
|
||||
// for du_dt, where K is linearized by using u from the previous timestep
|
||||
// for du_dt
|
||||
if (!T)
|
||||
{
|
||||
T = Add(1.0, Mmat, dt, Kmat);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
// mpirun -np 4 ex1p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/octahedron.mesh -o 1
|
||||
// mpirun -np 4 ex1p -m ../data/periodic-annulus-sector.msh
|
||||
// mpirun -np 4 ex1p -m ../data/periodic-torus-sector.msh
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 1
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2
|
||||
// ex22 -m ../data/inline-hex.mesh -o 2 -p 2 -pa
|
||||
// ex22 -m ../data/inline-wedge.mesh -o 1
|
||||
// ex22 -m ../data/inline-pyramid.mesh -o 1
|
||||
// ex22 -m ../data/star.mesh -r 1 -o 2 -sigma 10.0
|
||||
//
|
||||
// Device sample runs:
|
||||
|
||||
@@ -13,8 +13,6 @@
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 1
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 2 -p 2
|
||||
// mpirun -np 4 ex22p -m ../data/inline-hex.mesh -o 1 -p 2 -pa
|
||||
// mpirun -np 4 ex22p -m ../data/inline-wedge.mesh -o 1
|
||||
// mpirun -np 4 ex22p -m ../data/inline-pyramid.mesh -o 1
|
||||
// mpirun -np 4 ex22p -m ../data/star.mesh -o 2 -sigma 10.0
|
||||
//
|
||||
// Device sample runs:
|
||||
|
||||
@@ -113,6 +113,7 @@ int main(int argc, char *argv[])
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
mesh->ReorientTetMesh();
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use Nedelec or
|
||||
// Raviart-Thomas finite elements of the specified order.
|
||||
|
||||
@@ -141,6 +141,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use Nedelec or Raviart-Thomas finite elements of the specified order.
|
||||
|
||||
+4
-2
@@ -277,8 +277,10 @@ int main(int argc, char *argv[])
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 6. Set element attributes in order to distinguish elements in the
|
||||
// PML region
|
||||
// 6. Reorient mesh in case of a tet mesh
|
||||
mesh->ReorientTetMesh();
|
||||
|
||||
// Set element attributes in order to distinguish elements in the PML region
|
||||
pml->SetAttributes(mesh);
|
||||
|
||||
// 7. Define a finite element space on the mesh. Here we use the Nedelec
|
||||
|
||||
@@ -316,6 +316,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 7a. Reorient mesh in case of a tet mesh
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 8. Set element attributes in order to distinguish elements in the PML
|
||||
pml->SetAttributes(pmesh);
|
||||
|
||||
|
||||
+1
-2
@@ -16,8 +16,6 @@
|
||||
// ex3 -m ../data/beam-hex-nurbs.mesh
|
||||
// ex3 -m ../data/amr-hex.mesh
|
||||
// ex3 -m ../data/fichera-amr.mesh
|
||||
// ex3 -m ../data/ref-prism.mesh -o 1
|
||||
// ex3 -m ../data/octahedron.mesh -o 1
|
||||
// ex3 -m ../data/star-surf.mesh -o 1
|
||||
// ex3 -m ../data/mobius-strip.mesh -f 0.1
|
||||
// ex3 -m ../data/klein-bottle.mesh -f 0.1
|
||||
@@ -115,6 +113,7 @@ int main(int argc, char *argv[])
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
mesh->ReorientTetMesh();
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use the Nedelec
|
||||
// finite elements of the specified order.
|
||||
|
||||
+4
-3
@@ -16,8 +16,6 @@
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/ref-prism.mesh -o 1
|
||||
// mpirun -np 4 ex3p -m ../data/octahedron.mesh -o 1
|
||||
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
|
||||
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
|
||||
@@ -141,7 +139,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
|
||||
// meshes need to be reoriented before we can define high-order Nedelec
|
||||
// spaces on them.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
@@ -151,6 +151,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
// ex4 -m ../data/amr-hex.mesh
|
||||
// ex4 -m ../data/amr-hex.mesh -o 2 -hb
|
||||
// ex4 -m ../data/fichera-amr.mesh -o 2 -sc
|
||||
// ex4 -m ../data/ref-prism.mesh -o 1
|
||||
// ex4 -m ../data/octahedron.mesh -o 1
|
||||
// ex4 -m ../data/star-surf.mesh -o 1
|
||||
//
|
||||
// Device sample runs:
|
||||
|
||||
+4
-3
@@ -19,8 +19,6 @@
|
||||
// mpirun -np 3 ex4p -m ../data/amr-quad.mesh -o 2 -hb
|
||||
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
|
||||
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
|
||||
// mpirun -np 4 ex4p -m ../data/ref-prism.mesh -o 1
|
||||
// mpirun -np 4 ex4p -m ../data/octahedron.mesh -o 1
|
||||
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
|
||||
//
|
||||
// Device sample runs:
|
||||
@@ -137,7 +135,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
|
||||
// meshes need to be reoriented before we can define high-order Nedelec
|
||||
// spaces on them (this is needed in the ADS solver below).
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
@@ -147,6 +147,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Raviart-Thomas finite elements of the specified order.
|
||||
|
||||
@@ -106,6 +106,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 6. Define the trial, interfacial (trace) and test DPG spaces:
|
||||
// - The trial space, x0_space, contains the non-interfacial unknowns and
|
||||
|
||||
@@ -121,7 +121,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
|
||||
// meshes need to be reoriented before we can define high-order Nedelec
|
||||
// spaces on them.
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
@@ -131,6 +133,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
|
||||
@@ -122,7 +122,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
|
||||
// meshes need to be reoriented before we can define high-order Nedelec
|
||||
// spaces on them (this is needed in the ADS solver below).
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
@@ -132,6 +134,7 @@ int main(int argc, char *argv[])
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Raviart-Thomas finite elements of the specified order.
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
// MFEM Example 11 - Serial Version
|
||||
//
|
||||
// Compile with: make ex11
|
||||
//
|
||||
// Sample runs: ex11 -m ../data/square-disc.mesh
|
||||
// ex11 -m ../data/star.mesh
|
||||
// ex11 -m ../data/star-mixed.mesh
|
||||
// ex11 -m ../data/periodic-annulus-sector.msh
|
||||
// ex11 -m ../data/square-disc-p2.vtk -o 2
|
||||
// ex11 -m ../data/square-disc-p3.mesh -o 3
|
||||
// ex11 -m ../data/square-disc-nurbs.mesh -o -1
|
||||
// ex11 -m ../data/disc-nurbs.mesh -o -1 -n 20
|
||||
// ex11 -m ../data/star-surf.mesh
|
||||
// ex11 -m ../data/square-disc-surf.mesh
|
||||
// ex11 -m ../data/inline-segment.mesh
|
||||
// ex11 -m ../data/inline-quad.mesh
|
||||
// ex11 -m ../data/inline-tri.mesh
|
||||
// ex11 -m ../data/amr-quad.mesh
|
||||
// ex11 -m ../data/amr-hex.mesh
|
||||
// ex11 -m ../data/mobius-strip.mesh -n 8
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to solve the
|
||||
// eigenvalue problem -Delta u = lambda u with homogeneous
|
||||
// Dirichlet boundary conditions.
|
||||
//
|
||||
// We compute a number of the lowest eigenmodes by discretizing
|
||||
// the Laplacian and Mass operators using a FE space of the
|
||||
// specified order, or an isoparametric/isogeometric space if
|
||||
// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for
|
||||
// NURBS mesh, etc.)
|
||||
//
|
||||
// The example highlights the use of the ARPACK eigenvalue solver
|
||||
// (regular inverse mode). Reusing a single GLVis visualization
|
||||
// window for multiple eigenfunctions is also illustrated.
|
||||
//
|
||||
// We recommend viewing Example 1 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Parse command-line options.
|
||||
const char *mesh_file = "../../data/star.mesh";
|
||||
int ser_ref_levels = 1;
|
||||
int order = 1;
|
||||
int nev = 5;
|
||||
double dbc_eig = 1e3;
|
||||
bool visualization = 1;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree) or -1 for"
|
||||
" isoparametric space.");
|
||||
args.AddOption(&nev, "-n", "--num-eigs",
|
||||
"Number of desired eigenmodes.");
|
||||
args.AddOption(&dbc_eig, "-d", "--dbc-eig",
|
||||
"Eigenvalues associated with Dirichlet BC "
|
||||
"(should be larger than the maximum desired eigenvalue).");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
// 2. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume meshes with the same code.
|
||||
Mesh *mesh;
|
||||
ifstream imesh(mesh_file);
|
||||
if (!imesh)
|
||||
{
|
||||
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
|
||||
return 2;
|
||||
}
|
||||
mesh = new Mesh(imesh, 1, 1);
|
||||
imesh.close();
|
||||
int dim = mesh->Dimension();
|
||||
|
||||
// 3. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement (2 by default, or
|
||||
// specified on the command line with -rs).
|
||||
for (int lev = 0; lev < ser_ref_levels; lev++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
// 4. Define a finite element space on the mesh. Here we
|
||||
// use continuous Lagrange finite elements of the specified order. If
|
||||
// order < 1, we instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec;
|
||||
if (order > 0)
|
||||
{
|
||||
fec = new H1_FECollection(order, dim);
|
||||
}
|
||||
else if (mesh->GetNodes())
|
||||
{
|
||||
fec = mesh->GetNodes()->OwnFEC();
|
||||
}
|
||||
else
|
||||
{
|
||||
fec = new H1_FECollection(order = 1, dim);
|
||||
}
|
||||
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
|
||||
int size = fespace->GetVSize();
|
||||
|
||||
cout << "Number of unknowns: " << size << endl;
|
||||
|
||||
// 5. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite
|
||||
// element space. The first corresponds to the Laplacian operator -Delta,
|
||||
// while the second is a simple mass matrix needed on the right hand side
|
||||
// of the generalized eigenvalue problem below. The boundary conditions
|
||||
// are implemented by elimination with special values on the diagonal to
|
||||
// shift the Dirichlet eigenvalues out of the computational range. After
|
||||
// serial and parallel assembly we extract the corresponding parallel
|
||||
// matrices A and M.
|
||||
ConstantCoefficient one(1.0);
|
||||
Array<int> ess_bdr;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
}
|
||||
|
||||
BilinearForm *a = new BilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
if (mesh->bdr_attributes.Size() == 0)
|
||||
{
|
||||
// Add a mass term if the mesh has no boundary, e.g. periodic mesh or
|
||||
// closed surface.
|
||||
a->AddDomainIntegrator(new MassIntegrator(one));
|
||||
}
|
||||
a->Assemble();
|
||||
if (mesh->bdr_attributes.Size() != 0)
|
||||
{
|
||||
a->EliminateEssentialBCDiag(ess_bdr, dbc_eig);
|
||||
}
|
||||
a->Finalize();
|
||||
|
||||
BilinearForm *m = new BilinearForm(fespace);
|
||||
m->AddDomainIntegrator(new MassIntegrator(one));
|
||||
m->Assemble();
|
||||
if (mesh->bdr_attributes.Size() != 0)
|
||||
{
|
||||
// shift the eigenvalue corresponding to eliminated dofs to a large value
|
||||
m->EliminateEssentialBCDiag(ess_bdr, 1.0);
|
||||
}
|
||||
m->Finalize();
|
||||
|
||||
// 6. Define and configure the SPECTRA eigensolver and solve problem
|
||||
SpectraEigenSolver spectra;
|
||||
|
||||
spectra.SetNumModes(nev)
|
||||
.SetKrylov(10)
|
||||
.SetMaxIter(5000)
|
||||
.SetTol(1e-5)
|
||||
.SetOperators(*a, *m)
|
||||
.Solve();
|
||||
|
||||
Eigen::VectorXd eigenvalues = spectra.GetEigenvalues(nev);
|
||||
|
||||
// 7. Define a grid function to represent each of the eigenmodes returned by the solver.
|
||||
|
||||
GridFunction x(fespace);
|
||||
|
||||
// 8. Save the refined mesh and the modes in parallel.
|
||||
// This output can be viewed later using GLVis: "glvis -np <np> -m mesh -g mode"
|
||||
{
|
||||
ostringstream mesh_name, mode_name;
|
||||
mesh_name << "ex11.mesh";
|
||||
|
||||
ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
mesh_ofs.precision(8);
|
||||
mesh->Print(mesh_ofs);
|
||||
|
||||
for (int i = 0; i < nev; i++) {
|
||||
// conver Eigen Vector to MFEM Vector
|
||||
Vector eigenvector = VectorConverter<double>::from(spectra.GetEigenvector(i));
|
||||
|
||||
// convert eigenvector from Vector to GridFunction
|
||||
x = eigenvector;
|
||||
|
||||
mode_name << "mode_" << setfill('0') << setw(2) << i;
|
||||
|
||||
ofstream mode_ofs(mode_name.str().c_str());
|
||||
mode_ofs.precision(8);
|
||||
x.Save(mode_ofs);
|
||||
mode_name.str("");
|
||||
}
|
||||
}
|
||||
|
||||
// 10. Send the solution by socket to a GLVis server.
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream mode_sock(vishost, visport);
|
||||
mode_sock.precision(8);
|
||||
|
||||
for (int i=0; i<nev; i++)
|
||||
{
|
||||
cout << "Eigenmode " << i+1 << '/' << nev
|
||||
<< ", Lambda = " << eigenvalues[i] << endl;
|
||||
|
||||
// convert eigenvector from HypreParVector to ParGridFunction
|
||||
Vector eigenvector = VectorConverter<double>::from(spectra.GetEigenvector(i));
|
||||
x = eigenvector;
|
||||
|
||||
mode_sock << "solution\n" << *mesh << x << flush
|
||||
<< "window_title 'Eigenmode " << i+1 << '/' << nev
|
||||
<< ", Lambda = " << eigenvalues[i] << "'" << endl;
|
||||
|
||||
char c;
|
||||
cout << "press (q)uit or (c)ontinue --> " << flush;
|
||||
cin >> c;
|
||||
|
||||
if (c != 'c')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
mode_sock.close();
|
||||
}
|
||||
|
||||
// 10. Free the used memory.
|
||||
delete m;
|
||||
delete a;
|
||||
|
||||
delete fespace;
|
||||
if (order > 0)
|
||||
{
|
||||
delete fec;
|
||||
}
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
# Copyright (c) 2010-2021, 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.
|
||||
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/examples/spectra/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
# Use the MFEM install directory
|
||||
# MFEM_INSTALL_DIR = ../../mfem
|
||||
# CONFIG_MK = $(MFEM_INSTALL_DIR)/share/mfem/config.mk
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_EXAMPLES = ex11
|
||||
PAR_EXAMPLES =
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
EXAMPLES = $(SEQ_EXAMPLES)
|
||||
else
|
||||
EXAMPLES = $(PAR_EXAMPLES)
|
||||
endif
|
||||
RC_FILES = $(patsubst $(SRC)%,%,$(wildcard $(SRC)rc_*))
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all clean clean-build clean-exec
|
||||
|
||||
# Remove built-in rule
|
||||
%: %.cpp
|
||||
|
||||
# Replace the default implicit rule for *.cpp files
|
||||
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) $< -o $@ $(MFEM_LIBS)
|
||||
|
||||
all: $(EXAMPLES)
|
||||
|
||||
# Examples depend on their corresponding rc_* files:
|
||||
make-rc-rule = $(1): | $(filter rc_$(1)%,$(RC_FILES))
|
||||
$(foreach ex,$(EXAMPLES),$(eval $(call make-rc-rule,$(ex))))
|
||||
|
||||
# Rules to copy the rc_* files when building out-of-source:
|
||||
ifneq ($(SRC),)
|
||||
$(RC_FILES): %: $(SRC)%
|
||||
cp -pf $(<) .
|
||||
endif
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
$(error The MFEM library is not built)
|
||||
|
||||
clean: clean-build clean-exec
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ $(SEQ_EXAMPLES) $(PAR_EXAMPLES)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -rf *.mesh mode_*
|
||||
@@ -39,7 +39,6 @@ set(SRCS
|
||||
complex_fem.cpp
|
||||
convergence.cpp
|
||||
datacollection.cpp
|
||||
doftrans.cpp
|
||||
eltrans.cpp
|
||||
estimators.cpp
|
||||
fe.cpp
|
||||
@@ -120,7 +119,6 @@ set(HDRS
|
||||
complex_fem.hpp
|
||||
convergence.hpp
|
||||
datacollection.hpp
|
||||
doftrans.hpp
|
||||
eltrans.hpp
|
||||
estimators.hpp
|
||||
fe.hpp
|
||||
|
||||
+24
-58
@@ -391,7 +391,6 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
}
|
||||
|
||||
ElementTransformation *eltrans;
|
||||
DofTransformation * doftrans;
|
||||
Mesh *mesh = fes -> GetMesh();
|
||||
DenseMatrix elmat, *elmat_p;
|
||||
|
||||
@@ -425,7 +424,7 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
for (int i = 0; i < fes -> GetNE(); i++)
|
||||
{
|
||||
int elem_attr = fes->GetMesh()->GetAttribute(i);
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
if (element_matrices)
|
||||
{
|
||||
elmat_p = &(*element_matrices)(i);
|
||||
@@ -459,11 +458,6 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
{
|
||||
elmat_p = &elmat;
|
||||
}
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformDual(elmat);
|
||||
}
|
||||
elmat_p = &elmat;
|
||||
}
|
||||
if (static_cond)
|
||||
{
|
||||
@@ -509,7 +503,7 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
const FiniteElement &be = *fes->GetBE(i);
|
||||
doftrans = fes -> GetBdrElementVDofs (i, vdofs);
|
||||
fes -> GetBdrElementVDofs (i, vdofs);
|
||||
eltrans = fes -> GetBdrElementTransformation (i);
|
||||
int k = 0;
|
||||
for (; k < boundary_integs.Size(); k++)
|
||||
@@ -529,22 +523,17 @@ void BilinearForm::Assemble(int skip_zeros)
|
||||
boundary_integs[k]->AssembleElementMatrix(be, *eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
}
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformDual(elmat);
|
||||
}
|
||||
elmat_p = &elmat;
|
||||
if (!static_cond)
|
||||
{
|
||||
mat->AddSubMatrix(vdofs, vdofs, *elmat_p, skip_zeros);
|
||||
mat->AddSubMatrix(vdofs, vdofs, elmat, skip_zeros);
|
||||
if (hybridization)
|
||||
{
|
||||
hybridization->AssembleBdrMatrix(i, *elmat_p);
|
||||
hybridization->AssembleBdrMatrix(i, elmat);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static_cond->AssembleBdrMatrix(i, *elmat_p);
|
||||
static_cond->AssembleBdrMatrix(i, elmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1329,10 +1318,9 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
return;
|
||||
}
|
||||
|
||||
Array<int> tr_vdofs, te_vdofs;
|
||||
ElementTransformation *eltrans;
|
||||
DofTransformation * dom_dof_trans;
|
||||
DofTransformation * ran_dof_trans;
|
||||
DenseMatrix elmat;
|
||||
DenseMatrix elemmat;
|
||||
|
||||
Mesh *mesh = test_fes -> GetMesh();
|
||||
|
||||
@@ -1345,24 +1333,16 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
{
|
||||
for (int i = 0; i < test_fes -> GetNE(); i++)
|
||||
{
|
||||
dom_dof_trans = trial_fes -> GetElementVDofs (i, trial_vdofs);
|
||||
ran_dof_trans = test_fes -> GetElementVDofs (i, test_vdofs);
|
||||
trial_fes -> GetElementVDofs (i, tr_vdofs);
|
||||
test_fes -> GetElementVDofs (i, te_vdofs);
|
||||
eltrans = test_fes -> GetElementTransformation (i);
|
||||
|
||||
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
|
||||
elmat = 0.0;
|
||||
for (int k = 0; k < domain_integs.Size(); k++)
|
||||
{
|
||||
domain_integs[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i),
|
||||
*test_fes -> GetFE(i),
|
||||
*eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
if (ran_dof_trans || dom_dof_trans)
|
||||
{
|
||||
TransformDual(ran_dof_trans, dom_dof_trans, elmat);
|
||||
}
|
||||
mat -> AddSubMatrix (test_vdofs, trial_vdofs, elmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1394,12 +1374,9 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
const int bdr_attr = mesh->GetBdrAttribute(i);
|
||||
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
|
||||
|
||||
dom_dof_trans = trial_fes -> GetBdrElementVDofs (i, trial_vdofs);
|
||||
ran_dof_trans = test_fes -> GetBdrElementVDofs (i, test_vdofs);
|
||||
trial_fes -> GetBdrElementVDofs (i, tr_vdofs);
|
||||
test_fes -> GetBdrElementVDofs (i, te_vdofs);
|
||||
eltrans = test_fes -> GetBdrElementTransformation (i);
|
||||
|
||||
elmat.SetSize(test_vdofs.Size(), trial_vdofs.Size());
|
||||
elmat = 0.0;
|
||||
for (int k = 0; k < boundary_integs.Size(); k++)
|
||||
{
|
||||
if (boundary_integs_marker[k] &&
|
||||
@@ -1408,34 +1385,29 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
boundary_integs[k]->AssembleElementMatrix2 (*trial_fes -> GetBE(i),
|
||||
*test_fes -> GetBE(i),
|
||||
*eltrans, elemmat);
|
||||
elmat += elemmat;
|
||||
mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
if (ran_dof_trans || dom_dof_trans)
|
||||
{
|
||||
TransformDual(ran_dof_trans, dom_dof_trans, elmat);
|
||||
}
|
||||
mat -> AddSubMatrix (test_vdofs, trial_vdofs, elmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
|
||||
if (trace_face_integs.Size())
|
||||
{
|
||||
FaceElementTransformations *ftr;
|
||||
Array<int> test_vdofs2;
|
||||
Array<int> te_vdofs2;
|
||||
const FiniteElement *trial_face_fe, *test_fe1, *test_fe2;
|
||||
|
||||
int nfaces = mesh->GetNumFaces();
|
||||
for (int i = 0; i < nfaces; i++)
|
||||
{
|
||||
ftr = mesh->GetFaceElementTransformations(i);
|
||||
trial_fes->GetFaceVDofs(i, trial_vdofs);
|
||||
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs);
|
||||
trial_fes->GetFaceVDofs(i, tr_vdofs);
|
||||
test_fes->GetElementVDofs(ftr->Elem1No, te_vdofs);
|
||||
trial_face_fe = trial_fes->GetFaceElement(i);
|
||||
test_fe1 = test_fes->GetFE(ftr->Elem1No);
|
||||
if (ftr->Elem2No >= 0)
|
||||
{
|
||||
test_fes->GetElementVDofs(ftr->Elem2No, test_vdofs2);
|
||||
test_vdofs.Append(test_vdofs2);
|
||||
test_fes->GetElementVDofs(ftr->Elem2No, te_vdofs2);
|
||||
te_vdofs.Append(te_vdofs2);
|
||||
test_fe2 = test_fes->GetFE(ftr->Elem2No);
|
||||
}
|
||||
else
|
||||
@@ -1449,7 +1421,7 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
{
|
||||
trace_face_integs[k]->AssembleFaceMatrix(*trial_face_fe, *test_fe1,
|
||||
*test_fe2, *ftr, elemmat);
|
||||
mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
|
||||
mat->AddSubMatrix(te_vdofs, tr_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1489,8 +1461,8 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
ftr = mesh->GetBdrFaceTransformations(i);
|
||||
if (ftr)
|
||||
{
|
||||
trial_fes->GetFaceVDofs(ftr->ElementNo, trial_vdofs);
|
||||
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs);
|
||||
trial_fes->GetFaceVDofs(ftr->ElementNo, tr_vdofs);
|
||||
test_fes->GetElementVDofs(ftr->Elem1No, te_vdofs);
|
||||
trial_face_fe = trial_fes->GetFaceElement(ftr->ElementNo);
|
||||
test_fe1 = test_fes->GetFE(ftr->Elem1No);
|
||||
// The test_fe2 object is really a dummy and not used on the
|
||||
@@ -1507,7 +1479,7 @@ void MixedBilinearForm::Assemble (int skip_zeros)
|
||||
*test_fe1,
|
||||
*test_fe2,
|
||||
*ftr, elemmat);
|
||||
mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
|
||||
mat->AddSubMatrix(te_vdofs, tr_vdofs, elemmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1869,8 +1841,6 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
|
||||
|
||||
Array<int> dom_vdofs, ran_vdofs;
|
||||
ElementTransformation *T;
|
||||
DofTransformation * dom_dof_trans;
|
||||
DofTransformation * ran_dof_trans;
|
||||
const FiniteElement *dom_fe, *ran_fe;
|
||||
DenseMatrix totelmat, elmat;
|
||||
|
||||
@@ -1883,8 +1853,8 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
|
||||
{
|
||||
for (int i = 0; i < test_fes->GetNE(); i++)
|
||||
{
|
||||
dom_dof_trans = trial_fes->GetElementVDofs(i, dom_vdofs);
|
||||
ran_dof_trans = test_fes->GetElementVDofs(i, ran_vdofs);
|
||||
trial_fes->GetElementVDofs(i, dom_vdofs);
|
||||
test_fes->GetElementVDofs(i, ran_vdofs);
|
||||
T = test_fes->GetElementTransformation(i);
|
||||
dom_fe = trial_fes->GetFE(i);
|
||||
ran_fe = test_fes->GetFE(i);
|
||||
@@ -1897,10 +1867,6 @@ void DiscreteLinearOperator::Assemble(int skip_zeros)
|
||||
elmat);
|
||||
totelmat += elmat;
|
||||
}
|
||||
if (ran_dof_trans || dom_dof_trans)
|
||||
{
|
||||
TransformPrimal(ran_dof_trans, dom_dof_trans, totelmat);
|
||||
}
|
||||
mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
// Copyright (c) 2010-2021, 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"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
void DofTransformation::TransformPrimal(Vector &v) const
|
||||
{
|
||||
TransformPrimal(v.GetData());
|
||||
}
|
||||
|
||||
void DofTransformation::TransformPrimalCols(DenseMatrix &V) const
|
||||
{
|
||||
for (int c=0; c<V.Width(); c++)
|
||||
{
|
||||
TransformPrimal(V.GetColumn(c));
|
||||
}
|
||||
}
|
||||
|
||||
void DofTransformation::TransformDual(Vector &v) const
|
||||
{
|
||||
TransformDual(v.GetData());
|
||||
}
|
||||
|
||||
void DofTransformation::TransformDual(DenseMatrix &V) const
|
||||
{
|
||||
TransformDualCols(V);
|
||||
TransformDualRows(V);
|
||||
}
|
||||
|
||||
void DofTransformation::TransformDualRows(DenseMatrix &V) const
|
||||
{
|
||||
Vector row;
|
||||
for (int r=0; r<V.Height(); r++)
|
||||
{
|
||||
V.GetRow(r, row);
|
||||
TransformDual(row);
|
||||
V.SetRow(r, row);
|
||||
}
|
||||
}
|
||||
|
||||
void DofTransformation::TransformDualCols(DenseMatrix &V) const
|
||||
{
|
||||
for (int c=0; c<V.Width(); c++)
|
||||
{
|
||||
TransformDual(V.GetColumn(c));
|
||||
}
|
||||
}
|
||||
|
||||
void DofTransformation::InvTransformPrimal(Vector &v) const
|
||||
{
|
||||
InvTransformPrimal(v.GetData());
|
||||
}
|
||||
|
||||
void TransformPrimal(const DofTransformation *ran_dof_trans,
|
||||
const DofTransformation *dom_dof_trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
if (ran_dof_trans && dom_dof_trans)
|
||||
{
|
||||
ran_dof_trans->TransformPrimalCols(elmat);
|
||||
dom_dof_trans->TransformDualRows(elmat);
|
||||
}
|
||||
else if (ran_dof_trans)
|
||||
{
|
||||
ran_dof_trans->TransformPrimalCols(elmat);
|
||||
}
|
||||
else if (dom_dof_trans)
|
||||
{
|
||||
dom_dof_trans->TransformDualRows(elmat);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If both transformations are NULL this function should not be called
|
||||
}
|
||||
}
|
||||
|
||||
void TransformDual(const DofTransformation *ran_dof_trans,
|
||||
const DofTransformation *dom_dof_trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
if (ran_dof_trans && dom_dof_trans)
|
||||
{
|
||||
ran_dof_trans->TransformDualCols(elmat);
|
||||
dom_dof_trans->TransformDualRows(elmat);
|
||||
}
|
||||
else if (ran_dof_trans)
|
||||
{
|
||||
ran_dof_trans->TransformDualCols(elmat);
|
||||
}
|
||||
else if (dom_dof_trans)
|
||||
{
|
||||
dom_dof_trans->TransformDualRows(elmat);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If both transformations are NULL this function should not be called
|
||||
}
|
||||
}
|
||||
|
||||
void VDofTransformation::TransformPrimal(double *v) const
|
||||
{
|
||||
int size = doftrans_->Size();
|
||||
|
||||
if ((Ordering::Type)ordering_ == Ordering::byNODES || vdim_ == 1)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
doftrans_->TransformPrimal(&v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
doftrans_->TransformPrimal(vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VDofTransformation::InvTransformPrimal(double *v) const
|
||||
{
|
||||
int size = doftrans_->Height();
|
||||
|
||||
if ((Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
doftrans_->InvTransformPrimal(&v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
doftrans_->InvTransformPrimal(vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VDofTransformation::TransformDual(double *v) const
|
||||
{
|
||||
int size = doftrans_->Size();
|
||||
|
||||
if ((Ordering::Type)ordering_ == Ordering::byNODES)
|
||||
{
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
doftrans_->TransformDual(&v[i*size]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vec(size);
|
||||
for (int i=0; i<vdim_; i++)
|
||||
{
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
vec(j) = v[j*vdim_+i];
|
||||
}
|
||||
doftrans_->TransformDual(vec);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
v[j*vdim_+i] = vec(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const double ND_DofTransformation::T_data[24] =
|
||||
{
|
||||
1.0, 0.0, 0.0, 1.0,
|
||||
-1.0, -1.0, 0.0, 1.0,
|
||||
0.0, 1.0, -1.0, -1.0,
|
||||
1.0, 0.0, -1.0, -1.0,
|
||||
-1.0, -1.0, 1.0, 0.0,
|
||||
0.0, 1.0, 1.0, 0.0
|
||||
};
|
||||
|
||||
const DenseTensor ND_DofTransformation
|
||||
::T(const_cast<double*>(ND_DofTransformation::T_data), 2, 2, 6);
|
||||
|
||||
const double ND_DofTransformation::TInv_data[24] =
|
||||
{
|
||||
1.0, 0.0, 0.0, 1.0,
|
||||
-1.0, -1.0, 0.0, 1.0,
|
||||
-1.0, -1.0, 1.0, 0.0,
|
||||
1.0, 0.0, -1.0, -1.0,
|
||||
0.0, 1.0, -1.0, -1.0,
|
||||
0.0, 1.0, 1.0, 0.0
|
||||
};
|
||||
|
||||
const DenseTensor ND_DofTransformation
|
||||
::TInv(const_cast<double*>(TInv_data), 2, 2, 6);
|
||||
|
||||
ND_DofTransformation::ND_DofTransformation(int size, int p)
|
||||
: DofTransformation(size),
|
||||
order(p)
|
||||
{
|
||||
}
|
||||
|
||||
ND_TriDofTransformation::ND_TriDofTransformation(int p)
|
||||
: ND_DofTransformation(p*(p + 2), p)
|
||||
{
|
||||
}
|
||||
|
||||
void ND_TriDofTransformation::TransformPrimal(double *v) const
|
||||
{
|
||||
int nedofs = order; // number of DoFs per edge
|
||||
int nfdofs = order*(order-1); // number of DoFs per face
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<1; f++)
|
||||
{
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[3*nedofs + f*nfdofs + 2*i];
|
||||
T(Fo[f]).Mult(v2, &v[3*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ND_TriDofTransformation::InvTransformPrimal(double *v) const
|
||||
{
|
||||
int nedofs = order; // number of DoFs per edge
|
||||
int nfdofs = order*(order-1); // number of DoFs per face
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<1; f++)
|
||||
{
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[3*nedofs + f*nfdofs + 2*i];
|
||||
TInv(Fo[f]).Mult(v2, &v[3*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ND_TriDofTransformation::TransformDual(double *v) const
|
||||
{
|
||||
int nedofs = order; // number of DoFs per edge
|
||||
int nfdofs = order*(order-1); // number of DoFs per face
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<1; f++)
|
||||
{
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[3*nedofs + f*nfdofs + 2*i];
|
||||
TInv(Fo[f]).MultTranspose(v2, &v[3*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ND_TetDofTransformation::ND_TetDofTransformation(int p)
|
||||
: ND_DofTransformation(p*(p + 2)*(p + 3)/2, p)
|
||||
{
|
||||
}
|
||||
|
||||
void ND_TetDofTransformation::TransformPrimal(double *v) const
|
||||
{
|
||||
int nedofs = order; // number of DoFs per edge
|
||||
int nfdofs = order*(order-1); // number of DoFs per face
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<4; f++)
|
||||
{
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[6*nedofs + f*nfdofs + 2*i];
|
||||
T(Fo[f]).Mult(v2, &v[6*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ND_TetDofTransformation::InvTransformPrimal(double *v) const
|
||||
{
|
||||
int nedofs = order; // number of DoFs per edge
|
||||
int nfdofs = order*(order-1); // number of DoFs per face
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<4; f++)
|
||||
{
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[6*nedofs + f*nfdofs + 2*i];
|
||||
TInv(Fo[f]).Mult(v2, &v[6*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ND_TetDofTransformation::TransformDual(double *v) const
|
||||
{
|
||||
int nedofs = order; // number of DoFs per edge
|
||||
int nfdofs = order*(order-1); // number of DoFs per face
|
||||
|
||||
double data[2];
|
||||
Vector v2(data, 2);
|
||||
|
||||
// Transform face DoFs
|
||||
for (int f=0; f<4; f++)
|
||||
{
|
||||
for (int i=0; i<nfdofs/2; i++)
|
||||
{
|
||||
v2 = &v[6*nedofs + f*nfdofs + 2*i];
|
||||
TInv(Fo[f]).MultTranspose(v2, &v[6*nedofs + f*nfdofs + 2*i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,277 +0,0 @@
|
||||
// Copyright (c) 2010-2021, 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.
|
||||
|
||||
#ifndef MFEM_DOFTRANSFORM
|
||||
#define MFEM_DOFTRANSFORM
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "../linalg/linalg.hpp"
|
||||
#include "intrules.hpp"
|
||||
#include "fe.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** The DofTransformation class is an abstract base class for a family of
|
||||
transformations that map local degrees of freedom (DoFs), contained within
|
||||
individual elements, to global degrees of freedom, stored within
|
||||
GridFunction objects. These transformations are necessary to ensure that
|
||||
basis functions in neighboring elements align correctly. Closely related but
|
||||
complementary transformations are required for the entries stored in
|
||||
LinearForm and BilinearForm objects. The DofTransformation class is designed
|
||||
to apply the action of both of these types of DoF transformations.
|
||||
|
||||
Let the "primal transformation" be given by the operator T. This means that
|
||||
given a local element vector v the data that must be placed into a
|
||||
GridFunction object is v_t = T * v.
|
||||
|
||||
We also need the inverse of the primal transformation T^{-1} so that we can
|
||||
recover the local element vector from data read out of a GridFunction
|
||||
e.g. v = T^{-1} * v_t.
|
||||
|
||||
We need to preserve the action of our linear forms applied to primal
|
||||
vectors. In other words, if f is the local vector computed by a linear
|
||||
form then f * v = f_t * v_t (where "*" represents an inner product of
|
||||
vectors). This requires that f_t = T^{-T} * f i.e. the "dual transform" is
|
||||
given by the transpose of the inverse of the primal transformation.
|
||||
|
||||
For bilinear forms we require that v^T * A * v = v_t^T * A_t * v_t. This
|
||||
implies that A_t = T^{-T} * A * T^{-1}. This can be accomplished by
|
||||
performing dual transformations of the rows and columns of the matrix A.
|
||||
|
||||
For discrete linear operators the range must be modified with the primal
|
||||
transformation rather than the dual transformation because the result is a
|
||||
primal vector rather than a dual vector. This leads to the transformation
|
||||
D_t = T * D * T^{-1}. This can be accomplished by using a primal
|
||||
transformation on the columns of D and a dual transformation on its rows.
|
||||
*/
|
||||
class DofTransformation
|
||||
{
|
||||
protected:
|
||||
int size_;
|
||||
|
||||
Array<int> Fo;
|
||||
|
||||
DofTransformation(int size)
|
||||
: size_(size) {}
|
||||
|
||||
public:
|
||||
|
||||
inline int Size() const { return size_; }
|
||||
inline int Height() const { return size_; }
|
||||
inline int NumRows() const { return size_; }
|
||||
inline int Width() const { return size_; }
|
||||
inline int NumCols() const { return size_; }
|
||||
|
||||
/** @brief Configure the transformation using face orientations for the
|
||||
current element. */
|
||||
/// The face_orientation array can be obtained from Mesh::GetElementFaces.
|
||||
inline void SetFaceOrientations(const Array<int> & face_orientation)
|
||||
{ Fo = face_orientation; }
|
||||
|
||||
inline const Array<int> & GetFaceOrientations() const { return Fo; }
|
||||
|
||||
/** Transform local DoFs to align with the global DoFs. For example, this
|
||||
transformation can be used to map the local vector computed by
|
||||
FiniteElement::Project() to the transformed vector stored within a
|
||||
GridFunction object. */
|
||||
virtual void TransformPrimal(double *v) const = 0;
|
||||
virtual void TransformPrimal(Vector &v) const;
|
||||
|
||||
/// Transform groups of DoFs stored as dense matrices
|
||||
virtual void TransformPrimalCols(DenseMatrix &V) const;
|
||||
|
||||
/** Inverse transform local DoFs. Used to transform DoFs from a global vector
|
||||
back to their element-local form. For example, this must be used to
|
||||
transform the vector obtained using GridFunction::GetSubVector before it
|
||||
can be used to compute a local interpolation.
|
||||
*/
|
||||
virtual void InvTransformPrimal(double *v) const = 0;
|
||||
virtual void InvTransformPrimal(Vector &v) const;
|
||||
|
||||
/** Transform dual DoFs as computed by a LinearFormIntegrator before summing
|
||||
into a LinearForm object. */
|
||||
virtual void TransformDual(double *v) const = 0;
|
||||
virtual void TransformDual(Vector &v) const;
|
||||
|
||||
/** Transform a matrix of dual DoFs entries as computed by a
|
||||
BilinearFormIntegrator before summing into a BilinearForm object. */
|
||||
virtual void TransformDual(DenseMatrix &V) const;
|
||||
|
||||
/// Transform groups of dual DoFs stored as dense matrices
|
||||
virtual void TransformDualRows(DenseMatrix &V) const;
|
||||
virtual void TransformDualCols(DenseMatrix &V) const;
|
||||
|
||||
virtual ~DofTransformation() {}
|
||||
};
|
||||
|
||||
/** Transform a matrix of DoFs entries from different finite element spaces as
|
||||
computed by a DiscreteInterpolator before copying into a
|
||||
DiscreteLinearOperator.
|
||||
*/
|
||||
void TransformPrimal(const DofTransformation *ran_dof_trans,
|
||||
const DofTransformation *dom_dof_trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
/** Transform a matrix of dual DoFs entries from different finite element spaces
|
||||
as computed by a BilinearFormIntegrator before summing into a
|
||||
MixedBilinearForm object.
|
||||
*/
|
||||
void TransformDual(const DofTransformation *ran_dof_trans,
|
||||
const DofTransformation *dom_dof_trans,
|
||||
DenseMatrix &elmat);
|
||||
|
||||
/** The VDofTransformation class implements a nested transformation where an
|
||||
arbitrary DofTransformation is replicated with a vdim >= 1.
|
||||
*/
|
||||
class VDofTransformation : public DofTransformation
|
||||
{
|
||||
private:
|
||||
int vdim_;
|
||||
int ordering_;
|
||||
DofTransformation * doftrans_;
|
||||
|
||||
public:
|
||||
/** @brief Default constructor which requires that SetDofTransformation be
|
||||
called before use. */
|
||||
VDofTransformation(int vdim = 1, int ordering = 0)
|
||||
: DofTransformation(0),
|
||||
vdim_(vdim), ordering_(ordering),
|
||||
doftrans_(NULL) {}
|
||||
|
||||
/// Constructor with a known DofTransformation
|
||||
VDofTransformation(DofTransformation & doftrans, int vdim = 1,
|
||||
int ordering = 0)
|
||||
: DofTransformation(vdim * doftrans.Size()),
|
||||
vdim_(vdim), ordering_(ordering),
|
||||
doftrans_(&doftrans) {}
|
||||
|
||||
/// Set or change the vdim parameter
|
||||
inline void SetVDim(int vdim)
|
||||
{
|
||||
vdim_ = vdim;
|
||||
if (doftrans_)
|
||||
{
|
||||
size_ = vdim_ * doftrans_->Size();
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the current vdim value
|
||||
inline int GetVDim() const { return vdim_; }
|
||||
|
||||
/// Set or change the nested DofTransformation object
|
||||
inline void SetDofTransformation(DofTransformation & doftrans)
|
||||
{
|
||||
size_ = vdim_ * doftrans.Size();
|
||||
doftrans_ = &doftrans;
|
||||
}
|
||||
|
||||
/// Return the nested DofTransformation object
|
||||
inline DofTransformation * GetDofTransformation() const { return doftrans_; }
|
||||
|
||||
inline void SetFaceOrientation(const Array<int> & face_orientation)
|
||||
{ Fo = face_orientation; doftrans_->SetFaceOrientations(face_orientation); }
|
||||
|
||||
using DofTransformation::TransformPrimal;
|
||||
using DofTransformation::InvTransformPrimal;
|
||||
using DofTransformation::TransformDual;
|
||||
|
||||
void TransformPrimal(double *v) const;
|
||||
void InvTransformPrimal(double *v) const;
|
||||
void TransformDual(double *v) const;
|
||||
};
|
||||
|
||||
/** Abstract base class for high-order Nedelec spaces on elements with
|
||||
triangular faces.
|
||||
|
||||
The Nedelec DoFs on the interior of triangular faces come in pairs which
|
||||
share an interpolation point but have different vector directions. These
|
||||
directions depend on the orientation of the face and can therefore differ in
|
||||
neighboring elements. The mapping required to transform these DoFs can be
|
||||
implemented as series of 2x2 linear transformations. The raw data for these
|
||||
linear transformations is stored in the T_data and TInv_data arrays and can
|
||||
be accessed as DenseMatrices using the GetFaceTransform() and
|
||||
GetFaceInverseTransform() methods.
|
||||
*/
|
||||
class ND_DofTransformation : public DofTransformation
|
||||
{
|
||||
protected:
|
||||
static const double T_data[24];
|
||||
static const double TInv_data[24];
|
||||
static const DenseTensor T, TInv;
|
||||
int order;
|
||||
|
||||
ND_DofTransformation(int size, int order);
|
||||
|
||||
public:
|
||||
// Return the 2x2 transformation operator for the given face orientation
|
||||
static const DenseMatrix & GetFaceTransform(int ori) { return T(ori); }
|
||||
|
||||
// Return the 2x2 inverse transformation operator
|
||||
static const DenseMatrix & GetFaceInverseTransform(int ori)
|
||||
{ return TInv(ori); }
|
||||
};
|
||||
|
||||
/// DoF transformation implementation for the Nedelec basis on triangles
|
||||
class ND_TriDofTransformation : public ND_DofTransformation
|
||||
{
|
||||
public:
|
||||
ND_TriDofTransformation(int order);
|
||||
|
||||
using DofTransformation::TransformPrimal;
|
||||
using DofTransformation::InvTransformPrimal;
|
||||
using DofTransformation::TransformDual;
|
||||
|
||||
void TransformPrimal(double *v) const;
|
||||
|
||||
void InvTransformPrimal(double *v) const;
|
||||
|
||||
void TransformDual(double *v) const;
|
||||
};
|
||||
|
||||
/// DoF transformation implementation for the Nedelec basis on tetrahedra
|
||||
class ND_TetDofTransformation : public ND_DofTransformation
|
||||
{
|
||||
public:
|
||||
ND_TetDofTransformation(int order);
|
||||
|
||||
using DofTransformation::TransformPrimal;
|
||||
using DofTransformation::InvTransformPrimal;
|
||||
using DofTransformation::TransformDual;
|
||||
|
||||
void TransformPrimal(double *v) const;
|
||||
|
||||
void InvTransformPrimal(double *v) const;
|
||||
|
||||
void TransformDual(double *v) const;
|
||||
};
|
||||
|
||||
/// DoF transformation implementation for the Nedelec basis on wedge elements
|
||||
/** TODO: (Under development) */
|
||||
class ND_WedgeDofTransformation : public ND_DofTransformation
|
||||
{
|
||||
public:
|
||||
ND_WedgeDofTransformation(int order);
|
||||
|
||||
using DofTransformation::TransformPrimal;
|
||||
using DofTransformation::InvTransformPrimal;
|
||||
using DofTransformation::TransformDual;
|
||||
|
||||
void TransformPrimal(double *v) const;
|
||||
|
||||
void InvTransformPrimal(double *v) const;
|
||||
|
||||
void TransformDual(double *v) const;
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_DOFTRANSFORM
|
||||
@@ -380,7 +380,6 @@ void IsoparametricTransformation::SetIdentityTransformation(
|
||||
case Geometry::TETRAHEDRON : FElem = &TetrahedronFE; break;
|
||||
case Geometry::CUBE : FElem = &HexahedronFE; break;
|
||||
case Geometry::PRISM : FElem = &WedgeFE; break;
|
||||
case Geometry::PYRAMID : FElem = &PyramidFE; break;
|
||||
default:
|
||||
MFEM_ABORT("unknown Geometry::Type!");
|
||||
}
|
||||
|
||||
+2
-3
@@ -329,7 +329,7 @@ void KellyErrorEstimator::ComputeEstimates()
|
||||
error_estimates(e) = sqrt(factor * error_estimates(e));
|
||||
}
|
||||
|
||||
total_error = error_estimates.Norml2();
|
||||
total_error = error_estimates.Sum();
|
||||
delete flux;
|
||||
return;
|
||||
}
|
||||
@@ -452,10 +452,9 @@ void KellyErrorEstimator::ComputeEstimates()
|
||||
auto pfes = dynamic_cast<ParFiniteElementSpace*>(xfes);
|
||||
MFEM_VERIFY(pfes, "xfes is not a ParFiniteElementSpace pointer");
|
||||
|
||||
double process_local_error = pow(error_estimates.Norml2(),2.0);
|
||||
double process_local_error = error_estimates.Sum();
|
||||
MPI_Allreduce(&process_local_error, &total_error, 1, MPI_DOUBLE,
|
||||
MPI_SUM, pfes->GetComm());
|
||||
total_error = sqrt(total_error);
|
||||
#endif // MFEM_USE_MPI
|
||||
}
|
||||
|
||||
|
||||
+18
-1204
File diff suppressed because it is too large
Load Diff
-219
@@ -1313,64 +1313,6 @@ public:
|
||||
DenseMatrix &dshape) const;
|
||||
};
|
||||
|
||||
/// A linear element defined on a triangular prism
|
||||
class LinearWedgeFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct the LinearWedgeFiniteElement
|
||||
LinearWedgeFiniteElement();
|
||||
|
||||
/** @brief virtual function which evaluates the values of all
|
||||
shape functions at a given point ip and stores
|
||||
them in the vector shape of dimension Dof (4) */
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
|
||||
/** @brief virtual function which evaluates the values of all
|
||||
partial derivatives of all shape functions at a given
|
||||
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
|
||||
so that each row contains the derivatives of one shape function */
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const
|
||||
{ dofs = 0.0; dofs(vertex) = 1.0; }
|
||||
|
||||
/** @brief Get the dofs associated with the given @a face.
|
||||
@a *dofs is set to an internal array of the local dofc on the
|
||||
face, while *ndofs is set to the number of dofs on that face.
|
||||
*/
|
||||
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
|
||||
};
|
||||
|
||||
/// A linear element defined on a square pyramid
|
||||
class LinearPyramidFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct the LinearPyramidFiniteElement
|
||||
LinearPyramidFiniteElement();
|
||||
|
||||
/** @brief virtual function which evaluates the values of all
|
||||
shape functions at a given point ip and stores
|
||||
them in the vector shape of dimension Dof (4) */
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
|
||||
/** @brief virtual function which evaluates the values of all
|
||||
partial derivatives of all shape functions at a given
|
||||
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
|
||||
so that each row contains the derivatives of one shape function */
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const
|
||||
{ dofs = 0.0; dofs(vertex) = 1.0; }
|
||||
|
||||
/** @brief Get the dofs associated with the given @a face.
|
||||
@a *dofs is set to an internal array of the local dofc on the
|
||||
face, while *ndofs is set to the number of dofs on that face.
|
||||
*/
|
||||
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
|
||||
};
|
||||
|
||||
/// A 2D constant element on a triangle
|
||||
class P0TriangleFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
@@ -1748,32 +1690,6 @@ public:
|
||||
{ dofs(0) = 1.0; }
|
||||
};
|
||||
|
||||
/// A 3D constant element on a wedge
|
||||
class P0WdgFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct the P0WdgFiniteElement
|
||||
P0WdgFiniteElement ();
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const
|
||||
{ dofs(0) = 1.0; }
|
||||
};
|
||||
|
||||
/// A 3D constant element on a pyramid
|
||||
class P0PyrFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct the P0PyrFiniteElement
|
||||
P0PyrFiniteElement ();
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const
|
||||
{ dofs(0) = 1.0; }
|
||||
};
|
||||
|
||||
/** @brief Tensor products of 1D Lagrange1DFiniteElement
|
||||
(only degree 2 is functional) */
|
||||
class LagrangeHexFiniteElement : public NodalFiniteElement
|
||||
@@ -1912,10 +1828,6 @@ public:
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -1940,66 +1852,6 @@ public:
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
};
|
||||
|
||||
|
||||
/// A 3D 1st order Nedelec element on a wedge
|
||||
class Nedelec1WdgFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double tk[9][3];
|
||||
|
||||
public:
|
||||
/// Construct the Nedelec1WdgFiniteElement
|
||||
Nedelec1WdgFiniteElement();
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_ND(Trans, shape); }
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
};
|
||||
|
||||
|
||||
/// A 3D 1st order Nedelec element on a pyramid
|
||||
class Nedelec1PyrFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double tk[8][3];
|
||||
|
||||
public:
|
||||
/// Construct the Nedelec1PyrFiniteElement
|
||||
Nedelec1PyrFiniteElement();
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_ND(Trans, shape); }
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -2093,77 +1945,6 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/// A 3D 0th order Raviert-Thomas element on a wedge
|
||||
class RT0WdgFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double nk[5][3];
|
||||
|
||||
public:
|
||||
/// Construct the RT0WdgFiniteElement
|
||||
RT0WdgFiniteElement();
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_RT(Trans, shape); }
|
||||
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
using FiniteElement::Project;
|
||||
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const;
|
||||
};
|
||||
|
||||
|
||||
/// A 3D 0th order Raviert-Thomas element on a pyramid
|
||||
class RT0PyrFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double nk[5][3];
|
||||
|
||||
// If true match RT0TetFiniteElement rather than RT_TetrahedronElement(0)
|
||||
bool rt0;
|
||||
|
||||
public:
|
||||
/// Construct the RT0PyrFiniteElement
|
||||
RT0PyrFiniteElement(bool rt0tets = true);
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_RT(Trans, shape); }
|
||||
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
using FiniteElement::Project;
|
||||
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const;
|
||||
};
|
||||
|
||||
|
||||
class RotTriLinearHexFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
|
||||
+15
-121
@@ -33,9 +33,6 @@ int FiniteElementCollection::HasFaceDofs(Geometry::Type geom, int p) const
|
||||
case Geometry::PRISM:
|
||||
return max(GetNumDof(Geometry::TRIANGLE, p),
|
||||
GetNumDof(Geometry::SQUARE, p));
|
||||
case Geometry::PYRAMID:
|
||||
return max(GetNumDof(Geometry::TRIANGLE, p),
|
||||
GetNumDof(Geometry::SQUARE, p));
|
||||
default:
|
||||
MFEM_ABORT("unknown geometry type");
|
||||
}
|
||||
@@ -577,7 +574,6 @@ LinearFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
default:
|
||||
mfem_error ("LinearFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -595,7 +591,6 @@ int LinearFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PRISM: return 0;
|
||||
case Geometry::PYRAMID: return 0;
|
||||
default:
|
||||
mfem_error ("LinearFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1245,7 +1240,6 @@ Const3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
default:
|
||||
mfem_error ("Const3DFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1263,7 +1257,6 @@ int Const3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TETRAHEDRON: return 1;
|
||||
case Geometry::CUBE: return 1;
|
||||
case Geometry::PRISM: return 1;
|
||||
case Geometry::PYRAMID: return 1;
|
||||
default:
|
||||
mfem_error ("Const3DFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1284,8 +1277,6 @@ LinearDiscont3DFECollection::FiniteElementForGeometry(
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
default:
|
||||
mfem_error ("LinearDiscont3DFECollection: unknown geometry type.");
|
||||
@@ -1302,8 +1293,6 @@ int LinearDiscont3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TRIANGLE: return 0;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 4;
|
||||
case Geometry::PYRAMID: return 5;
|
||||
case Geometry::PRISM: return 6;
|
||||
case Geometry::CUBE: return 8;
|
||||
default:
|
||||
mfem_error ("LinearDiscont3DFECollection: unknown geometry type.");
|
||||
@@ -1405,8 +1394,6 @@ ND1_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
case Geometry::CUBE: return &HexahedronFE;
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
default:
|
||||
mfem_error ("ND1_3DFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1423,8 +1410,6 @@ int ND1_3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PRISM: return 0;
|
||||
case Geometry::PYRAMID: return 0;
|
||||
default:
|
||||
mfem_error ("ND1_3DFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1454,8 +1439,6 @@ RT0_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::SQUARE: return &QuadrilateralFE;
|
||||
case Geometry::CUBE: return &HexahedronFE;
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
default:
|
||||
mfem_error ("RT0_3DFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1472,8 +1455,6 @@ int RT0_3DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::SQUARE: return 1;
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PRISM: return 0;
|
||||
case Geometry::PYRAMID: return 0;
|
||||
default:
|
||||
mfem_error ("RT0_3DFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1749,7 +1730,6 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
H1_dof[Geometry::TETRAHEDRON] = (TriDof*pm3)/3;
|
||||
H1_dof[Geometry::CUBE] = QuadDof*pm1;
|
||||
H1_dof[Geometry::PRISM] = TriDof*pm1;
|
||||
H1_dof[Geometry::PYRAMID] = 0;
|
||||
if (b_type == BasisType::Positive)
|
||||
{
|
||||
H1_Elements[Geometry::TETRAHEDRON] = new H1Pos_TetrahedronElement(p);
|
||||
@@ -1763,7 +1743,6 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
H1_Elements[Geometry::CUBE] = new H1_HexahedronElement(p, btype);
|
||||
H1_Elements[Geometry::PRISM] = new H1_WedgeElement(p, btype);
|
||||
}
|
||||
H1_Elements[Geometry::PYRAMID] = new LinearPyramidFiniteElement;
|
||||
|
||||
const int &TetDof = H1_dof[Geometry::TETRAHEDRON];
|
||||
TetDofOrd[0] = new int[24*TetDof];
|
||||
@@ -1858,21 +1837,6 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
H1_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
if (GeomType != Geometry::PYRAMID || this->GetOrder() == 1)
|
||||
{
|
||||
return H1_Elements[GeomType];
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("H1 Pyramid basis functions are not yet supported "
|
||||
"for order > 1.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const int *H1_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const
|
||||
{
|
||||
@@ -2112,12 +2076,9 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
L2_Elements[Geometry::CUBE] = new L2_HexahedronElement(p, btype);
|
||||
L2_Elements[Geometry::PRISM] = new L2_WedgeElement(p, btype);
|
||||
}
|
||||
L2_Elements[Geometry::PYRAMID] = new P0PyrFiniteElement;
|
||||
|
||||
L2_Elements[Geometry::TETRAHEDRON]->SetMapType(map_type);
|
||||
L2_Elements[Geometry::CUBE]->SetMapType(map_type);
|
||||
L2_Elements[Geometry::PRISM]->SetMapType(map_type);
|
||||
L2_Elements[Geometry::PYRAMID]->SetMapType(map_type);
|
||||
// Trace element use the default Gauss-Legendre nodal points for positive basis
|
||||
if (b_type == BasisType::Positive)
|
||||
{
|
||||
@@ -2238,21 +2199,6 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
L2_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
if (GeomType != Geometry::PYRAMID || this->GetOrder() == 0)
|
||||
{
|
||||
return L2_Elements[GeomType];
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("L2 Pyramid basis functions are not yet supported "
|
||||
"for order > 0.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const int *L2_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const
|
||||
{
|
||||
@@ -2344,12 +2290,6 @@ RT_FECollection::RT_FECollection(const int order, const int dim,
|
||||
|
||||
RT_Elements[Geometry::CUBE] = new RT_HexahedronElement(p, cb_type, ob_type);
|
||||
RT_dof[Geometry::CUBE] = 3*p*pp1*pp1;
|
||||
|
||||
RT_Elements[Geometry::PRISM] = new RT0WdgFiniteElement;
|
||||
RT_dof[Geometry::PRISM] = 0;
|
||||
|
||||
RT_Elements[Geometry::PYRAMID] = new RT0PyrFiniteElement(false);
|
||||
RT_dof[Geometry::PYRAMID] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2493,22 +2433,6 @@ void RT_FECollection::InitFaces(const int p, const int dim,
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
RT_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
if ((GeomType != Geometry::PRISM && GeomType != Geometry::PYRAMID) ||
|
||||
this->GetOrder() == 1)
|
||||
{
|
||||
return RT_Elements[GeomType];
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("RT Wedge and Pyramid basis functions are not yet supported "
|
||||
"for order > 0.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const int *RT_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const
|
||||
{
|
||||
@@ -2732,31 +2656,18 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
|
||||
{
|
||||
for (int i = 0; i + j <= pm2; i++)
|
||||
{
|
||||
int k0 = p*pm1 - (p - j)*(pm1 - j) + 2*i;
|
||||
int k1 = 2*pm2 - 2*i + ((2*p-3)-j)*j;
|
||||
int k2 = 2*pm2 - 2*j + ((2*p-3)-i)*i;
|
||||
int k3 = p*pm1 - 2 - 3*j - i - (i+j)*(i+j);
|
||||
int k4 = p*pm1 - 2 - 3*i - j - (i+j)*(i+j);
|
||||
int k5 = p*pm1 - (p - i)*(pm1 - i) + 2*j;
|
||||
|
||||
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][k0 ] = k0;
|
||||
TriDofOrd[0][k0+1] = k0 + 1;
|
||||
// (1,0,2)
|
||||
TriDofOrd[1][k0 ] = k1;
|
||||
TriDofOrd[1][k0+1] = k1 + 1;
|
||||
// (2,0,1)
|
||||
TriDofOrd[2][k0 ] = k2;
|
||||
TriDofOrd[2][k0+1] = k2 + 1;
|
||||
// (2,1,0)
|
||||
TriDofOrd[3][k0 ] = k3;
|
||||
TriDofOrd[3][k0+1] = k3 + 1;
|
||||
// (1,2,0)
|
||||
TriDofOrd[4][k0 ] = k4;
|
||||
TriDofOrd[4][k0+1] = k4 + 1;
|
||||
TriDofOrd[0][k1 ] = k1;
|
||||
TriDofOrd[0][k1+1] = k1 + 1;
|
||||
// (0,2,1)
|
||||
TriDofOrd[5][k0 ] = k5;
|
||||
TriDofOrd[5][k0+1] = k5 + 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2769,28 +2680,6 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
|
||||
// TODO: cb_type and ob_type for tets
|
||||
ND_Elements[Geometry::TETRAHEDRON] = new ND_TetrahedronElement(p);
|
||||
ND_dof[Geometry::TETRAHEDRON] = p*pm1*pm2/2;
|
||||
|
||||
ND_Elements[Geometry::PRISM] = new Nedelec1WdgFiniteElement;
|
||||
ND_dof[Geometry::PRISM] = 0;
|
||||
|
||||
ND_Elements[Geometry::PYRAMID] = new Nedelec1PyrFiniteElement;
|
||||
ND_dof[Geometry::PYRAMID] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
ND_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
if ((GeomType != Geometry::PRISM && GeomType != Geometry::PYRAMID) ||
|
||||
this->GetOrder() == 1)
|
||||
{
|
||||
return ND_Elements[GeomType];
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("ND Wedge and Pyramid basis functions are not yet supported "
|
||||
"for order > 1.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2803,6 +2692,11 @@ const int *ND_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
}
|
||||
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)
|
||||
|
||||
+14
-16
@@ -228,7 +228,8 @@ public:
|
||||
const int btype = BasisType::GaussLobatto);
|
||||
|
||||
virtual const FiniteElement *FiniteElementForGeometry(
|
||||
Geometry::Type GeomType) const;
|
||||
Geometry::Type GeomType) const
|
||||
{ return H1_Elements[GeomType]; }
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const
|
||||
{ return H1_dof[GeomType]; }
|
||||
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
|
||||
@@ -301,7 +302,10 @@ public:
|
||||
const int map_type = FiniteElement::VALUE);
|
||||
|
||||
virtual const FiniteElement *FiniteElementForGeometry(
|
||||
Geometry::Type GeomType) const;
|
||||
Geometry::Type GeomType) const
|
||||
{
|
||||
return L2_Elements[GeomType];
|
||||
}
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
if (L2_Elements[GeomType])
|
||||
@@ -367,7 +371,8 @@ public:
|
||||
const int ob_type = BasisType::GaussLegendre);
|
||||
|
||||
virtual const FiniteElement *FiniteElementForGeometry(
|
||||
Geometry::Type GeomType) const;
|
||||
Geometry::Type GeomType) const
|
||||
{ return RT_Elements[GeomType]; }
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const
|
||||
{ return RT_dof[GeomType]; }
|
||||
virtual const int *DofOrderForOrientation(Geometry::Type GeomType,
|
||||
@@ -425,7 +430,8 @@ public:
|
||||
const int ob_type = BasisType::GaussLegendre);
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{ return ND_Elements[GeomType]; }
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const
|
||||
{ return ND_dof[GeomType]; }
|
||||
@@ -523,10 +529,9 @@ private:
|
||||
const BiLinear2DFiniteElement QuadrilateralFE;
|
||||
const Linear3DFiniteElement TetrahedronFE;
|
||||
const TriLinear3DFiniteElement ParallelepipedFE;
|
||||
const LinearWedgeFiniteElement WedgeFE;
|
||||
const LinearPyramidFiniteElement PyramidFE;
|
||||
const H1_WedgeElement WedgeFE;
|
||||
public:
|
||||
LinearFECollection() : FiniteElementCollection(1) { }
|
||||
LinearFECollection() : FiniteElementCollection(1), WedgeFE(1) { }
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
@@ -931,11 +936,10 @@ class Const3DFECollection : public FiniteElementCollection
|
||||
private:
|
||||
const P0TetFiniteElement TetrahedronFE;
|
||||
const P0HexFiniteElement ParallelepipedFE;
|
||||
const P0WdgFiniteElement WedgeFE;
|
||||
const P0PyrFiniteElement PyramidFE;
|
||||
const L2_WedgeElement WedgeFE;
|
||||
|
||||
public:
|
||||
Const3DFECollection() : FiniteElementCollection(0) { }
|
||||
Const3DFECollection() : FiniteElementCollection(0), WedgeFE(0) { }
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
@@ -956,8 +960,6 @@ class LinearDiscont3DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const Linear3DFiniteElement TetrahedronFE;
|
||||
const LinearPyramidFiniteElement PyramidFE;
|
||||
const LinearWedgeFiniteElement WedgeFE;
|
||||
const TriLinear3DFiniteElement ParallelepipedFE;
|
||||
|
||||
public:
|
||||
@@ -1034,8 +1036,6 @@ class ND1_3DFECollection : public FiniteElementCollection
|
||||
private:
|
||||
const Nedelec1HexFiniteElement HexahedronFE;
|
||||
const Nedelec1TetFiniteElement TetrahedronFE;
|
||||
const Nedelec1WdgFiniteElement WedgeFE;
|
||||
const Nedelec1PyrFiniteElement PyramidFE;
|
||||
|
||||
public:
|
||||
ND1_3DFECollection() : FiniteElementCollection(1) { }
|
||||
@@ -1061,8 +1061,6 @@ private:
|
||||
const P0QuadFiniteElement QuadrilateralFE;
|
||||
const RT0HexFiniteElement HexahedronFE;
|
||||
const RT0TetFiniteElement TetrahedronFE;
|
||||
const RT0WdgFiniteElement WedgeFE;
|
||||
const RT0PyrFiniteElement PyramidFE;
|
||||
public:
|
||||
RT0_3DFECollection() : FiniteElementCollection(1) { }
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "geom.hpp"
|
||||
#include "fe.hpp"
|
||||
#include "fe_coll.hpp"
|
||||
#include "doftrans.hpp"
|
||||
#include "eltrans.hpp"
|
||||
#include "coefficient.hpp"
|
||||
#include "complex_fem.hpp"
|
||||
|
||||
+50
-323
@@ -58,12 +58,9 @@ DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
|
||||
|
||||
FiniteElementSpace::FiniteElementSpace()
|
||||
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
|
||||
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
|
||||
bdofs(NULL),
|
||||
elem_dof(NULL), elem_fos(NULL), bdr_elem_dof(NULL), bdr_elem_fos(NULL),
|
||||
face_dof(NULL),
|
||||
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0), bdofs(NULL),
|
||||
elem_dof(NULL), bdr_elem_dof(NULL), face_dof(NULL),
|
||||
NURBSext(NULL), own_ext(false),
|
||||
DoFTrans(0), VDoFTrans(vdim, ordering),
|
||||
cP(NULL), cR(NULL), cR_hp(NULL), cP_is_set(false),
|
||||
Th(Operator::ANY_TYPE),
|
||||
sequence(0), mesh_sequence(0), orders_changed(false), relaxed_hp(false)
|
||||
@@ -72,7 +69,6 @@ FiniteElementSpace::FiniteElementSpace()
|
||||
FiniteElementSpace::FiniteElementSpace(const FiniteElementSpace &orig,
|
||||
Mesh *mesh,
|
||||
const FiniteElementCollection *fec)
|
||||
: VDoFTrans(orig.vdim, orig.ordering)
|
||||
{
|
||||
mesh = mesh ? mesh : orig.mesh;
|
||||
fec = fec ? fec : orig.fec;
|
||||
@@ -263,36 +259,16 @@ void FiniteElementSpace::AdjustVDofs (Array<int> &vdofs)
|
||||
}
|
||||
}
|
||||
|
||||
DofTransformation *
|
||||
FiniteElementSpace::GetElementVDofs(int i, Array<int> &vdofs) const
|
||||
void FiniteElementSpace::GetElementVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
DofTransformation * doftrans = GetElementDofs(i, vdofs);
|
||||
GetElementDofs(i, vdofs);
|
||||
DofsToVDofs(vdofs);
|
||||
if (vdim == 1 || doftrans == NULL)
|
||||
{
|
||||
return doftrans;
|
||||
}
|
||||
else
|
||||
{
|
||||
VDoFTrans.SetDofTransformation(*doftrans);
|
||||
return &VDoFTrans;
|
||||
}
|
||||
}
|
||||
|
||||
DofTransformation *
|
||||
FiniteElementSpace::GetBdrElementVDofs(int i, Array<int> &vdofs) const
|
||||
void FiniteElementSpace::GetBdrElementVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
DofTransformation * doftrans = GetBdrElementDofs(i, vdofs);
|
||||
GetBdrElementDofs(i, vdofs);
|
||||
DofsToVDofs(vdofs);
|
||||
if (vdim == 1 || doftrans == NULL)
|
||||
{
|
||||
return doftrans;
|
||||
}
|
||||
else
|
||||
{
|
||||
VDoFTrans.SetDofTransformation(*doftrans);
|
||||
return &VDoFTrans;
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetFaceVDofs(int i, Array<int> &vdofs) const
|
||||
@@ -331,39 +307,21 @@ void FiniteElementSpace::BuildElementToDofTable() const
|
||||
|
||||
// TODO: can we call GetElementDofs only once per element?
|
||||
Table *el_dof = new Table;
|
||||
Table *el_fos = (mesh->Dimension() > 2) ? (new Table) : NULL;
|
||||
Array<int> dofs;
|
||||
Array<int> F, Fo;
|
||||
el_dof -> MakeI (mesh -> GetNE());
|
||||
if (el_fos) { el_fos -> MakeI (mesh -> GetNE()); }
|
||||
for (int i = 0; i < mesh -> GetNE(); i++)
|
||||
{
|
||||
GetElementDofs (i, dofs);
|
||||
el_dof -> AddColumnsInRow (i, dofs.Size());
|
||||
|
||||
if (el_fos)
|
||||
{
|
||||
mesh->GetElementFaces(i, F, Fo);
|
||||
el_fos -> AddColumnsInRow (i, Fo.Size());
|
||||
}
|
||||
}
|
||||
el_dof -> MakeJ();
|
||||
if (el_fos) { el_fos -> MakeJ(); }
|
||||
for (int i = 0; i < mesh -> GetNE(); i++)
|
||||
{
|
||||
GetElementDofs (i, dofs);
|
||||
el_dof -> AddConnections (i, (int *)dofs, dofs.Size());
|
||||
|
||||
if (el_fos)
|
||||
{
|
||||
mesh->GetElementFaces(i, F, Fo);
|
||||
el_fos -> AddConnections (i, (int *)Fo, Fo.Size());
|
||||
}
|
||||
}
|
||||
el_dof -> ShiftUpI();
|
||||
if (el_fos) { el_fos -> ShiftUpI(); }
|
||||
elem_dof = el_dof;
|
||||
elem_fos = el_fos;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::BuildBdrElementToDofTable() const
|
||||
@@ -417,9 +375,7 @@ void FiniteElementSpace::BuildFaceToDofTable() const
|
||||
void FiniteElementSpace::RebuildElementToDofTable()
|
||||
{
|
||||
delete elem_dof;
|
||||
delete elem_fos;
|
||||
elem_dof = NULL;
|
||||
elem_fos = NULL;
|
||||
BuildElementToDofTable();
|
||||
}
|
||||
|
||||
@@ -1359,10 +1315,8 @@ const FaceQuadratureInterpolator
|
||||
|
||||
SparseMatrix *FiniteElementSpace::RefinementMatrix_main(
|
||||
const int coarse_ndofs, const Table &coarse_elem_dof,
|
||||
const Table *coarse_elem_fos, const DenseTensor localP[]) const
|
||||
const DenseTensor localP[]) const
|
||||
{
|
||||
/// TODO: Implement DofTransformation support
|
||||
|
||||
MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
|
||||
|
||||
Array<int> dofs, coarse_dofs, coarse_vdofs;
|
||||
@@ -1445,8 +1399,7 @@ void FiniteElementSpace::GetLocalRefinementMatrices(
|
||||
}
|
||||
|
||||
SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
|
||||
const Table* old_elem_dof,
|
||||
const Table* old_elem_fos)
|
||||
const Table* old_elem_dof)
|
||||
{
|
||||
MFEM_VERIFY(GetNE() >= old_elem_dof->Size(),
|
||||
"Previous mesh is not coarser.");
|
||||
@@ -1459,16 +1412,13 @@ SparseMatrix* FiniteElementSpace::RefinementMatrix(int old_ndofs,
|
||||
GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
|
||||
}
|
||||
|
||||
return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
|
||||
localP);
|
||||
return RefinementMatrix_main(old_ndofs, *old_elem_dof, localP);
|
||||
}
|
||||
|
||||
FiniteElementSpace::RefinementOperator::RefinementOperator
|
||||
(const FiniteElementSpace* fespace, Table* old_elem_dof, Table* old_elem_fos,
|
||||
int old_ndofs)
|
||||
(const FiniteElementSpace* fespace, Table* old_elem_dof, int old_ndofs)
|
||||
: fespace(fespace)
|
||||
, old_elem_dof(old_elem_dof)
|
||||
, old_elem_fos(old_elem_fos)
|
||||
{
|
||||
MFEM_VERIFY(fespace->GetNE() >= old_elem_dof->Size(),
|
||||
"Previous mesh is not coarser.");
|
||||
@@ -1482,14 +1432,12 @@ FiniteElementSpace::RefinementOperator::RefinementOperator
|
||||
{
|
||||
fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
|
||||
}
|
||||
|
||||
ConstructDoFTrans();
|
||||
}
|
||||
|
||||
FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
const FiniteElementSpace *fespace, const FiniteElementSpace *coarse_fes)
|
||||
: Operator(fespace->GetVSize(), coarse_fes->GetVSize()),
|
||||
fespace(fespace), old_elem_dof(NULL), old_elem_fos(NULL)
|
||||
fespace(fespace), old_elem_dof(NULL)
|
||||
{
|
||||
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
|
||||
|
||||
@@ -1501,50 +1449,11 @@ FiniteElementSpace::RefinementOperator::RefinementOperator(
|
||||
|
||||
// Make a copy of the coarse elem_dof Table.
|
||||
old_elem_dof = new Table(coarse_fes->GetElementToDofTable());
|
||||
|
||||
// Make a copy of the coarse elem_fos Table if it exists.
|
||||
if (coarse_fes->GetElementToFaceOrientationTable())
|
||||
{
|
||||
old_elem_fos = new Table(*coarse_fes->GetElementToFaceOrientationTable());
|
||||
}
|
||||
|
||||
ConstructDoFTrans();
|
||||
}
|
||||
|
||||
FiniteElementSpace::RefinementOperator::~RefinementOperator()
|
||||
{
|
||||
delete old_elem_dof;
|
||||
delete old_elem_fos;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::RefinementOperator
|
||||
::ConstructDoFTrans()
|
||||
{
|
||||
old_DoFTrans.SetSize(Geometry::NUM_GEOMETRIES);
|
||||
for (int i=0; i<old_DoFTrans.Size(); i++)
|
||||
{
|
||||
old_DoFTrans[i] = NULL;
|
||||
}
|
||||
|
||||
const FiniteElementCollection *fec = fespace->FEColl();
|
||||
if (dynamic_cast<const ND_FECollection*>(fec))
|
||||
{
|
||||
const FiniteElement * nd_tri =
|
||||
fec->FiniteElementForGeometry(Geometry::TRIANGLE);
|
||||
if (nd_tri)
|
||||
{
|
||||
old_DoFTrans[Geometry::TRIANGLE] =
|
||||
new ND_TriDofTransformation(nd_tri->GetOrder());
|
||||
}
|
||||
|
||||
const FiniteElement * nd_tet =
|
||||
fec->FiniteElementForGeometry(Geometry::TETRAHEDRON);
|
||||
if (nd_tet)
|
||||
{
|
||||
old_DoFTrans[Geometry::TETRAHEDRON] =
|
||||
new ND_TetDofTransformation(nd_tet->GetOrder());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::RefinementOperator
|
||||
@@ -1553,7 +1462,7 @@ void FiniteElementSpace::RefinementOperator
|
||||
Mesh* mesh = fespace->GetMesh();
|
||||
const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
|
||||
|
||||
Array<int> dofs, vdofs, old_dofs, old_vdofs, old_Fo;
|
||||
Array<int> dofs, vdofs, old_dofs, old_vdofs;
|
||||
|
||||
int vdim = fespace->GetVDim();
|
||||
int old_ndofs = width / vdim;
|
||||
@@ -1568,53 +1477,18 @@ void FiniteElementSpace::RefinementOperator
|
||||
|
||||
subY.SetSize(lP.Height());
|
||||
|
||||
DofTransformation *doftrans = fespace->GetElementDofs(k, dofs);
|
||||
fespace->GetElementDofs(k, dofs);
|
||||
old_elem_dof->GetRow(emb.parent, old_dofs);
|
||||
|
||||
if (!doftrans)
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
dofs.Copy(vdofs);
|
||||
fespace->DofsToVDofs(vd, vdofs);
|
||||
old_dofs.Copy(old_vdofs);
|
||||
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
|
||||
x.GetSubVector(old_vdofs, subX);
|
||||
lP.Mult(subX, subY);
|
||||
y.SetSubVector(vdofs, subY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
old_elem_fos->GetRow(emb.parent, old_Fo);
|
||||
old_DoFTrans[geom]->SetFaceOrientations(old_Fo);
|
||||
|
||||
DofTransformation *new_doftrans = NULL;
|
||||
VDofTransformation *vdoftrans =
|
||||
dynamic_cast<VDofTransformation*>(doftrans);
|
||||
if (vdoftrans)
|
||||
{
|
||||
new_doftrans = doftrans;
|
||||
doftrans = vdoftrans->GetDofTransformation();
|
||||
}
|
||||
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
dofs.Copy(vdofs);
|
||||
fespace->DofsToVDofs(vd, vdofs);
|
||||
old_dofs.Copy(old_vdofs);
|
||||
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
|
||||
x.GetSubVector(old_vdofs, subX);
|
||||
old_DoFTrans[geom]->InvTransformPrimal(subX);
|
||||
lP.Mult(subX, subY);
|
||||
doftrans->TransformPrimal(subY);
|
||||
y.SetSubVector(vdofs, subY);
|
||||
}
|
||||
|
||||
if (vdoftrans)
|
||||
{
|
||||
doftrans = new_doftrans;
|
||||
}
|
||||
dofs.Copy(vdofs);
|
||||
fespace->DofsToVDofs(vd, vdofs);
|
||||
old_dofs.Copy(old_vdofs);
|
||||
fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
|
||||
x.GetSubVector(old_vdofs, subX);
|
||||
lP.Mult(subX, subY);
|
||||
y.SetSubVector(vdofs, subY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1630,12 +1504,12 @@ void FiniteElementSpace::RefinementOperator
|
||||
Array<char> processed(fespace->GetVSize());
|
||||
processed = 0;
|
||||
|
||||
Array<int> f_dofs, c_dofs, f_vdofs, c_vdofs, old_Fo;
|
||||
Array<int> f_dofs, c_dofs, f_vdofs, c_vdofs;
|
||||
|
||||
int vdim = fespace->GetVDim();
|
||||
int old_ndofs = width / vdim;
|
||||
|
||||
Vector subY, subX, subYt, subXt;
|
||||
Vector subY, subX;
|
||||
|
||||
for (int k = 0; k < mesh->GetNE(); k++)
|
||||
{
|
||||
@@ -1643,77 +1517,30 @@ void FiniteElementSpace::RefinementOperator
|
||||
const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
|
||||
const DenseMatrix &lP = localP[geom](emb.matrix);
|
||||
|
||||
DofTransformation * doftrans = fespace->GetElementDofs(k, f_dofs);
|
||||
fespace->GetElementDofs(k, f_dofs);
|
||||
old_elem_dof->GetRow(emb.parent, c_dofs);
|
||||
|
||||
if (!doftrans)
|
||||
subY.SetSize(lP.Width());
|
||||
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
subY.SetSize(lP.Width());
|
||||
f_dofs.Copy(f_vdofs);
|
||||
fespace->DofsToVDofs(vd, f_vdofs);
|
||||
c_dofs.Copy(c_vdofs);
|
||||
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
|
||||
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
x.GetSubVector(f_vdofs, subX);
|
||||
|
||||
for (int p = 0; p < f_dofs.Size(); ++p)
|
||||
{
|
||||
f_dofs.Copy(f_vdofs);
|
||||
fespace->DofsToVDofs(vd, f_vdofs);
|
||||
c_dofs.Copy(c_vdofs);
|
||||
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
|
||||
|
||||
x.GetSubVector(f_vdofs, subX);
|
||||
|
||||
for (int p = 0; p < f_dofs.Size(); ++p)
|
||||
if (processed[DecodeDof(f_dofs[p])])
|
||||
{
|
||||
if (processed[DecodeDof(f_dofs[p])])
|
||||
{
|
||||
subX[p] = 0.0;
|
||||
}
|
||||
subX[p] = 0.0;
|
||||
}
|
||||
|
||||
lP.MultTranspose(subX, subY);
|
||||
y.AddElementVector(c_vdofs, subY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
subYt.SetSize(lP.Width());
|
||||
|
||||
old_elem_fos->GetRow(emb.parent, old_Fo);
|
||||
old_DoFTrans[geom]->SetFaceOrientations(old_Fo);
|
||||
|
||||
DofTransformation *new_doftrans = NULL;
|
||||
VDofTransformation *vdoftrans =
|
||||
dynamic_cast<VDofTransformation*>(doftrans);
|
||||
if (vdoftrans)
|
||||
{
|
||||
new_doftrans = doftrans;
|
||||
doftrans = vdoftrans->GetDofTransformation();
|
||||
}
|
||||
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
f_dofs.Copy(f_vdofs);
|
||||
fespace->DofsToVDofs(vd, f_vdofs);
|
||||
c_dofs.Copy(c_vdofs);
|
||||
fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
|
||||
|
||||
x.GetSubVector(f_vdofs, subX);
|
||||
old_DoFTrans[geom]->InvTransformPrimal(subX);
|
||||
|
||||
for (int p = 0; p < f_dofs.Size(); ++p)
|
||||
{
|
||||
if (processed[DecodeDof(f_dofs[p])])
|
||||
{
|
||||
subX[p] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
lP.MultTranspose(subX, subY);
|
||||
doftrans->TransformPrimal(subY);
|
||||
y.AddElementVector(c_vdofs, subY);
|
||||
}
|
||||
|
||||
if (vdoftrans)
|
||||
{
|
||||
doftrans = new_doftrans;
|
||||
}
|
||||
lP.MultTranspose(subX, subY);
|
||||
y.AddElementVector(c_vdofs, subY);
|
||||
}
|
||||
|
||||
for (int p = 0; p < f_dofs.Size(); ++p)
|
||||
@@ -1723,7 +1550,6 @@ void FiniteElementSpace::RefinementOperator
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: Implement DofTransformation support
|
||||
FiniteElementSpace::DerefinementOperator::DerefinementOperator(
|
||||
const FiniteElementSpace *f_fes, const FiniteElementSpace *c_fes,
|
||||
BilinearFormIntegrator *mass_integ)
|
||||
@@ -1881,11 +1707,8 @@ void FiniteElementSpace::GetLocalDerefinementMatrices(Geometry::Type geom,
|
||||
}
|
||||
|
||||
SparseMatrix* FiniteElementSpace::DerefinementMatrix(int old_ndofs,
|
||||
const Table* old_elem_dof,
|
||||
const Table* old_elem_fos)
|
||||
const Table* old_elem_dof)
|
||||
{
|
||||
/// TODO: Implement DofTransformation support
|
||||
|
||||
MFEM_VERIFY(Nonconforming(), "Not implemented for conforming meshes.");
|
||||
MFEM_VERIFY(old_ndofs, "Missing previous (finer) space.");
|
||||
MFEM_VERIFY(ndofs <= old_ndofs, "Previous space is not finer.");
|
||||
@@ -1991,7 +1814,6 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
|
||||
this->ordering = (Ordering::Type) ordering;
|
||||
|
||||
elem_dof = NULL;
|
||||
elem_fos = NULL;
|
||||
face_dof = NULL;
|
||||
|
||||
sequence = 0;
|
||||
@@ -2019,8 +1841,6 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
|
||||
UpdateNURBS();
|
||||
cP = cR = cR_hp = NULL;
|
||||
cP_is_set = false;
|
||||
|
||||
ConstructDoFTrans();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2028,41 +1848,9 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
|
||||
own_ext = 0;
|
||||
Construct();
|
||||
}
|
||||
|
||||
BuildElementToDofTable();
|
||||
}
|
||||
|
||||
void FiniteElementSpace::ConstructDoFTrans()
|
||||
{
|
||||
DestroyDoFTrans();
|
||||
|
||||
VDoFTrans.SetVDim(vdim);
|
||||
DoFTrans.SetSize(Geometry::NUM_GEOMETRIES);
|
||||
for (int i=0; i<DoFTrans.Size(); i++)
|
||||
{
|
||||
DoFTrans[i] = NULL;
|
||||
}
|
||||
if (mesh->Dimension() < 3) { return; }
|
||||
if (dynamic_cast<const ND_FECollection*>(fec))
|
||||
{
|
||||
const FiniteElement * nd_tri =
|
||||
fec->FiniteElementForGeometry(Geometry::TRIANGLE);
|
||||
if (nd_tri)
|
||||
{
|
||||
DoFTrans[Geometry::TRIANGLE] =
|
||||
new ND_TriDofTransformation(nd_tri->GetOrder());
|
||||
}
|
||||
|
||||
const FiniteElement * nd_tet =
|
||||
fec->FiniteElementForGeometry(Geometry::TETRAHEDRON);
|
||||
if (nd_tet)
|
||||
{
|
||||
DoFTrans[Geometry::TETRAHEDRON] =
|
||||
new ND_TetDofTransformation(nd_tet->GetOrder());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NURBSExtension *FiniteElementSpace::StealNURBSext()
|
||||
{
|
||||
if (NURBSext && !own_ext)
|
||||
@@ -2158,9 +1946,7 @@ void FiniteElementSpace::Construct()
|
||||
"Variable order space requires a nonconforming mesh.");
|
||||
|
||||
elem_dof = NULL;
|
||||
elem_fos = NULL;
|
||||
bdr_elem_dof = NULL;
|
||||
bdr_elem_fos = NULL;
|
||||
face_dof = NULL;
|
||||
|
||||
ndofs = 0;
|
||||
@@ -2258,8 +2044,6 @@ void FiniteElementSpace::Construct()
|
||||
|
||||
ndofs = nvdofs + nedofs + nfdofs + nbdofs;
|
||||
|
||||
ConstructDoFTrans();
|
||||
|
||||
// record the current mesh sequence number to detect refinement etc.
|
||||
mesh_sequence = mesh->GetSequence();
|
||||
|
||||
@@ -2511,22 +2295,14 @@ int FiniteElementSpace::GetNVariants(int entity, int index) const
|
||||
static const char* msg_orders_changed =
|
||||
"Element orders changed, you need to Update() the space first.";
|
||||
|
||||
DofTransformation *
|
||||
FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
|
||||
void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!orders_changed, msg_orders_changed);
|
||||
|
||||
if (elem_dof)
|
||||
{
|
||||
elem_dof->GetRow(elem, dofs);
|
||||
|
||||
if (DoFTrans[mesh->GetElementBaseGeometry(elem)])
|
||||
{
|
||||
Array<int> Fo;
|
||||
elem_fos -> GetRow (elem, Fo);
|
||||
DoFTrans[mesh->GetElementBaseGeometry(elem)]->SetFaceOrientations(Fo);
|
||||
}
|
||||
return DoFTrans[mesh->GetElementBaseGeometry(elem)];
|
||||
return;
|
||||
}
|
||||
|
||||
Array<int> V, E, Eo, F, Fo; // TODO: LocalArray
|
||||
@@ -2550,11 +2326,6 @@ FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
|
||||
{
|
||||
nfd += fec->GetNumDof(mesh->GetFaceGeometry(F[i]), order);
|
||||
}
|
||||
if (DoFTrans[mesh->GetElementBaseGeometry(elem)])
|
||||
{
|
||||
DoFTrans[mesh->GetElementBaseGeometry(elem)]
|
||||
-> SetFaceOrientations(Fo);
|
||||
}
|
||||
}
|
||||
|
||||
dofs.SetSize(0);
|
||||
@@ -2612,7 +2383,6 @@ FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs) const
|
||||
dofs.Append(bbase + j);
|
||||
}
|
||||
}
|
||||
return DoFTrans[mesh->GetElementBaseGeometry(elem)];
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetFE(int i) const
|
||||
@@ -2645,27 +2415,18 @@ const FiniteElement *FiniteElementSpace::GetFE(int i) const
|
||||
return FE;
|
||||
}
|
||||
|
||||
DofTransformation *
|
||||
FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
|
||||
void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!orders_changed, msg_orders_changed);
|
||||
|
||||
if (bdr_elem_dof)
|
||||
{
|
||||
bdr_elem_dof->GetRow(bel, dofs);
|
||||
|
||||
if (DoFTrans[mesh->GetBdrElementBaseGeometry(bel)])
|
||||
{
|
||||
Array<int> Fo;
|
||||
bdr_elem_fos -> GetRow (bel, Fo);
|
||||
DoFTrans[mesh->GetBdrElementBaseGeometry(bel)]->
|
||||
SetFaceOrientations(Fo);
|
||||
}
|
||||
return DoFTrans[mesh->GetBdrElementBaseGeometry(bel)];
|
||||
return;
|
||||
}
|
||||
|
||||
Array<int> V, E, Eo, Fo; // TODO: LocalArray
|
||||
int F, oF;
|
||||
Array<int> V, E, Eo; // TODO: LocalArray
|
||||
int F, Fo;
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
auto geom = mesh->GetBdrElementGeometry(bel);
|
||||
@@ -2684,17 +2445,7 @@ FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
|
||||
|
||||
if (nv) { mesh->GetBdrElementVertices(bel, V); }
|
||||
if (ne) { mesh->GetBdrElementEdges(bel, E, Eo); }
|
||||
if (nf)
|
||||
{
|
||||
mesh->GetBdrElementFace(bel, &F, &oF);
|
||||
|
||||
if (DoFTrans[mesh->GetBdrElementBaseGeometry(bel)])
|
||||
{
|
||||
Fo.Append(oF);
|
||||
DoFTrans[mesh->GetBdrElementBaseGeometry(bel)]->
|
||||
SetFaceOrientations(Fo);
|
||||
}
|
||||
}
|
||||
if (nf) { mesh->GetBdrElementFace(bel, &F, &Fo); }
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + nf);
|
||||
@@ -2727,15 +2478,13 @@ FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs) const
|
||||
if (nf) // face DOFs
|
||||
{
|
||||
int fbase = (var_face_dofs.Size() > 0) ? FindFaceDof(F, nf) : F*nf;
|
||||
const int *ind = fec->GetDofOrdering(geom, order, oF);
|
||||
const int *ind = fec->GetDofOrdering(geom, order, Fo);
|
||||
|
||||
for (int j = 0; j < nf; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
|
||||
}
|
||||
}
|
||||
|
||||
return DoFTrans[mesh->GetBdrElementBaseGeometry(bel)];
|
||||
}
|
||||
|
||||
int FiniteElementSpace::GetFaceDofs(int face, Array<int> &dofs,
|
||||
@@ -3045,8 +2794,6 @@ void FiniteElementSpace::Destroy()
|
||||
}
|
||||
E2BFQ_array.SetSize(0);
|
||||
|
||||
DestroyDoFTrans();
|
||||
|
||||
dof_elem_array.DeleteAll();
|
||||
dof_ldof_array.DeleteAll();
|
||||
|
||||
@@ -3059,9 +2806,7 @@ void FiniteElementSpace::Destroy()
|
||||
else
|
||||
{
|
||||
delete elem_dof;
|
||||
delete elem_fos;
|
||||
delete bdr_elem_dof;
|
||||
delete bdr_elem_fos;
|
||||
delete face_dof;
|
||||
|
||||
delete [] bdofs;
|
||||
@@ -3069,15 +2814,6 @@ void FiniteElementSpace::Destroy()
|
||||
ceed::RemoveBasisAndRestriction(this);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::DestroyDoFTrans()
|
||||
{
|
||||
for (int i = 0; i < DoFTrans.Size(); i++)
|
||||
{
|
||||
delete DoFTrans[i];
|
||||
}
|
||||
DoFTrans.SetSize(0);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetTransferOperator(
|
||||
const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
|
||||
{
|
||||
@@ -3095,8 +2831,6 @@ void FiniteElementSpace::GetTransferOperator(
|
||||
}
|
||||
T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
|
||||
coarse_fes.GetElementToDofTable(),
|
||||
coarse_fes.
|
||||
GetElementToFaceOrientationTable(),
|
||||
localP));
|
||||
}
|
||||
else
|
||||
@@ -3199,7 +2933,6 @@ void FiniteElementSpace::Update(bool want_transform)
|
||||
}
|
||||
|
||||
Table* old_elem_dof = NULL;
|
||||
Table* old_elem_fos = NULL;
|
||||
int old_ndofs;
|
||||
bool old_orders_changed = orders_changed;
|
||||
|
||||
@@ -3207,9 +2940,7 @@ void FiniteElementSpace::Update(bool want_transform)
|
||||
if (want_transform)
|
||||
{
|
||||
old_elem_dof = elem_dof;
|
||||
old_elem_fos = elem_fos;
|
||||
elem_dof = NULL;
|
||||
elem_fos = NULL;
|
||||
old_ndofs = ndofs;
|
||||
}
|
||||
|
||||
@@ -3235,18 +2966,15 @@ void FiniteElementSpace::Update(bool want_transform)
|
||||
{
|
||||
if (Th.Type() != Operator::MFEM_SPARSEMAT)
|
||||
{
|
||||
Th.Reset(new RefinementOperator(this, old_elem_dof,
|
||||
old_elem_fos, old_ndofs));
|
||||
Th.Reset(new RefinementOperator(this, old_elem_dof, old_ndofs));
|
||||
// The RefinementOperator takes ownership of 'old_elem_dof', so
|
||||
// we no longer own it:
|
||||
old_elem_dof = NULL;
|
||||
old_elem_fos = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate fully assembled matrix
|
||||
Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof,
|
||||
old_elem_fos));
|
||||
Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3254,7 +2982,7 @@ void FiniteElementSpace::Update(bool want_transform)
|
||||
case Mesh::DEREFINE:
|
||||
{
|
||||
BuildConformingInterpolation();
|
||||
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
|
||||
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof));
|
||||
if (cP && cR)
|
||||
{
|
||||
Th.SetOperatorOwner(false);
|
||||
@@ -3269,7 +2997,6 @@ void FiniteElementSpace::Update(bool want_transform)
|
||||
}
|
||||
|
||||
delete old_elem_dof;
|
||||
delete old_elem_fos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-30
@@ -16,7 +16,6 @@
|
||||
#include "../linalg/sparsemat.hpp"
|
||||
#include "../mesh/mesh.hpp"
|
||||
#include "fe_coll.hpp"
|
||||
#include "doftrans.hpp"
|
||||
#include "restriction.hpp"
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
@@ -129,9 +128,7 @@ protected:
|
||||
|
||||
// precalculated DOFs for each element, boundary element, and face
|
||||
mutable Table *elem_dof; // owned (except in NURBS FE space)
|
||||
mutable Table *elem_fos; // face orientations by element index
|
||||
mutable Table *bdr_elem_dof; // owned (except in NURBS FE space)
|
||||
mutable Table *bdr_elem_fos; // bdr face orientations by bdr element index
|
||||
mutable Table *face_dof; // owned; in var-order space contains variant 0 DOFs
|
||||
|
||||
Array<int> dof_elem_array, dof_ldof_array;
|
||||
@@ -140,9 +137,6 @@ protected:
|
||||
int own_ext;
|
||||
mutable Array<int> face_to_be; // NURBS FE space only
|
||||
|
||||
Array<DofTransformation*> DoFTrans;
|
||||
mutable VDofTransformation VDoFTrans;
|
||||
|
||||
/** Matrix representing the prolongation from the global conforming dofs to
|
||||
a set of intermediate partially conforming dofs, e.g. the dofs associated
|
||||
with a "cut" space on a non-conforming mesh. */
|
||||
@@ -195,9 +189,6 @@ protected:
|
||||
void Construct();
|
||||
void Destroy();
|
||||
|
||||
void ConstructDoFTrans();
|
||||
void DestroyDoFTrans();
|
||||
|
||||
void BuildElementToDofTable() const;
|
||||
void BuildBdrElementToDofTable() const;
|
||||
void BuildFaceToDofTable() const;
|
||||
@@ -292,19 +283,12 @@ protected:
|
||||
const FiniteElementSpace* fespace;
|
||||
DenseTensor localP[Geometry::NumGeom];
|
||||
Table* old_elem_dof; // Owned.
|
||||
Table* old_elem_fos; // Owned.
|
||||
|
||||
Array<DofTransformation*> old_DoFTrans;
|
||||
mutable VDofTransformation old_VDoFTrans;
|
||||
|
||||
void ConstructDoFTrans();
|
||||
|
||||
public:
|
||||
/** Construct the operator based on the elem_dof table of the original
|
||||
(coarse) space. The class takes ownership of the table. */
|
||||
RefinementOperator(const FiniteElementSpace* fespace,
|
||||
Table *old_elem_dof/*takes ownership*/,
|
||||
Table *old_elem_fos/*takes ownership*/, int old_ndofs);
|
||||
Table *old_elem_dof/*takes ownership*/, int old_ndofs);
|
||||
RefinementOperator(const FiniteElementSpace *fespace,
|
||||
const FiniteElementSpace *coarse_fes);
|
||||
virtual void Mult(const Vector &x, Vector &y) const;
|
||||
@@ -318,7 +302,6 @@ protected:
|
||||
const FiniteElementSpace *fine_fes; // Not owned.
|
||||
DenseTensor localR[Geometry::NumGeom];
|
||||
Table *coarse_elem_dof; // Owned.
|
||||
// Table *coarse_elem_fos; // Owned.
|
||||
Table coarse_to_fine;
|
||||
Array<int> coarse_to_ref_type;
|
||||
Array<Geometry::Type> ref_type_to_geom;
|
||||
@@ -340,7 +323,6 @@ protected:
|
||||
the same vector dimension, vdim. */
|
||||
SparseMatrix *RefinementMatrix_main(const int coarse_ndofs,
|
||||
const Table &coarse_elem_dof,
|
||||
const Table *coarse_elem_fos,
|
||||
const DenseTensor localP[]) const;
|
||||
|
||||
void GetLocalRefinementMatrices(Geometry::Type geom,
|
||||
@@ -351,12 +333,10 @@ protected:
|
||||
/** Calculate explicit GridFunction interpolation matrix (after mesh
|
||||
refinement). NOTE: consider using the RefinementOperator class instead
|
||||
of the fully assembled matrix, which can take a lot of memory. */
|
||||
SparseMatrix* RefinementMatrix(int old_ndofs, const Table* old_elem_dof,
|
||||
const Table* old_elem_fos);
|
||||
SparseMatrix* RefinementMatrix(int old_ndofs, const Table* old_elem_dof);
|
||||
|
||||
/// Calculate GridFunction restriction matrix after mesh derefinement.
|
||||
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof,
|
||||
const Table* old_elem_fos);
|
||||
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof);
|
||||
|
||||
/** @brief Return in @a localP the local refinement matrices that map
|
||||
between fespaces after mesh refinement. */
|
||||
@@ -634,11 +614,10 @@ public:
|
||||
int GetBdrAttribute(int i) const { return mesh->GetBdrAttribute(i); }
|
||||
|
||||
/// Returns indices of degrees of freedom of element 'elem'.
|
||||
virtual DofTransformation *GetElementDofs(int elem, Array<int> &dofs) const;
|
||||
virtual void GetElementDofs(int elem, Array<int> &dofs) const;
|
||||
|
||||
/// Returns indices of degrees of freedom for boundary element 'bel'.
|
||||
virtual DofTransformation *GetBdrElementDofs(int bel,
|
||||
Array<int> &dofs) const;
|
||||
virtual void GetBdrElementDofs(int bel, Array<int> &dofs) const;
|
||||
|
||||
/** @brief Returns the indices of the degrees of freedom for the specified
|
||||
face, including the DOFs for the edges and the vertices of the face. */
|
||||
@@ -687,10 +666,10 @@ public:
|
||||
static void AdjustVDofs(Array<int> &vdofs);
|
||||
|
||||
/// Returns indexes of degrees of freedom in array dofs for i'th element.
|
||||
DofTransformation *GetElementVDofs(int i, Array<int> &vdofs) const;
|
||||
void GetElementVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// Returns indexes of degrees of freedom for i'th boundary element.
|
||||
DofTransformation *GetBdrElementVDofs(int i, Array<int> &vdofs) const;
|
||||
void GetBdrElementVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// Returns indexes of degrees of freedom for i'th face element (2D and 3D).
|
||||
void GetFaceVDofs(int i, Array<int> &vdofs) const;
|
||||
@@ -716,8 +695,6 @@ public:
|
||||
is preserved. */
|
||||
void ReorderElementToDofTable();
|
||||
|
||||
const Table *GetElementToFaceOrientationTable() const { return elem_fos; }
|
||||
|
||||
/** @brief Return a reference to the internal Table that stores the lists of
|
||||
scalar dofs, for each mesh element, as returned by GetElementDofs(). */
|
||||
const Table &GetElementToDofTable() const { return *elem_dof; }
|
||||
|
||||
+7
-262
@@ -11,19 +11,15 @@
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../mesh/wedge.hpp"
|
||||
#include "../mesh/pyramid.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
const char *Geometry::Name[NumGeom] =
|
||||
{
|
||||
"Point", "Segment", "Triangle", "Square", "Tetrahedron", "Cube", "Prism",
|
||||
"Pyramid"
|
||||
};
|
||||
{ "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, 1./3 };
|
||||
{ 1.0, 1.0, 0.5, 1.0, 1./6, 1.0, 0.5 };
|
||||
|
||||
Geometry::Geometry()
|
||||
{
|
||||
@@ -143,28 +139,6 @@ Geometry::Geometry()
|
||||
GeomVert[6]->IntPoint(5).y = 1.0;
|
||||
GeomVert[6]->IntPoint(5).z = 1.0;
|
||||
|
||||
// Vertices for Geometry::PYRAMID
|
||||
GeomVert[7] = new IntegrationRule(5);
|
||||
GeomVert[7]->IntPoint(0).x = 0.0;
|
||||
GeomVert[7]->IntPoint(0).y = 0.0;
|
||||
GeomVert[7]->IntPoint(0).z = 0.0;
|
||||
|
||||
GeomVert[7]->IntPoint(1).x = 1.0;
|
||||
GeomVert[7]->IntPoint(1).y = 0.0;
|
||||
GeomVert[7]->IntPoint(1).z = 0.0;
|
||||
|
||||
GeomVert[7]->IntPoint(2).x = 1.0;
|
||||
GeomVert[7]->IntPoint(2).y = 1.0;
|
||||
GeomVert[7]->IntPoint(2).z = 0.0;
|
||||
|
||||
GeomVert[7]->IntPoint(3).x = 0.0;
|
||||
GeomVert[7]->IntPoint(3).y = 1.0;
|
||||
GeomVert[7]->IntPoint(3).z = 0.0;
|
||||
|
||||
GeomVert[7]->IntPoint(4).x = 0.0;
|
||||
GeomVert[7]->IntPoint(4).y = 0.0;
|
||||
GeomVert[7]->IntPoint(4).z = 1.0;
|
||||
|
||||
GeomCenter[POINT].x = 0.0;
|
||||
GeomCenter[POINT].y = 0.0;
|
||||
GeomCenter[POINT].z = 0.0;
|
||||
@@ -193,10 +167,6 @@ Geometry::Geometry()
|
||||
GeomCenter[PRISM].y = 1.0 / 3.0;
|
||||
GeomCenter[PRISM].z = 0.5;
|
||||
|
||||
GeomCenter[PYRAMID].x = 0.375;
|
||||
GeomCenter[PYRAMID].y = 0.375;
|
||||
GeomCenter[PYRAMID].z = 0.25;
|
||||
|
||||
GeomToPerfGeomJac[POINT] = NULL;
|
||||
GeomToPerfGeomJac[SEGMENT] = new DenseMatrix(1);
|
||||
GeomToPerfGeomJac[TRIANGLE] = new DenseMatrix(2);
|
||||
@@ -204,7 +174,6 @@ Geometry::Geometry()
|
||||
GeomToPerfGeomJac[TETRAHEDRON] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[CUBE] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[PRISM] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[PYRAMID] = new DenseMatrix(3);
|
||||
|
||||
PerfGeomToGeomJac[POINT] = NULL;
|
||||
PerfGeomToGeomJac[SEGMENT] = NULL;
|
||||
@@ -213,7 +182,6 @@ Geometry::Geometry()
|
||||
PerfGeomToGeomJac[TETRAHEDRON] = new DenseMatrix(3);
|
||||
PerfGeomToGeomJac[CUBE] = NULL;
|
||||
PerfGeomToGeomJac[PRISM] = new DenseMatrix(3);
|
||||
PerfGeomToGeomJac[PYRAMID] = new DenseMatrix(3);
|
||||
|
||||
GeomToPerfGeomJac[SEGMENT]->Diag(1.0, 1);
|
||||
{
|
||||
@@ -242,14 +210,6 @@ Geometry::Geometry()
|
||||
*GeomToPerfGeomJac[PRISM] = pri_T.Jacobian();
|
||||
CalcInverse(pri_T.Jacobian(), *PerfGeomToGeomJac[PRISM]);
|
||||
}
|
||||
{
|
||||
IsoparametricTransformation pyr_T;
|
||||
pyr_T.SetFE(&PyramidFE);
|
||||
GetPerfPointMat (PYRAMID, pyr_T.GetPointMat());
|
||||
pyr_T.SetIntPoint(&GeomCenter[PYRAMID]);
|
||||
*GeomToPerfGeomJac[PYRAMID] = pyr_T.Jacobian();
|
||||
CalcInverse(pyr_T.Jacobian(), *PerfGeomToGeomJac[PYRAMID]);
|
||||
}
|
||||
}
|
||||
|
||||
Geometry::~Geometry()
|
||||
@@ -273,7 +233,6 @@ const IntegrationRule * Geometry::GetVertices(int GeomType)
|
||||
case Geometry::TETRAHEDRON: return GeomVert[4];
|
||||
case Geometry::CUBE: return GeomVert[5];
|
||||
case Geometry::PRISM: return GeomVert[6];
|
||||
case Geometry::PYRAMID: return GeomVert[7];
|
||||
default:
|
||||
mfem_error ("Geometry::GetVertices(...)");
|
||||
}
|
||||
@@ -351,25 +310,6 @@ void Geometry::GetRandomPoint(int GeomType, IntegrationPoint &ip)
|
||||
ip.y = 1.0 - ip.y;
|
||||
}
|
||||
break;
|
||||
case Geometry::PYRAMID:
|
||||
ip.x = double(rand()) / RAND_MAX;
|
||||
ip.y = double(rand()) / RAND_MAX;
|
||||
ip.z = double(rand()) / RAND_MAX;
|
||||
if (ip.x + ip.z > 1.0 && ip.y < ip.x)
|
||||
{
|
||||
double x = ip.x;
|
||||
ip.x = ip.y;
|
||||
ip.y = 1.0 - ip.z;
|
||||
ip.z = 1.0 - x;
|
||||
}
|
||||
else if (ip.y + ip.z > 1.0)
|
||||
{
|
||||
double z = ip.z;
|
||||
ip.z = 1.0 - ip.y;
|
||||
ip.y = ip.x;
|
||||
ip.x = 1.0 - z;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
}
|
||||
@@ -431,10 +371,6 @@ bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip)
|
||||
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;
|
||||
case Geometry::PYRAMID:
|
||||
if (ip.x < 0.0 || ip.y < 0.0 || ip.x+ip.z > 1.0 || ip.y+ip.z > 1.0 ||
|
||||
ip.z < 0.0 || ip.z > 1.0) { return false; }
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
}
|
||||
@@ -505,17 +441,6 @@ bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip, double eps)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Geometry::PYRAMID:
|
||||
if (internal::FuzzyLT(ip.x, 0.0, eps)
|
||||
|| internal::FuzzyLT(ip.y, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.x+ip.z, 1.0, eps)
|
||||
|| internal::FuzzyGT(ip.y+ip.z, 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!");
|
||||
}
|
||||
@@ -630,16 +555,6 @@ bool Geometry::ProjectPoint(int GeomType, const IntegrationPoint &beg,
|
||||
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);
|
||||
}
|
||||
case Geometry::PYRAMID:
|
||||
{
|
||||
double lend[6] = { end.x, end.y, end.z,
|
||||
1.0-end.x-end.z, 1.0-end.y-end.z, 1.0-end.z
|
||||
};
|
||||
double lbeg[6] = { beg.x, beg.y, beg.z,
|
||||
1.0-beg.x-beg.z, 1.0-beg.y-beg.z, 1.0-beg.z
|
||||
};
|
||||
return internal::IntersectSegment<6,3>(lbeg, lend, end);
|
||||
}
|
||||
default:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
}
|
||||
@@ -737,43 +652,6 @@ bool Geometry::ProjectPoint(int GeomType, IntegrationPoint &ip)
|
||||
return in_tri && in_z;
|
||||
}
|
||||
|
||||
case PYRAMID:
|
||||
{
|
||||
if (ip.x < 0.0)
|
||||
{
|
||||
ip.x = 0.0;
|
||||
internal::ProjectTriangle(ip.y, ip.z);
|
||||
return false;
|
||||
}
|
||||
if (ip.y < 0.0)
|
||||
{
|
||||
ip.y = 0.0;
|
||||
internal::ProjectTriangle(ip.x, ip.z);
|
||||
return false;
|
||||
}
|
||||
if (ip.z < 0.0)
|
||||
{
|
||||
ip.z = 0.0;
|
||||
if (ip.x > 1.0) { ip.x = 1.0; }
|
||||
if (ip.y > 1.0) { ip.y = 1.0; }
|
||||
return false;
|
||||
}
|
||||
if (ip.x >= ip.y)
|
||||
{
|
||||
bool in_y = true;
|
||||
bool in_tri = internal::ProjectTriangle(ip.x, ip.z);
|
||||
if (ip.y > ip.z) { in_y = false; ip.y = ip.z; }
|
||||
return in_tri && in_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool in_x = true;
|
||||
bool in_tri = internal::ProjectTriangle(ip.y, ip.z);
|
||||
if (ip.x > ip.z) { in_x = false; ip.x = ip.z; }
|
||||
return in_tri && in_x;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
}
|
||||
@@ -848,17 +726,6 @@ void Geometry::GetPerfPointMat(int GeomType, DenseMatrix &pm)
|
||||
}
|
||||
break;
|
||||
|
||||
case Geometry::PYRAMID:
|
||||
{
|
||||
pm.SetSize (3, 5);
|
||||
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.5; pm(1,4) = 0.5; pm(2,4) = 0.7071067811865475;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
mfem_error ("Geometry::GetPerfPointMat (...)");
|
||||
}
|
||||
@@ -877,13 +744,13 @@ void Geometry::JacToPerfJac(int GeomType, const DenseMatrix &J,
|
||||
}
|
||||
}
|
||||
|
||||
const int Geometry::NumBdrArray[NumGeom] = { 0, 2, 3, 4, 4, 6, 5, 5 };
|
||||
const int Geometry::Dimension[NumGeom] = { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
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, 5 };
|
||||
const int Geometry::NumEdges[NumGeom] = { 0, 1, 3, 4, 6, 12, 9, 8 };
|
||||
const int Geometry::NumFaces[NumGeom] = { 0, 0, 1, 1, 4, 6, 5, 5 };
|
||||
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}};
|
||||
@@ -1030,30 +897,6 @@ Constants<Geometry::PRISM>::VertToVert::J[9][2] =
|
||||
{5, 4} // 4,5:4
|
||||
};
|
||||
|
||||
const int Geometry::
|
||||
Constants<Geometry::PYRAMID>::Edges[8][2] =
|
||||
{{0, 1}, {1, 2}, {3, 2}, {0, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PYRAMID>::FaceTypes[5] =
|
||||
{
|
||||
Geometry::SQUARE,
|
||||
Geometry::TRIANGLE, Geometry::TRIANGLE,
|
||||
Geometry::TRIANGLE, Geometry::TRIANGLE
|
||||
};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PYRAMID>::FaceVert[5][4] =
|
||||
{{3, 2, 1, 0}, {0, 1, 4, -1}, {1, 2, 4, -1}, {2, 3, 4, -1}, {3, 0, 4, -1}};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PYRAMID>::VertToVert::I[5] = {0, 3, 5, 7, 8};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PYRAMID>::VertToVert::J[8][2] =
|
||||
{
|
||||
{1, 0}, {3, 3}, {4, 4}, // 0,1:0 0,3:3 0,4:4
|
||||
{2, 1}, {4, 5}, // 1,2:1 1,4:5
|
||||
{3,-3}, {4, 6}, // 2,3:-3 2,4:6
|
||||
{4, 7} // 3,4:7
|
||||
};
|
||||
|
||||
|
||||
GeometryRefiner::GeometryRefiner()
|
||||
{
|
||||
@@ -1419,104 +1262,6 @@ RefinedGeometry * GeometryRefiner::Refine(Geometry::Type Geom,
|
||||
return RG;
|
||||
}
|
||||
|
||||
case Geometry::PYRAMID:
|
||||
{
|
||||
const int n = Times;
|
||||
RG = new RefinedGeometry ((n+1)*(n+2)*(2*n+3)/6,
|
||||
5*n*(2*n-1)*(2*n+1)/3, 0);
|
||||
RG->Times = Times;
|
||||
RG->ETimes = ETimes;
|
||||
RG->Type = type;
|
||||
// enumerate and define the vertices
|
||||
m = 0;
|
||||
for (k = 0; k <= n; k++)
|
||||
{
|
||||
const double *cpij =
|
||||
poly1d.GetPoints(Times - k, BasisType::GetNodalBasis(type));
|
||||
for (j = 0; j <= n - k; j++)
|
||||
for (i = 0; i <= n - k; i++)
|
||||
{
|
||||
IntegrationPoint &ip = RG->RefPts.IntPoint(m);
|
||||
if (type == 0)
|
||||
{
|
||||
ip.x = (n > k) ? (double(i) / (n - k)) : 0.0;
|
||||
ip.y = (n > k) ? (double(j) / (n - k)) : 0.0;
|
||||
ip.z = double(k) / n;
|
||||
}
|
||||
else
|
||||
{
|
||||
ip.x = cpij[i] * (1.0 - cp[k]);
|
||||
ip.y = cpij[j] * (1.0 - cp[k]);
|
||||
ip.z = cp[k];
|
||||
}
|
||||
m++;
|
||||
}
|
||||
}
|
||||
if (m != (n+1)*(n+2)*(2*n+3)/6)
|
||||
{
|
||||
mfem_error("GeometryRefiner::Refine() for PYRAMID #1");
|
||||
}
|
||||
// elements
|
||||
Array<int> &G = RG->RefGeoms;
|
||||
m = 0;
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
int lk = k * (k * (2 * k - 6 * n - 9) + 6 * n * (n + 3) + 13) / 6;
|
||||
int lkp1 = (k + 1) *
|
||||
(k * (2 * k - 6 * n -5) + 6 * n * (n + 2) + 6) / 6;
|
||||
for (j = 0; j < n - k; j++)
|
||||
{
|
||||
for (i = 0; i < n - k; i++)
|
||||
{
|
||||
G[m++] = lk + j * (n - k + 1) + i;
|
||||
G[m++] = lk + j * (n - k + 1) + i + 1;
|
||||
G[m++] = lk + (j + 1) * (n - k + 1) + i + 1;
|
||||
G[m++] = lk + (j + 1) * (n - k + 1) + i;
|
||||
G[m++] = lkp1 + j * (n - k) + i;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < n - k - 1; j++)
|
||||
{
|
||||
for (i = 0; i < n - k - 1; i++)
|
||||
{
|
||||
G[m++] = lkp1 + j * (n - k) + i;
|
||||
G[m++] = lkp1 + (j + 1) * (n - k) + i;
|
||||
G[m++] = lkp1 + (j + 1) * (n - k) + i + 1;
|
||||
G[m++] = lkp1 + j * (n - k) + i + 1;
|
||||
G[m++] = lk + (j + 1) * (n - k + 1) + i + 1;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < n - k; j++)
|
||||
{
|
||||
for (i = 0; i < n - k - 1; i++)
|
||||
{
|
||||
G[m++] = lk + j * (n - k + 1) + i + 1;
|
||||
G[m++] = lk + (j + 1) * (n - k + 1) + i + 1;
|
||||
G[m++] = lkp1 + j * (n - k) + i;
|
||||
G[m++] = lkp1 + j * (n - k) + i + 1;
|
||||
G[m++] = -1;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < n - k - 1; j++)
|
||||
{
|
||||
for (i = 0; i < n - k; i++)
|
||||
{
|
||||
G[m++] = lk + (j + 1) * (n - k + 1) + i;
|
||||
G[m++] = lk + (j + 1) * (n - k + 1) + i + 1;
|
||||
G[m++] = lkp1 + (j + 1) * (n - k) + i;
|
||||
G[m++] = lkp1 + j * (n - k) + i;
|
||||
G[m++] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m != 5*n*(2*n-1)*(2*n+1)/3)
|
||||
{
|
||||
mfem_error("GeometryRefiner::Refine() for PYRAMID #2");
|
||||
}
|
||||
RGeom[Geometry::PYRAMID].Append(RG);
|
||||
return RG;
|
||||
}
|
||||
|
||||
case Geometry::PRISM:
|
||||
{
|
||||
const int n = Times;
|
||||
|
||||
+2
-22
@@ -27,7 +27,6 @@ namespace mfem
|
||||
Geometry::TETRAHEDRON - w/ vert. (0,0,0),(1,0,0),(0,1,0),(0,0,1)
|
||||
Geometry::CUBE - the unit cube
|
||||
Geometry::PRISM - w/ vert. (0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,0,1),(0,1,1)
|
||||
Geometry::PYRAMID - w/ vert. (0,0,0),(1,0,0),(1,1,0),(0,1,0),(0,0,1)
|
||||
*/
|
||||
class Geometry
|
||||
{
|
||||
@@ -35,7 +34,7 @@ public:
|
||||
enum Type
|
||||
{
|
||||
INVALID = -1,
|
||||
POINT = 0, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM, PYRAMID,
|
||||
POINT = 0, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM,
|
||||
NUM_GEOMETRIES
|
||||
};
|
||||
|
||||
@@ -252,26 +251,7 @@ template <> struct Geometry::Constants<Geometry::PRISM>
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct Geometry::Constants<Geometry::PYRAMID>
|
||||
{
|
||||
static const int Dimension = 3;
|
||||
static const int NumVert = 5;
|
||||
static const int NumEdges = 8;
|
||||
static const int Edges[NumEdges][2];
|
||||
static const int NumFaces = 5;
|
||||
static const int FaceTypes[NumFaces];
|
||||
static const int MaxFaceVert = 4;
|
||||
static const int FaceVert[NumFaces][MaxFaceVert];
|
||||
// Upper-triangular part of the local vertex-to-vertex graph.
|
||||
struct VertToVert
|
||||
{
|
||||
static const int I[NumVert];
|
||||
static const int J[NumEdges][2]; // {end,edge_idx}
|
||||
};
|
||||
};
|
||||
|
||||
// Defined in fe.cpp to ensure construction after 'mfem::TriangleFE' and
|
||||
// `mfem::TetrahedronFE`.
|
||||
// Defined in fe.cpp to ensure construction after 'mfem::WedgeFE'.
|
||||
extern Geometry Geometries;
|
||||
|
||||
|
||||
|
||||
+54
-166
@@ -255,8 +255,6 @@ void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi,
|
||||
GridFunction &u = *this;
|
||||
|
||||
ElementTransformation *Transf;
|
||||
DofTransformation *udoftrans;
|
||||
DofTransformation *fdoftrans;
|
||||
|
||||
FiniteElementSpace *ufes = u.FESpace();
|
||||
FiniteElementSpace *ffes = flux.FESpace();
|
||||
@@ -276,23 +274,15 @@ void GridFunction::SumFluxAndCount(BilinearFormIntegrator &blfi,
|
||||
continue;
|
||||
}
|
||||
|
||||
udoftrans = ufes->GetElementVDofs(i, udofs);
|
||||
fdoftrans = ffes->GetElementVDofs(i, fdofs);
|
||||
ufes->GetElementVDofs(i, udofs);
|
||||
ffes->GetElementVDofs(i, fdofs);
|
||||
|
||||
u.GetSubVector(udofs, ul);
|
||||
if (udoftrans)
|
||||
{
|
||||
udoftrans->InvTransformPrimal(ul);
|
||||
}
|
||||
|
||||
Transf = ufes->GetElementTransformation(i);
|
||||
blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
|
||||
*ffes->GetFE(i), fl, wcoef);
|
||||
|
||||
if (fdoftrans)
|
||||
{
|
||||
fdoftrans->TransformPrimal(fl);
|
||||
}
|
||||
flux.AddElementVector(fdofs, fl);
|
||||
|
||||
FiniteElementSpace::AdjustVDofs(fdofs);
|
||||
@@ -374,7 +364,7 @@ void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
|
||||
|
||||
int k;
|
||||
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
const FiniteElement *FElem = fes->GetFE(i);
|
||||
const IntegrationRule *ElemVert =
|
||||
Geometries.GetVertices(FElem->GetGeomType());
|
||||
@@ -384,10 +374,6 @@ void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
|
||||
vdim--;
|
||||
Vector loc_data;
|
||||
GetSubVector(vdofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
|
||||
if (FElem->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
@@ -417,7 +403,7 @@ double GridFunction::GetValue(int i, const IntegrationPoint &ip, int vdim)
|
||||
const
|
||||
{
|
||||
Array<int> dofs;
|
||||
DofTransformation * doftrans = fes->GetElementDofs(i, dofs);
|
||||
fes->GetElementDofs(i, dofs);
|
||||
fes->DofsToVDofs(vdim-1, dofs);
|
||||
Vector DofVal(dofs.Size()), LocVec;
|
||||
const FiniteElement *fe = fes->GetFE(i);
|
||||
@@ -432,10 +418,6 @@ const
|
||||
fe->CalcPhysShape(*Tr, DofVal);
|
||||
}
|
||||
GetSubVector(dofs, LocVec);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(LocVec);
|
||||
}
|
||||
|
||||
return (DofVal * LocVec);
|
||||
}
|
||||
@@ -446,13 +428,9 @@ void GridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
|
||||
const FiniteElement *FElem = fes->GetFE(i);
|
||||
int dof = FElem->GetDof();
|
||||
Array<int> vdofs;
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
Vector loc_data;
|
||||
GetSubVector(vdofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
if (FElem->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
Vector shape(dof);
|
||||
@@ -492,35 +470,30 @@ const
|
||||
Array<int> dofs;
|
||||
int n = ir.GetNPoints();
|
||||
vals.SetSize(n);
|
||||
DofTransformation * doftrans = fes->GetElementDofs(i, dofs);
|
||||
fes->GetElementDofs(i, dofs);
|
||||
fes->DofsToVDofs(vdim-1, dofs);
|
||||
const FiniteElement *FElem = fes->GetFE(i);
|
||||
int dof = FElem->GetDof();
|
||||
Vector DofVal(dof), loc_data(dof);
|
||||
GetSubVector(dofs, loc_data);
|
||||
if (doftrans)
|
||||
if (FElem->GetMapType() == FiniteElement::VALUE)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
FElem->CalcShape(ir.IntPoint(k), DofVal);
|
||||
vals(k) = DofVal * loc_data;
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < n; k++)
|
||||
if (FElem->GetMapType() == FiniteElement::VALUE)
|
||||
else
|
||||
{
|
||||
ElementTransformation *Tr = fes->GetElementTransformation(i);
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
FElem->CalcShape(ir.IntPoint(k), DofVal);
|
||||
vals(k) = DofVal * loc_data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ElementTransformation *Tr = fes->GetElementTransformation(i);
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
Tr->SetIntPoint(&ir.IntPoint(k));
|
||||
FElem->CalcPhysShape(*Tr, DofVal);
|
||||
vals(k) = DofVal * loc_data;
|
||||
}
|
||||
Tr->SetIntPoint(&ir.IntPoint(k));
|
||||
FElem->CalcPhysShape(*Tr, DofVal);
|
||||
vals(k) = DofVal * loc_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals,
|
||||
@@ -888,12 +861,11 @@ void GridFunction::GetVectorValue(ElementTransformation &T,
|
||||
|
||||
Array<int> vdofs;
|
||||
const FiniteElement *fe = NULL;
|
||||
DofTransformation * doftrans = NULL;
|
||||
|
||||
switch (T.ElementType)
|
||||
{
|
||||
case ElementTransformation::ELEMENT:
|
||||
doftrans = fes->GetElementVDofs(T.ElementNo, vdofs);
|
||||
fes->GetElementVDofs(T.ElementNo, vdofs);
|
||||
fe = fes->GetFE(T.ElementNo);
|
||||
break;
|
||||
case ElementTransformation::EDGE:
|
||||
@@ -984,10 +956,6 @@ void GridFunction::GetVectorValue(ElementTransformation &T,
|
||||
int dof = fe->GetDof();
|
||||
Vector loc_data;
|
||||
GetSubVector(vdofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
if (fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
Vector shape(dof);
|
||||
@@ -1030,14 +998,10 @@ void GridFunction::GetVectorValues(ElementTransformation &T,
|
||||
int dof = FElem->GetDof();
|
||||
|
||||
Array<int> vdofs;
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(T.ElementNo, vdofs);
|
||||
fes->GetElementVDofs(T.ElementNo, vdofs);
|
||||
|
||||
Vector loc_data;
|
||||
GetSubVector(vdofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
|
||||
int nip = ir.GetNPoints();
|
||||
|
||||
if (FElem->GetRangeType() == FiniteElement::SCALAR)
|
||||
@@ -1125,8 +1089,6 @@ void GridFunction::GetValuesFrom(const GridFunction &orig_func)
|
||||
// Without averaging ...
|
||||
|
||||
const FiniteElementSpace *orig_fes = orig_func.FESpace();
|
||||
DofTransformation * doftrans;
|
||||
DofTransformation * orig_doftrans;
|
||||
Array<int> vdofs, orig_vdofs;
|
||||
Vector shape, loc_values, orig_loc_values;
|
||||
int i, j, d, ne, dof, odof, vdim;
|
||||
@@ -1135,13 +1097,9 @@ void GridFunction::GetValuesFrom(const GridFunction &orig_func)
|
||||
vdim = fes->GetVDim();
|
||||
for (i = 0; i < ne; i++)
|
||||
{
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
orig_doftrans = orig_fes->GetElementVDofs(i, orig_vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
orig_fes->GetElementVDofs(i, orig_vdofs);
|
||||
orig_func.GetSubVector(orig_vdofs, orig_loc_values);
|
||||
if (orig_doftrans)
|
||||
{
|
||||
orig_doftrans->InvTransformPrimal(orig_loc_values);
|
||||
}
|
||||
const FiniteElement *fe = fes->GetFE(i);
|
||||
const FiniteElement *orig_fe = orig_fes->GetFE(i);
|
||||
dof = fe->GetDof();
|
||||
@@ -1159,10 +1117,6 @@ void GridFunction::GetValuesFrom(const GridFunction &orig_func)
|
||||
shape * ((const double *)orig_loc_values + d * odof) ;
|
||||
}
|
||||
}
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(loc_values);
|
||||
}
|
||||
SetSubVector(vdofs, loc_values);
|
||||
}
|
||||
}
|
||||
@@ -1172,10 +1126,8 @@ void GridFunction::GetBdrValuesFrom(const GridFunction &orig_func)
|
||||
// Without averaging ...
|
||||
|
||||
const FiniteElementSpace *orig_fes = orig_func.FESpace();
|
||||
// DofTransformation * doftrans;
|
||||
// DofTransformation * orig_doftrans;
|
||||
Array<int> vdofs, orig_vdofs;
|
||||
Vector shape, loc_values, loc_values_t, orig_loc_values, orig_loc_values_t;
|
||||
Vector shape, loc_values, orig_loc_values;
|
||||
int i, j, d, nbe, dof, odof, vdim;
|
||||
|
||||
nbe = fes->GetNBE();
|
||||
@@ -1213,33 +1165,37 @@ void GridFunction::GetVectorFieldValues(
|
||||
Array<int> vdofs;
|
||||
ElementTransformation *transf;
|
||||
|
||||
int d, k, n, sdim, dof;
|
||||
int d, j, k, n, sdim, dof, ind;
|
||||
|
||||
n = ir.GetNPoints();
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
const FiniteElement *fe = fes->GetFE(i);
|
||||
dof = fe->GetDof();
|
||||
sdim = fes->GetMesh()->SpaceDimension();
|
||||
// int *dofs = &vdofs[comp*dof];
|
||||
int *dofs = &vdofs[comp*dof];
|
||||
transf = fes->GetElementTransformation(i);
|
||||
transf->Transform(ir, tr);
|
||||
vals.SetSize(n, sdim);
|
||||
DenseMatrix vshape(dof, sdim);
|
||||
Vector loc_data, val(sdim);
|
||||
GetSubVector(vdofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
double a;
|
||||
for (k = 0; k < n; k++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(k);
|
||||
transf->SetIntPoint(&ip);
|
||||
fe->CalcVShape(*transf, vshape);
|
||||
vshape.MultTranspose(loc_data, val);
|
||||
for (d = 0; d < sdim; d++)
|
||||
{
|
||||
vals(k,d) = val(d);
|
||||
a = 0.0;
|
||||
for (j = 0; j < dof; j++)
|
||||
if ( (ind=dofs[j]) >= 0 )
|
||||
{
|
||||
a += vshape(j, d) * data[ind];
|
||||
}
|
||||
else
|
||||
{
|
||||
a -= vshape(j, d) * data[-1-ind];
|
||||
}
|
||||
vals(k, d) = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1409,13 +1365,9 @@ void GridFunction::GetVectorGradientHat(
|
||||
const FiniteElement *FElem = fes->GetFE(elNo);
|
||||
int dim = FElem->GetDim(), dof = FElem->GetDof();
|
||||
Array<int> vdofs;
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(elNo, vdofs);
|
||||
fes->GetElementVDofs(elNo, vdofs);
|
||||
Vector loc_data;
|
||||
GetSubVector(vdofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
// assuming scalar FE
|
||||
int vdim = fes->GetVDim();
|
||||
DenseMatrix dshape(dof, dim);
|
||||
@@ -1454,13 +1406,9 @@ double GridFunction::GetDivergence(ElementTransformation &T) const
|
||||
{
|
||||
// Assuming RT-type space
|
||||
Array<int> dofs;
|
||||
DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
|
||||
fes->GetElementDofs(elNo, dofs);
|
||||
Vector loc_data, divshape(fe->GetDof());
|
||||
GetSubVector(dofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
fe->CalcDivShape(T.GetIntPoint(), divshape);
|
||||
return (loc_data * divshape) / T.Weight();
|
||||
}
|
||||
@@ -1551,13 +1499,9 @@ void GridFunction::GetCurl(ElementTransformation &T, Vector &curl) const
|
||||
{
|
||||
// Assuming ND-type space
|
||||
Array<int> dofs;
|
||||
DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
|
||||
fes->GetElementDofs(elNo, dofs);
|
||||
Vector loc_data;
|
||||
GetSubVector(dofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
DenseMatrix curl_shape(fe->GetDof(), fe->GetDim() == 3 ? 3 : 1);
|
||||
fe->CalcCurlShape(T.GetIntPoint(), curl_shape);
|
||||
curl.SetSize(curl_shape.Width());
|
||||
@@ -1699,12 +1643,8 @@ void GridFunction::GetGradients(ElementTransformation &tr,
|
||||
DenseMatrix dshape(fe->GetDof(), fe->GetDim());
|
||||
Vector lval, gh(fe->GetDim()), gcol;
|
||||
Array<int> dofs;
|
||||
DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
|
||||
fes->GetElementDofs(elNo, dofs);
|
||||
GetSubVector(dofs, lval);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(lval);
|
||||
}
|
||||
grad.SetSize(fe->GetDim(), ir.GetNPoints());
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
@@ -1784,8 +1724,6 @@ void GridFunction::GetElementAverages(GridFunction &avgs) const
|
||||
{
|
||||
MassIntegrator Mi;
|
||||
DenseMatrix loc_mass;
|
||||
DofTransformation * te_doftrans;
|
||||
DofTransformation * tr_doftrans;
|
||||
Array<int> te_dofs, tr_dofs;
|
||||
Vector loc_avgs, loc_this;
|
||||
Vector int_psi(avgs.Size());
|
||||
@@ -1796,19 +1734,11 @@ void GridFunction::GetElementAverages(GridFunction &avgs) const
|
||||
{
|
||||
Mi.AssembleElementMatrix2(*fes->GetFE(i), *avgs.FESpace()->GetFE(i),
|
||||
*fes->GetElementTransformation(i), loc_mass);
|
||||
tr_doftrans = fes->GetElementDofs(i, tr_dofs);
|
||||
te_doftrans = avgs.FESpace()->GetElementDofs(i, te_dofs);
|
||||
fes->GetElementDofs(i, tr_dofs);
|
||||
avgs.FESpace()->GetElementDofs(i, te_dofs);
|
||||
GetSubVector(tr_dofs, loc_this);
|
||||
if (tr_doftrans)
|
||||
{
|
||||
tr_doftrans->InvTransformPrimal(loc_this);
|
||||
}
|
||||
loc_avgs.SetSize(te_dofs.Size());
|
||||
loc_mass.Mult(loc_this, loc_avgs);
|
||||
if (te_doftrans)
|
||||
{
|
||||
te_doftrans->TransformPrimal(loc_avgs);
|
||||
}
|
||||
avgs.AddElementVector(te_dofs, loc_avgs);
|
||||
loc_this = 1.0; // assume the local basis for 'this' sums to 1
|
||||
loc_mass.Mult(loc_this, loc_avgs);
|
||||
@@ -1823,12 +1753,8 @@ void GridFunction::GetElementAverages(GridFunction &avgs) const
|
||||
void GridFunction::GetElementDofValues(int el, Vector &dof_vals) const
|
||||
{
|
||||
Array<int> dof_idx;
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(el, dof_idx);
|
||||
fes->GetElementVDofs(el, dof_idx);
|
||||
GetSubVector(dof_idx, dof_vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(dof_vals);
|
||||
}
|
||||
}
|
||||
|
||||
void GridFunction::ProjectGridFunction(const GridFunction &src)
|
||||
@@ -1864,21 +1790,13 @@ void GridFunction::ProjectGridFunction(const GridFunction &src)
|
||||
cached_geom = geom;
|
||||
}
|
||||
|
||||
DofTransformation * src_doftrans = src.fes->GetElementVDofs(i, src_vdofs);
|
||||
src.fes->GetElementVDofs(i, src_vdofs);
|
||||
src.GetSubVector(src_vdofs, src_lvec);
|
||||
if (src_doftrans)
|
||||
{
|
||||
src_doftrans->InvTransformPrimal(src_lvec);
|
||||
}
|
||||
for (int vd = 0; vd < vdim; vd++)
|
||||
{
|
||||
P.Mult(&src_lvec[vd*P.Width()], &dest_lvec[vd*P.Height()]);
|
||||
}
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(i, dest_vdofs);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(dest_lvec);
|
||||
}
|
||||
fes->GetElementVDofs(i, dest_vdofs);
|
||||
SetSubVector(dest_vdofs, dest_lvec);
|
||||
}
|
||||
}
|
||||
@@ -1887,15 +1805,10 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
|
||||
const Vector &lo_, const Vector &hi_)
|
||||
{
|
||||
Array<int> vdofs;
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
int size = vdofs.Size();
|
||||
Vector vals, new_vals(size);
|
||||
|
||||
GetSubVector(vdofs, vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(vals);
|
||||
}
|
||||
|
||||
MFEM_ASSERT(weights.Size() == size, "Different # of weights and dofs.");
|
||||
MFEM_ASSERT(lo_.Size() == size, "Different # of lower bounds and dofs.");
|
||||
@@ -1912,10 +1825,6 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
|
||||
slbqp.SetPrintLevel(0); // print messages only if not converged
|
||||
slbqp.Mult(vals, new_vals);
|
||||
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(new_vals);
|
||||
}
|
||||
SetSubVector(vdofs, new_vals);
|
||||
}
|
||||
|
||||
@@ -1923,14 +1832,10 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
|
||||
double min_, double max_)
|
||||
{
|
||||
Array<int> vdofs;
|
||||
DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
int size = vdofs.Size();
|
||||
Vector vals, new_vals(size);
|
||||
GetSubVector(vdofs, vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(vals);
|
||||
}
|
||||
|
||||
double max_val = vals.Max();
|
||||
double min_val = vals.Min();
|
||||
@@ -1938,10 +1843,6 @@ void GridFunction::ImposeBounds(int i, const Vector &weights,
|
||||
if (max_val <= min_)
|
||||
{
|
||||
new_vals = min_;
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(new_vals);
|
||||
}
|
||||
SetSubVector(vdofs, new_vals);
|
||||
return;
|
||||
}
|
||||
@@ -2377,7 +2278,6 @@ void GridFunction::ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff,
|
||||
void GridFunction::ProjectCoefficient(Coefficient &coeff)
|
||||
{
|
||||
DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
|
||||
DofTransformation * doftrans = NULL;
|
||||
|
||||
if (delta_c == NULL)
|
||||
{
|
||||
@@ -2386,13 +2286,9 @@ void GridFunction::ProjectCoefficient(Coefficient &coeff)
|
||||
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
}
|
||||
@@ -2438,17 +2334,11 @@ void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
|
||||
DofTransformation * doftrans = NULL;
|
||||
|
||||
for (i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
vals.SetSize(vdofs.Size());
|
||||
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformPrimal(vals);
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
}
|
||||
@@ -2511,7 +2401,6 @@ void GridFunction::ProjectCoefficient(Coefficient *coeff[])
|
||||
double val;
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *transf;
|
||||
// DofTransformation * doftrans;
|
||||
Array<int> vdofs;
|
||||
|
||||
vdim = fes->GetVDim();
|
||||
@@ -2521,7 +2410,6 @@ void GridFunction::ProjectCoefficient(Coefficient *coeff[])
|
||||
fdof = fe->GetDof();
|
||||
transf = fes->GetElementTransformation(i);
|
||||
const IntegrationRule &ir = fe->GetNodes();
|
||||
// doftrans = fes->GetElementVDofs(i, vdofs);
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
for (j = 0; j < fdof; j++)
|
||||
{
|
||||
|
||||
@@ -910,9 +910,6 @@ IntegrationRules::IntegrationRules(int Ref, int type_):
|
||||
TetrahedronIntRules.SetSize(32, h_mt);
|
||||
TetrahedronIntRules = NULL;
|
||||
|
||||
PyramidIntRules.SetSize(32, h_mt);
|
||||
PyramidIntRules = NULL;
|
||||
|
||||
PrismIntRules.SetSize(32, h_mt);
|
||||
PrismIntRules = NULL;
|
||||
|
||||
@@ -933,7 +930,6 @@ const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
|
||||
case Geometry::TETRAHEDRON: ir_array = &TetrahedronIntRules; break;
|
||||
case Geometry::CUBE: ir_array = &CubeIntRules; break;
|
||||
case Geometry::PRISM: ir_array = &PrismIntRules; break;
|
||||
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
|
||||
default:
|
||||
mfem_error("IntegrationRules::Get(...) : Unknown geometry type!");
|
||||
ir_array = NULL;
|
||||
@@ -980,7 +976,6 @@ void IntegrationRules::Set(int GeomType, int Order, IntegrationRule &IntRule)
|
||||
case Geometry::TETRAHEDRON: ir_array = &TetrahedronIntRules; break;
|
||||
case Geometry::CUBE: ir_array = &CubeIntRules; break;
|
||||
case Geometry::PRISM: ir_array = &PrismIntRules; break;
|
||||
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
|
||||
default:
|
||||
mfem_error("IntegrationRules::Set(...) : Unknown geometry type!");
|
||||
ir_array = NULL;
|
||||
@@ -1024,7 +1019,6 @@ IntegrationRules::~IntegrationRules()
|
||||
DeleteIntRuleArray(TetrahedronIntRules);
|
||||
DeleteIntRuleArray(CubeIntRules);
|
||||
DeleteIntRuleArray(PrismIntRules);
|
||||
DeleteIntRuleArray(PyramidIntRules);
|
||||
}
|
||||
|
||||
|
||||
@@ -1047,8 +1041,6 @@ IntegrationRule *IntegrationRules::GenerateIntegrationRule(int GeomType,
|
||||
return CubeIntegrationRule(Order);
|
||||
case Geometry::PRISM:
|
||||
return PrismIntegrationRule(Order);
|
||||
case Geometry::PYRAMID:
|
||||
return PyramidIntegrationRule(Order);
|
||||
default:
|
||||
mfem_error("IntegrationRules::Set(...) : Unknown geometry type!");
|
||||
return NULL;
|
||||
@@ -1656,30 +1648,6 @@ IntegrationRule *IntegrationRules::TetrahedronIntegrationRule(int Order)
|
||||
}
|
||||
}
|
||||
|
||||
// Integration rules for reference pyramid
|
||||
IntegrationRule *IntegrationRules::PyramidIntegrationRule(int Order)
|
||||
{
|
||||
// This is a simple integration rule adapted from an integration
|
||||
// rule for a cube which seems to be adequate for now. When we
|
||||
// implement high order finite elements for pyramids we should
|
||||
// revisit this and see if we can improve upon it.
|
||||
const IntegrationRule &irc = Get(Geometry::CUBE, Order);
|
||||
int npts = irc.GetNPoints();
|
||||
AllocIntRule(PyramidIntRules, Order);
|
||||
PyramidIntRules[Order] = new IntegrationRule(npts);
|
||||
|
||||
for (int k=0; k<npts; k++)
|
||||
{
|
||||
const IntegrationPoint & ipc = irc.IntPoint(k);
|
||||
IntegrationPoint & ipp = PyramidIntRules[Order]->IntPoint(k);
|
||||
ipp.x = ipc.x * (1.0 - ipc.z);
|
||||
ipp.y = ipc.y * (1.0 - ipc.z);
|
||||
ipp.z = ipc.z;
|
||||
ipp.weight = ipc.weight / 3.0;
|
||||
}
|
||||
return PyramidIntRules[Order];
|
||||
}
|
||||
|
||||
// Integration rules for reference prism
|
||||
IntegrationRule *IntegrationRules::PrismIntegrationRule(int Order)
|
||||
{
|
||||
|
||||
@@ -323,7 +323,6 @@ private:
|
||||
Array<IntegrationRule *> TriangleIntRules;
|
||||
Array<IntegrationRule *> SquareIntRules;
|
||||
Array<IntegrationRule *> TetrahedronIntRules;
|
||||
Array<IntegrationRule *> PyramidIntRules;
|
||||
Array<IntegrationRule *> PrismIntRules;
|
||||
Array<IntegrationRule *> CubeIntRules;
|
||||
|
||||
@@ -352,7 +351,6 @@ private:
|
||||
IntegrationRule *TriangleIntegrationRule(int Order);
|
||||
IntegrationRule *SquareIntegrationRule(int Order);
|
||||
IntegrationRule *TetrahedronIntegrationRule(int Order);
|
||||
IntegrationRule *PyramidIntegrationRule(int Order);
|
||||
IntegrationRule *PrismIntegrationRule(int Order);
|
||||
IntegrationRule *CubeIntegrationRule(int Order);
|
||||
|
||||
|
||||
+2
-11
@@ -103,7 +103,6 @@ void LinearForm::Assemble()
|
||||
{
|
||||
Array<int> vdofs;
|
||||
ElementTransformation *eltrans;
|
||||
DofTransformation *doftrans;
|
||||
Vector elemvect;
|
||||
|
||||
int i;
|
||||
@@ -135,14 +134,10 @@ void LinearForm::Assemble()
|
||||
if ( domain_integs_marker[k] == NULL ||
|
||||
(*(domain_integs_marker[k]))[elem_attr-1] == 1 )
|
||||
{
|
||||
doftrans = fes -> GetElementVDofs (i, vdofs);
|
||||
fes -> GetElementVDofs (i, vdofs);
|
||||
eltrans = fes -> GetElementTransformation (i);
|
||||
domain_integs[k]->AssembleRHSElementVect(*fes->GetFE(i),
|
||||
*eltrans, elemvect);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformDual(elemvect);
|
||||
}
|
||||
AddElementVector (vdofs, elemvect);
|
||||
}
|
||||
}
|
||||
@@ -179,7 +174,7 @@ void LinearForm::Assemble()
|
||||
{
|
||||
const int bdr_attr = mesh->GetBdrAttribute(i);
|
||||
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
|
||||
doftrans = fes -> GetBdrElementVDofs (i, vdofs);
|
||||
fes -> GetBdrElementVDofs (i, vdofs);
|
||||
eltrans = fes -> GetBdrElementTransformation (i);
|
||||
for (int k=0; k < boundary_integs.Size(); k++)
|
||||
{
|
||||
@@ -189,10 +184,6 @@ void LinearForm::Assemble()
|
||||
boundary_integs[k]->AssembleRHSElementVect(*fes->GetBE(i),
|
||||
*eltrans, elemvect);
|
||||
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->TransformDual(elemvect);
|
||||
}
|
||||
AddElementVector (vdofs, elemvect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +321,6 @@ const
|
||||
{
|
||||
X.SetSpace(pfes);
|
||||
Y.SetSpace(pfes);
|
||||
Ytmp.SetSize(pfes->GetTrueVSize());
|
||||
}
|
||||
|
||||
X.Distribute(&x);
|
||||
@@ -336,8 +335,7 @@ const
|
||||
" implemented");
|
||||
mat->Mult(X, Y);
|
||||
}
|
||||
pfes->GetProlongationMatrix()->MultTranspose(Y, Ytmp);
|
||||
y.Add(a,Ytmp);
|
||||
pfes->Dof_TrueDof_Matrix()->MultTranspose(a, Y, 1.0, y);
|
||||
}
|
||||
|
||||
void ParBilinearForm::FormLinearSystem(
|
||||
|
||||
@@ -33,7 +33,6 @@ protected:
|
||||
|
||||
/// Auxiliary objects used in TrueAddMult().
|
||||
mutable ParGridFunction X, Y;
|
||||
mutable Vector Ytmp;
|
||||
|
||||
OperatorHandle p_mat, p_mat_e;
|
||||
|
||||
|
||||
+53
-319
@@ -128,9 +128,6 @@ void ParFiniteElementSpace::ParInit(ParMesh *pm)
|
||||
{
|
||||
ApplyLDofSigns(*elem_dof);
|
||||
}
|
||||
|
||||
// Check for shared trianglular faces with interior Nedelec DoFs
|
||||
CheckNDSTriaDofs();
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::Construct()
|
||||
@@ -467,53 +464,32 @@ void ParFiniteElementSpace::ApplyLDofSigns(Table &el_dof) const
|
||||
ApplyLDofSigns(all_dofs);
|
||||
}
|
||||
|
||||
DofTransformation *
|
||||
ParFiniteElementSpace::GetElementDofs(int i, Array<int> &dofs) const
|
||||
void ParFiniteElementSpace::GetElementDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
if (elem_dof)
|
||||
{
|
||||
elem_dof->GetRow(i, dofs);
|
||||
|
||||
if (DoFTrans[mesh->GetElementBaseGeometry(i)])
|
||||
{
|
||||
Array<int> Fo;
|
||||
elem_fos->GetRow(i, Fo);
|
||||
DoFTrans[mesh->GetElementBaseGeometry(i)]->SetFaceOrientations(Fo);
|
||||
return DoFTrans[mesh->GetElementBaseGeometry(i)];
|
||||
}
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
DofTransformation * doftrans = FiniteElementSpace::GetElementDofs(i, dofs);
|
||||
FiniteElementSpace::GetElementDofs(i, dofs);
|
||||
if (Conforming())
|
||||
{
|
||||
ApplyLDofSigns(dofs);
|
||||
}
|
||||
return doftrans;
|
||||
}
|
||||
|
||||
DofTransformation *
|
||||
ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
|
||||
void ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
if (bdr_elem_dof)
|
||||
{
|
||||
bdr_elem_dof->GetRow(i, dofs);
|
||||
|
||||
if (DoFTrans[mesh->GetBdrElementBaseGeometry(i)])
|
||||
{
|
||||
Array<int> Fo;
|
||||
bdr_elem_fos -> GetRow (i, Fo);
|
||||
DoFTrans[mesh->GetBdrElementBaseGeometry(i)]->SetFaceOrientations(Fo);
|
||||
return DoFTrans[mesh->GetBdrElementBaseGeometry(i)];
|
||||
}
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
DofTransformation * doftrans =
|
||||
FiniteElementSpace::GetBdrElementDofs(i, dofs);
|
||||
FiniteElementSpace::GetBdrElementDofs(i, dofs);
|
||||
if (Conforming())
|
||||
{
|
||||
ApplyLDofSigns(dofs);
|
||||
}
|
||||
return doftrans;
|
||||
}
|
||||
|
||||
int ParFiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs,
|
||||
@@ -681,267 +657,60 @@ void ParFiniteElementSpace::GenerateGlobalOffsets() const
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::CheckNDSTriaDofs()
|
||||
{
|
||||
// Check for Nedelec basis
|
||||
bool nd_basis = dynamic_cast<const ND_FECollection*>(fec);
|
||||
if (!nd_basis)
|
||||
{
|
||||
nd_strias = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for interior face dofs on triangles (the use of TETRAHEDRON
|
||||
// is not an error)
|
||||
bool nd_fdof = fec->HasFaceDofs(Geometry::TETRAHEDRON,
|
||||
GetMaxElementOrder());
|
||||
if (!nd_fdof)
|
||||
{
|
||||
nd_strias = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for shared triangle faces
|
||||
bool strias = false;
|
||||
{
|
||||
int ngrps = pmesh->GetNGroups();
|
||||
for (int g = 1; g < ngrps; g++)
|
||||
{
|
||||
strias |= pmesh->GroupNTriangles(g);
|
||||
}
|
||||
}
|
||||
|
||||
// Combine results
|
||||
int loc_nd_strias = strias ? 1 : 0;
|
||||
int glb_nd_strias = 0;
|
||||
MPI_Allreduce(&loc_nd_strias, &glb_nd_strias, 1,
|
||||
MPI_INTEGER, MPI_SUM, MyComm);
|
||||
nd_strias = glb_nd_strias > 0;
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::Build_Dof_TrueDof_Matrix() const // matrix P
|
||||
{
|
||||
MFEM_ASSERT(Conforming(), "wrong code path");
|
||||
|
||||
if (P) { return; }
|
||||
|
||||
if (!nd_strias)
|
||||
int ldof = GetVSize();
|
||||
int ltdof = TrueVSize();
|
||||
|
||||
HYPRE_Int *i_diag = Memory<HYPRE_Int>(ldof+1);
|
||||
HYPRE_Int *j_diag = Memory<HYPRE_Int>(ltdof);
|
||||
int diag_counter;
|
||||
|
||||
HYPRE_Int *i_offd = Memory<HYPRE_Int>(ldof+1);
|
||||
HYPRE_Int *j_offd = Memory<HYPRE_Int>(ldof-ltdof);
|
||||
int offd_counter;
|
||||
|
||||
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(ldof-ltdof);
|
||||
|
||||
HYPRE_BigInt *col_starts = GetTrueDofOffsets();
|
||||
HYPRE_BigInt *row_starts = GetDofOffsets();
|
||||
|
||||
Array<Pair<HYPRE_BigInt, int> > cmap_j_offd(ldof-ltdof);
|
||||
|
||||
i_diag[0] = i_offd[0] = 0;
|
||||
diag_counter = offd_counter = 0;
|
||||
for (int i = 0; i < ldof; i++)
|
||||
{
|
||||
// Safe to assume 1-1 correspondence between shared dofs
|
||||
int ldof = GetVSize();
|
||||
int ltdof = TrueVSize();
|
||||
|
||||
HYPRE_Int *i_diag = Memory<HYPRE_Int>(ldof+1);
|
||||
HYPRE_Int *j_diag = Memory<HYPRE_Int>(ltdof);
|
||||
int diag_counter;
|
||||
|
||||
HYPRE_Int *i_offd = Memory<HYPRE_Int>(ldof+1);
|
||||
HYPRE_Int *j_offd = Memory<HYPRE_Int>(ldof-ltdof);
|
||||
int offd_counter;
|
||||
|
||||
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(ldof-ltdof);
|
||||
|
||||
HYPRE_BigInt *col_starts = GetTrueDofOffsets();
|
||||
HYPRE_BigInt *row_starts = GetDofOffsets();
|
||||
|
||||
Array<Pair<HYPRE_BigInt, int> > cmap_j_offd(ldof-ltdof);
|
||||
|
||||
i_diag[0] = i_offd[0] = 0;
|
||||
diag_counter = offd_counter = 0;
|
||||
for (int i = 0; i < ldof; i++)
|
||||
int ltdof = GetLocalTDofNumber(i);
|
||||
if (ltdof >= 0)
|
||||
{
|
||||
int ltdof = GetLocalTDofNumber(i);
|
||||
if (ltdof >= 0)
|
||||
{
|
||||
j_diag[diag_counter++] = ltdof;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmap_j_offd[offd_counter].one = GetGlobalTDofNumber(i);
|
||||
cmap_j_offd[offd_counter].two = offd_counter;
|
||||
offd_counter++;
|
||||
}
|
||||
i_diag[i+1] = diag_counter;
|
||||
i_offd[i+1] = offd_counter;
|
||||
j_diag[diag_counter++] = ltdof;
|
||||
}
|
||||
|
||||
SortPairs<HYPRE_BigInt, int>(cmap_j_offd, offd_counter);
|
||||
|
||||
for (int i = 0; i < offd_counter; i++)
|
||||
else
|
||||
{
|
||||
cmap[i] = cmap_j_offd[i].one;
|
||||
j_offd[cmap_j_offd[i].two] = i;
|
||||
cmap_j_offd[offd_counter].one = GetGlobalTDofNumber(i);
|
||||
cmap_j_offd[offd_counter].two = offd_counter;
|
||||
offd_counter++;
|
||||
}
|
||||
|
||||
P = new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
|
||||
i_diag, j_diag, i_offd, j_offd,
|
||||
cmap, offd_counter);
|
||||
i_diag[i+1] = diag_counter;
|
||||
i_offd[i+1] = offd_counter;
|
||||
}
|
||||
else
|
||||
|
||||
SortPairs<HYPRE_BigInt, int>(cmap_j_offd, offd_counter);
|
||||
|
||||
for (int i = 0; i < offd_counter; i++)
|
||||
{
|
||||
// Some shared dofs will be linear combinations of others
|
||||
int ldof = GetVSize();
|
||||
int ltdof = TrueVSize();
|
||||
|
||||
HYPRE_Int gdof = -1;
|
||||
HYPRE_Int gtdof = -1;
|
||||
|
||||
MPI_Allreduce(&ldof, &gdof, 1, HYPRE_MPI_INT, MPI_SUM, MyComm);
|
||||
MPI_Allreduce(<dof, >dof, 1, HYPRE_MPI_INT, MPI_SUM, MyComm);
|
||||
|
||||
// Ensure face orientations have been communicated
|
||||
pmesh->ExchangeFaceNbrData();
|
||||
|
||||
// Locate and count non-zeros in off-diagonal portion of P
|
||||
int nnz_offd = 0;
|
||||
Array<int> ldsize(ldof); ldsize = 0;
|
||||
Array<int> ltori(ldof); ltori = 0; // Local triangle orientations
|
||||
{
|
||||
int ngrps = pmesh->GetNGroups();
|
||||
int nedofs = fec->DofForGeometry(Geometry::SEGMENT);
|
||||
Array<int> sdofs;
|
||||
for (int g = 1; g < ngrps; g++)
|
||||
{
|
||||
if (pmesh->gtopo.IAmMaster(g))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int ei=0; ei<pmesh->GroupNEdges(g); ei++)
|
||||
{
|
||||
this->GetSharedEdgeDofs(g, ei, sdofs);
|
||||
for (int i=0; i<sdofs.Size(); i++)
|
||||
{
|
||||
int ind = (sdofs[i]>=0) ? sdofs[i] : (-sdofs[i]-1);
|
||||
if (ldsize[ind] == 0) { nnz_offd++; }
|
||||
ldsize[ind] = 1;
|
||||
}
|
||||
}
|
||||
for (int fi=0; fi<pmesh->GroupNTriangles(g); fi++)
|
||||
{
|
||||
int face, ori, info1, info2;
|
||||
pmesh->GroupTriangle(g, fi, face, ori);
|
||||
pmesh->GetFaceInfos(face, &info1, &info2);
|
||||
this->GetSharedTriangleDofs(g, fi, sdofs);
|
||||
for (int i=0; i<3*nedofs; i++)
|
||||
{
|
||||
int ind = (sdofs[i]>=0) ? sdofs[i] : (-sdofs[i]-1);
|
||||
if (ldsize[ind] == 0) { nnz_offd++; }
|
||||
ldsize[ind] = 1;
|
||||
}
|
||||
for (int i=3*nedofs; i<sdofs.Size(); i++)
|
||||
{
|
||||
if (ldsize[sdofs[i]] == 0) { nnz_offd += 2; }
|
||||
ldsize[sdofs[i]] = 2;
|
||||
ltori[sdofs[i]] = info2 % 64;
|
||||
}
|
||||
}
|
||||
for (int fi=0; fi<pmesh->GroupNQuadrilaterals(g); fi++)
|
||||
{
|
||||
this->GetSharedQuadrilateralDofs(g, fi, sdofs);
|
||||
for (int i=0; i<sdofs.Size(); i++)
|
||||
{
|
||||
int ind = (sdofs[i]>=0) ? sdofs[i] : (-sdofs[i]-1);
|
||||
if (ldsize[ind] == 0) { nnz_offd++; }
|
||||
ldsize[ind] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HYPRE_Int *i_diag = new HYPRE_Int[ldof+1];
|
||||
HYPRE_Int *j_diag = new HYPRE_Int[ltdof];
|
||||
double *d_diag = new double[ltdof];
|
||||
int diag_counter;
|
||||
|
||||
HYPRE_Int *i_offd = new HYPRE_Int[ldof+1];
|
||||
HYPRE_Int *j_offd = new HYPRE_Int[nnz_offd];
|
||||
double *d_offd = new double[nnz_offd];
|
||||
int offd_counter;
|
||||
|
||||
HYPRE_BigInt *cmap = new HYPRE_BigInt[ldof-ltdof];
|
||||
|
||||
HYPRE_BigInt *col_starts = GetTrueDofOffsets();
|
||||
HYPRE_BigInt *row_starts = GetDofOffsets();
|
||||
|
||||
Array<Pair<HYPRE_BigInt, int> > cmap_j_offd(ldof-ltdof);
|
||||
|
||||
i_diag[0] = i_offd[0] = 0;
|
||||
diag_counter = offd_counter = 0;
|
||||
int offd_col_counter = 0;
|
||||
for (int i = 0; i < ldof; i++)
|
||||
{
|
||||
int ltdof = GetLocalTDofNumber(i);
|
||||
if (ltdof >= 0)
|
||||
{
|
||||
j_diag[diag_counter] = ltdof;
|
||||
d_diag[diag_counter++] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ldsize[i] == 1)
|
||||
{
|
||||
cmap_j_offd[offd_col_counter].one = GetGlobalTDofNumber(i);
|
||||
cmap_j_offd[offd_col_counter].two = offd_counter;
|
||||
offd_counter++;
|
||||
offd_col_counter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmap_j_offd[offd_col_counter].one = GetGlobalTDofNumber(i);
|
||||
cmap_j_offd[offd_col_counter].two = offd_counter;
|
||||
offd_counter += 2;
|
||||
offd_col_counter++;
|
||||
i_diag[i+1] = diag_counter;
|
||||
i_offd[i+1] = offd_counter;
|
||||
i++;
|
||||
cmap_j_offd[offd_col_counter].one = GetGlobalTDofNumber(i);
|
||||
cmap_j_offd[offd_col_counter].two = offd_counter;
|
||||
offd_counter += 2;
|
||||
offd_col_counter++;
|
||||
}
|
||||
}
|
||||
i_diag[i+1] = diag_counter;
|
||||
i_offd[i+1] = offd_counter;
|
||||
}
|
||||
|
||||
SortPairs<HYPRE_BigInt, int>(cmap_j_offd, offd_col_counter);
|
||||
|
||||
for (int i = 0; i < nnz_offd; i++)
|
||||
{
|
||||
j_offd[i] = -1;
|
||||
d_offd[i] = 0.0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < offd_col_counter; i++)
|
||||
{
|
||||
cmap[i] = cmap_j_offd[i].one;
|
||||
j_offd[cmap_j_offd[i].two] = i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ldof; i++)
|
||||
{
|
||||
if (i_offd[i+1] == i_offd[i] + 1)
|
||||
{
|
||||
d_offd[i_offd[i]] = 1.0;
|
||||
}
|
||||
else if (i_offd[i+1] == i_offd[i] + 2)
|
||||
{
|
||||
const double * T = ND_DofTransformation
|
||||
::GetFaceTransform(ltori[i]).GetData();
|
||||
j_offd[i_offd[i] + 1] = j_offd[i_offd[i]] + 1;
|
||||
d_offd[i_offd[i]] = T[0]; d_offd[i_offd[i] + 1] = T[2];
|
||||
i++;
|
||||
j_offd[i_offd[i] + 1] = j_offd[i_offd[i]];
|
||||
j_offd[i_offd[i]] = j_offd[i_offd[i] + 1] - 1;
|
||||
d_offd[i_offd[i]] = T[1]; d_offd[i_offd[i] + 1] = T[3];
|
||||
}
|
||||
}
|
||||
|
||||
P = new HypreParMatrix(MyComm, gdof, gtdof, row_starts, col_starts,
|
||||
i_diag, j_diag, d_diag, i_offd, j_offd, d_offd,
|
||||
offd_col_counter, cmap);
|
||||
cmap[i] = cmap_j_offd[i].one;
|
||||
j_offd[cmap_j_offd[i].two] = i;
|
||||
}
|
||||
|
||||
P = new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
|
||||
i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
|
||||
|
||||
SparseMatrix Pdiag;
|
||||
P->GetDiag(Pdiag);
|
||||
R = Transpose(Pdiag);
|
||||
@@ -1144,8 +913,6 @@ const Operator *ParFiniteElementSpace::GetProlongationMatrix() const
|
||||
{
|
||||
if (Pconf) { return Pconf; }
|
||||
|
||||
if (nd_strias) { return Dof_TrueDof_Matrix(); }
|
||||
|
||||
if (NRanks == 1)
|
||||
{
|
||||
Pconf = new IdentityOperator(GetTrueVSize());
|
||||
@@ -1449,29 +1216,10 @@ void ParFiniteElementSpace::ExchangeFaceNbrData()
|
||||
delete [] requests;
|
||||
}
|
||||
|
||||
DofTransformation *ParFiniteElementSpace::GetFaceNbrElementVDofs(
|
||||
void ParFiniteElementSpace::GetFaceNbrElementVDofs(
|
||||
int i, Array<int> &vdofs) const
|
||||
{
|
||||
face_nbr_element_dof.GetRow(i, vdofs);
|
||||
|
||||
DofTransformation *doftrans = NULL;
|
||||
Geometry::Type geom = GetFaceNbrFE(i)->GetGeomType();
|
||||
if (DoFTrans[geom])
|
||||
{
|
||||
Array<int> F, Fo;
|
||||
pmesh->GetFaceNbrElementFaces(pmesh->GetNE() + i, F, Fo);
|
||||
doftrans = DoFTrans[geom];
|
||||
doftrans->SetFaceOrientations(Fo);
|
||||
}
|
||||
if (vdim == 1 || doftrans == NULL)
|
||||
{
|
||||
return doftrans;
|
||||
}
|
||||
else
|
||||
{
|
||||
VDoFTrans.SetDofTransformation(*doftrans);
|
||||
return &VDoFTrans;
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const
|
||||
@@ -1530,17 +1278,12 @@ const FiniteElement *ParFiniteElementSpace::GetFaceNbrFaceFE(int i) const
|
||||
|
||||
void ParFiniteElementSpace::Lose_Dof_TrueDof_Matrix()
|
||||
{
|
||||
P -> StealData();
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
|
||||
hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
|
||||
hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
|
||||
P -> StealData();
|
||||
dof_offsets.LoseData();
|
||||
tdof_offsets.LoseData();
|
||||
#else
|
||||
dof_offsets.DeleteAll();
|
||||
tdof_offsets.DeleteAll();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::ConstructTrueDofs()
|
||||
@@ -2783,8 +2526,7 @@ static int_type* make_j_array(int_type* I, int nrows)
|
||||
|
||||
HypreParMatrix*
|
||||
ParFiniteElementSpace::RebalanceMatrix(int old_ndofs,
|
||||
const Table* old_elem_dof,
|
||||
const Table* old_elem_fos)
|
||||
const Table* old_elem_dof)
|
||||
{
|
||||
MFEM_VERIFY(Nonconforming(), "Only supported for nonconforming meshes.");
|
||||
MFEM_VERIFY(old_dof_offsets.Size(), "ParFiniteElementSpace::Update needs to "
|
||||
@@ -2909,8 +2651,7 @@ struct DerefDofMessage
|
||||
|
||||
HypreParMatrix*
|
||||
ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
const Table* old_elem_dof,
|
||||
const Table *old_elem_fos)
|
||||
const Table* old_elem_dof)
|
||||
{
|
||||
int nrk = HYPRE_AssumedPartitionCheck() ? 2 : NRanks;
|
||||
|
||||
@@ -3266,16 +3007,13 @@ void ParFiniteElementSpace::Update(bool want_transform)
|
||||
}
|
||||
|
||||
Table* old_elem_dof = NULL;
|
||||
Table* old_elem_fos = NULL;
|
||||
int old_ndofs;
|
||||
|
||||
// save old DOF table
|
||||
if (want_transform)
|
||||
{
|
||||
old_elem_dof = elem_dof;
|
||||
old_elem_fos = elem_fos;
|
||||
elem_dof = NULL;
|
||||
elem_fos = NULL;
|
||||
old_ndofs = ndofs;
|
||||
Swap(dof_offsets, old_dof_offsets);
|
||||
}
|
||||
@@ -3297,25 +3035,22 @@ void ParFiniteElementSpace::Update(bool want_transform)
|
||||
{
|
||||
if (Th.Type() != Operator::MFEM_SPARSEMAT)
|
||||
{
|
||||
Th.Reset(new RefinementOperator(this, old_elem_dof,
|
||||
old_elem_fos, old_ndofs));
|
||||
Th.Reset(new RefinementOperator(this, old_elem_dof, old_ndofs));
|
||||
// The RefinementOperator takes ownership of 'old_elem_dofs', so
|
||||
// we no longer own it:
|
||||
old_elem_dof = NULL;
|
||||
old_elem_fos = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// calculate fully assembled matrix
|
||||
Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
|
||||
Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Mesh::DEREFINE:
|
||||
{
|
||||
Th.Reset(ParallelDerefinementMatrix(old_ndofs, old_elem_dof,
|
||||
old_elem_fos));
|
||||
Th.Reset(ParallelDerefinementMatrix(old_ndofs, old_elem_dof));
|
||||
if (Nonconforming())
|
||||
{
|
||||
Th.SetOperatorOwner(false);
|
||||
@@ -3327,7 +3062,7 @@ void ParFiniteElementSpace::Update(bool want_transform)
|
||||
|
||||
case Mesh::REBALANCE:
|
||||
{
|
||||
Th.Reset(RebalanceMatrix(old_ndofs, old_elem_dof, old_elem_fos));
|
||||
Th.Reset(RebalanceMatrix(old_ndofs, old_elem_dof));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3336,7 +3071,6 @@ void ParFiniteElementSpace::Update(bool want_transform)
|
||||
}
|
||||
|
||||
delete old_elem_dof;
|
||||
delete old_elem_fos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-17
@@ -87,12 +87,6 @@ private:
|
||||
this is a TransposeOperator wrapping R. */
|
||||
mutable Operator *R_transpose;
|
||||
|
||||
/// Flag indicating the existence of shared triangles with interior ND dofs
|
||||
bool nd_strias;
|
||||
|
||||
/// Resets nd_strias flag at constuction or after rebalancing
|
||||
void CheckNDSTriaDofs();
|
||||
|
||||
ParNURBSExtension *pNURBSext() const
|
||||
{ return dynamic_cast<ParNURBSExtension *>(NURBSext); }
|
||||
|
||||
@@ -180,16 +174,14 @@ private:
|
||||
The result is a parallel permutation matrix that can be used to update
|
||||
all grid functions defined on this space. */
|
||||
HypreParMatrix* RebalanceMatrix(int old_ndofs,
|
||||
const Table* old_elem_dof,
|
||||
const Table* old_elem_fos);
|
||||
const Table* old_elem_dof);
|
||||
|
||||
/** Calculate a GridFunction restriction matrix after mesh derefinement.
|
||||
The matrix is constructed so that the new grid function interpolates
|
||||
the original function, i.e., the original function is evaluated at the
|
||||
nodes of the coarse function. */
|
||||
HypreParMatrix* ParallelDerefinementMatrix(int old_ndofs,
|
||||
const Table *old_elem_dof,
|
||||
const Table *old_elem_fos);
|
||||
const Table *old_elem_dof);
|
||||
|
||||
/// Updates the internal mesh pointer. @warning @a new_mesh must be
|
||||
/// <b>topologically identical</b> to the existing mesh. Used if the address
|
||||
@@ -210,8 +202,6 @@ public:
|
||||
int num_face_nbr_dofs;
|
||||
// Face-neighbor-element to face-neighbor dof
|
||||
Table face_nbr_element_dof;
|
||||
// Face-neighbor-element face orientations
|
||||
Table face_nbr_element_fos;
|
||||
// Face-neighbor to ldof in the face-neighbor numbering
|
||||
Table face_nbr_ldof;
|
||||
// The global ldof indices of the face-neighbor dofs
|
||||
@@ -289,10 +279,10 @@ public:
|
||||
virtual int GetTrueVSize() const { return ltdof_size; }
|
||||
|
||||
/// Returns indexes of degrees of freedom in array dofs for i'th element.
|
||||
virtual DofTransformation *GetElementDofs(int i, Array<int> &dofs) const;
|
||||
virtual void GetElementDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
/// Returns indexes of degrees of freedom for i'th boundary element.
|
||||
virtual DofTransformation *GetBdrElementDofs(int i, Array<int> &dofs) const;
|
||||
virtual void GetBdrElementDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
/** Returns the indexes of the degrees of freedom for i'th face
|
||||
including the dofs for the edges and the vertices of the face. */
|
||||
@@ -392,7 +382,7 @@ public:
|
||||
// Face-neighbor functions
|
||||
void ExchangeFaceNbrData();
|
||||
int GetFaceNbrVSize() const { return num_face_nbr_dofs; }
|
||||
DofTransformation *GetFaceNbrElementVDofs(int i, Array<int> &vdofs) const;
|
||||
void GetFaceNbrElementVDofs(int i, Array<int> &vdofs) const;
|
||||
void GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const;
|
||||
const FiniteElement *GetFaceNbrFE(int i) const;
|
||||
const FiniteElement *GetFaceNbrFaceFE(int i) const;
|
||||
@@ -407,8 +397,6 @@ public:
|
||||
bool Conforming() const { return pmesh->pncmesh == NULL && !nonconf_P; }
|
||||
bool Nonconforming() const { return pmesh->pncmesh != NULL || nonconf_P; }
|
||||
|
||||
bool SharedNDTriangleDofs() const { return nd_strias; }
|
||||
|
||||
// Transfer parallel true-dof data from coarse_fes, defined on a coarse mesh,
|
||||
// to this FE space, defined on a refined mesh. See full documentation in the
|
||||
// base class, FiniteElementSpace::GetTrueTransferOperator.
|
||||
|
||||
+2
-12
@@ -325,14 +325,9 @@ void ParGridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
|
||||
if (nbr_el_no >= 0)
|
||||
{
|
||||
Array<int> dofs;
|
||||
DofTransformation * doftrans = pfes->GetFaceNbrElementVDofs(nbr_el_no,
|
||||
dofs);
|
||||
pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs);
|
||||
Vector loc_data;
|
||||
face_nbr_data.GetSubVector(dofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
const FiniteElement *FElem = pfes->GetFaceNbrFE(nbr_el_no);
|
||||
int dof = FElem->GetDof();
|
||||
if (FElem->GetRangeType() == FiniteElement::SCALAR)
|
||||
@@ -442,17 +437,12 @@ void ParGridFunction::GetVectorValue(ElementTransformation &T,
|
||||
}
|
||||
|
||||
Array<int> vdofs;
|
||||
DofTransformation * doftrans = pfes->GetFaceNbrElementVDofs(nbr_el_no,
|
||||
vdofs);
|
||||
pfes->GetFaceNbrElementVDofs(nbr_el_no, vdofs);
|
||||
const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no);
|
||||
|
||||
int dof = fe->GetDof();
|
||||
Vector loc_data;
|
||||
face_nbr_data.GetSubVector(vdofs, loc_data);
|
||||
if (doftrans)
|
||||
{
|
||||
doftrans->InvTransformPrimal(loc_data);
|
||||
}
|
||||
if (fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
Vector shape(dof);
|
||||
|
||||
+1
-2
@@ -175,8 +175,7 @@ const Operator &InterpolationGridTransfer::ForwardOperator()
|
||||
localP[elem_geoms[i]]);
|
||||
}
|
||||
F.Reset(ran_fes.RefinementMatrix_main(
|
||||
dom_fes.GetNDofs(), dom_fes.GetElementToDofTable(),
|
||||
dom_fes.GetElementToFaceOrientationTable(), localP));
|
||||
dom_fes.GetNDofs(), dom_fes.GetElementToDofTable(), localP));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -21,16 +21,12 @@
|
||||
#define MFEM_PERF_FUNCTION CALI_CXX_MARK_FUNCTION
|
||||
#define MFEM_PERF_BEGIN(s) CALI_MARK_BEGIN(s)
|
||||
#define MFEM_PERF_END(s) CALI_MARK_END(s)
|
||||
#define MFEM_PERF_SCOPE(name) \
|
||||
cali::Annotation::Guard cali_autogenerated_guard_name(cali::Annotation("function").begin(std::string(name).c_str()))
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define MFEM_PERF_FUNCTION
|
||||
#define MFEM_PERF_BEGIN(s)
|
||||
#define MFEM_PERF_END(s)
|
||||
#define MFEM_PERF_SCOPE(name)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#define MFEM_FORALL_HPP
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "annotation.hpp"
|
||||
#include "error.hpp"
|
||||
#include "backends.hpp"
|
||||
#include "device.hpp"
|
||||
|
||||
@@ -118,11 +118,6 @@ int STable3D::Index (int r, int c, int f) const
|
||||
{
|
||||
STable3DNode *node;
|
||||
|
||||
if (r >= Size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Sort3 (r, c, f);
|
||||
|
||||
for (node = Rows[r]; node != NULL; node = node->Prev)
|
||||
|
||||
@@ -78,16 +78,6 @@ if (MFEM_USE_MPI)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_ARPACK)
|
||||
list(APPEND SRCS eigensolvers.cpp arpack.cpp)
|
||||
list(APPEND HDRS eigensolvers.hpp arpack.hpp)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_SPECTRA)
|
||||
list(APPEND SRCS spectra.cpp)
|
||||
list(APPEND HDRS eigen.hpp spectra.hpp)
|
||||
endif()
|
||||
|
||||
if (MFEM_USE_SUNDIALS)
|
||||
list(APPEND SRCS sundials.cpp)
|
||||
list(APPEND HDRS sundials.hpp)
|
||||
|
||||
-1122
File diff suppressed because it is too large
Load Diff
@@ -1,240 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef MFEM_ARPACK
|
||||
#define MFEM_ARPACK
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#ifdef MFEM_USE_ARPACK
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include <mpi.h>
|
||||
#include "hypre.hpp"
|
||||
#endif
|
||||
|
||||
#include "operator.hpp"
|
||||
|
||||
#define DSAUPD dsaupd_
|
||||
#define DSEUPD dseupd_
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
#define PDSAUPD pdsaupd_
|
||||
#define PDSEUPD pdseupd_
|
||||
#endif
|
||||
|
||||
extern "C" void DSAUPD(int *ido,char *bmat, int *n,
|
||||
char *which, int *nev,double *tol,double *resid,
|
||||
int *ncv,double *v, int *ldv,
|
||||
int *iparam, int *ipntr,
|
||||
double *workd, double *workl, int *lworkl, int *info);
|
||||
|
||||
extern "C" void DSEUPD(int *, char *,int *, double *,
|
||||
double *,int *, double *,char *, int *, char *,
|
||||
int *,double *,double *,int *, double *,
|
||||
int *, int *,int *, double *,
|
||||
double *,int *, int *);
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
extern "C" void PDSAUPD(int *comm, int *ido,char *bmat, int *n,
|
||||
char *which, int *nev,double *tol,double *resid,
|
||||
int *ncv,double *v, int *ldv,
|
||||
int *iparam, int *ipntr,
|
||||
double *workd, double *workl, int *lworkl, int *info);
|
||||
|
||||
extern "C" void PDSEUPD(int *comm, int *, char *,int *, double *,
|
||||
double *,int *, double *,char *, int *, char *,
|
||||
int *,double *,double *,int *, double *,
|
||||
int *, int *,int *, double *,
|
||||
double *,int *, int *);
|
||||
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
void arpackgetcommdbg_(int *,int *,int *);
|
||||
void arpacksetcommdbg_(int *,int *,int *);
|
||||
void arpacksymdbg_(int *,int *,int *,int *,int *,int *,int *);
|
||||
void arpacknonsymdbg_(int *,int *,int *,int *,int *,int *,int *);
|
||||
void arpackcmplxdbg_(int *,int *,int *,int *,int *,int *,int *);
|
||||
}
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
class ArPackSym : public Eigensolver
|
||||
{
|
||||
public:
|
||||
|
||||
ArPackSym();
|
||||
virtual ~ArPackSym();
|
||||
|
||||
/** ARPACK modes are described in section 3.5 of the ARPACK manual.
|
||||
Mode 1: regular mode to solve A x = lambda x
|
||||
No solver and no mass matrix are needed.
|
||||
Mode 2: regular inverse mode to solve A x = lambda M x
|
||||
Both A and M are needed and the solver should compute M^{-1}.
|
||||
Mode 3: shift-invert mode to solve either A x = lambda x
|
||||
or A x = lambda M x
|
||||
Mass matrix is optional. The solver should compute
|
||||
(A-sigma I)^{-1} or (A-sigma M)^{-1}. The shift parameter,
|
||||
sigma, also needs to be set with SetShift().
|
||||
Mode 4: Buckling mode to solve K x = lambda K_G x
|
||||
K is set using SetMassMatrix(), K_G is set using SetOperator(),
|
||||
and the solver should compute (K-sigma K_G)^{-1}. The shift
|
||||
parameter, sigma, also needs to be set with SetShift().
|
||||
Mode 5: Cayley mode to solve A x = lambda M x
|
||||
Both A and M are needed and the solver should compute
|
||||
(A - sigma M)^{-1}. The shift parameter, sigma, also needs
|
||||
to be set with SetShift().
|
||||
*/
|
||||
void SetMode(int mode);
|
||||
|
||||
inline void SetTol(double tol) { tol_ = tol; }
|
||||
inline void SetMaxIter(int max_iter) { max_iter_ = max_iter; }
|
||||
inline void SetPrintLevel(int logging) { logging_ = logging; }
|
||||
inline void SetShift(double sigma) { sigma_ = sigma; }
|
||||
inline void SetNumModes(int num_eigs) { nev_ = num_eigs; }
|
||||
|
||||
virtual void SetSolver(Solver & solver);
|
||||
virtual void SetOperator(Operator & A);
|
||||
virtual void SetMassMatrix(Operator & M);
|
||||
|
||||
void Solve();
|
||||
|
||||
/// Collect the converged eigenvalues
|
||||
virtual void GetEigenvalues(Array<double> & eigenvalues);
|
||||
|
||||
/// Extract a single eigenvector
|
||||
virtual Vector & GetEigenvector(unsigned int i);
|
||||
|
||||
/// Transfer ownership of the converged eigenvectors
|
||||
Vector ** StealEigenvectors();
|
||||
|
||||
protected:
|
||||
|
||||
int myid_; // Index of this processor
|
||||
int max_iter_;
|
||||
int logging_;
|
||||
|
||||
// The following variables are for ARPACK
|
||||
int nloc_; // number of items stored locally
|
||||
int nev_; // number of requested eigenvalues
|
||||
int ncv_; // number of ritz vectors
|
||||
int rvec_; // boolean to return eigenvectors as well
|
||||
int mode_; // 1 = standard, 2 = generalized, 3 = shift invert,
|
||||
// 4 = buckling, 5 = Cayley
|
||||
int lworkl_; // length of lworkl_ work array
|
||||
int iparam_[12]; // arpack parameters
|
||||
int ipntr_[12]; // arpack pointers
|
||||
|
||||
char bmat_; // I for standard problem, G for generalized
|
||||
char which_[3]; // spectrum portion: LA, SA, LM, SM, BE
|
||||
char hwmny_; // DSEUPD: A for all eigenvalues, S for some
|
||||
|
||||
double tol_; // relative accuracy bound for Ritz values
|
||||
double sigma_; // eigenvalue shift parameter
|
||||
|
||||
int * select_;// workspace used during eigenvalue computation
|
||||
double * dv_; // Ritz values
|
||||
double * v_; // ncv Lanczos basis vectors
|
||||
double * resid_; // residual vector
|
||||
double * workd_; // work array for 3 vectors used in Arnoldi iteration
|
||||
double * workl_; // work array
|
||||
|
||||
// Operators and Vectors needed outside of ARPACK
|
||||
Solver * solver_;
|
||||
Operator * A_;
|
||||
Operator * B_;
|
||||
|
||||
Vector * w_;
|
||||
Vector * x_;
|
||||
Vector * y_;
|
||||
Vector * z_;
|
||||
|
||||
Vector ** eigenvectors_;
|
||||
|
||||
string solverName_;
|
||||
|
||||
void reverseComm();
|
||||
|
||||
int reverseCommMode1();
|
||||
int reverseCommMode2();
|
||||
int reverseCommMode3();
|
||||
int reverseCommMode4();
|
||||
int reverseCommMode5();
|
||||
|
||||
virtual void prepareEigenvectors();
|
||||
|
||||
void printErrors(const int & info, const int iparam[],
|
||||
const char & bmat, const int & n,
|
||||
const char which[],
|
||||
const int & nev, const int & ncv,
|
||||
const int & lworkl );
|
||||
|
||||
private:
|
||||
|
||||
virtual int computeNlocf() { return nloc_; }
|
||||
virtual int computeIter(int & ido);
|
||||
virtual int computeEigs();
|
||||
|
||||
};
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
class ParArPackSym : public ArPackSym
|
||||
{
|
||||
public:
|
||||
ParArPackSym(MPI_Comm comm);
|
||||
virtual ~ParArPackSym() {}
|
||||
|
||||
void SetOperator(Operator & A);
|
||||
void SetMassMatrix(Operator & M);
|
||||
|
||||
/// Collect the converged eigenvalues
|
||||
void GetEigenvalues(Array<double> & eigenvalues);
|
||||
|
||||
/// Extract a single eigenvector
|
||||
Vector & GetEigenvector(unsigned int i);
|
||||
|
||||
/// Transfer ownership of the converged eigenvectors
|
||||
// HypreParVector ** StealEigenvectors();
|
||||
Vector ** StealEigenvectors();
|
||||
|
||||
protected:
|
||||
|
||||
void prepareEigenvectors();
|
||||
|
||||
private:
|
||||
|
||||
MPI_Comm comm_;
|
||||
MPI_Fint commf_; // Fortran style MPI communicator
|
||||
int numProcs_; // Number of processors
|
||||
|
||||
HYPRE_Int * part_; // parallel partitioning for eigenvectors
|
||||
|
||||
int computeNlocf();
|
||||
int computeIter(int & ido);
|
||||
int computeEigs();
|
||||
|
||||
};
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
};
|
||||
|
||||
#endif // MFEM_USE_ARPACK
|
||||
|
||||
#endif // MFEM_ARPACK
|
||||
@@ -787,16 +787,10 @@ HypreParMatrix * ComplexHypreParMatrix::GetSystemMatrix() const
|
||||
2 * num_cols_offd, cmap,
|
||||
true);
|
||||
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
// Give the new matrix ownership of row_starts and col_starts
|
||||
hypre_ParCSRMatrix *hA = (hypre_ParCSRMatrix*)(*A);
|
||||
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(hA,1);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(hA,1);
|
||||
#else
|
||||
mfem_hypre_TFree_host(row_starts);
|
||||
mfem_hypre_TFree_host(col_starts);
|
||||
#endif
|
||||
|
||||
return A;
|
||||
}
|
||||
|
||||
@@ -763,13 +763,6 @@ public:
|
||||
tdata.New(i*j*k);
|
||||
}
|
||||
|
||||
DenseTensor(double *d, int i, int j, int k)
|
||||
: Mk(NULL, i, j)
|
||||
{
|
||||
nk = k;
|
||||
tdata.Wrap(d, i*j*k, false);
|
||||
}
|
||||
|
||||
DenseTensor(int i, int j, int k, MemoryType mt)
|
||||
: Mk(NULL, i, j)
|
||||
{
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
#ifndef MFEM_EIGEN_HPP
|
||||
#define MFEM_EIGEN_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
#include "vector.hpp"
|
||||
#include "sparsemat.hpp"
|
||||
#include "densemat.hpp"
|
||||
|
||||
namespace mfem{
|
||||
/** @brief Eigen template specialization for vector conversion */
|
||||
template <typename T>
|
||||
struct VectorConverter {
|
||||
static Vector from(const Eigen::Matrix<T, Eigen::Dynamic, 1>& other)
|
||||
{
|
||||
Vector v(other.rows());
|
||||
|
||||
for (size_t i = 0; i < v.Size(); i++)
|
||||
v(i) = other(i);
|
||||
|
||||
return std::move(v);
|
||||
}
|
||||
|
||||
static Eigen::Matrix<T, Eigen::Dynamic, 1> to(const Vector& other)
|
||||
{
|
||||
Eigen::Matrix<T, Eigen::Dynamic, 1> v(other.Size());
|
||||
|
||||
for (size_t i = 0; i < v.Size(); i++)
|
||||
v(i) = other(i);
|
||||
|
||||
return std::move(v);
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Eigen template specialization for dense matrix conversion */
|
||||
template <typename T>
|
||||
struct DenseMatrixConverter {
|
||||
static DenseMatrix from(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& other)
|
||||
{
|
||||
DenseMatrix mat(other.rows(), other.cols());
|
||||
|
||||
for (size_t j = 0; j < mat.Width(); j++)
|
||||
for (size_t i = 0; i < mat.Height(); i++)
|
||||
mat(i, j) = other(i, j);
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
static Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> to(const DenseMatrix& other)
|
||||
{
|
||||
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> mat(other.Height(), other.Width());
|
||||
|
||||
for (size_t j = 0; j < mat.cols(); j++)
|
||||
for (size_t i = 0; i < mat.rows(); i++)
|
||||
mat(i, j) = other(i, j);
|
||||
|
||||
return mat;
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Eigen template specialization for sparse matrix conversion */
|
||||
template <class T>
|
||||
struct SparseMatrixConverter {
|
||||
static SparseMatrix from(const Eigen::SparseMatrix<T, Eigen::RowMajor>& other)
|
||||
{
|
||||
return SparseMatrix(other.outerIndexPtr(), other.innerIndexPtr(), other.valuePtr(), other.rows(), other.cols());
|
||||
}
|
||||
|
||||
static Eigen::SparseMatrix<T, Eigen::RowMajor> to(const SparseMatrix& other)
|
||||
{
|
||||
// MFEM memory info
|
||||
const int *I = other.GetI(), *J = other.GetJ();
|
||||
const T* Data = other.GetData();
|
||||
|
||||
// Eigen triplet
|
||||
std::vector<Eigen::Triplet<double>> tripletList;
|
||||
tripletList.reserve(other.GetMemoryData().Capacity());
|
||||
|
||||
for (size_t i = 0; i < other.Size(); i++) {
|
||||
for (size_t k = I[i], end = I[i + 1]; k < end; k++)
|
||||
tripletList.push_back(Eigen::Triplet<double>(i, J[k], Data[k]));
|
||||
}
|
||||
|
||||
// Create Eigen sparse matrix
|
||||
Eigen::SparseMatrix<T, Eigen::RowMajor> mat(other.Height(), other.Width());
|
||||
mat.setFromTriplets(tripletList.begin(), tripletList.end());
|
||||
|
||||
return mat;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MFEM_EIGEN_HPP
|
||||
@@ -1,23 +0,0 @@
|
||||
// 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 "linalg.hpp"
|
||||
#include "eigensolver.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
Eigensolver::Eigensolver()
|
||||
{}
|
||||
|
||||
};
|
||||
@@ -1,53 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef MFEM_EIGENSOLVERS
|
||||
#define MFEM_EIGENSOLVERS
|
||||
|
||||
#include "vector.hpp"
|
||||
#include "operator.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Abstract Eigensolver
|
||||
class Eigensolver
|
||||
{
|
||||
public:
|
||||
|
||||
Eigensolver();
|
||||
virtual ~Eigensolver() {}
|
||||
|
||||
virtual void SetTol(double tol) = 0;
|
||||
virtual void SetMaxIter(int max_iter) = 0;
|
||||
virtual void SetPrintLevel(int logging) = 0;
|
||||
virtual void SetNumModes(int num_eigs) = 0;
|
||||
|
||||
virtual void SetOperator(Operator & A) = 0;
|
||||
virtual void SetMassMatrix(Operator & M) = 0;
|
||||
|
||||
/// Perform the eigenvalue solve
|
||||
virtual void Solve() = 0;
|
||||
|
||||
/// Collect the converged eigenvalues
|
||||
virtual void GetEigenvalues(Array<double> & eigenvalues) = 0;
|
||||
|
||||
/// Extract a single eigenvector
|
||||
virtual Vector & GetEigenvector(unsigned int i) = 0;
|
||||
|
||||
/// Transfer ownership of the converged eigenvectors
|
||||
virtual Vector ** StealEigenvectors() = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+1
-63
@@ -88,9 +88,7 @@ HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
|
||||
{
|
||||
x = hypre_ParVectorCreate(comm,glob_size,col);
|
||||
hypre_ParVectorInitialize(x);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParVectorSetPartitioningOwner(x,0);
|
||||
#endif
|
||||
// The data will be destroyed by hypre (this is the default)
|
||||
hypre_ParVectorSetDataOwner(x,1);
|
||||
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
|
||||
@@ -107,9 +105,7 @@ HypreParVector::HypreParVector(MPI_Comm comm, HYPRE_BigInt glob_size,
|
||||
hypre_ParVectorSetDataOwner(x,1); // owns the seq vector
|
||||
hypre_Vector *x_loc = hypre_ParVectorLocalVector(x);
|
||||
hypre_SeqVectorSetDataOwner(x_loc,0);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParVectorSetPartitioningOwner(x,0);
|
||||
#endif
|
||||
double tmp = 0.0;
|
||||
hypre_VectorData(x_loc) = &tmp;
|
||||
#ifdef HYPRE_USING_CUDA
|
||||
@@ -132,9 +128,7 @@ HypreParVector::HypreParVector(const HypreParVector &y) : Vector()
|
||||
x = hypre_ParVectorCreate(y.x -> comm, y.x -> global_size,
|
||||
y.x -> partitioning);
|
||||
hypre_ParVectorInitialize(x);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParVectorSetPartitioningOwner(x,0);
|
||||
#endif
|
||||
hypre_ParVectorSetDataOwner(x,1);
|
||||
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
|
||||
_SetDataAndSize_();
|
||||
@@ -168,9 +162,7 @@ HypreParVector::HypreParVector(ParFiniteElementSpace *pfes)
|
||||
x = hypre_ParVectorCreate(pfes->GetComm(), pfes->GlobalTrueVSize(),
|
||||
pfes->GetTrueDofOffsets());
|
||||
hypre_ParVectorInitialize(x);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParVectorSetPartitioningOwner(x,0);
|
||||
#endif
|
||||
// The data will be destroyed by hypre (this is the default)
|
||||
hypre_ParVectorSetDataOwner(x,1);
|
||||
hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1);
|
||||
@@ -691,10 +683,8 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, HYPRE_BigInt glob_size,
|
||||
A = hypre_ParCSRMatrixCreate(comm, glob_size, glob_size, row_starts,
|
||||
row_starts, 0, diag->NumNonZeroElems(), 0);
|
||||
hypre_ParCSRMatrixSetDataOwner(A,1);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(A,0);
|
||||
#endif
|
||||
|
||||
hypre_CSRMatrixSetDataOwner(A->diag,0);
|
||||
diagOwner = CopyCSR(diag, mem_diag, A->diag, false);
|
||||
@@ -736,10 +726,8 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
|
||||
row_starts, col_starts,
|
||||
0, diag->NumNonZeroElems(), 0);
|
||||
hypre_ParCSRMatrixSetDataOwner(A,1);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(A,0);
|
||||
#endif
|
||||
|
||||
hypre_CSRMatrixSetDataOwner(A->diag,0);
|
||||
diagOwner = CopyCSR(diag, mem_diag, A->diag, false);
|
||||
@@ -782,10 +770,8 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
|
||||
offd->Width(), diag->NumNonZeroElems(),
|
||||
offd->NumNonZeroElems());
|
||||
hypre_ParCSRMatrixSetDataOwner(A,1);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(A,0);
|
||||
#endif
|
||||
|
||||
hypre_CSRMatrixSetDataOwner(A->diag,0);
|
||||
diagOwner = CopyCSR(diag, mem_diag, A->diag, own_diag_offd);
|
||||
@@ -831,10 +817,8 @@ HypreParMatrix::HypreParMatrix(
|
||||
A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
|
||||
row_starts, col_starts, offd_num_cols, 0, 0);
|
||||
hypre_ParCSRMatrixSetDataOwner(A,1);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(A,0);
|
||||
#endif
|
||||
|
||||
HYPRE_Int local_num_rows = hypre_CSRMatrixNumRows(A->diag);
|
||||
|
||||
@@ -947,10 +931,8 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm,
|
||||
A = hypre_ParCSRMatrixCreate(comm, global_num_rows, global_num_cols,
|
||||
row_starts, col_starts, 0, nnz, 0);
|
||||
hypre_ParCSRMatrixSetDataOwner(A,1);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(A,0);
|
||||
#endif
|
||||
|
||||
hypre_CSRMatrixSetDataOwner(A->diag,0);
|
||||
diagOwner = CopyBoolCSR(diag, mem_diag, A->diag);
|
||||
@@ -1007,10 +989,8 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int id, int np,
|
||||
}
|
||||
|
||||
hypre_ParCSRMatrixSetDataOwner(A,1);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(A,0);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(A,0);
|
||||
#endif
|
||||
|
||||
mem_diag.data.New(diag_nnz);
|
||||
for (HYPRE_Int i = 0; i < diag_nnz; i++)
|
||||
@@ -1197,13 +1177,6 @@ HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows,
|
||||
{
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
|
||||
}
|
||||
#if MFEM_HYPRE_VERSION > 22200
|
||||
mfem_hypre_TFree_host(row_starts);
|
||||
if (rows != cols)
|
||||
{
|
||||
mfem_hypre_TFree_host(col_starts);
|
||||
}
|
||||
#endif
|
||||
hypre_MatvecCommPkgCreate(A);
|
||||
|
||||
height = GetNumRows();
|
||||
@@ -1290,7 +1263,6 @@ void HypreParMatrix::SetOwnerFlags(signed char diag, signed char offd,
|
||||
|
||||
void HypreParMatrix::CopyRowStarts()
|
||||
{
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
if (!A || hypre_ParCSRMatrixOwnsRowStarts(A) ||
|
||||
(hypre_ParCSRMatrixRowStarts(A) == hypre_ParCSRMatrixColStarts(A) &&
|
||||
hypre_ParCSRMatrixOwnsColStarts(A)))
|
||||
@@ -1325,12 +1297,10 @@ void HypreParMatrix::CopyRowStarts()
|
||||
hypre_ParCSRMatrixColStarts(A) = new_row_starts;
|
||||
hypre_ParCSRMatrixOwnsColStarts(A) = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HypreParMatrix::CopyColStarts()
|
||||
{
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
if (!A || hypre_ParCSRMatrixOwnsColStarts(A) ||
|
||||
(hypre_ParCSRMatrixRowStarts(A) == hypre_ParCSRMatrixColStarts(A) &&
|
||||
hypre_ParCSRMatrixOwnsRowStarts(A)))
|
||||
@@ -1369,7 +1339,6 @@ void HypreParMatrix::CopyColStarts()
|
||||
{
|
||||
hypre_ParCSRMatrixOwnsColStarts(A) = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HypreParMatrix::GetDiag(Vector &diag) const
|
||||
@@ -1822,14 +1791,9 @@ HypreParMatrix* HypreParMatrix::LeftDiagMult(const SparseMatrix &D,
|
||||
DA_diag, DA_offd, new_col_map_offd,
|
||||
own_diag_offd);
|
||||
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
// Give ownership of row_starts, col_starts, and col_map_offd to DA
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(DA->A, 1);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(DA->A, 1);
|
||||
#else
|
||||
mfem_hypre_TFree_host(new_row_starts);
|
||||
mfem_hypre_TFree_host(new_col_starts);
|
||||
#endif
|
||||
DA->colMapOwner = 1;
|
||||
|
||||
return DA;
|
||||
@@ -1984,22 +1948,18 @@ void HypreParMatrix::Threshold(double threshold)
|
||||
row_starts = hypre_ParCSRMatrixRowStarts(A);
|
||||
col_starts = hypre_ParCSRMatrixColStarts(A);
|
||||
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
bool old_owns_row = hypre_ParCSRMatrixOwnsRowStarts(A);
|
||||
bool old_owns_col = hypre_ParCSRMatrixOwnsColStarts(A);
|
||||
#endif
|
||||
HYPRE_BigInt global_num_rows = hypre_ParCSRMatrixGlobalNumRows(A);
|
||||
HYPRE_BigInt global_num_cols = hypre_ParCSRMatrixGlobalNumCols(A);
|
||||
parcsr_A_ptr = hypre_ParCSRMatrixCreate(comm, global_num_rows,
|
||||
global_num_cols,
|
||||
row_starts, col_starts,
|
||||
0, 0, 0);
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrixOwnsRowStarts(parcsr_A_ptr) = old_owns_row;
|
||||
hypre_ParCSRMatrixOwnsColStarts(parcsr_A_ptr) = old_owns_col;
|
||||
hypre_ParCSRMatrixOwnsRowStarts(A) = 0;
|
||||
hypre_ParCSRMatrixOwnsColStarts(A) = 0;
|
||||
#endif
|
||||
|
||||
csr_A = hypre_MergeDiagAndOffd(A);
|
||||
|
||||
@@ -2034,12 +1994,7 @@ void HypreParMatrix::Threshold(double threshold)
|
||||
|
||||
hypre_ParCSRMatrixSetNumNonzeros(A);
|
||||
/* Make sure that the first entry in each row is the diagonal one. */
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
if (row_starts == col_starts)
|
||||
#else
|
||||
if ((row_starts[0] == col_starts[0]) &&
|
||||
(row_starts[1] == col_starts[1]))
|
||||
#endif
|
||||
{
|
||||
hypre_CSRMatrixReorder(hypre_ParCSRMatrixDiag(A));
|
||||
}
|
||||
@@ -2548,14 +2503,11 @@ HypreParMatrix * RAP(const HypreParMatrix *A, const HypreParMatrix *P)
|
||||
// hypre_ParCSRMatrixRAPKT
|
||||
}
|
||||
#else
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
HYPRE_Int P_owns_its_col_starts =
|
||||
hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P));
|
||||
#endif
|
||||
|
||||
hypre_BoomerAMGBuildCoarseOperator(*P,*A,*P,&rap);
|
||||
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
/* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
|
||||
from P (even if it does not own them)! */
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(rap,0);
|
||||
@@ -2564,7 +2516,6 @@ HypreParMatrix * RAP(const HypreParMatrix *A, const HypreParMatrix *P)
|
||||
{
|
||||
hypre_ParCSRMatrixSetColStartsOwner(*P, 1);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
hypre_ParCSRMatrixSetNumNonzeros(rap);
|
||||
@@ -2585,16 +2536,13 @@ HypreParMatrix * RAP(const HypreParMatrix * Rt, const HypreParMatrix *A,
|
||||
hypre_ParCSRMatrixDestroy(Q);
|
||||
}
|
||||
#else
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
HYPRE_Int P_owns_its_col_starts =
|
||||
hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P));
|
||||
HYPRE_Int Rt_owns_its_col_starts =
|
||||
hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*Rt));
|
||||
#endif
|
||||
|
||||
hypre_BoomerAMGBuildCoarseOperator(*Rt,*A,*P,&rap);
|
||||
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
/* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
|
||||
from Rt and P (even if they do not own them)! */
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(rap,0);
|
||||
@@ -2607,7 +2555,6 @@ HypreParMatrix * RAP(const HypreParMatrix * Rt, const HypreParMatrix *A,
|
||||
{
|
||||
hypre_ParCSRMatrixSetColStartsOwner(*Rt, 1);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
hypre_ParCSRMatrixSetNumNonzeros(rap);
|
||||
@@ -3197,12 +3144,8 @@ void HypreSmoother::SetOperator(const Operator &op)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
min_eig_est = 0;
|
||||
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est);
|
||||
#else
|
||||
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est, &min_eig_est);
|
||||
#endif
|
||||
}
|
||||
Z = new HypreParVector(*A);
|
||||
}
|
||||
@@ -3216,12 +3159,8 @@ void HypreSmoother::SetOperator(const Operator &op)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
min_eig_est = 0;
|
||||
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est);
|
||||
#else
|
||||
hypre_ParCSRMaxEigEstimate(*A, poly_scale, &max_eig_est, &min_eig_est);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The Taubin and FIR polynomials are defined on [0, 2]
|
||||
@@ -5058,11 +4997,11 @@ HypreADS::HypreADS(const HypreParMatrix &A, ParFiniteElementSpace *face_fespace)
|
||||
void HypreADS::Init(ParFiniteElementSpace *face_fespace)
|
||||
{
|
||||
int cycle_type = 11;
|
||||
int rlx_type = 2;
|
||||
int rlx_sweeps = 1;
|
||||
double rlx_weight = 1.0;
|
||||
double rlx_omega = 1.0;
|
||||
#ifndef HYPRE_USING_CUDA
|
||||
int rlx_type = 2;
|
||||
int amg_coarsen_type = 10;
|
||||
int amg_agg_levels = 1;
|
||||
int amg_rlx_type = 8;
|
||||
@@ -5070,7 +5009,6 @@ void HypreADS::Init(ParFiniteElementSpace *face_fespace)
|
||||
int amg_interp_type = 6;
|
||||
int amg_Pmax = 4;
|
||||
#else
|
||||
int rlx_type = 1;
|
||||
int amg_coarsen_type = 8;
|
||||
int amg_agg_levels = 0;
|
||||
int amg_rlx_type = 18;
|
||||
|
||||
@@ -508,10 +508,8 @@ void hypre_ParCSRMatrixEliminateAAe(hypre_ParCSRMatrix *A,
|
||||
hypre_ParCSRMatrixColStarts(A),
|
||||
0, 0, 0);
|
||||
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(*Ae, 0);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(*Ae, 0);
|
||||
#endif
|
||||
|
||||
hypre_CSRMatrix *Ae_diag = hypre_ParCSRMatrixDiag(*Ae);
|
||||
hypre_CSRMatrix *Ae_offd = hypre_ParCSRMatrixOffd(*Ae);
|
||||
@@ -1004,17 +1002,10 @@ void hypre_ParCSRMatrixSplit(hypre_ParCSRMatrix *A,
|
||||
|
||||
hypre_ParCSRMatrixOwnsData(blocks[i]) = 1;
|
||||
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
/* only the first block will own the row/col_starts */
|
||||
hypre_ParCSRMatrixOwnsRowStarts(blocks[i]) = !i;
|
||||
hypre_ParCSRMatrixOwnsColStarts(blocks[i]) = !i;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MFEM_HYPRE_VERSION > 22200
|
||||
mfem_hypre_TFree_host(row_starts);
|
||||
mfem_hypre_TFree_host(col_starts);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Based on hypre_CSRMatrixMatvec in hypre's csr_matvec.c */
|
||||
@@ -1925,12 +1916,9 @@ hypre_ParCSRMatrixAdd(hypre_ParCSRMatrix *A,
|
||||
|
||||
/* C owns diag, offd, and cmap. */
|
||||
hypre_ParCSRMatrixSetDataOwner(C, 1);
|
||||
|
||||
#if MFEM_HYPRE_VERSION <= 22200
|
||||
/* C does not own row and column starts. */
|
||||
hypre_ParCSRMatrixSetRowStartsOwner(C, 0);
|
||||
hypre_ParCSRMatrixSetColStartsOwner(C, 0);
|
||||
#endif
|
||||
|
||||
return C;
|
||||
}
|
||||
|
||||
+1169
File diff suppressed because it is too large
Load Diff
+244
@@ -0,0 +1,244 @@
|
||||
#ifndef MFEM_IMEX
|
||||
#define MFEM_IMEX
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "operator.hpp"
|
||||
#include "ode.hpp"
|
||||
#include <vector>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** Class for spatial discretizations of a PDE resulting in the time-dependent,
|
||||
nonlinear set of ODEs with implicit-explicit additive partition
|
||||
M*du/dt = N_E(u,t) + N_I(u,t).
|
||||
MFEM typically treats time integration as
|
||||
du/dt = F^{-1} G(u),
|
||||
Here F represents what MFEM calls the “implicit” part, and G represents the
|
||||
“explicit” part; in simpler terms, F is typically just a mass matrix.
|
||||
|
||||
For BDF schemes, the ImplicitSolve function is a bit different, and it is
|
||||
more natural to apply M and M^{-1} separate from the Mult functions, so we
|
||||
include MassMult and MassInv as functions to be provided, and do not include
|
||||
such actions in the Mult functions. */
|
||||
class IMEXTimeDependentOperator : public TimeDependentOperator
|
||||
{
|
||||
protected:
|
||||
mutable Vector temp; // Auxillary vector
|
||||
|
||||
public:
|
||||
// Sets linearly implicit to false by default
|
||||
IMEXTimeDependentOperator(int n, double t=0.0, Type type=EXPLICIT)
|
||||
: TimeDependentOperator(n, t, type) { };
|
||||
~IMEXTimeDependentOperator() { };
|
||||
|
||||
/** Apply action of implicit part of operator y <- N_I(x,y). For fully
|
||||
implicit schemes, this just corresponds to applying the time-dependent
|
||||
(nonlinear) operator.
|
||||
PREVIOUSLY CALLED ExplicitMult */
|
||||
virtual void ImplicitMult(const Vector &x, Vector &y) const = 0;
|
||||
|
||||
/** Apply action of explicit part of operator y <- N_E(x,y) */
|
||||
virtual void ExplicitMult(const Vector &x, Vector &y) const { y = 0.0; };
|
||||
|
||||
/** Solve k = f(x+dt*k) for stage k, where f() is the implicit part of
|
||||
the operator. Used in Runge-Kutta methods. */
|
||||
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k)
|
||||
{ mfem::mfem_error("IMEXTimeDependentOperator::ImplicitSolve() is not overridden!"); };
|
||||
|
||||
/** Solve M*x - dtf(x, t) = b for solution x, where f() is the implicit
|
||||
part of the operator. Used in BDF methods. */
|
||||
virtual void ImplicitSolve2(const double dt, const Vector &b, Vector &x)
|
||||
{ mfem::mfem_error("IMEXTimeDependentOperator::ImplicitSolve2() is not overridden!"); };
|
||||
|
||||
/** Apply action mass matrix, y = M*x.
|
||||
If not re-implemented, this method simply generates an error.
|
||||
PREVIOUSLY CALLED ImplictMult */
|
||||
virtual void MassMult(const Vector &x, Vector &y) const = 0;
|
||||
|
||||
/** Apply action of inverse of mass matrix, y = M^{-1}*x.
|
||||
If not re-implemented, this method simply generates an error.
|
||||
NOTE : only necessary for PolyIMEX methods. */
|
||||
virtual void MassInv(const Vector &x, Vector &y) const = 0;
|
||||
};
|
||||
|
||||
/** Class holding RK Butcher tableau, and associated data required by
|
||||
implicit and explicit splitting. */
|
||||
class IMEXRKData
|
||||
{
|
||||
public:
|
||||
// Implicit Runge Kutta type. Enumeration (s, \sigma, p):
|
||||
// - s = number of implicit stages
|
||||
// - \sigma = number of explicit stages
|
||||
// - p = order
|
||||
// In this notation, when s = \sigma, we satisfy (2.3)/(2.4) in
|
||||
// Ascher et al., and do not need to compute the final explicit
|
||||
// stage. This is represented in the stiffly_accurate boolean.
|
||||
enum Type {
|
||||
IMEX111 = 111,
|
||||
IMEX121 = 121,
|
||||
IMEX122 = 122,
|
||||
IMEX222 = 222,
|
||||
IMEX232 = 232,
|
||||
IMEX233 = 233,
|
||||
IMEX443 = 443,
|
||||
// ARK ESDIRK-ERK schemes: enumeration (s,p), for total number of
|
||||
// stages s.
|
||||
ARK43 = -43
|
||||
};
|
||||
|
||||
IMEXRKData() : s(-1) { };
|
||||
IMEXRKData(Type ID_) : ID(ID_) { SetData(); };
|
||||
~IMEXRKData() { };
|
||||
|
||||
/// Set explicit RK data
|
||||
void SetExplicitData(DenseMatrix Ae_, Vector be_, Vector ce_);
|
||||
/// Set implicit RK data
|
||||
void SetImplicitData(DenseMatrix Ai_, Vector bi_, Vector ci_, bool esdirk_=false);
|
||||
void SetID(Type ID_) { ID=ID_; SetData(); };
|
||||
|
||||
bool esdirk;
|
||||
bool stiffly_accurate;
|
||||
bool use_final_exp_stage;
|
||||
int s;
|
||||
|
||||
DenseMatrix Ai; // Implicit Butcher matrix
|
||||
Vector bi; // Implicit Butcher tableau weights
|
||||
DenseMatrix Ae; // Explicit Butcher matrix
|
||||
Vector be; // Explicit Butcher tableau weights
|
||||
Vector c0; // Butcher tableau nodes (same for implicit and explicit!)
|
||||
|
||||
private:
|
||||
Type ID;
|
||||
void SetData();
|
||||
void InitData();
|
||||
};
|
||||
|
||||
/** Class for two-part additive IMEX RK method, where explicit and implicit
|
||||
stage vectors are stored. Assume same abscissae, {c}, for both schemes.
|
||||
Butcher Data must be provided either in a custom IMEXRKData object, or
|
||||
using the IMEXRKData::Type for predefined tableaux. */
|
||||
class IMEXRK : public ODESolver
|
||||
{
|
||||
protected:
|
||||
IMEXRKData tableaux;
|
||||
std::vector< Vector *> exp_stages;
|
||||
std::vector< Vector *> imp_stages;
|
||||
IMEXTimeDependentOperator *imex; // Spatial discretization.
|
||||
|
||||
public:
|
||||
IMEXRK(IMEXRKData tableaux_) : ODESolver(), tableaux(tableaux_) { };
|
||||
IMEXRK(IMEXRKData::Type type_) : ODESolver(), tableaux(type_) { };
|
||||
~IMEXRK();
|
||||
void Init(IMEXTimeDependentOperator &_imex);
|
||||
void Step(Vector &x, double &t, double &dt) override;
|
||||
};
|
||||
|
||||
/** Class holding BDF integrator data. Setting alpha < 0 (the default
|
||||
constructor) defines alpha = 2/(q-1), corresponding to classical BDF
|
||||
of order q. */
|
||||
class BDFData
|
||||
{
|
||||
public:
|
||||
|
||||
enum Type {
|
||||
BDF1 = 01, BDF2 = 02, BDF3 = 03, BDF4 = 04,
|
||||
IMEX_BDF1 = 11, IMEX_BDF2 = 12, IMEX_BDF3 = 13,
|
||||
IMEX_BDF4 = 14
|
||||
};
|
||||
|
||||
BDFData() { };
|
||||
BDFData(Type ID_, double alpha_=-1) : ID(ID_), alpha(alpha_) { SetData(); };
|
||||
~BDFData() { };
|
||||
|
||||
int GetID() { return static_cast<int>(ID); };
|
||||
void SetID(Type ID_, double alpha_=-1)
|
||||
{
|
||||
ID=ID_;
|
||||
alpha = alpha_;
|
||||
SetData();
|
||||
};
|
||||
void Print()
|
||||
{
|
||||
std::cout << "q = " << q << "\n";
|
||||
std::cout << "alpha = " << alpha << "\n";
|
||||
std::cout << "A:\n";
|
||||
A.PrintMatlab();
|
||||
std::cout << "Be:\n";
|
||||
Be.PrintMatlab();
|
||||
std::cout << "Bi:\n";
|
||||
Bi.Print();
|
||||
std::cout << "z:\n";
|
||||
z0.Print();
|
||||
};
|
||||
|
||||
double alpha;
|
||||
int q; // Number of previous values stored
|
||||
bool shifted_nodes; // false = clssical BDF, true = Polynomial BDF w/ shifted nodes
|
||||
DenseMatrix A; // Previous solution coefficients
|
||||
Vector Bi; // Implicit coefficients
|
||||
DenseMatrix Be; // Explicit coefficients
|
||||
Vector z0;
|
||||
|
||||
|
||||
private:
|
||||
Type ID;
|
||||
void SetData();
|
||||
void InitData();
|
||||
};
|
||||
|
||||
/** Class for IMEX-BDF methods, including classical IMEX-BDF and IMEX-
|
||||
Polynomial-BDF (IMEX-PBDF). IMEX-PBDF methods have an additional
|
||||
alpha parameter, where larger alpha leads to smaller stability
|
||||
regions and a smaller leading accuracy constant, while smaller
|
||||
alpha leads to larger stabiltiy regions and a larger accuracy
|
||||
constant. For classical methods, there are two implementations:
|
||||
- ClassicalStep() stores previous solutions and the explicit
|
||||
part of the operator evaluated on the solution, and
|
||||
- ClassicalStepNoStore() does not store the explicit
|
||||
component, but must re-evaluate q times during each time
|
||||
step.
|
||||
This option can be set via the recompute_exp input. The type of
|
||||
scheme must be set through the BDFData structure or BDFData::Type.
|
||||
There is also an option to use pointwise Lagrange interpolating
|
||||
polynomials to provide an initial guess for the ImplicitSolve. This
|
||||
is set via InterpolateGuess(). This option is only implemented for
|
||||
PBDF. */
|
||||
class IMEXBDF : public ODESolver
|
||||
{
|
||||
private:
|
||||
BDFData data;
|
||||
bool recompute_exp;
|
||||
bool interpolate;
|
||||
int initialized;
|
||||
double dt_prev;
|
||||
std::vector< Vector*> sols;
|
||||
std::vector< Vector*> exp_sols;
|
||||
IMEXTimeDependentOperator *imex; // Spatial discretization
|
||||
IMEXRK *RKsolver;
|
||||
std::vector<double> exp_nodes;
|
||||
|
||||
void AlphaStep(Vector &x, double &t, double &dt);
|
||||
void ClassicalStep(Vector &x, double &t, double &dt);
|
||||
void ClassicalStepNoStore(Vector &x, double &t, double &dt);
|
||||
|
||||
public:
|
||||
IMEXBDF(BDFData data_, bool recompute_exp_=false) :
|
||||
ODESolver(), data(data_), recompute_exp(recompute_exp_),
|
||||
interpolate(false) { };
|
||||
IMEXBDF(BDFData::Type scheme, bool recompute_exp_=false) :
|
||||
ODESolver(), recompute_exp(recompute_exp_), interpolate(false)
|
||||
{ data.SetID(scheme); };
|
||||
IMEXBDF(BDFData::Type scheme, double alpha) :
|
||||
ODESolver(), interpolate(false), recompute_exp(false)
|
||||
{ data.SetID(scheme, alpha); };
|
||||
~IMEXBDF();
|
||||
|
||||
void Init(IMEXTimeDependentOperator &_imex);
|
||||
void Step(Vector &x, double &t, double &dt);
|
||||
void InterpolateGuess() {interpolate = true; };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+1
-10
@@ -31,6 +31,7 @@
|
||||
#include "invariants.hpp"
|
||||
#include "constraints.hpp"
|
||||
#include "auxiliary.hpp"
|
||||
#include "imex.hpp"
|
||||
|
||||
#ifdef MFEM_USE_AMGX
|
||||
#include "amgxsolver.hpp"
|
||||
@@ -48,16 +49,6 @@
|
||||
#include "ginkgo.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_ARPACK
|
||||
#include "eigensolver.hpp"
|
||||
#include "arpack.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_SPECTRA
|
||||
#include "eigen.hpp"
|
||||
#include "spectra.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
#include "hypre_parcsr.hpp"
|
||||
#include "hypre.hpp"
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
#include "spectra.hpp"
|
||||
|
||||
#include "../fem/bilinearform.hpp"
|
||||
|
||||
namespace mfem {
|
||||
SpectraEigenSolver::SpectraEigenSolver()
|
||||
{
|
||||
// Init params
|
||||
_nconv = 0;
|
||||
_nev = 1;
|
||||
_ncv = 1;
|
||||
_max_iter = 1000;
|
||||
_tol = 1e-3;
|
||||
}
|
||||
|
||||
SpectraEigenSolver::~SpectraEigenSolver()
|
||||
{
|
||||
delete _A_s, _B_s, _S, _G;
|
||||
}
|
||||
|
||||
/// Set dimension of Krylov subspace in the Lanczos method
|
||||
SpectraEigenSolver& SpectraEigenSolver::SetKrylov(double ncv)
|
||||
{
|
||||
_ncv = ncv;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set solver tolerance
|
||||
SpectraEigenSolver& SpectraEigenSolver::SetTol(double tol)
|
||||
{
|
||||
_tol = tol;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set maximum number of iterations
|
||||
SpectraEigenSolver& SpectraEigenSolver::SetMaxIter(int max_iter)
|
||||
{
|
||||
_max_iter = max_iter;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set the number of required eigenmodes
|
||||
SpectraEigenSolver& SpectraEigenSolver::SetNumModes(int nev)
|
||||
{
|
||||
_nev = nev;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set operator for standard eigenvalue problem (A*x = lambda*x)
|
||||
SpectraEigenSolver& SpectraEigenSolver::SetOperator(const Operator& A)
|
||||
{
|
||||
// Set EIGEN operators
|
||||
_A_e = SparseMatrixConverter<double>::to(static_cast<const BilinearForm&>(A).SpMat());
|
||||
|
||||
// Set SPECTRA operators
|
||||
_A_s = new SparseSymMatProd<double>(_A_e);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set operator for generalized eigenvalue problem (A*x = lambda*B*x)
|
||||
SpectraEigenSolver& SpectraEigenSolver::SetOperators(const Operator& A, const Operator& B)
|
||||
{
|
||||
// Set EIGEN operators
|
||||
_A_e = SparseMatrixConverter<double>::to(static_cast<const BilinearForm&>(A).SpMat());
|
||||
_B_e = SparseMatrixConverter<double>::to(static_cast<const BilinearForm&>(B).SpMat());
|
||||
|
||||
// Set SPECTRA operators
|
||||
_A_s = new SparseSymMatProd<double>(_A_e);
|
||||
_B_s = new SparseCholesky<double>(_B_e);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Solve the eigenvalue problem for the specified number of eigenvalues
|
||||
void SpectraEigenSolver::Solve()
|
||||
{
|
||||
// Set the dimension of the Krilov space equal to the number of requested eigenvalues if necessary
|
||||
if (_ncv < _nev)
|
||||
_ncv = _nev;
|
||||
|
||||
if (!_B_s) {
|
||||
_S = new SymEigsSolver<SparseSymMatProd<double>>(*_A_s, _nev, _ncv);
|
||||
_S->init();
|
||||
_nconv = _S->compute(SortRule::SmallestMagn, _max_iter, _tol, SortRule::SmallestMagn);
|
||||
}
|
||||
else {
|
||||
_G = new SymGEigsSolver<SparseSymMatProd<double>, SparseCholesky<double>, GEigsMode::Cholesky>(*_A_s, *_B_s, _nev, _ncv);
|
||||
_G->init();
|
||||
_nconv = _G->compute(SortRule::SmallestMagn, _max_iter, _tol, SortRule::SmallestMagn);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of converged eigenvalues
|
||||
int SpectraEigenSolver::GetNumConverged()
|
||||
{
|
||||
return _nconv;
|
||||
}
|
||||
|
||||
/// Get the corresponding eigenvalue
|
||||
double SpectraEigenSolver::GetEigenvalue(unsigned int i) const
|
||||
{
|
||||
if (!_B_s) {
|
||||
if (_S->info() == CompInfo::Successful && i < _nconv)
|
||||
return _S->eigenvalues()[i];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if (_G->info() == CompInfo::Successful && i < _nconv)
|
||||
return _G->eigenvalues()[i];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::VectorXd SpectraEigenSolver::GetEigenvalues(unsigned int i) const
|
||||
{
|
||||
if (!_B_s) {
|
||||
if (_S->info() == CompInfo::Successful && i < _nconv)
|
||||
return _S->eigenvalues().segment(0, i);
|
||||
}
|
||||
else {
|
||||
if (_G->info() == CompInfo::Successful && i < _nconv)
|
||||
return _G->eigenvalues().segment(0, i);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the corresponding eigenvector
|
||||
Eigen::VectorXd SpectraEigenSolver::GetEigenvector(unsigned int i) const
|
||||
{
|
||||
if (!_B_s) {
|
||||
if (_S->info() == CompInfo::Successful && i < _nconv)
|
||||
return _S->eigenvectors().col(i);
|
||||
}
|
||||
else {
|
||||
if (_G->info() == CompInfo::Successful && i < _nconv)
|
||||
return _G->eigenvectors().col(i);
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::MatrixXd SpectraEigenSolver::GetEigenvectors(unsigned int i) const
|
||||
{
|
||||
if (!_B_s) {
|
||||
if (_S->info() == CompInfo::Successful && i < _nconv)
|
||||
return _S->eigenvectors().topRows(i);
|
||||
}
|
||||
else {
|
||||
if (_G->info() == CompInfo::Successful && i < _nconv)
|
||||
return _G->eigenvectors().topRows(i);
|
||||
}
|
||||
}
|
||||
} // namespace mfem
|
||||
@@ -1,77 +0,0 @@
|
||||
#ifndef MFEM_SPECTRA_HPP
|
||||
#define MFEM_SPECTRA_HPP
|
||||
|
||||
#include <Spectra/GenEigsSolver.h>
|
||||
#include <Spectra/MatOp/SparseCholesky.h>
|
||||
#include <Spectra/MatOp/SparseGenMatProd.h>
|
||||
#include <Spectra/SymEigsSolver.h>
|
||||
#include <Spectra/SymGEigsSolver.h>
|
||||
|
||||
#include "eigen.hpp"
|
||||
|
||||
using namespace Spectra;
|
||||
|
||||
namespace mfem {
|
||||
class SpectraEigenSolver {
|
||||
public:
|
||||
SpectraEigenSolver();
|
||||
|
||||
virtual ~SpectraEigenSolver();
|
||||
|
||||
/// Set dimension of Krylov subspace in the Lanczos method
|
||||
SpectraEigenSolver& SetKrylov(double ncv);
|
||||
|
||||
/// Set solver tolerance
|
||||
SpectraEigenSolver& SetTol(double tol);
|
||||
|
||||
/// Set maximum number of iterations
|
||||
SpectraEigenSolver& SetMaxIter(int max_iter);
|
||||
|
||||
/// Set the number of required eigenmodes
|
||||
SpectraEigenSolver& SetNumModes(int nev);
|
||||
|
||||
/// Set operator for standard eigenvalue problem (A*x = lambda*x)
|
||||
SpectraEigenSolver& SetOperator(const Operator& A);
|
||||
|
||||
/// Set operator for generalized eigenvalue problem (A*x = lambda*B*x)
|
||||
SpectraEigenSolver& SetOperators(const Operator& A, const Operator& B);
|
||||
|
||||
/// Solve the eigenvalue problem for the specified number of eigenvalues
|
||||
void Solve();
|
||||
|
||||
/// Get the number of converged eigenvalues
|
||||
int GetNumConverged();
|
||||
|
||||
/// Get the corresponding eigenvalue
|
||||
double GetEigenvalue(unsigned int i) const;
|
||||
|
||||
Eigen::VectorXd GetEigenvalues(unsigned int i = 0) const;
|
||||
|
||||
/// Get the corresponding eigenvector
|
||||
Eigen::VectorXd GetEigenvector(unsigned int i) const;
|
||||
|
||||
Eigen::MatrixXd GetEigenvectors(unsigned int i) const;
|
||||
|
||||
protected:
|
||||
// Params
|
||||
int _nconv, _nev, _ncv, _max_iter;
|
||||
double _tol;
|
||||
|
||||
// EIGEN Operators
|
||||
Eigen::SparseMatrix<double> _A_e, _B_e;
|
||||
|
||||
// Spectra Operators
|
||||
SparseSymMatProd<double>* _A_s = nullptr;
|
||||
SparseCholesky<double>* _B_s = nullptr;
|
||||
|
||||
// Eigenvalue solution based on Spectra
|
||||
SymEigsSolver<SparseSymMatProd<double>>* _S = nullptr;
|
||||
SymGEigsSolver<SparseSymMatProd<double>, SparseCholesky<double>, GEigsMode::Cholesky>* _G = nullptr;
|
||||
|
||||
// // Eigenvalue solution based on Eigen
|
||||
// Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd>* _S = nullptr;
|
||||
// Eigen::GeneralizedSelfAdjointEigenSolver<Eigen::MatrixXd>* _G = nullptr;
|
||||
};
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_SPECTRA_HPP
|
||||
@@ -119,7 +119,7 @@ $(if $(word 2,$(SRC)),$(error Spaces in SRC = "$(SRC)" are not supported))
|
||||
MFEM_GIT_STRING = $(shell [ -d $(MFEM_DIR)/.git ] && git -C $(MFEM_DIR) \
|
||||
describe --all --long --abbrev=40 --dirty --always 2> /dev/null)
|
||||
|
||||
EXAMPLE_SUBDIRS = amgx caliper ginkgo hiop petsc pumi sundials superlu
|
||||
EXAMPLE_SUBDIRS = amgx ginkgo hiop petsc pumi sundials superlu
|
||||
EXAMPLE_DIRS := examples $(addprefix examples/,$(EXAMPLE_SUBDIRS))
|
||||
EXAMPLE_TEST_DIRS := examples
|
||||
|
||||
@@ -274,7 +274,7 @@ endif
|
||||
# List of MFEM dependencies, that require the *_LIB variable to be non-empty
|
||||
MFEM_REQ_LIB_DEPS = SUPERLU MUMPS METIS FMS CONDUIT SIDRE LAPACK SUNDIALS MESQUITE\
|
||||
SUITESPARSE STRUMPACK GINKGO GNUTLS NETCDF PETSC SLEPC MPFR PUMI HIOP GSLIB\
|
||||
OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER ARPACK
|
||||
OCCA CEED RAJA UMPIRE MKL_CPARDISO AMGX CALIPER
|
||||
|
||||
PETSC_ERROR_MSG = $(if $(PETSC_FOUND),,. PETSC config not found: $(PETSC_VARS))
|
||||
SLEPC_ERROR_MSG = $(if $(SLEPC_FOUND),,. SLEPC config not found: $(SLEPC_VARS))
|
||||
@@ -292,7 +292,7 @@ ifeq ($(MAKECMDGOALS),config)
|
||||
endif
|
||||
|
||||
# List of MFEM dependencies, processed below
|
||||
MFEM_DEPENDENCIES = $(MFEM_REQ_LIB_DEPS) SPECTRA LIBUNWIND OPENMP CUDA HIP
|
||||
MFEM_DEPENDENCIES = $(MFEM_REQ_LIB_DEPS) LIBUNWIND OPENMP CUDA HIP
|
||||
|
||||
# List of deprecated MFEM dependencies, processed below
|
||||
MFEM_LEGACY_DEPENDENCIES = OPENMP
|
||||
@@ -340,7 +340,7 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
|
||||
MFEM_USE_PUMI MFEM_USE_HIOP MFEM_USE_GSLIB MFEM_USE_CUDA MFEM_USE_HIP\
|
||||
MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_RAJA MFEM_USE_UMPIRE MFEM_USE_SIMD\
|
||||
MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_AMGX MFEM_USE_MUMPS\
|
||||
MFEM_USE_CALIPER MFEM_USE_ARPACK MFEM_USE_SPECTRA MFEM_SOURCE_DIR MFEM_INSTALL_DIR
|
||||
MFEM_USE_CALIPER MFEM_SOURCE_DIR MFEM_INSTALL_DIR
|
||||
|
||||
# List of makefile variables that will be written to config.mk:
|
||||
MFEM_CONFIG_VARS = MFEM_CXX MFEM_HOST_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS\
|
||||
@@ -652,8 +652,6 @@ status info:
|
||||
$(info MFEM_USE_SUNDIALS = $(MFEM_USE_SUNDIALS))
|
||||
$(info MFEM_USE_MESQUITE = $(MFEM_USE_MESQUITE))
|
||||
$(info MFEM_USE_SUITESPARSE = $(MFEM_USE_SUITESPARSE))
|
||||
$(info MFEM_USE_ARPACK = $(MFEM_USE_ARPACK))
|
||||
$(info MFEM_USE_SPECTRA = $(MFEM_USE_SPECTRA))
|
||||
$(info MFEM_USE_SUPERLU = $(MFEM_USE_SUPERLU))
|
||||
$(info MFEM_USE_MUMPS = $(MFEM_USE_MUMPS))
|
||||
$(info MFEM_USE_STRUMPACK = $(MFEM_USE_STRUMPACK))
|
||||
|
||||
@@ -19,7 +19,6 @@ set(SRCS
|
||||
ncmesh.cpp
|
||||
nurbs.cpp
|
||||
point.cpp
|
||||
pyramid.cpp
|
||||
quadrilateral.cpp
|
||||
segment.cpp
|
||||
tetrahedron.cpp
|
||||
@@ -39,7 +38,6 @@ set(HDRS
|
||||
ncmesh.hpp
|
||||
nurbs.hpp
|
||||
point.hpp
|
||||
pyramid.hpp
|
||||
quadrilateral.hpp
|
||||
segment.hpp
|
||||
tetrahedron.hpp
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public:
|
||||
|
||||
/// Constants for the classes derived from Element.
|
||||
enum Type { POINT, SEGMENT, TRIANGLE, QUADRILATERAL,
|
||||
TETRAHEDRON, HEXAHEDRON, WEDGE, PYRAMID
|
||||
TETRAHEDRON, HEXAHEDRON, WEDGE
|
||||
};
|
||||
|
||||
/// Default element constructor.
|
||||
|
||||
+9
-308
@@ -335,7 +335,6 @@ FiniteElement *Mesh::GetTransformationFEforElementType(Element::Type ElemType)
|
||||
case Element::TETRAHEDRON : return &TetrahedronFE;
|
||||
case Element::HEXAHEDRON : return &HexahedronFE;
|
||||
case Element::WEDGE : return &WedgeFE;
|
||||
case Element::PYRAMID : return &PyramidFE;
|
||||
default:
|
||||
MFEM_ABORT("Unknown element type \"" << ElemType << "\"");
|
||||
break;
|
||||
@@ -736,31 +735,6 @@ void Mesh::GetLocalTriToWdgTransformation(
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::GetLocalTriToPyrTransformation(
|
||||
IsoparametricTransformation &Transf, int i)
|
||||
{
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
|
||||
Transf.SetFE(&TriangleFE);
|
||||
// (i/64) is the local face no. in the pyr
|
||||
MFEM_VERIFY(i >= 64, "Local face index " << i/64
|
||||
<< " is not a triangular face of a pyramid.");
|
||||
const int *pv = pyr_t::FaceVert[i/64];
|
||||
// (i%64) is the orientation of the pyramid face
|
||||
// w.r.t. the face element
|
||||
const int *to = tri_t::Orient[i%64];
|
||||
const IntegrationRule *PyrVert =
|
||||
Geometries.GetVertices(Geometry::PYRAMID);
|
||||
locpm.SetSize(3, 3);
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
const IntegrationPoint &vert = PyrVert->IntPoint(pv[to[j]]);
|
||||
locpm(0, j) = vert.x;
|
||||
locpm(1, j) = vert.y;
|
||||
locpm(2, j) = vert.z;
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::GetLocalQuadToHexTransformation(
|
||||
IsoparametricTransformation &Transf, int i)
|
||||
{
|
||||
@@ -807,29 +781,6 @@ void Mesh::GetLocalQuadToWdgTransformation(
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::GetLocalQuadToPyrTransformation(
|
||||
IsoparametricTransformation &Transf, int i)
|
||||
{
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
|
||||
Transf.SetFE(&QuadrilateralFE);
|
||||
// (i/64) is the local face no. in the pyr
|
||||
MFEM_VERIFY(i < 64, "Local face index " << i/64
|
||||
<< " is not a quadrilateral face of a pyramid.");
|
||||
const int *pv = pyr_t::FaceVert[i/64];
|
||||
// (i%64) is the orientation of the quad
|
||||
const int *qo = quad_t::Orient[i%64];
|
||||
const IntegrationRule *PyrVert = Geometries.GetVertices(Geometry::PYRAMID);
|
||||
locpm.SetSize(3, 4);
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
const IntegrationPoint &vert = PyrVert->IntPoint(pv[qo[j]]);
|
||||
locpm(0, j) = vert.x;
|
||||
locpm(1, j) = vert.y;
|
||||
locpm(2, j) = vert.z;
|
||||
}
|
||||
}
|
||||
|
||||
const GeometricFactors* Mesh::GetGeometricFactors(const IntegrationRule& ir,
|
||||
const int flags,
|
||||
MemoryType d_mt)
|
||||
@@ -911,19 +862,10 @@ void Mesh::GetLocalFaceTransformation(
|
||||
{
|
||||
GetLocalTriToTetTransformation(Transf, info);
|
||||
}
|
||||
else if (elem_type == Element::WEDGE)
|
||||
{
|
||||
GetLocalTriToWdgTransformation(Transf, info);
|
||||
}
|
||||
else if (elem_type == Element::PYRAMID)
|
||||
{
|
||||
GetLocalTriToPyrTransformation(Transf, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
|
||||
"face type " << face_type
|
||||
<< " and element type " << elem_type << "\n");
|
||||
MFEM_ASSERT(elem_type == Element::WEDGE, "");
|
||||
GetLocalTriToWdgTransformation(Transf, info);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -932,19 +874,10 @@ void Mesh::GetLocalFaceTransformation(
|
||||
{
|
||||
GetLocalQuadToHexTransformation(Transf, info);
|
||||
}
|
||||
else if (elem_type == Element::WEDGE)
|
||||
{
|
||||
GetLocalQuadToWdgTransformation(Transf, info);
|
||||
}
|
||||
else if (elem_type == Element::PYRAMID)
|
||||
{
|
||||
GetLocalQuadToPyrTransformation(Transf, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
|
||||
"face type " << face_type
|
||||
<< " and element type " << elem_type << "\n");
|
||||
MFEM_ASSERT(elem_type == Element::WEDGE, "");
|
||||
GetLocalQuadToWdgTransformation(Transf, info);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1437,20 +1370,6 @@ int Mesh::AddWedge(const int *vi, int attr)
|
||||
return NumOfElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Pyramid(v1, v2, v3, v4, v5, attr);
|
||||
return NumOfElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddPyramid(const int *vi, int attr)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
elements[NumOfElements] = new Pyramid(vi, attr);
|
||||
return NumOfElements++;
|
||||
}
|
||||
|
||||
int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
|
||||
int attr)
|
||||
{
|
||||
@@ -1504,25 +1423,6 @@ void Mesh::AddHexAsWedges(const int *vi, int attr)
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::AddHexAsPyramids(const int *vi, int attr)
|
||||
{
|
||||
static const int hex_to_pyr[6][5] =
|
||||
{
|
||||
{ 0, 1, 2, 3, 8 }, { 0, 4, 5, 1, 8 }, { 1, 5, 6, 2, 8 },
|
||||
{ 2, 6, 7, 3, 8 }, { 3, 7, 4, 0, 8 }, { 7, 6, 5, 4, 8 }
|
||||
};
|
||||
int ti[5];
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
for (int j = 0; j < 5; j++)
|
||||
{
|
||||
ti[j] = vi[hex_to_pyr[i][j]];
|
||||
}
|
||||
AddPyramid(ti, attr);
|
||||
}
|
||||
}
|
||||
|
||||
int Mesh::AddElement(Element *elem)
|
||||
{
|
||||
CheckEnlarge(elements, NumOfElements);
|
||||
@@ -2792,16 +2692,11 @@ void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
|
||||
NElem *= 2;
|
||||
NBdrElem += 2*nx*ny;
|
||||
}
|
||||
else if (type == Element::PYRAMID)
|
||||
{
|
||||
NElem *= 6;
|
||||
NVert += nx * ny * nz;
|
||||
}
|
||||
|
||||
InitMesh(3, 3, NVert, NElem, NBdrElem);
|
||||
|
||||
double coord[3];
|
||||
int ind[9];
|
||||
int ind[8];
|
||||
|
||||
// Sets vertices and the corresponding coordinates
|
||||
for (z = 0; z <= nz; z++)
|
||||
@@ -2817,25 +2712,8 @@ void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == Element::PYRAMID)
|
||||
{
|
||||
for (z = 0; z < nz; z++)
|
||||
{
|
||||
coord[2] = (((double) z + 0.5) / nz) * sz;
|
||||
for (y = 0; y < ny; y++)
|
||||
{
|
||||
coord[1] = (((double) y + 0.5 ) / ny) * sy;
|
||||
for (x = 0; x < nx; x++)
|
||||
{
|
||||
coord[0] = (((double) x + 0.5 ) / nx) * sx;
|
||||
AddVertex(coord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
|
||||
#define VTXP(XC, YC, ZC) ((nx+1)*(ny+1)*(nz+1)+(XC)+((YC)+(ZC)*ny)*nx)
|
||||
|
||||
// Sets elements and the corresponding indices of vertices
|
||||
if (sfc_ordering && type == Element::HEXAHEDRON)
|
||||
@@ -2886,11 +2764,6 @@ void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
|
||||
{
|
||||
AddHexAsWedges(ind, 1);
|
||||
}
|
||||
else if (type == Element::PYRAMID)
|
||||
{
|
||||
ind[8] = VTXP( x, y, z);
|
||||
AddHexAsPyramids(ind, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddHex(ind, 1);
|
||||
@@ -3555,7 +3428,6 @@ Element *Mesh::NewElement(int geom)
|
||||
#endif
|
||||
case Geometry::CUBE: return (new Hexahedron);
|
||||
case Geometry::PRISM: return (new Wedge);
|
||||
case Geometry::PYRAMID: return (new Pyramid);
|
||||
default:
|
||||
MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
|
||||
}
|
||||
@@ -3648,15 +3520,6 @@ void Mesh::SetMeshGen()
|
||||
meshgen |= 4;
|
||||
break;
|
||||
|
||||
case Element::PYRAMID:
|
||||
mesh_geoms |= (1 << Geometry::PYRAMID);
|
||||
mesh_geoms |= (1 << Geometry::SQUARE);
|
||||
mesh_geoms |= (1 << Geometry::TRIANGLE);
|
||||
mesh_geoms |= (1 << Geometry::SEGMENT);
|
||||
mesh_geoms |= (1 << Geometry::POINT);
|
||||
meshgen |= 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
MFEM_ABORT("invalid element type: " << type);
|
||||
break;
|
||||
@@ -4111,12 +3974,6 @@ void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> ref_factors,
|
||||
}
|
||||
}
|
||||
|
||||
if (Dim > 2)
|
||||
{
|
||||
GetElementToFaceTable(false);
|
||||
GenerateFaces();
|
||||
}
|
||||
|
||||
// Add refined boundary elements
|
||||
for (int el = 0; el < orig_mesh.GetNBE(); el++)
|
||||
{
|
||||
@@ -5197,19 +5054,6 @@ int Mesh::CheckElementOrientation(bool fix_it)
|
||||
}
|
||||
break;
|
||||
|
||||
case Element::PYRAMID:
|
||||
// only check the Jacobian at the center of the element
|
||||
GetElementJacobian(i, J);
|
||||
if (J.Det() < 0.0)
|
||||
{
|
||||
wo++;
|
||||
if (fix_it)
|
||||
{
|
||||
// how?
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Element::HEXAHEDRON:
|
||||
// only check the Jacobian at the center of the element
|
||||
GetElementJacobian(i, J);
|
||||
@@ -6292,22 +6136,6 @@ void Mesh::GenerateFaces()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::PYRAMID:
|
||||
{
|
||||
for (int j = 0; j < 1; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
AddQuadFaceElement(j, ef[j], i,
|
||||
v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
|
||||
}
|
||||
for (int j = 1; j < 5; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
AddTriangleFaceElement(j, ef[j], i,
|
||||
v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::HEXAHEDRON:
|
||||
{
|
||||
for (int j = 0; j < 6; j++)
|
||||
@@ -6400,20 +6228,6 @@ STable3D *Mesh::GetFacesTable()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::PYRAMID:
|
||||
{
|
||||
for (int j = 0; j < 1; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
|
||||
}
|
||||
for (int j = 1; j < 5; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::WEDGE:
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
@@ -6488,22 +6302,6 @@ STable3D *Mesh::GetElementToFaceTable(int ret_ftbl)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::PYRAMID:
|
||||
{
|
||||
for (int j = 0; j < 1; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
el_to_face->Push(
|
||||
i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
|
||||
}
|
||||
for (int j = 1; j < 5; j++)
|
||||
{
|
||||
const int *fv = pyr_t::FaceVert[j];
|
||||
el_to_face->Push(
|
||||
i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::HEXAHEDRON:
|
||||
{
|
||||
// find the face by the vertices with the smallest 3 numbers
|
||||
@@ -7840,22 +7638,8 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
|
||||
}
|
||||
}
|
||||
|
||||
int pyr_counter = 0;
|
||||
if (HasGeometry(Geometry::PYRAMID))
|
||||
{
|
||||
for (int i = 0; i < elements.Size(); i++)
|
||||
{
|
||||
if (elements[i]->GetType() == Element::PYRAMID)
|
||||
{
|
||||
pyr_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Map from edge-index to vertex-index, needed for ReorientTetMesh() for
|
||||
// parallel meshes.
|
||||
// Note: with the removal of ReorientTetMesh() this may no longer
|
||||
// be needed. Unfortunately, it's hard to be sure.
|
||||
Array<int> e2v;
|
||||
if (HasGeometry(Geometry::TETRAHEDRON))
|
||||
{
|
||||
@@ -7911,7 +7695,7 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
|
||||
Array<Element*> new_boundary;
|
||||
|
||||
vertices.SetSize(oelem + hex_counter);
|
||||
new_elements.SetSize(8 * NumOfElements + 2 * pyr_counter);
|
||||
new_elements.SetSize(8 * NumOfElements);
|
||||
CoarseFineTr.embeddings.SetSize(new_elements.Size());
|
||||
|
||||
hex_counter = 0;
|
||||
@@ -8177,73 +7961,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
|
||||
}
|
||||
break;
|
||||
|
||||
case Element::PYRAMID:
|
||||
{
|
||||
const int *f = el_to_face->GetRow(i);
|
||||
// pyr_counter++;
|
||||
|
||||
for (int fi = 0; fi < 1; fi++)
|
||||
{
|
||||
for (int k = 0; k < 4; k++)
|
||||
{
|
||||
vv[k] = v[pyr_t::FaceVert[fi][k]];
|
||||
}
|
||||
AverageVertices(vv, 4, oface + f2qf[f[fi]]);
|
||||
}
|
||||
|
||||
for (int ei = 0; ei < 8; ei++)
|
||||
{
|
||||
for (int k = 0; k < 2; k++)
|
||||
{
|
||||
vv[k] = v[pyr_t::Edges[ei][k]];
|
||||
}
|
||||
AverageVertices(vv, 2, oedge+e[ei]);
|
||||
}
|
||||
|
||||
const int qf0 = f2qf[f[0]];
|
||||
|
||||
new_elements[j++] =
|
||||
new Pyramid(v[0], oedge+e[0], oface+qf0,
|
||||
oedge+e[3], oedge+e[4], attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Pyramid(oedge+e[0], v[1], oedge+e[1],
|
||||
oface+qf0, oedge+e[5], attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Pyramid(oface+qf0, oedge+e[1], v[2],
|
||||
oedge+e[2], oedge+e[6], attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Pyramid(oedge+e[3], oface+qf0, oedge+e[2],
|
||||
v[3], oedge+e[7], attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Pyramid(oedge+e[4], oedge+e[5], oedge+e[6],
|
||||
oedge+e[7], v[4], attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Pyramid(oedge+e[7], oedge+e[6], oedge+e[5],
|
||||
oedge+e[4], oface+qf0, attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Tetrahedron(oedge+e[0], oedge+e[4], oedge+e[5],
|
||||
oface+qf0, attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Tetrahedron(oedge+e[1], oedge+e[5], oedge+e[6],
|
||||
oface+qf0, attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Tetrahedron(oedge+e[2], oedge+e[6], oedge+e[7],
|
||||
oface+qf0, attr);
|
||||
|
||||
new_elements[j++] =
|
||||
new Tetrahedron(oedge+e[3], oedge+e[7], oedge+e[4],
|
||||
oface+qf0, attr);
|
||||
}
|
||||
break;
|
||||
|
||||
case Element::HEXAHEDRON:
|
||||
{
|
||||
const int *f = el_to_face->GetRow(i);
|
||||
@@ -8375,7 +8092,7 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
|
||||
}
|
||||
mfem::Swap(boundary, new_boundary);
|
||||
|
||||
static const double A = 0.0, B = 0.5, C = 1.0, D = -1.0;
|
||||
static const double A = 0.0, B = 0.5, C = 1.0;
|
||||
static double tet_children[3*4*16] =
|
||||
{
|
||||
A,A,A, B,A,A, A,B,A, A,A,B,
|
||||
@@ -8401,19 +8118,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
|
||||
A,A,B, A,B,B, B,A,B, B,B,A,
|
||||
A,A,B, B,A,B, B,A,A, B,B,A
|
||||
};
|
||||
static double pyr_children[3*5*10] =
|
||||
{
|
||||
A,A,A, B,A,A, B,B,A, A,B,A, A,A,B,
|
||||
B,A,A, C,A,A, C,B,A, B,B,A, B,A,B,
|
||||
B,B,A, C,B,A, C,C,A, B,C,A, B,B,B,
|
||||
A,B,A, B,B,A, B,C,A, A,C,A, A,B,B,
|
||||
A,A,B, B,A,B, B,B,B, A,B,B, A,A,C,
|
||||
A,B,B, B,B,B, B,A,B, A,A,B, B,B,A,
|
||||
B,A,A, A,A,B, B,A,B, B,B,A, D,D,D,
|
||||
C,B,A, B,A,B, B,B,B, B,B,A, D,D,D,
|
||||
B,C,A, B,B,B, A,B,B, B,B,A, D,D,D,
|
||||
A,B,A, A,B,B, A,A,B, B,B,A, D,D,D
|
||||
};
|
||||
static double pri_children[3*6*8] =
|
||||
{
|
||||
A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
|
||||
@@ -8439,8 +8143,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
|
||||
|
||||
CoarseFineTr.point_matrices[Geometry::TETRAHEDRON]
|
||||
.UseExternalData(tet_children, 3, 4, 16);
|
||||
CoarseFineTr.point_matrices[Geometry::PYRAMID]
|
||||
.UseExternalData(pyr_children, 3, 5, 10);
|
||||
CoarseFineTr.point_matrices[Geometry::PRISM]
|
||||
.UseExternalData(pri_children, 3, 6, 8);
|
||||
CoarseFineTr.point_matrices[Geometry::CUBE]
|
||||
@@ -8457,7 +8159,7 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
|
||||
}
|
||||
|
||||
NumOfVertices = vertices.Size();
|
||||
NumOfElements = 8 * NumOfElements + 2 * pyr_counter;
|
||||
NumOfElements = 8 * NumOfElements;
|
||||
NumOfBdrElements = 4 * NumOfBdrElements;
|
||||
|
||||
GetElementToFaceTable();
|
||||
@@ -9041,7 +8743,7 @@ void Mesh::GeneralRefinement(const Array<Refinement> &refinements,
|
||||
else if (nonconforming < 0)
|
||||
{
|
||||
// determine if nonconforming refinement is suitable
|
||||
if ((meshgen & 2) || (meshgen & 4) || (meshgen & 8))
|
||||
if ((meshgen & 2) || (meshgen & 4))
|
||||
{
|
||||
nonconforming = 1; // tensor product elements and wedges
|
||||
}
|
||||
@@ -9825,7 +9527,6 @@ void Mesh::Printer(std::ostream &out, std::string section_delimiter) const
|
||||
"# TETRAHEDRON = 4\n"
|
||||
"# CUBE = 5\n"
|
||||
"# PRISM = 6\n"
|
||||
"# PYRAMID = 7\n"
|
||||
"#\n";
|
||||
|
||||
out << "\ndimension\n" << Dim;
|
||||
|
||||
+1
-19
@@ -177,7 +177,6 @@ protected:
|
||||
int own_nodes;
|
||||
|
||||
static const int vtk_quadratic_tet[10];
|
||||
static const int vtk_quadratic_pyramid[13];
|
||||
static const int vtk_quadratic_wedge[18];
|
||||
static const int vtk_quadratic_hex[27];
|
||||
|
||||
@@ -196,7 +195,6 @@ public:
|
||||
typedef Geometry::Constants<Geometry::TETRAHEDRON> tet_t;
|
||||
typedef Geometry::Constants<Geometry::CUBE> hex_t;
|
||||
typedef Geometry::Constants<Geometry::PRISM> pri_t;
|
||||
typedef Geometry::Constants<Geometry::PYRAMID> pyr_t;
|
||||
|
||||
enum Operation { NONE, REFINE, DEREFINE, REBALANCE };
|
||||
|
||||
@@ -375,17 +373,11 @@ protected:
|
||||
void GetLocalTriToWdgTransformation (IsoparametricTransformation &loc,
|
||||
int i);
|
||||
/// Used in GetFaceElementTransformations (...)
|
||||
void GetLocalTriToPyrTransformation (IsoparametricTransformation &loc,
|
||||
int i);
|
||||
/// Used in GetFaceElementTransformations (...)
|
||||
void GetLocalQuadToHexTransformation (IsoparametricTransformation &loc,
|
||||
int i);
|
||||
/// Used in GetFaceElementTransformations (...)
|
||||
void GetLocalQuadToWdgTransformation (IsoparametricTransformation &loc,
|
||||
int i);
|
||||
/// Used in GetFaceElementTransformations (...)
|
||||
void GetLocalQuadToPyrTransformation (IsoparametricTransformation &loc,
|
||||
int i);
|
||||
|
||||
/** Used in GetFaceElementTransformations to account for the fact that a
|
||||
slave face occupies only a portion of its master face. */
|
||||
@@ -665,15 +657,11 @@ public:
|
||||
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr = 1);
|
||||
int AddWedge(const int *vi, int attr = 1);
|
||||
|
||||
int AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr = 1);
|
||||
int AddPyramid(const int *vi, int attr = 1);
|
||||
|
||||
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
|
||||
int attr = 1);
|
||||
int AddHex(const int *vi, int attr = 1);
|
||||
void AddHexAsTets(const int *vi, int attr = 1);
|
||||
void AddHexAsWedges(const int *vi, int attr = 1);
|
||||
void AddHexAsPyramids(const int *vi, int attr = 1);
|
||||
|
||||
/// The parameter @a elem should be allocated using the NewElement() method
|
||||
int AddElement(Element *elem);
|
||||
@@ -841,16 +829,10 @@ public:
|
||||
|
||||
/** @brief Get the mesh generator/type.
|
||||
|
||||
The purpose of this is to be able to quickly tell what type of elements
|
||||
one has in the mesh. Examination of this bitmask along with knowledge
|
||||
of the mesh dimension can be used to identify which element types are
|
||||
present.
|
||||
|
||||
@return A bitmask:
|
||||
- bit 0 - simplices are present in the mesh (triangles, tets),
|
||||
- bit 1 - tensor product elements are present in the mesh (quads, hexes),
|
||||
- bit 2 - the mesh has wedge elements.
|
||||
- bit 3 - the mesh has pyramid elements.
|
||||
|
||||
In parallel, the result takes into account elements on all processors.
|
||||
*/
|
||||
@@ -1245,7 +1227,7 @@ public:
|
||||
satisfy: v0 < min(v1, v2).
|
||||
|
||||
@note Refinement does not work after a call to this method! */
|
||||
MFEM_DEPRECATED virtual void ReorientTetMesh();
|
||||
virtual void ReorientTetMesh();
|
||||
|
||||
int *CartesianPartitioning(int nxyz[]);
|
||||
int *GeneratePartitioning(int nparts, int part_method = 1);
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "mesh_operators.hpp"
|
||||
#include "nurbs.hpp"
|
||||
#include "wedge.hpp"
|
||||
#include "pyramid.hpp"
|
||||
|
||||
#ifdef MFEM_USE_MESQUITE
|
||||
#include "mesquite.hpp"
|
||||
|
||||
+21
-61
@@ -352,11 +352,6 @@ void Mesh::ReadTrueGridMesh(std::istream &input)
|
||||
const int Mesh::vtk_quadratic_tet[10] =
|
||||
{ 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 };
|
||||
|
||||
// see Pyramid::edges & Mesh::GenerateFaces
|
||||
// https://www.vtk.org/doc/nightly/html/classvtkBiQuadraticQuadraticWedge.html
|
||||
const int Mesh::vtk_quadratic_pyramid[13] =
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
|
||||
// see Wedge::edges & Mesh::GenerateFaces
|
||||
// https://www.vtk.org/doc/nightly/html/classvtkBiQuadraticQuadraticWedge.html
|
||||
const int Mesh::vtk_quadratic_wedge[18] =
|
||||
@@ -519,7 +514,8 @@ void Mesh::CreateVTKMesh(const Vector &points, const Array<int> &cell_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Generate faces and edges so that we can define FE space on the mesh
|
||||
// Generate faces and edges so that we can define
|
||||
// FE space on the mesh
|
||||
FinalizeTopology();
|
||||
|
||||
FiniteElementCollection *fec;
|
||||
@@ -550,8 +546,6 @@ void Mesh::CreateVTKMesh(const Vector &points, const Array<int> &cell_data,
|
||||
vtk_mfem = vtk_quadratic_hex; break;
|
||||
case Geometry::PRISM:
|
||||
vtk_mfem = vtk_quadratic_wedge; break;
|
||||
case Geometry::PYRAMID:
|
||||
vtk_mfem = vtk_quadratic_pyramid; break;
|
||||
default:
|
||||
vtk_mfem = NULL; // suppress a warning
|
||||
break;
|
||||
@@ -1400,10 +1394,6 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
|
||||
{
|
||||
type = Element::WEDGE;
|
||||
}
|
||||
else if (eltype == "pyramid")
|
||||
{
|
||||
type = Element::PYRAMID;
|
||||
}
|
||||
else if (eltype == "tet")
|
||||
{
|
||||
type = Element::TETRAHEDRON;
|
||||
@@ -1458,7 +1448,7 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
|
||||
Make2D(nx, ny, type, sx, sy, generate_edges, true);
|
||||
}
|
||||
else if (type == Element::TETRAHEDRON || type == Element::WEDGE ||
|
||||
type == Element::HEXAHEDRON || type == Element::PYRAMID)
|
||||
type == Element::HEXAHEDRON)
|
||||
{
|
||||
MFEM_VERIFY(nx > 0 && ny > 0 && nz > 0 &&
|
||||
sx > 0.0 && sy > 0.0 && sz > 0.0,
|
||||
@@ -1895,9 +1885,6 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
ho_wdg[2] = wdg18; ho_wdg[3] = wdg40;
|
||||
ho_pyr[2] = pyr14; ho_pyr[3] = pyr30;
|
||||
|
||||
bool has_nonpositive_phys_domain = false;
|
||||
bool has_positive_phys_domain = false;
|
||||
|
||||
if (binary)
|
||||
{
|
||||
int n_elem_part = 0; // partial sum of elements that are read
|
||||
@@ -1948,19 +1935,17 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
vert_indices[vi] = it->second;
|
||||
}
|
||||
|
||||
// Non-positive attributes are not allowed in MFEM. However,
|
||||
// by default, Gmsh sets the physical domain of all elements
|
||||
// to zero. In the case that all elements have physical domain
|
||||
// zero, we will given them attribute 1. If only some elements
|
||||
// have physical domain zero, we will throw an error.
|
||||
// non-positive attributes are not allowed in MFEM
|
||||
if (phys_domain <= 0)
|
||||
{
|
||||
has_nonpositive_phys_domain = true;
|
||||
phys_domain = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_positive_phys_domain = true;
|
||||
MFEM_ABORT("Non-positive element attribute in Gmsh mesh!\n"
|
||||
"By default Gmsh sets element tags (attributes)"
|
||||
" to '0' but MFEM requires that they be"
|
||||
" positive integers.\n"
|
||||
"Use \"Physical Curve\", \"Physical Surface\","
|
||||
" or \"Physical Volume\" to set tags/attributes"
|
||||
" for all curves, surfaces, or volumes in your"
|
||||
" Gmsh geometry to values which are >= 1.");
|
||||
}
|
||||
|
||||
// initialize the mesh element
|
||||
@@ -2177,19 +2162,17 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
vert_indices[vi] = it->second;
|
||||
}
|
||||
|
||||
// Non-positive attributes are not allowed in MFEM. However,
|
||||
// by default, Gmsh sets the physical domain of all elements
|
||||
// to zero. In the case that all elements have physical domain
|
||||
// zero, we will given them attribute 1. If only some elements
|
||||
// have physical domain zero, we will throw an error.
|
||||
// non-positive attributes are not allowed in MFEM
|
||||
if (phys_domain <= 0)
|
||||
{
|
||||
has_nonpositive_phys_domain = true;
|
||||
phys_domain = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_positive_phys_domain = true;
|
||||
MFEM_ABORT("Non-positive element attribute in Gmsh mesh!\n"
|
||||
"By default Gmsh sets element tags (attributes)"
|
||||
" to '0' but MFEM requires that they be"
|
||||
" positive integers.\n"
|
||||
"Use \"Physical Curve\", \"Physical Surface\","
|
||||
" or \"Physical Volume\" to set tags/attributes"
|
||||
" for all curves, surfaces, or volumes in your"
|
||||
" Gmsh geometry to values which are >= 1.");
|
||||
}
|
||||
|
||||
// initialize the mesh element
|
||||
@@ -2374,24 +2357,6 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
} // el (all elements)
|
||||
} // if ASCII
|
||||
|
||||
if (has_positive_phys_domain && has_nonpositive_phys_domain)
|
||||
{
|
||||
MFEM_ABORT("Non-positive element attribute in Gmsh mesh!\n"
|
||||
"By default Gmsh sets element tags (attributes)"
|
||||
" to '0' but MFEM requires that they be"
|
||||
" positive integers.\n"
|
||||
"Use \"Physical Curve\", \"Physical Surface\","
|
||||
" or \"Physical Volume\" to set tags/attributes"
|
||||
" for all curves, surfaces, or volumes in your"
|
||||
" Gmsh geometry to values which are >= 1.");
|
||||
}
|
||||
else if (has_nonpositive_phys_domain)
|
||||
{
|
||||
mfem::out << "\nGmsh reader: all element attributes were zero.\n"
|
||||
<< "MFEM only supports positive element attributes.\n"
|
||||
<< "Setting element attributes to 1.\n\n";
|
||||
}
|
||||
|
||||
if (!elements_3D.empty())
|
||||
{
|
||||
Dim = 3;
|
||||
@@ -2480,10 +2445,6 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
// initialize mesh_geoms so we can create Nodes FE space below
|
||||
this->SetMeshGen();
|
||||
|
||||
// Generate faces and edges so that we can define
|
||||
// FE space on the mesh
|
||||
this->FinalizeTopology();
|
||||
|
||||
// Construct GridFunction for uniformly spaced high order coords
|
||||
FiniteElementCollection* nfec;
|
||||
FiniteElementSpace* nfes;
|
||||
@@ -2705,7 +2666,6 @@ void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
// Convert nodes to discontinuous GridFunction (if they aren't already)
|
||||
if (mesh_order == 1)
|
||||
{
|
||||
this->FinalizeTopology();
|
||||
this->SetMeshGen();
|
||||
this->SetCurvature(1, true, spaceDim, Ordering::byVDIM);
|
||||
}
|
||||
|
||||
+4
-243
@@ -34,7 +34,6 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
|
||||
group_sedge(pmesh.group_sedge),
|
||||
group_stria(pmesh.group_stria),
|
||||
group_squad(pmesh.group_squad),
|
||||
face_nbr_el_to_face(NULL),
|
||||
glob_elem_offset(-1),
|
||||
glob_offset_sequence(-1),
|
||||
gtopo(pmesh.gtopo)
|
||||
@@ -106,8 +105,7 @@ ParMesh& ParMesh::operator=(ParMesh &&mesh)
|
||||
|
||||
ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
int part_method)
|
||||
: face_nbr_el_to_face(NULL)
|
||||
, glob_elem_offset(-1)
|
||||
: glob_elem_offset(-1)
|
||||
, glob_offset_sequence(-1)
|
||||
, gtopo(comm)
|
||||
{
|
||||
@@ -854,7 +852,6 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh)
|
||||
: MyComm(pncmesh.MyComm)
|
||||
, NRanks(pncmesh.NRanks)
|
||||
, MyRank(pncmesh.MyRank)
|
||||
, face_nbr_el_to_face(NULL)
|
||||
, glob_elem_offset(-1)
|
||||
, glob_offset_sequence(-1)
|
||||
, gtopo(MyComm)
|
||||
@@ -921,8 +918,7 @@ void ParMesh::FinalizeParTopo()
|
||||
}
|
||||
|
||||
ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine)
|
||||
: face_nbr_el_to_face(NULL)
|
||||
, glob_elem_offset(-1)
|
||||
: glob_elem_offset(-1)
|
||||
, glob_offset_sequence(-1)
|
||||
, gtopo(comm)
|
||||
{
|
||||
@@ -1133,7 +1129,6 @@ void ParMesh::MakeRefined_(ParMesh &orig_mesh, int ref_factor, int ref_type)
|
||||
MyComm = orig_mesh.GetComm();
|
||||
NRanks = orig_mesh.GetNRanks();
|
||||
MyRank = orig_mesh.GetMyRank();
|
||||
face_nbr_el_to_face = NULL;
|
||||
glob_elem_offset = -1;
|
||||
glob_offset_sequence = -1;
|
||||
gtopo = orig_mesh.gtopo;
|
||||
@@ -2078,11 +2073,6 @@ void ParMesh::ExchangeFaceNbrData()
|
||||
|
||||
ExchangeFaceNbrData(gr_sface, s2l_face);
|
||||
|
||||
if (Dim == 3)
|
||||
{
|
||||
GetFaceNbrElementToFaceTable();
|
||||
}
|
||||
|
||||
if (del_tables) { delete gr_sface; }
|
||||
|
||||
if ( have_face_nbr_data ) { return; }
|
||||
@@ -2151,8 +2141,6 @@ void ParMesh::ExchangeFaceNbrData(Table *gr_sface, int *s2l_face)
|
||||
el_marker = -1;
|
||||
vertex_marker = -1;
|
||||
|
||||
Array<int> fcs, cor;
|
||||
|
||||
Table send_face_nbr_elemdata, send_face_nbr_facedata;
|
||||
|
||||
send_face_nbr_elements.MakeI(num_face_nbrs);
|
||||
@@ -2182,9 +2170,7 @@ void ParMesh::ExchangeFaceNbrData(Table *gr_sface, int *s2l_face)
|
||||
send_face_nbr_vertices.AddAColumnInRow(fn);
|
||||
}
|
||||
|
||||
const int nf = elements[el]->GetNFaces();
|
||||
|
||||
send_face_nbr_elemdata.AddColumnsInRow(fn, nv + nf + 2);
|
||||
send_face_nbr_elemdata.AddColumnsInRow(fn, nv + 2);
|
||||
}
|
||||
}
|
||||
send_face_nbr_facedata.AddColumnsInRow(fn, 2*num_sfaces);
|
||||
@@ -2236,13 +2222,6 @@ void ParMesh::ExchangeFaceNbrData(Table *gr_sface, int *s2l_face)
|
||||
send_face_nbr_elemdata.AddConnection(
|
||||
fn, GetElementBaseGeometry(el));
|
||||
send_face_nbr_elemdata.AddConnections(fn, v, nv);
|
||||
|
||||
if (Dim == 3)
|
||||
{
|
||||
const int nf = elements[el]->GetNFaces();
|
||||
GetElementFaces(el, fcs, cor);
|
||||
send_face_nbr_elemdata.AddConnections(fn, cor, nf);
|
||||
}
|
||||
}
|
||||
send_face_nbr_facedata.AddConnection(fn, el);
|
||||
int info = faces_info[lface].Elem1Inf;
|
||||
@@ -2288,13 +2267,12 @@ void ParMesh::ExchangeFaceNbrData(Table *gr_sface, int *s2l_face)
|
||||
for (int el = 0; el < num_elems; el++)
|
||||
{
|
||||
const int nv = elements[elems[el]]->GetNVertices();
|
||||
const int nf = (Dim == 3) ? elements[elems[el]]->GetNFaces() : 0;
|
||||
elemdata += 2; // skip the attribute and the geometry type
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
elemdata[j] = vertex_marker[elemdata[j]];
|
||||
}
|
||||
elemdata += nv + nf;
|
||||
elemdata += nv;
|
||||
|
||||
el_marker[elems[el]] = el;
|
||||
}
|
||||
@@ -2345,8 +2323,6 @@ void ParMesh::ExchangeFaceNbrData(Table *gr_sface, int *s2l_face)
|
||||
|
||||
// convert the element data into face_nbr_elements
|
||||
face_nbr_elements.SetSize(face_nbr_elements_offset[num_face_nbrs]);
|
||||
face_nbr_el_ori.Clear();
|
||||
face_nbr_el_ori.SetSize(face_nbr_elements_offset[num_face_nbrs], 6);
|
||||
while (true)
|
||||
{
|
||||
int fn;
|
||||
@@ -2374,20 +2350,9 @@ void ParMesh::ExchangeFaceNbrData(Table *gr_sface, int *s2l_face)
|
||||
}
|
||||
el->SetVertices(recv_elemdata);
|
||||
recv_elemdata += nv;
|
||||
if (Dim == 3)
|
||||
{
|
||||
int nf = el->GetNFaces();
|
||||
int * fn_ori = face_nbr_el_ori.GetRow(elem_off);
|
||||
for (int j = 0; j < nf; j++)
|
||||
{
|
||||
fn_ori[j] = recv_elemdata[j];
|
||||
}
|
||||
recv_elemdata += nf;
|
||||
}
|
||||
face_nbr_elements[elem_off++] = el;
|
||||
}
|
||||
}
|
||||
face_nbr_el_ori.Finalize();
|
||||
|
||||
MPI_Waitall(num_face_nbrs, send_requests, statuses);
|
||||
|
||||
@@ -2546,179 +2511,6 @@ void ParMesh::ExchangeFaceNbrNodes()
|
||||
}
|
||||
}
|
||||
|
||||
STable3D *ParMesh::GetSharedFacesTable()
|
||||
{
|
||||
STable3D *sfaces_tbl = new STable3D(face_nbr_vertices.Size());
|
||||
for (int i = 0; i < face_nbr_elements.Size(); i++)
|
||||
{
|
||||
const int *v = face_nbr_elements[i]->GetVertices();
|
||||
switch (face_nbr_elements[i]->GetType())
|
||||
{
|
||||
case Element::TETRAHEDRON:
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
const int *fv = tet_t::FaceVert[j];
|
||||
sfaces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::WEDGE:
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
const int *fv = pri_t::FaceVert[j];
|
||||
sfaces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
}
|
||||
for (int j = 2; j < 5; j++)
|
||||
{
|
||||
const int *fv = pri_t::FaceVert[j];
|
||||
sfaces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::HEXAHEDRON:
|
||||
{
|
||||
// find the face by the vertices with the smallest 3 numbers
|
||||
// z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
|
||||
for (int j = 0; j < 6; j++)
|
||||
{
|
||||
const int *fv = hex_t::FaceVert[j];
|
||||
sfaces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MFEM_ABORT("Unexpected type of Element.");
|
||||
}
|
||||
}
|
||||
return sfaces_tbl;
|
||||
}
|
||||
|
||||
STable3D *ParMesh::GetFaceNbrElementToFaceTable(int ret_ftbl)
|
||||
{
|
||||
int i, *v;
|
||||
STable3D * faces_tbl = GetFacesTable();
|
||||
STable3D * sfaces_tbl = GetSharedFacesTable();
|
||||
|
||||
if (face_nbr_el_to_face != NULL)
|
||||
{
|
||||
delete face_nbr_el_to_face;
|
||||
}
|
||||
face_nbr_el_to_face = new Table(face_nbr_elements.Size(), 6);
|
||||
for (i = 0; i < face_nbr_elements.Size(); i++)
|
||||
{
|
||||
v = face_nbr_elements[i]->GetVertices();
|
||||
switch (face_nbr_elements[i]->GetType())
|
||||
{
|
||||
case Element::TETRAHEDRON:
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
const int *fv = tet_t::FaceVert[j];
|
||||
int lf = faces_tbl->Index(v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
if (lf < 0)
|
||||
{
|
||||
lf = sfaces_tbl->Index(v[fv[0]], v[fv[1]], v[fv[2]]);
|
||||
if (lf >= 0)
|
||||
{
|
||||
lf += NumOfFaces;
|
||||
}
|
||||
}
|
||||
face_nbr_el_to_face->Push(i, lf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::WEDGE:
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
const int *fv = pri_t::FaceVert[j];
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[0]], v[fv[1]], v[fv[2]]));
|
||||
}
|
||||
for (int j = 2; j < 5; j++)
|
||||
{
|
||||
const int *fv = pri_t::FaceVert[j];
|
||||
int k = 0;
|
||||
int max = v[fv[0]];
|
||||
|
||||
if (max < v[fv[1]]) { max = v[fv[1]], k = 1; }
|
||||
if (max < v[fv[2]]) { max = v[fv[2]], k = 2; }
|
||||
if (max < v[fv[3]]) { k = 3; }
|
||||
|
||||
switch (k)
|
||||
{
|
||||
case 0:
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[1]],v[fv[2]],v[fv[3]]));
|
||||
break;
|
||||
case 1:
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[0]],v[fv[2]],v[fv[3]]));
|
||||
break;
|
||||
case 2:
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[0]],v[fv[1]],v[fv[3]]));
|
||||
break;
|
||||
case 3:
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[0]],v[fv[1]],v[fv[2]]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Element::HEXAHEDRON:
|
||||
{
|
||||
// find the face by the vertices with the smallest 3 numbers
|
||||
// z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
|
||||
for (int j = 0; j < 6; j++)
|
||||
{
|
||||
const int *fv = hex_t::FaceVert[j];
|
||||
int k = 0;
|
||||
int max = v[fv[0]];
|
||||
|
||||
if (max < v[fv[1]]) { max = v[fv[1]], k = 1; }
|
||||
if (max < v[fv[2]]) { max = v[fv[2]], k = 2; }
|
||||
if (max < v[fv[3]]) { k = 3; }
|
||||
|
||||
switch (k)
|
||||
{
|
||||
case 0:
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[1]],v[fv[2]],v[fv[3]]));
|
||||
break;
|
||||
case 1:
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[0]],v[fv[2]],v[fv[3]]));
|
||||
break;
|
||||
case 2:
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[0]],v[fv[1]],v[fv[3]]));
|
||||
break;
|
||||
case 3:
|
||||
face_nbr_el_to_face->Push(
|
||||
i, faces_tbl->Index(v[fv[0]],v[fv[1]],v[fv[2]]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MFEM_ABORT("Unexpected type of Element.");
|
||||
}
|
||||
}
|
||||
face_nbr_el_to_face->Finalize();
|
||||
|
||||
if (ret_ftbl)
|
||||
{
|
||||
return faces_tbl;
|
||||
}
|
||||
delete faces_tbl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ParMesh::GetFaceNbrRank(int fn) const
|
||||
{
|
||||
if (Conforming())
|
||||
@@ -2736,37 +2528,6 @@ int ParMesh::GetFaceNbrRank(int fn) const
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParMesh::GetFaceNbrElementFaces(int i, Array<int> &fcs, Array<int> &cor) const
|
||||
{
|
||||
int n, j;
|
||||
int el_nbr = i - GetNE();
|
||||
if (face_nbr_el_to_face)
|
||||
{
|
||||
face_nbr_el_to_face->GetRow(el_nbr, fcs);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("ParMesh::GetFaceNbrElementFaces(...) : "
|
||||
"face_nbr_el_to_face not generated.");
|
||||
}
|
||||
if (el_nbr < face_nbr_el_ori.Size())
|
||||
{
|
||||
const int * row = face_nbr_el_ori.GetRow(el_nbr);
|
||||
n = fcs.Size();
|
||||
cor.SetSize(n);
|
||||
for (j=0; j<n; j++)
|
||||
{
|
||||
cor[j] = row[j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("ParMesh::GetFaceNbrElementFaces(...) : "
|
||||
"face_nbr_el_to_face not generated.");
|
||||
}
|
||||
}
|
||||
|
||||
Table *ParMesh::GetFaceToAllElementTable() const
|
||||
{
|
||||
const Array<int> *s2l_face;
|
||||
|
||||
+3
-15
@@ -75,9 +75,6 @@ protected:
|
||||
// sface ids: all triangles first, then all quads
|
||||
Array<int> sface_lface;
|
||||
|
||||
Table *face_nbr_el_to_face;
|
||||
Table face_nbr_el_ori; // orientations for each face (from nbr processor)
|
||||
|
||||
IsoparametricTransformation FaceNbrTransformation;
|
||||
|
||||
// glob_elem_offset + local element number defines a global element numbering
|
||||
@@ -106,8 +103,6 @@ protected:
|
||||
bool DecodeFaceSplittings(HashTable<Hashed2> &v_to_v, const int *v,
|
||||
const Array<unsigned> &codes, int &pos);
|
||||
|
||||
STable3D *GetFaceNbrElementToFaceTable(int ret_ftbl = 0);
|
||||
|
||||
void GetFaceNbrElementTransformation(
|
||||
int i, IsoparametricTransformation *ElTr);
|
||||
|
||||
@@ -201,9 +196,6 @@ protected:
|
||||
void BuildSharedVertMapping(int nvert, const Table* vert_element,
|
||||
const Array<int> &vert_global_local);
|
||||
|
||||
// Similar to Mesh::GetFacesTable()
|
||||
STable3D *GetSharedFacesTable();
|
||||
|
||||
/// Ensure that bdr_attributes and attributes agree across processors
|
||||
void DistributeAttributes(Array<int> &attr);
|
||||
|
||||
@@ -224,9 +216,8 @@ protected:
|
||||
|
||||
public:
|
||||
/// Default constructor. Create an empty @a ParMesh.
|
||||
ParMesh() : MyComm(0), NRanks(0), MyRank(-1), face_nbr_el_to_face(NULL),
|
||||
glob_elem_offset(-1), glob_offset_sequence(-1),
|
||||
have_face_nbr_data(false), pncmesh(NULL) { }
|
||||
ParMesh() : MyComm(0), NRanks(0), MyRank(-1), glob_elem_offset(-1),
|
||||
glob_offset_sequence(-1), have_face_nbr_data(false), pncmesh(NULL) { }
|
||||
|
||||
/// Create a parallel mesh by partitioning a serial Mesh.
|
||||
/** The mesh is partitioned automatically or using external partitioning
|
||||
@@ -350,9 +341,6 @@ public:
|
||||
int GetFaceNbrGroup(int fn) const { return face_nbr_group[fn]; }
|
||||
int GetFaceNbrRank(int fn) const;
|
||||
|
||||
/** Similar to Mesh::GetElementFaces */
|
||||
void GetFaceNbrElementFaces(int i, Array<int> &fcs, Array<int> &cor) const;
|
||||
|
||||
/** Similar to Mesh::GetFaceToElementTable with added face-neighbor elements
|
||||
with indices offset by the local number of elements. */
|
||||
Table *GetFaceToAllElementTable() const;
|
||||
@@ -382,7 +370,7 @@ public:
|
||||
int GetSharedFace(int sface) const;
|
||||
|
||||
/// See the remarks for the serial version in mesh.hpp
|
||||
MFEM_DEPRECATED virtual void ReorientTetMesh();
|
||||
virtual void ReorientTetMesh();
|
||||
|
||||
/// Utility function: sum integers from all processors (Allreduce).
|
||||
virtual long ReduceInt(int value) const;
|
||||
|
||||
+2
-1
@@ -84,7 +84,8 @@ public:
|
||||
the PUMI and MFEM meshes. E.g.,
|
||||
PUMI_tet{v0,v1,v2,v3} ---> MFEM_tet{v1,v0,v3,v2}
|
||||
* Note that change in the orientation can be caused by
|
||||
fixing wrong boundary element orientations */
|
||||
a) fixing wrong boundary element orientations
|
||||
b) a call to ReorientTetMesh() which is required for Nedelec */
|
||||
int RotationPUMItoMFEM(apf::Mesh2* apf_mesh,
|
||||
apf::MeshEntity* tet,
|
||||
int elemId);
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2010-2021, 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.
|
||||
|
||||
// Implementation of class Pyramid
|
||||
|
||||
#include "mesh_headers.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
Pyramid::Pyramid(const int *ind, int attr)
|
||||
: Element(Geometry::PYRAMID)
|
||||
{
|
||||
attribute = attr;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
indices[i] = ind[i];
|
||||
}
|
||||
}
|
||||
|
||||
Pyramid::Pyramid(int ind1, int ind2, int ind3, int ind4, int ind5, int attr)
|
||||
: Element(Geometry::PYRAMID)
|
||||
{
|
||||
attribute = attr;
|
||||
indices[0] = ind1;
|
||||
indices[1] = ind2;
|
||||
indices[2] = ind3;
|
||||
indices[3] = ind4;
|
||||
indices[4] = ind5;
|
||||
}
|
||||
|
||||
void Pyramid::SetVertices(const int *ind)
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
indices[i] = ind[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Pyramid::GetVertices(Array<int> &v) const
|
||||
{
|
||||
v.SetSize(5);
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
v[i] = indices[i];
|
||||
}
|
||||
}
|
||||
|
||||
int Pyramid::GetNFaces(int &nFaceVertices) const
|
||||
{
|
||||
MFEM_ABORT("this method is not valid for Pyramid elements");
|
||||
nFaceVertices = 4;
|
||||
return 5;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
// Copyright (c) 2010-2021, 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.
|
||||
|
||||
#ifndef MFEM_PYRAMID
|
||||
#define MFEM_PYRAMID
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "element.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Data type Pyramid element
|
||||
class Pyramid : public Element
|
||||
{
|
||||
protected:
|
||||
int indices[5];
|
||||
|
||||
public:
|
||||
typedef Geometry::Constants<Geometry::PYRAMID> geom_t;
|
||||
|
||||
Pyramid() : Element(Geometry::PYRAMID) { }
|
||||
|
||||
/// Constructs pyramid by specifying the indices and the attribute.
|
||||
Pyramid(const int *ind, int attr = 1);
|
||||
|
||||
/// Constructs pyramid by specifying the indices and the attribute.
|
||||
Pyramid(int ind1, int ind2, int ind3, int ind4, int ind5,
|
||||
int attr = 1);
|
||||
|
||||
/// Return element's type.
|
||||
virtual Type GetType() const { return Element::PYRAMID; }
|
||||
|
||||
/// Set the vertices according to the given input.
|
||||
virtual void SetVertices(const int *ind);
|
||||
|
||||
/// Returns the indices of the element's vertices.
|
||||
virtual void GetVertices(Array<int> &v) const;
|
||||
|
||||
virtual int *GetVertices() { return indices; }
|
||||
|
||||
virtual int GetNVertices() const { return 5; }
|
||||
|
||||
virtual int GetNEdges() const { return 8; }
|
||||
|
||||
virtual const int *GetEdgeVertices(int ei) const
|
||||
{ return geom_t::Edges[ei]; }
|
||||
|
||||
/// @deprecated Use GetNFaces(void) and GetNFaceVertices(int) instead.
|
||||
MFEM_DEPRECATED virtual int GetNFaces(int &nFaceVertices) const;
|
||||
|
||||
virtual int GetNFaces() const { return 5; }
|
||||
|
||||
virtual int GetNFaceVertices(int fi) const
|
||||
{ return ( ( fi < 1 ) ? 4 : 3); }
|
||||
|
||||
virtual const int *GetFaceVertices(int fi) const
|
||||
{ return geom_t::FaceVert[fi]; }
|
||||
|
||||
virtual Element *Duplicate(Mesh *m) const
|
||||
{ return new Pyramid(indices, attribute); }
|
||||
|
||||
virtual ~Pyramid() { }
|
||||
};
|
||||
|
||||
extern class LinearPyramidFiniteElement PyramidFE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+2
-1
@@ -71,7 +71,8 @@ public:
|
||||
virtual ~Wedge() { }
|
||||
};
|
||||
|
||||
extern class LinearWedgeFiniteElement WedgeFE;
|
||||
// Defined in fe.cpp to ensure construction after 'mfem::poly1d'.
|
||||
extern class H1_WedgeElement WedgeFE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -409,14 +409,18 @@ int main(int argc, char *argv[])
|
||||
ref_list.DeleteAll();
|
||||
}
|
||||
|
||||
// 10. Rebalance the mesh. Since the mesh was adaptively refined in a
|
||||
// 10. Reorient the mesh. Must be done after refinement but before definition
|
||||
// of higher order Nedelec spaces
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 11. Rebalance the mesh. Since the mesh was adaptively refined in a
|
||||
// non-uniform way it will be computationally unbalanced.
|
||||
if (pmesh->Nonconforming())
|
||||
{
|
||||
pmesh->Rebalance();
|
||||
}
|
||||
|
||||
// 11. Define the parallel finite element spaces. We use:
|
||||
// 12. Define the parallel finite element spaces. We use:
|
||||
//
|
||||
// H(curl) for electric field,
|
||||
// H(div) for magnetic flux,
|
||||
@@ -464,14 +468,13 @@ int main(int argc, char *argv[])
|
||||
int Vsize_rt = HDivFESpace.GetVSize();
|
||||
int Vsize_h1 = HGradFESpace.GetVSize();
|
||||
|
||||
// 12. Declare storage for field data.
|
||||
// The big BlockVector stores the fields as
|
||||
// 0 Temperature
|
||||
// 1 Temperature Flux
|
||||
// 2 P field
|
||||
// 3 E field
|
||||
// 4 B field
|
||||
// 5 Joule Heating
|
||||
// the big BlockVector stores the fields as
|
||||
// 0 Temperature
|
||||
// 1 Temperature Flux
|
||||
// 2 P field
|
||||
// 3 E field
|
||||
// 4 B field
|
||||
// 5 Joule Heating
|
||||
|
||||
Array<int> true_offset(7);
|
||||
true_offset[0] = 0;
|
||||
|
||||
@@ -4003,6 +4003,11 @@ TEST_CASE("3D Bilinear Weak Curl Integrators",
|
||||
Mesh mesh =
|
||||
Mesh::MakeCartesian3D(n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
|
||||
|
||||
if (type == Element::TETRAHEDRON)
|
||||
{
|
||||
mesh.ReorientTetMesh();
|
||||
}
|
||||
|
||||
SECTION("Operators on ND for element type " + std::to_string(type))
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
@@ -4462,6 +4467,11 @@ TEST_CASE("3D Bilinear Weak Curl Cross Integrators",
|
||||
Mesh mesh =
|
||||
Mesh::MakeCartesian3D(n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
|
||||
|
||||
if (type == Element::TETRAHEDRON)
|
||||
{
|
||||
mesh.ReorientTetMesh();
|
||||
}
|
||||
|
||||
SECTION("Operators on ND for element type " + std::to_string(type))
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
@@ -5310,9 +5320,15 @@ TEST_CASE("3D Bilinear Curl Curl Integrators",
|
||||
for (int type = (int)Element::TETRAHEDRON;
|
||||
type <= (int)Element::HEXAHEDRON; type++)
|
||||
{
|
||||
type++;
|
||||
Mesh mesh =
|
||||
Mesh::MakeCartesian3D(n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
|
||||
|
||||
if (type == Element::TETRAHEDRON)
|
||||
{
|
||||
mesh.ReorientTetMesh();
|
||||
}
|
||||
|
||||
SECTION("Operators on ND for element type " + std::to_string(type))
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
@@ -5419,6 +5435,11 @@ TEST_CASE("3D Bilinear Mixed Curl Curl Integrators",
|
||||
Mesh mesh =
|
||||
Mesh::MakeCartesian3D(n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
|
||||
|
||||
if (type == Element::TETRAHEDRON)
|
||||
{
|
||||
mesh.ReorientTetMesh();
|
||||
}
|
||||
|
||||
SECTION("Operators on ND for element type " + std::to_string(type))
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
@@ -5576,6 +5597,11 @@ TEST_CASE("3D Bilinear Mixed Cross Curl Curl Integrators",
|
||||
Mesh mesh =
|
||||
Mesh::MakeCartesian3D(n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
|
||||
|
||||
if (type == Element::TETRAHEDRON)
|
||||
{
|
||||
mesh.ReorientTetMesh();
|
||||
}
|
||||
|
||||
SECTION("Operators on ND for element type " + std::to_string(type))
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
@@ -5648,6 +5674,11 @@ TEST_CASE("3D Bilinear Mixed Cross Grad Curl Integrators",
|
||||
Mesh mesh =
|
||||
Mesh::MakeCartesian3D(n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
|
||||
|
||||
if (type == Element::TETRAHEDRON)
|
||||
{
|
||||
mesh.ReorientTetMesh();
|
||||
}
|
||||
|
||||
SECTION("Operators on H1 for element type " + std::to_string(type))
|
||||
{
|
||||
H1_FECollection fec_h1(order, dim);
|
||||
|
||||
@@ -72,6 +72,10 @@ TEST_CASE("Build Dof To Arrays",
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
mesh->ReorientTetMesh();
|
||||
}
|
||||
|
||||
for (int bt = (int)BasisType::H1; bt <= (int)BasisType::L2; bt++)
|
||||
{
|
||||
@@ -173,6 +177,10 @@ TEST_CASE("Build Dof To Arrays (Parallel)",
|
||||
}
|
||||
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
if (dim == 3)
|
||||
{
|
||||
pmesh.ReorientTetMesh();
|
||||
}
|
||||
|
||||
for (int bt = (int)BasisType::H1; bt <= (int)BasisType::L2; bt++)
|
||||
{
|
||||
|
||||
@@ -1,343 +0,0 @@
|
||||
// Copyright (c) 2010-2021, 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 "mfem.hpp"
|
||||
#include "catch.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
namespace doftrans
|
||||
{
|
||||
|
||||
TEST_CASE("DoF Transformation Classes",
|
||||
"[DofTransformation]"
|
||||
"[ND_TetDofTransformation]")
|
||||
{
|
||||
int p = 4;
|
||||
int seed = 123;
|
||||
|
||||
double tol = 1e-13;
|
||||
|
||||
SECTION("Nedelec Tetrahedral Transformations")
|
||||
{
|
||||
ND_TetDofTransformation T(p);
|
||||
|
||||
Array<int> ori(4);
|
||||
ori[0] = 1;
|
||||
ori[1] = 3;
|
||||
ori[2] = 5;
|
||||
ori[3] = 1;
|
||||
|
||||
T.SetFaceOrientations(ori);
|
||||
|
||||
Vector u(T.Width());
|
||||
Vector v(T.Width());
|
||||
Vector f(T.Width());
|
||||
Vector ut;
|
||||
Vector vt;
|
||||
Vector ft;
|
||||
|
||||
u.Randomize(seed);
|
||||
v.Randomize(seed+1);
|
||||
f.Randomize(seed+2);
|
||||
|
||||
SECTION("Inverse DoF transformation")
|
||||
{
|
||||
Vector w;
|
||||
|
||||
ut = u; T.TransformPrimal(ut);
|
||||
w = ut; T.InvTransformPrimal(w);
|
||||
|
||||
w -= u;
|
||||
|
||||
REQUIRE(w.Norml2() < tol * u.Norml2());
|
||||
}
|
||||
|
||||
SECTION("Inner product with linear form f(v)")
|
||||
{
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
ft = f; T.TransformDual(ft);
|
||||
|
||||
double fv = f * v;
|
||||
|
||||
REQUIRE(fabs(fv - ft * vt) < tol * fabs(fv));
|
||||
}
|
||||
|
||||
DenseMatrix A(T.Width());
|
||||
{
|
||||
Vector Ac;
|
||||
for (int i=0; i<A.Width(); i++)
|
||||
{
|
||||
A.GetColumnReference(i, Ac);
|
||||
Ac.Randomize(seed+i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Inner product of two primal vectors")
|
||||
{
|
||||
// The matrix A in this case should be regarded as a BilinearForm.
|
||||
DenseMatrix tA;
|
||||
DenseMatrix At;
|
||||
DenseMatrix tAt;
|
||||
|
||||
ut = u; T.TransformPrimal(ut);
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
|
||||
At = A; T.TransformDualRows(At);
|
||||
tA = A; T.TransformDualCols(tA);
|
||||
tAt = A; T.TransformDual(tAt);
|
||||
|
||||
double uAv = A.InnerProduct(v, u);
|
||||
|
||||
REQUIRE(fabs(uAv - At.InnerProduct(vt, u )) < tol * fabs(uAv));
|
||||
REQUIRE(fabs(uAv - tA.InnerProduct(v , ut)) < tol * fabs(uAv));
|
||||
REQUIRE(fabs(uAv - tAt.InnerProduct(vt, ut)) < tol * fabs(uAv));
|
||||
}
|
||||
SECTION("Inner product of a primal vector and a dual vector")
|
||||
{
|
||||
// The matrix A in this case should be regarded as a
|
||||
// DiscreteLinearOperator.
|
||||
DenseMatrix tA;
|
||||
DenseMatrix At;
|
||||
DenseMatrix tAt;
|
||||
|
||||
ft = f; T.TransformDual(ft);
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
|
||||
At = A; T.TransformDualRows(At);
|
||||
tA = A; T.TransformPrimalCols(tA);
|
||||
tAt = At; T.TransformPrimalCols(tAt);
|
||||
|
||||
double fAv = A.InnerProduct(v, f);
|
||||
|
||||
REQUIRE(fabs(fAv - At.InnerProduct(vt, f )) < tol * fabs(fAv));
|
||||
REQUIRE(fabs(fAv - tA.InnerProduct(v , ft)) < tol * fabs(fAv));
|
||||
REQUIRE(fabs(fAv - tAt.InnerProduct(vt, ft)) < tol * fabs(fAv));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("DoF Transformation Functions",
|
||||
"[DofTransformation]"
|
||||
"[TransformPrimal]"
|
||||
"[TransformDual]")
|
||||
{
|
||||
int p = 3, q = 4;
|
||||
int seed = 123;
|
||||
|
||||
double tol = 1e-13;
|
||||
|
||||
ND_TetDofTransformation Tp(p);
|
||||
ND_TetDofTransformation Tq(q);
|
||||
|
||||
Array<int> ori(4);
|
||||
ori[0] = 1;
|
||||
ori[1] = 3;
|
||||
ori[2] = 5;
|
||||
ori[3] = 1;
|
||||
|
||||
Tp.SetFaceOrientations(ori);
|
||||
Tq.SetFaceOrientations(ori);
|
||||
|
||||
DenseMatrix A(Tp.Width(), Tq.Width());
|
||||
{
|
||||
Vector Ac;
|
||||
for (int i=0; i<A.Width(); i++)
|
||||
{
|
||||
A.GetColumnReference(i, Ac);
|
||||
Ac.Randomize(seed+i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("TransformPrimal")
|
||||
{
|
||||
// The matrix A in this case should be regarded as a
|
||||
// DiscreteLinearOperator.
|
||||
|
||||
Vector v(Tq.Width());
|
||||
Vector f(Tp.Width());
|
||||
Vector vt;
|
||||
Vector ft;
|
||||
|
||||
v.Randomize(seed);
|
||||
f.Randomize(seed+1);
|
||||
|
||||
vt = v; Tq.TransformPrimal(vt);
|
||||
ft = f; Tp.TransformDual(ft);
|
||||
|
||||
DenseMatrix nAn;
|
||||
DenseMatrix tA;
|
||||
DenseMatrix At;
|
||||
DenseMatrix tAt;
|
||||
|
||||
nAn = A; TransformPrimal(NULL, NULL, nAn);
|
||||
At = A; TransformPrimal(NULL, &Tq, At);
|
||||
tA = A; TransformPrimal( &Tp, NULL, tA);
|
||||
tAt = A; TransformPrimal( &Tp, &Tq, tAt);
|
||||
|
||||
double fAv = A.InnerProduct(v, f);
|
||||
|
||||
REQUIRE(fabs(fAv - nAn.InnerProduct(v , f )) < tol * fabs(fAv));
|
||||
REQUIRE(fabs(fAv - At.InnerProduct(vt, f )) < tol * fabs(fAv));
|
||||
REQUIRE(fabs(fAv - tA.InnerProduct(v , ft)) < tol * fabs(fAv));
|
||||
REQUIRE(fabs(fAv - tAt.InnerProduct(vt, ft)) < tol * fabs(fAv));
|
||||
}
|
||||
SECTION("TransformDual")
|
||||
{
|
||||
// The matrix A in this case should be regarded as a BilinearForm.
|
||||
|
||||
Vector u(Tp.Width());
|
||||
Vector v(Tq.Width());
|
||||
Vector ut;
|
||||
Vector vt;
|
||||
|
||||
u.Randomize(seed);
|
||||
v.Randomize(seed+1);
|
||||
|
||||
ut = u; Tp.TransformPrimal(ut);
|
||||
vt = v; Tq.TransformPrimal(vt);
|
||||
|
||||
DenseMatrix nAn;
|
||||
DenseMatrix tA;
|
||||
DenseMatrix At;
|
||||
DenseMatrix tAt;
|
||||
|
||||
nAn = A; TransformDual(NULL, NULL, nAn);
|
||||
At = A; TransformDual(NULL, &Tq, At);
|
||||
tA = A; TransformDual( &Tp, NULL, tA);
|
||||
tAt = A; TransformDual( &Tp, &Tq, tAt);
|
||||
|
||||
double uAv = A.InnerProduct(v, u);
|
||||
|
||||
REQUIRE(fabs(uAv - nAn.InnerProduct(v , u )) < tol * fabs(uAv));
|
||||
REQUIRE(fabs(uAv - At.InnerProduct(vt, u )) < tol * fabs(uAv));
|
||||
REQUIRE(fabs(uAv - tA.InnerProduct(v , ut)) < tol * fabs(uAv));
|
||||
REQUIRE(fabs(uAv - tAt.InnerProduct(vt, ut)) < tol * fabs(uAv));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("VDoF Transformation Class",
|
||||
"[DofTransformation]"
|
||||
"[VDofTransformation]")
|
||||
{
|
||||
int p = 4;
|
||||
int vdim = 3;
|
||||
int seed = 123;
|
||||
|
||||
double tol = 1e-13;
|
||||
|
||||
ND_TetDofTransformation Tnd(p);
|
||||
|
||||
Array<int> ori(4);
|
||||
ori[0] = 1;
|
||||
ori[1] = 3;
|
||||
ori[2] = 5;
|
||||
ori[3] = 1;
|
||||
|
||||
Tnd.SetFaceOrientations(ori);
|
||||
|
||||
SECTION("VDim == 1")
|
||||
{
|
||||
VDofTransformation T(Tnd);
|
||||
|
||||
Vector v(T.Width());
|
||||
Vector f(T.Width());
|
||||
Vector vt;
|
||||
Vector ft;
|
||||
|
||||
v.Randomize(seed);
|
||||
f.Randomize(seed+1);
|
||||
|
||||
SECTION("Inverse DoF transformation")
|
||||
{
|
||||
Vector w;
|
||||
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
w = vt; T.InvTransformPrimal(w);
|
||||
|
||||
w -= v;
|
||||
|
||||
REQUIRE(w.Norml2() < tol * v.Norml2());
|
||||
}
|
||||
SECTION("Inner product with linear form f(v)")
|
||||
{
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
ft = f; T.TransformDual(ft);
|
||||
|
||||
double fv = f * v;
|
||||
|
||||
REQUIRE(fabs(fv - ft * vt) < tol * fabs(fv));
|
||||
}
|
||||
}
|
||||
SECTION("VDim > 1")
|
||||
{
|
||||
Vector v(vdim * Tnd.Width());
|
||||
Vector f(vdim * Tnd.Width());
|
||||
Vector vt;
|
||||
Vector ft;
|
||||
|
||||
v.Randomize(seed);
|
||||
f.Randomize(seed+1);
|
||||
|
||||
SECTION("Ordering == byNODES")
|
||||
{
|
||||
VDofTransformation T(Tnd, vdim, Ordering::byNODES);
|
||||
|
||||
SECTION("Inverse DoF transformation")
|
||||
{
|
||||
Vector w;
|
||||
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
w = vt; T.InvTransformPrimal(w);
|
||||
|
||||
w -= v;
|
||||
|
||||
REQUIRE(w.Norml2() < tol * v.Norml2());
|
||||
}
|
||||
SECTION("Inner product with linear form f(v)")
|
||||
{
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
ft = f; T.TransformDual(ft);
|
||||
|
||||
double fv = f * v;
|
||||
|
||||
REQUIRE(fabs(fv - ft * vt) < tol * fabs(fv));
|
||||
}
|
||||
}
|
||||
SECTION("Ordering == byVDIM")
|
||||
{
|
||||
VDofTransformation T(Tnd, vdim, Ordering::byVDIM);
|
||||
|
||||
SECTION("Inverse DoF transformation")
|
||||
{
|
||||
Vector w;
|
||||
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
w = vt; T.InvTransformPrimal(w);
|
||||
|
||||
w -= v;
|
||||
|
||||
REQUIRE(w.Norml2() < tol * v.Norml2());
|
||||
}
|
||||
SECTION("Inner product with linear form f(v)")
|
||||
{
|
||||
vt = v; T.TransformPrimal(vt);
|
||||
ft = f; T.TransformDual(ft);
|
||||
|
||||
double fv = f * v;
|
||||
|
||||
REQUIRE(fabs(fv - ft * vt) < tol * fabs(fv));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace doftrans
|
||||
@@ -159,6 +159,10 @@ TEST_CASE("Domain Integration (Vector Field)",
|
||||
int dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
mesh->UniformRefinement();
|
||||
if (dim == 3)
|
||||
{
|
||||
mesh->ReorientTetMesh();
|
||||
}
|
||||
|
||||
Vector f1(sdim); f1 = 1.0;
|
||||
Vector fx(sdim); fx = 0.0; fx[0] = 1.0;
|
||||
@@ -349,6 +353,10 @@ TEST_CASE("Domain Integration in Parallel (Vector Field)",
|
||||
}
|
||||
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
if (dim == 3)
|
||||
{
|
||||
pmesh.ReorientTetMesh();
|
||||
}
|
||||
|
||||
Vector f1(sdim); f1 = 1.0;
|
||||
Vector fx(sdim); fx = 0.0; fx[0] = 1.0;
|
||||
|
||||
@@ -1,673 +0,0 @@
|
||||
// Copyright (c) 2010-2021, 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 "mfem.hpp"
|
||||
#include "unit_tests.hpp"
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
namespace eigs
|
||||
{
|
||||
|
||||
static double a_ = M_PI;
|
||||
static double b_ = M_PI / sqrt(2.0);
|
||||
static double c_ = M_PI / 2.0;
|
||||
|
||||
enum MeshType
|
||||
{
|
||||
SEGMENT = 0,
|
||||
QUADRILATERAL = 1,
|
||||
TRIANGLE2A = 2,
|
||||
TRIANGLE2B = 3,
|
||||
TRIANGLE2C = 4,
|
||||
TRIANGLE4 = 5,
|
||||
MIXED2D = 6,
|
||||
HEXAHEDRON = 7,
|
||||
HEXAHEDRON2A = 8,
|
||||
HEXAHEDRON2B = 9,
|
||||
HEXAHEDRON2C = 10,
|
||||
HEXAHEDRON2D = 11,
|
||||
WEDGE2 = 12,
|
||||
TETRAHEDRA = 13,
|
||||
WEDGE4 = 14,
|
||||
MIXED3D6 = 15,
|
||||
MIXED3D8 = 16
|
||||
};
|
||||
|
||||
Mesh * GetMesh(MeshType type);
|
||||
|
||||
int eigs[21] =
|
||||
{
|
||||
1,4,9,16,25,36,49,
|
||||
3,6,9,11,12,17,18,
|
||||
7,10,13,15,16,19,21
|
||||
};
|
||||
|
||||
#ifdef MFEM_USE_LAPACK
|
||||
#
|
||||
TEST_CASE("Laplacian Eigenvalues",
|
||||
"[H1_FECollection]"
|
||||
"[GridFunction]"
|
||||
"[BilinearForm]")
|
||||
{
|
||||
int order = 3;
|
||||
|
||||
for (int mt = (int)MeshType::SEGMENT;
|
||||
mt <= (int)MeshType::MIXED3D8; mt++)
|
||||
{
|
||||
Mesh *mesh = GetMesh((MeshType)mt);
|
||||
int dim = mesh->Dimension();
|
||||
if (dim < 3 ||
|
||||
mt == MeshType::HEXAHEDRON ||
|
||||
mt == MeshType::WEDGE2 ||
|
||||
mt == MeshType::TETRAHEDRA ||
|
||||
mt == MeshType::WEDGE4 ||
|
||||
mt == MeshType::MIXED3D8 )
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
H1_FECollection fec(order, dim);
|
||||
FiniteElementSpace fespace(mesh, &fec);
|
||||
int size = fespace.GetTrueVSize();
|
||||
std::cout << mt << " Eigenvalue system size: " << size << std::endl;
|
||||
|
||||
Array<int> ess_bdr;
|
||||
if (mesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(mesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
}
|
||||
Array<int> ess_bdr_tdofs;
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_bdr_tdofs);
|
||||
int bsize = ess_bdr_tdofs.Size();
|
||||
|
||||
BilinearForm a(&fespace);
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator);
|
||||
a.Assemble();
|
||||
a.EliminateEssentialBCDiag(ess_bdr, 1.0);
|
||||
a.Finalize();
|
||||
|
||||
BilinearForm m(&fespace);
|
||||
m.AddDomainIntegrator(new MassIntegrator);
|
||||
m.Assemble();
|
||||
// shift the eigenvalue corresponding to eliminated dofs to a large value
|
||||
m.EliminateEssentialBCDiag(ess_bdr, std::numeric_limits<double>::min());
|
||||
m.Finalize();
|
||||
|
||||
DenseMatrix Ad(size);
|
||||
DenseMatrix Md(size);
|
||||
DenseMatrix vd(size);
|
||||
|
||||
Ad = 0.0;
|
||||
Md = 0.0;
|
||||
Vector one(size);
|
||||
Vector done(size);
|
||||
one = 0.0;
|
||||
for (int i=0; i<size; i++)
|
||||
{
|
||||
one[i] = 1.0;
|
||||
a.Mult(one, done);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
Ad(j, i) = done[j];
|
||||
}
|
||||
m.Mult(one, done);
|
||||
for (int j=0; j<size; j++)
|
||||
{
|
||||
Md(j, i) = done[j];
|
||||
}
|
||||
one[i] = 0.0;
|
||||
}
|
||||
for (int i=0; i<bsize; i++)
|
||||
{
|
||||
int ei = ess_bdr_tdofs[i];
|
||||
Ad(ei,ei) = 0.0;
|
||||
Md(ei,ei) = 1.0;
|
||||
}
|
||||
|
||||
int nev = dim;
|
||||
Vector deigs(size);
|
||||
Ad.Eigenvalues(Md, deigs, vd);
|
||||
|
||||
Array<int> exact_eigs(&eigs[7 * (dim - 1)], 7);
|
||||
|
||||
double max_err = 0.0;
|
||||
for (int i=bsize; i<std::min(size,bsize+nev); i++)
|
||||
{
|
||||
double lc = deigs[i];
|
||||
double le = exact_eigs[i-bsize];
|
||||
double err = 100.0 * fabs(le - lc) / le;
|
||||
max_err = std::max(max_err, err);
|
||||
REQUIRE(err < 5.0);
|
||||
}
|
||||
std::cout << mt << " Maximum relative error: " << max_err << "%"
|
||||
<< std::endl;
|
||||
|
||||
delete mesh;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_LAPACK
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
#
|
||||
TEST_CASE("Laplacian Eigenvalues in Parallel",
|
||||
"[H1_FECollection]"
|
||||
"[GridFunction]"
|
||||
"[BilinearForm]"
|
||||
"[Parallel]")
|
||||
{
|
||||
int num_procs;
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
|
||||
int my_rank;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
|
||||
|
||||
int order = 3;
|
||||
int seed = 75;
|
||||
|
||||
for (int mt = (int)MeshType::SEGMENT;
|
||||
mt <= (int)MeshType::MIXED3D8; mt++)
|
||||
{
|
||||
Mesh *mesh = GetMesh((MeshType)mt);
|
||||
int dim = mesh->Dimension();
|
||||
if (dim < 3 ||
|
||||
mt == MeshType::HEXAHEDRON ||
|
||||
mt == MeshType::WEDGE2 ||
|
||||
mt == MeshType::TETRAHEDRA ||
|
||||
mt == MeshType::WEDGE4 ||
|
||||
mt == MeshType::MIXED3D8 )
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
while (mesh->GetNE() < num_procs)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
|
||||
H1_FECollection fec(order, dim);
|
||||
ParFiniteElementSpace fespace(&pmesh, &fec);
|
||||
HYPRE_Int size = fespace.GlobalTrueVSize();
|
||||
if (my_rank == 0)
|
||||
{
|
||||
std::cout << mt << " Eigenvalue system size: " << size << std::endl;
|
||||
}
|
||||
|
||||
Array<int> ess_bdr;
|
||||
if (pmesh.bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
}
|
||||
Array<int> ess_bdr_tdofs;
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_bdr_tdofs);
|
||||
|
||||
ParBilinearForm a(&fespace);
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator);
|
||||
a.Assemble();
|
||||
a.EliminateEssentialBCDiag(ess_bdr, 1.0);
|
||||
a.Finalize();
|
||||
|
||||
ParBilinearForm m(&fespace);
|
||||
m.AddDomainIntegrator(new MassIntegrator);
|
||||
m.Assemble();
|
||||
// shift the eigenvalue corresponding to eliminated dofs to a large value
|
||||
m.EliminateEssentialBCDiag(ess_bdr, std::numeric_limits<double>::min());
|
||||
m.Finalize();
|
||||
|
||||
HypreParMatrix *A = a.ParallelAssemble();
|
||||
HypreParMatrix *M = m.ParallelAssemble();
|
||||
|
||||
HypreBoomerAMG amg(*A);
|
||||
amg.SetPrintLevel(0);
|
||||
|
||||
int nev = dim;
|
||||
|
||||
HypreLOBPCG lobpcg(MPI_COMM_WORLD);
|
||||
lobpcg.SetNumModes(nev);
|
||||
lobpcg.SetRandomSeed(seed);
|
||||
lobpcg.SetPreconditioner(amg);
|
||||
lobpcg.SetMaxIter(200);
|
||||
lobpcg.SetTol(1e-8);
|
||||
lobpcg.SetPrecondUsageMode(1);
|
||||
lobpcg.SetPrintLevel(0);
|
||||
lobpcg.SetMassMatrix(*M);
|
||||
lobpcg.SetOperator(*A);
|
||||
|
||||
Array<double> eigenvalues;
|
||||
lobpcg.Solve();
|
||||
lobpcg.GetEigenvalues(eigenvalues);
|
||||
|
||||
Array<int> exact_eigs(&eigs[7 * (dim - 1)], 7);
|
||||
|
||||
double max_err = 0.0;
|
||||
for (int i=0; i<nev; i++)
|
||||
{
|
||||
double lc = eigenvalues[i];
|
||||
double le = exact_eigs[i];
|
||||
double err = 100.0 * fabs(le - lc) / le;
|
||||
max_err = std::max(max_err, err);
|
||||
REQUIRE(err < 5.0);
|
||||
}
|
||||
if (my_rank == 0)
|
||||
{
|
||||
std::cout << mt << " Maximum relative error: " << max_err << "%"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
delete A;
|
||||
delete M;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
Mesh * GetMesh(MeshType type)
|
||||
{
|
||||
Mesh * mesh = NULL;
|
||||
double c[3];
|
||||
int v[8];
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SEGMENT:
|
||||
mesh = new Mesh(1, 2, 1);
|
||||
c[0] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_;
|
||||
mesh->AddVertex(c);
|
||||
v[0] = 0; v[1] = 1;
|
||||
mesh->AddSegment(v);
|
||||
{
|
||||
Element * el = mesh->NewElement(Geometry::POINT);
|
||||
el->SetAttribute(1);
|
||||
el->SetVertices(&v[0]);
|
||||
mesh->AddBdrElement(el);
|
||||
}
|
||||
{
|
||||
Element * el = mesh->NewElement(Geometry::POINT);
|
||||
el->SetAttribute(2);
|
||||
el->SetVertices(&v[1]);
|
||||
mesh->AddBdrElement(el);
|
||||
}
|
||||
break;
|
||||
case QUADRILATERAL:
|
||||
mesh = new Mesh(2, 4, 1);
|
||||
c[0] = 0.0; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
|
||||
mesh->AddQuad(v);
|
||||
break;
|
||||
case TRIANGLE2A:
|
||||
mesh = new Mesh(2, 4, 2);
|
||||
c[0] = 0.0; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 1; v[2] = 2;
|
||||
mesh->AddTri(v);
|
||||
v[0] = 2; v[1] = 3; v[2] = 0;
|
||||
mesh->AddTri(v);
|
||||
break;
|
||||
case TRIANGLE2B:
|
||||
mesh = new Mesh(2, 4, 2);
|
||||
c[0] = 0.0; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 1; v[1] = 2; v[2] = 0;
|
||||
mesh->AddTri(v);
|
||||
v[0] = 3; v[1] = 0; v[2] = 2;
|
||||
mesh->AddTri(v);
|
||||
break;
|
||||
case TRIANGLE2C:
|
||||
mesh = new Mesh(2, 4, 2);
|
||||
c[0] = 0.0; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 2; v[1] = 0; v[2] = 1;
|
||||
mesh->AddTri(v);
|
||||
v[0] = 0; v[1] = 2; v[2] = 3;
|
||||
mesh->AddTri(v);
|
||||
break;
|
||||
case TRIANGLE4:
|
||||
mesh = new Mesh(2, 5, 4);
|
||||
c[0] = 0.0; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * a_; c[1] = 0.5 * b_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 1; v[2] = 4;
|
||||
mesh->AddTri(v);
|
||||
v[0] = 1; v[1] = 2; v[2] = 4;
|
||||
mesh->AddTri(v);
|
||||
v[0] = 2; v[1] = 3; v[2] = 4;
|
||||
mesh->AddTri(v);
|
||||
v[0] = 3; v[1] = 0; v[2] = 4;
|
||||
mesh->AddTri(v);
|
||||
break;
|
||||
case MIXED2D:
|
||||
mesh = new Mesh(2, 6, 4);
|
||||
c[0] = 0.0; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * b_; c[1] = 0.5 * b_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_ - 0.5 * b_; c[1] = 0.5 * b_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 1; v[2] = 5; v[3] = 4;
|
||||
mesh->AddQuad(v);
|
||||
v[0] = 1; v[1] = 2; v[2] = 5;
|
||||
mesh->AddTri(v);
|
||||
v[0] = 2; v[1] = 3; v[2] = 4; v[3] = 5;
|
||||
mesh->AddQuad(v);
|
||||
v[0] = 3; v[1] = 0; v[2] = 4;
|
||||
mesh->AddTri(v);
|
||||
break;
|
||||
case HEXAHEDRON:
|
||||
mesh = new Mesh(3, 8, 1);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
|
||||
v[4] = 4; v[5] = 5; v[6] = 6; v[7] = 7;
|
||||
mesh->AddHex(v);
|
||||
break;
|
||||
case HEXAHEDRON2A:
|
||||
case HEXAHEDRON2B:
|
||||
case HEXAHEDRON2C:
|
||||
case HEXAHEDRON2D:
|
||||
mesh = new Mesh(3, 12, 2);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * a_; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * a_; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * a_; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * a_; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 5; v[2] = 11; v[3] = 6;
|
||||
v[4] = 1; v[5] = 4; v[6] = 10; v[7] = 7;
|
||||
mesh->AddHex(v);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HEXAHEDRON2A: // Face Orientation 1
|
||||
v[0] = 4; v[1] = 10; v[2] = 7; v[3] = 1;
|
||||
v[4] = 3; v[5] = 9; v[6] = 8; v[7] = 2;
|
||||
mesh->AddHex(v);
|
||||
break;
|
||||
case HEXAHEDRON2B: // Face Orientation 3
|
||||
v[0] = 10; v[1] = 7; v[2] = 1; v[3] = 4;
|
||||
v[4] = 9; v[5] = 8; v[6] = 2; v[7] = 3;
|
||||
mesh->AddHex(v);
|
||||
break;
|
||||
case HEXAHEDRON2C: // Face Orientation 5
|
||||
v[0] = 7; v[1] = 1; v[2] = 4; v[3] = 10;
|
||||
v[4] = 8; v[5] = 2; v[6] = 3; v[7] = 9;
|
||||
mesh->AddHex(v);
|
||||
break;
|
||||
case HEXAHEDRON2D: // Face Orientation 7
|
||||
v[0] = 1; v[1] = 4; v[2] = 10; v[3] = 7;
|
||||
v[4] = 2; v[5] = 3; v[6] = 9; v[7] = 8;
|
||||
mesh->AddHex(v);
|
||||
break;
|
||||
default:
|
||||
// Cannot happen
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WEDGE2:
|
||||
mesh = new Mesh(3, 8, 2);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 4; v[4] = 5; v[5] = 6;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 0; v[1] = 2; v[2] = 3; v[3] = 4; v[4] = 6; v[5] = 7;
|
||||
mesh->AddWedge(v);
|
||||
break;
|
||||
case TETRAHEDRA:
|
||||
mesh = new Mesh(3, 8, 5);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 2; v[2] = 7; v[3] = 5;
|
||||
mesh->AddTet(v);
|
||||
v[0] = 6; v[1] = 7; v[2] = 2; v[3] = 5;
|
||||
mesh->AddTet(v);
|
||||
v[0] = 4; v[1] = 7; v[2] = 5; v[3] = 0;
|
||||
mesh->AddTet(v);
|
||||
v[0] = 1; v[1] = 0; v[2] = 5; v[3] = 2;
|
||||
mesh->AddTet(v);
|
||||
v[0] = 3; v[1] = 7; v[2] = 0; v[3] = 2;
|
||||
mesh->AddTet(v);
|
||||
break;
|
||||
case WEDGE4:
|
||||
mesh = new Mesh(3, 10, 4);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * a_; c[1] = 0.5 * b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * a_; c[1] = 0.5 * b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 1; v[2] = 4; v[3] = 5; v[4] = 6; v[5] = 9;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 1; v[1] = 2; v[2] = 4; v[3] = 6; v[4] = 7; v[5] = 9;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 2; v[1] = 3; v[2] = 4; v[3] = 7; v[4] = 8; v[5] = 9;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 3; v[1] = 0; v[2] = 4; v[3] = 8; v[4] = 5; v[5] = 9;
|
||||
mesh->AddWedge(v);
|
||||
break;
|
||||
case MIXED3D6:
|
||||
mesh = new Mesh(3, 12, 6);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * c_; c[1] = 0.5 * c_; c[2] = 0.5 * c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_ - 0.5 * c_; c[1] = 0.5 * c_; c[2] = 0.5 * c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_ - 0.5 * c_; c[1] = b_ - 0.5 * c_; c[2] = 0.5 * c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.5 * c_; c[1] = b_ - 0.5 * c_; c[2] = 0.5 * c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
|
||||
v[4] = 4; v[5] = 5; v[6] = 6; v[7] = 7;
|
||||
mesh->AddHex(v);
|
||||
v[0] = 0; v[1] = 4; v[2] = 8; v[3] = 1; v[4] = 5; v[5] = 9;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 1; v[1] = 5; v[2] = 9; v[3] = 2; v[4] = 6; v[5] = 10;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 2; v[1] = 6; v[2] = 10; v[3] = 3; v[4] = 7; v[5] = 11;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 3; v[1] = 7; v[2] = 11; v[3] = 0; v[4] = 4; v[5] = 8;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 4; v[1] = 5; v[2] = 6; v[3] = 7;
|
||||
v[4] = 8; v[5] = 9; v[6] = 10; v[7] = 11;
|
||||
mesh->AddHex(v);
|
||||
break;
|
||||
case MIXED3D8:
|
||||
mesh = new Mesh(3, 10, 8);
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
c[0] = 0.25 * a_; c[1] = 0.5 * b_; c[2] = 0.5 * c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.75 * a_; c[1] = 0.5 * b_; c[2] = 0.5 * c_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = 0.0; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = a_; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
c[0] = 0.0; c[1] = b_; c[2] = c_;
|
||||
mesh->AddVertex(c);
|
||||
|
||||
v[0] = 0; v[1] = 3; v[2] = 4; v[3] = 1; v[4] = 2; v[5] = 5;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 3; v[1] = 9; v[2] = 4; v[3] = 2; v[4] = 8; v[5] = 5;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 9; v[1] = 6; v[2] = 4; v[3] = 8; v[4] = 7; v[5] = 5;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 6; v[1] = 0; v[2] = 4; v[3] = 7; v[4] = 1; v[5] = 5;
|
||||
mesh->AddWedge(v);
|
||||
v[0] = 0; v[1] = 3; v[2] = 9; v[3] = 4;
|
||||
mesh->AddTet(v);
|
||||
v[0] = 0; v[1] = 9; v[2] = 6; v[3] = 4;
|
||||
mesh->AddTet(v);
|
||||
v[0] = 1; v[1] = 7; v[2] = 2; v[3] = 5;
|
||||
mesh->AddTet(v);
|
||||
v[0] = 8; v[1] = 2; v[2] = 7; v[3] = 5;
|
||||
mesh->AddTet(v);
|
||||
break;
|
||||
}
|
||||
mesh->FinalizeTopology();
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
} // namespace eigs
|
||||
@@ -3049,7 +3049,7 @@ TEST_CASE("3D GetVectorValue in Parallel",
|
||||
int log = 1;
|
||||
int n = (int)ceil(pow(2*num_procs, 1.0 / 3.0));
|
||||
int dim = 3;
|
||||
int order = 2;
|
||||
int order = 1;
|
||||
int npts = 0;
|
||||
|
||||
double tol = 1e-6;
|
||||
@@ -3060,6 +3060,10 @@ TEST_CASE("3D GetVectorValue in Parallel",
|
||||
Mesh mesh = Mesh::MakeCartesian3D(
|
||||
n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
if (type == Element::TETRAHEDRON)
|
||||
{
|
||||
pmesh.ReorientTetMesh();
|
||||
}
|
||||
mesh.Clear();
|
||||
|
||||
VectorFunctionCoefficient funcCoef(dim, Func_3D_lin);
|
||||
@@ -3111,7 +3115,6 @@ TEST_CASE("3D GetVectorValue in Parallel",
|
||||
dgv_x.ExchangeFaceNbrData();
|
||||
dgi_x.ExchangeFaceNbrData();
|
||||
|
||||
Vector x(dim); x = 0.0;
|
||||
Vector f_val(dim); f_val = 0.0;
|
||||
|
||||
Vector h1_gfc_val(dim); h1_gfc_val = 0.0;
|
||||
@@ -3134,7 +3137,6 @@ TEST_CASE("3D GetVectorValue in Parallel",
|
||||
{
|
||||
std::cout << "Shared Face Evaluation 3D" << std::endl;
|
||||
}
|
||||
|
||||
for (int sf = 0; sf < pmesh.GetNSharedFaces(); sf++)
|
||||
{
|
||||
FaceElementTransformations *FET =
|
||||
@@ -3165,7 +3167,6 @@ TEST_CASE("3D GetVectorValue in Parallel",
|
||||
npts++;
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
T->SetIntPoint(&ip);
|
||||
T->Transform(ip, x);
|
||||
|
||||
funcCoef.Eval(f_val, *T, ip);
|
||||
|
||||
@@ -3222,11 +3223,9 @@ TEST_CASE("3D GetVectorValue in Parallel",
|
||||
}
|
||||
if (log > 0 && nd_gfc_dist > tol)
|
||||
{
|
||||
std::cout << e << ":" << j
|
||||
<< " x = (" << x[0] << "," << x[1] << ","
|
||||
<< x[2] << ")\n nd gfc ("
|
||||
std::cout << e << ":" << j << " nd gfc ("
|
||||
<< f_val[0] << "," << f_val[1] << ","
|
||||
<< f_val[2] << ")\n vs. ("
|
||||
<< f_val[2] << ") vs. ("
|
||||
<< nd_gfc_val[0] << "," << nd_gfc_val[1] << ","
|
||||
<< nd_gfc_val[2] << ") "
|
||||
<< nd_gfc_dist << std::endl;
|
||||
@@ -3358,7 +3357,6 @@ TEST_CASE("3D GetVectorValue in Parallel",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << my_rank << ": Checked GridFunction::GetVectorValue at "
|
||||
<< npts << " 3D points" << std::endl;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user