Compare commits

..
3 Commits
Author SHA1 Message Date
bensworth d8501138bc Some mods for compiling 2021-08-18 09:42:36 -06:00
bensworth c679c99b35 minor mods for MFEM 2021-08-18 09:08:24 -06:00
bensworth 3f9a3658a6 Added framework for IMEX BDF and RK; not included in MFEM config/setup yet 2021-08-18 09:03:18 -06:00
101 changed files with 1863 additions and 12969 deletions
+1 -15
View File
@@ -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/*
-1
View File
@@ -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
-18
View File
@@ -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
======================================
-66
View File
@@ -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
+1 -1
View File
@@ -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).
-6
View File
@@ -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
-2
View File
@@ -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@
-15
View File
@@ -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)
-9
View File
@@ -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
-43
View File
@@ -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
-38
View File
@@ -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
-47
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
-286
View File
@@ -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;
}
-69
View File
@@ -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.*
+2 -2
View File
@@ -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
View File
@@ -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);
-1
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
-1
View File
@@ -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
-2
View File
@@ -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:
-2
View File
@@ -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:
+1
View File
@@ -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.
+1
View File
@@ -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
View File
@@ -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
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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.
-2
View File
@@ -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
View File
@@ -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.
+1
View File
@@ -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
+4 -1
View File
@@ -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.
+4 -1
View File
@@ -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.
-250
View File
@@ -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;
}
-67
View File
@@ -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_*
-2
View File
@@ -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
View File
@@ -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);
}
}
-358
View File
@@ -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
-277
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
-219
View File
@@ -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
View File
@@ -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
View File
@@ -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) { }
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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++)
{
-32
View File
@@ -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)
{
-2
View File
@@ -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
View File
@@ -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);
}
}
+1 -3
View File
@@ -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(
-1
View File
@@ -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
View File
@@ -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(&ltdof, &gtdof, 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
{
-4
View File
@@ -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
-1
View File
@@ -13,7 +13,6 @@
#define MFEM_FORALL_HPP
#include "../config/config.hpp"
#include "annotation.hpp"
#include "error.hpp"
#include "backends.hpp"
#include "device.hpp"
-5
View File
@@ -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)
-10
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
-240
View File
@@ -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
-6
View File
@@ -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;
}
-7
View File
@@ -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)
{
-94
View File
@@ -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
-23
View File
@@ -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()
{}
};
-53
View File
@@ -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
View File
@@ -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;
-12
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+244
View File
@@ -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
View File
@@ -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"
-157
View File
@@ -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
-77
View File
@@ -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
+4 -6
View File
@@ -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))
-2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
-64
View File
@@ -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;
}
}
-78
View File
@@ -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
View File
@@ -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;
}
+13 -10
View File
@@ -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;
+31
View File
@@ -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++)
{
-343
View File
@@ -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
+8
View File
@@ -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;
-673
View File
@@ -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
+7 -9
View File
@@ -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