Compare commits

..
Author SHA1 Message Date
Jan Nikl 4667cf9d39 Silenced tee. 2026-03-16 13:30:20 -07:00
Jan Nikl 1e6c8ecf56 Removed compilation checks. 2026-03-16 12:54:15 -07:00
Jan Nikl 95c844f519 Replaced tee -p by trap. 2026-03-16 12:30:43 -07:00
Jan Nikl b5b0f2382f Removed unnecessary move of the server. 2026-03-16 12:03:04 -07:00
Jan Nikl bbdc39d605 Added error when run on a non-POSIX platform. 2026-03-16 12:01:22 -07:00
Jan Nikl 7fed49c38b Added visualization server to ex1p. 2026-03-16 10:59:15 -07:00
Tzanio Kolev fa89c5e98c Merge pull request #4856 from mfem/phys-range-dim
Range and curl dimension in physical space
2026-03-13 07:44:40 -07:00
Tzanio Kolev 0980bda63b Merge pull request #5215 from balay/barry/update-for-petsc-v3.25-PetscCtx
Update to change in PETSc API (in v3.25) for PetscCtx and PetscCtxRt
2026-03-13 07:44:06 -07:00
Will Pazner 82abd48bba Merge pull request #5080 from mfem/cmake-config
CMake config.mk for CUDA and HIP
2026-03-11 12:18:25 -04:00
Tzanio Kolev d4374a9d5f Merge branch 'master' into cmake-config 2026-03-10 11:08:23 -07:00
Tzanio Kolev dcd3a25730 Merge branch 'master' into barry/update-for-petsc-v3.25-PetscCtx 2026-03-10 11:01:46 -07:00
Andrew Ho 0f99528c62 Merge branch 'master' into phys-range-dim 2026-03-05 12:45:42 -08:00
Veselin Dobrev ddfd74e899 Merge pull request #5255 from mfem/catch-tests
fix clang compiler warning for __COUNTER__
2026-03-05 12:39:29 -08:00
Mark L. Stowell 0248720eeb Merge branch 'master' into phys-range-dim 2026-03-05 09:35:14 -08:00
Andrew Ho feded39641 Merge branch 'master' into catch-tests 2026-03-05 09:28:31 -08:00
Tzanio Kolev 09128b9a5d Merge pull request #5240 from mfem/bugfix/chapan39/use-mfem-abort-kernel-in-device
dfem integrate: use mfem abort kernel in device code
2026-03-04 09:55:23 -08:00
Tzanio Kolev 68383b462b Merge pull request #5231 from mfem/plasma-dir-dev
Plasma Miniapp Directory
2026-03-04 09:54:48 -08:00
Tzanio Kolev 24d5609585 Merge pull request #5212 from mfem/najlkin/fix-cmplx-assign
[BUG] Complex grid function copy assignment
2026-03-04 09:54:25 -08:00
Andrew Ho 670a3f9a45 comment on why TPL_LIBRARIES is reversed twice 2026-03-03 11:43:02 -08:00
Andrew Ho 7baae02d65 Merge remote-tracking branch 'base/cmake-config' into cmake-config 2026-03-02 16:31:18 -08:00
Andrew Ho 728a0f313b move cudart to MFEM_EXT_LIBS 2026-03-02 16:30:31 -08:00
Andrew Ho 1bb624e2a8 fix clang compiler warning for __COUNTER__ 2026-03-02 14:05:28 -08:00
Tzanio Kolev ee7ccd6464 Merge branch 'master' into plasma-dir-dev 2026-03-02 11:56:51 -08:00
Stowell, Mark L. a3ae5a6f01 Changing copyright date to pass CI checks 2026-03-02 09:22:29 -08:00
Andrew HoandNuno Nobre 9243d00549 Update config/cmake/modules/MfemCmakeUtilities.cmake
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2026-02-28 14:53:22 -08:00
Andrew HoandNuno Nobre 4fe3db5a5f Update config/cmake/modules/MfemCmakeUtilities.cmake
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2026-02-28 14:53:15 -08:00
Andrew Ho 55bb710cba fixed wrong dir being marked as system 2026-02-27 14:02:24 -08:00
Andrew HoandNuno Nobre 7ad6939454 Update config/cmake/modules/MfemCmakeUtilities.cmake
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2026-02-27 07:06:16 -08:00
60cc94e5a1 Update to use PetscCtxRt from (3,25,0), and cleanup duplicate code
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
Co-authored-by: Satish Balay <balay@mcs.anl.gov>
2026-02-26 11:57:27 -06:00
Satish Balay 9122ac1839 update KSPMonitorFn usage for < (3,24,0) 2026-02-26 11:57:22 -06:00
Satish Balay 864186117d update PetscCtxDestroyFn usage for < (3,23,0) 2026-02-26 11:56:15 -06:00
Ketan Mittal 35de169fd0 Merge branch 'master' into plasma-dir-dev 2026-02-26 09:42:51 -08:00
Andrew Ho 0a3184ab31 MFEM_EXPORT_GPU_CONFIG should export CPU config.mk when set to off 2026-02-24 11:56:38 -08:00
Mark L. Stowell a438e09caf Merge branch 'master' into plasma-dir-dev 2026-02-24 11:02:04 -08:00
Alex Tyler Chapman ea03a86df2 Merge branch 'master' into bugfix/chapan39/use-mfem-abort-kernel-in-device 2026-02-24 10:32:30 -08:00
chapman39 6ef7a9e6fb 80 chars/ line 2026-02-24 10:32:18 -08:00
Alex Tyler Chapman db7dd30d32 Merge branch 'master' into bugfix/chapan39/use-mfem-abort-kernel-in-device 2026-02-23 09:33:23 -08:00
chapman39 a1fe3a19b1 dfem integrate: use mfem abort kernel in device code 2026-02-19 17:45:11 -08:00
Satish Balay 213ccd7a4e rework PetscContainerSetCtxDestroy() usage for < (3,23,0) 2026-02-18 15:51:42 -06:00
Tzanio Kolev 2b14134496 Merge branch 'master' into najlkin/fix-cmplx-assign 2026-02-17 08:27:01 -08:00
Stowell, Mark L. 794a5fbfc2 Adding miniapps/plasma subdirectory to build system 2026-02-11 11:56:06 -08:00
Stowell, Mark L. 746a62f017 Adding plasma miniapp directory 2026-02-11 11:53:01 -08:00
Andrew Ho 26e9057f02 revert change, updated comment to why libdl gets special treatment 2026-01-30 07:27:04 -08:00
Jan Nikl 16dfa11f27 Minor docstring correction. 2026-01-28 15:45:20 -08:00
Jan Nikl c7774e3c1c Fixed complex grid function copy assignment. 2026-01-28 15:34:55 -08:00
Andrew Ho 194f3d8140 suggestions from Veselin 2026-01-21 11:45:20 -08:00
Mark L. Stowell 3f9b44a9cd Merge branch 'master' into phys-range-dim 2026-01-21 10:38:56 -08:00
John Camier caa973d6a0 Merge branch 'master' into cmake-config 2026-01-13 08:13:47 -08:00
Andrew Ho ad40704e20 Merge branch 'master' into cmake-config 2026-01-06 11:55:40 -08:00
Andrew Ho d3470c07c9 Merge branch 'master' into cmake-config 2025-12-16 12:05:27 -08:00
Andrew Ho 06a15cb7a9 missed one old unsetting of shared_link_flag 2025-12-01 17:02:05 -08:00
Andrew Ho d19ff6c676 Merge branch 'master' into cmake-config 2025-12-01 12:33:24 -08:00
Andrew Ho d85fbc6504 review suggestions 2025-11-25 14:35:38 -08:00
Andrew Ho 29346a87b6 Merge branch 'master' into cmake-config 2025-11-25 14:31:21 -05:00
Andrew Ho 3464f7a004 Merge branch 'master' into cmake-config 2025-10-28 11:08:38 -07:00
Andrew Ho 7de48e47ad Merge branch 'master' into cmake-config 2025-10-24 09:24:50 -07:00
Andrew Ho 70814c640b fixes for hip 2025-10-20 14:01:50 -07:00
Andrew Ho e9d3ae80f7 remove debug printout 2025-10-20 13:30:20 -07:00
Andrew Ho c8efc23c12 seems to be building external laghos now 2025-10-20 13:26:04 -07:00
Andrew Ho f26eb33252 Merge remote-tracking branch 'base/cmake-gpu' into cmake-config 2025-10-20 10:25:58 -07:00
Andrew Ho 05e622f837 improving config.mk file generated by cmake to work with hip/cuda
Still need to export compiler flags
2025-10-20 08:33:17 -07:00
Mark L. Stowell e9f84b033f Merge branch 'master' into phys-range-dim 2025-10-15 06:49:33 -07:00
Mark L. Stowell 83fd119b95 Merge branch 'master' into phys-range-dim 2025-07-01 10:16:58 -07:00
Mark L. Stowell 4aecb86d71 Merge branch 'master' into phys-range-dim 2025-05-19 17:51:08 -07:00
Stowell, Mark L. 776a4c1815 Updating unit tests 2025-05-11 14:40:05 -07:00
Stowell, Mark L. c870d7dc1c Using new MapType entries and implementing new GetPhys*Dim methods 2025-05-11 14:39:49 -07:00
Stowell, Mark L. 8519889074 Adding new MapType entries for R2D and R1D classes 2025-05-11 14:38:50 -07:00
45 changed files with 621 additions and 2759 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ runs:
steps:
- uses: ./.github/actions/sanitize/config
- uses: actions/cache@v5
- uses: actions/cache@v4
if: ${{env.DEBUG == 'true'}}
id: debug
with:
+1 -1
View File
@@ -36,7 +36,7 @@ runs:
steps:
- uses: ./.github/actions/sanitize/config
- uses: actions/cache@v5
- uses: actions/cache@v4
if: ${{env.DEBUG == 'true' && inputs.cache-skip != 'true'}}
id: debug
with:
+5 -5
View File
@@ -23,7 +23,7 @@ inputs:
runs:
using: 'composite'
steps:
- uses: actions/cache/restore@v5 # Cache for LLVM libcxx
- uses: actions/cache/restore@v4 # Cache for LLVM libcxx
with:
path: ${{env.LLVM_DIR}}
fail-on-cache-miss: true
@@ -32,14 +32,14 @@ runs:
- uses: ./.github/actions/sanitize/mpi
if: ${{inputs.par == 'true'}}
- uses: actions/cache/restore@v5 # Cache for Hypre
- uses: actions/cache/restore@v4 # Cache for Hypre
if: ${{inputs.par == 'true'}}
with:
path: ${{env.HYPRE_DIR}}
fail-on-cache-miss: true
key: ${{runner.os}}-ompi-build-${{env.HYPRE_DIR}}-int32-fp64-v2.5
- uses: actions/cache/restore@v5 # Cache for Metis
- uses: actions/cache/restore@v4 # Cache for Metis
if: ${{inputs.par == 'true'}}
with:
path: ${{env.METIS_DIR}}
@@ -51,13 +51,13 @@ runs:
run: ln -s -f ${{env.HYPRE_DIR}} hypre && ln -s -f ${{env.METIS_DIR}} metis-4.0
shell: bash
- uses: actions/cache/restore@v5 # Cache for LSAN suppression file
- uses: actions/cache/restore@v4 # Cache for LSAN suppression file
with:
path: ${{env.LSAN_DIR}}
fail-on-cache-miss: true
key: build-lsan-suppression-file
- uses: actions/checkout@v6 # Checkout the repository
- uses: actions/checkout@v4 # Checkout the repository
with:
path: mfem
# ref: ${{env.BRANCH}}
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
# It's easier to reference named variables than indexes of the matrix
- name: Set Environment
+4 -4
View File
@@ -153,7 +153,7 @@ jobs:
# /home/runner/work/mfem/mfem/mfem
# Note: Done now to access "install-hypre" and "install-metis" actions.
- name: checkout mfem
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
path: ${{ env.MFEM_TOP_DIR }}
# Fetch the complete history for codecov to access commits ID
@@ -225,7 +225,7 @@ jobs:
- name: cache hypre
id: hypre-cache
if: matrix.mpi == 'par'
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-ompi-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-${{ matrix.precision }}-v2.5
@@ -255,7 +255,7 @@ jobs:
- name: cache metis
id: metis-cache
if: matrix.mpi == 'par' && matrix.os != 'windows-latest'
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.5
@@ -270,7 +270,7 @@ jobs:
- name: cache vcpkg (Windows)
id: vcpkg-cache
if: matrix.os == 'windows-latest'
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: vcpkg_cache
key: ${{ runner.os }}-${{ matrix.mpi }}-vcpkg-v1
+4 -4
View File
@@ -40,11 +40,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -57,7 +57,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v4
uses: github/codeql-action/autobuild@v2
# ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -70,4 +70,4 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v2
+3 -3
View File
@@ -39,7 +39,7 @@ jobs:
steps:
- name: checkout MFEM
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
path: mfem
@@ -50,7 +50,7 @@ jobs:
- name: Cache Hypre Install
id: hypre-cache
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-ompi-build-${{ env.HYPRE_TOP_DIR }}-v2.5
@@ -65,7 +65,7 @@ jobs:
- name: Cache Metis Install
id: metis-cache
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.5
+4 -4
View File
@@ -38,7 +38,7 @@ jobs:
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: copyright check
id: copyright
@@ -93,7 +93,7 @@ jobs:
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: get astyle
run: |
@@ -110,7 +110,7 @@ jobs:
github.event.pull_request.head.repo.full_name != github.repository)
steps:
- name: checkout mfem
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: get doxygen and graphviz
run: |
@@ -135,7 +135,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout mfem
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
fetch-depth: 0
+2 -2
View File
@@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
name: 2.19.0
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/config
- name: Cache
id: cache
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ${{env.HYPRE_DIR}}
key: ${{runner.os}}-ompi-build-${{env.HYPRE_DIR}}-int32-fp64-v2.5
+2 -2
View File
@@ -27,13 +27,13 @@ jobs:
llvm_use_sanitizer: "Undefined"
name: ${{matrix.sanitizer}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/config
with:
NO_FLAGS: true
- name: Cache
id: cache
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ${{env.LLVM_DIR}}
key: build-libcxx-${{env.LLVM_VER}}-${{matrix.sanitizer}}
+2 -2
View File
@@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
name: lsan.supp
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/config
- name: Cache
id: cache
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ${{env.LSAN_DIR}}
key: build-lsan-suppression-file
+2 -2
View File
@@ -17,11 +17,11 @@ jobs:
runs-on: ubuntu-latest
name: 4.0.3
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/config
- name: Cache
id: cache
uses: actions/cache@v5
uses: actions/cache@v4
with:
path: ${{env.METIS_DIR}}
key: ${{runner.os}}-build-${{env.METIS_DIR}}-v2.5
+7 -7
View File
@@ -28,7 +28,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/mfem
with:
par: ${{inputs.par}}
@@ -40,7 +40,7 @@ jobs:
env:
ex: ${{inputs.par && 'ex1p' || 'ex1'}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -58,7 +58,7 @@ jobs:
env:
exclude: ${{inputs.par && '-E "_ser"' || ''}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -82,7 +82,7 @@ jobs:
env:
exclude: ${{inputs.par && '-E "_ser"' || ''}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -107,7 +107,7 @@ jobs:
run: ${{inputs.par && '-R "_cpu_np"' || ''}}
exclude: ${{inputs.par && '"unit_tests|debug"' || '"^unit_tests$|debug"'}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -131,7 +131,7 @@ jobs:
env:
unit_tests: ${{inputs.par && 'punit_tests' || 'unit_tests'}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/restore
id: restore
with:
@@ -165,7 +165,7 @@ jobs:
unit_tests: ${{inputs.par && 'punit_tests' || 'unit_tests'}}
np: ${{inputs.par && '_np=2' || ''}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
- uses: ./.github/actions/sanitize/restore
id: restore
with:
-16
View File
@@ -8,22 +8,6 @@
https://mfem.org
Version 4.10 (development)
==========================
Discretization improvements
---------------------------
- Replaced legacy simplex quadrature rules with symmetric positive-weight
rules for triangles (orders 0-25) and tetrahedra (orders 0-20). These
rules guarantee all-positive weights and interior quadrature points,
improving numerical stability. Higher orders fall back to Grundmann-Moller.
Triangle rules: Witherden & Vincent, Comput. Math. Appl. 69(10):1232-1241,
2015.
Tet rules (d=1-13): Witherden & Vincent (ibid).
Tet rules (d=14-20): Chuluunbaatar et al., Comput. Math. Appl. 124:89-97,
2022.
Version 4.9.1 (development)
===========================
+2 -2
View File
@@ -5,9 +5,9 @@
// Sample runs:
// mpirun -np 4 ex12p -m ../data/beam-tri.mesh
// mpirun -np 4 ex12p -m ../data/beam-quad.mesh
// mpirun -np 4 ex12p -m ../data/beam-tet.mesh -s 464 -n 10 -o 2 -elast
// mpirun -np 4 ex12p -m ../data/beam-tet.mesh -s 462 -n 10 -o 2 -elast
// mpirun -np 4 ex12p -m ../data/beam-hex.mesh -s 3878
// mpirun -np 4 ex12p -m ../data/beam-wedge.mesh -s 82
// mpirun -np 4 ex12p -m ../data/beam-wedge.mesh -s 81
// mpirun -np 4 ex12p -m ../data/beam-tri.mesh -s 3877 -o 2 -sys
// mpirun -np 4 ex12p -m ../data/beam-quad.mesh -s 4544 -n 6 -o 3 -elast
// mpirun -np 4 ex12p -m ../data/beam-quad-nurbs.mesh
+94
View File
@@ -66,6 +66,26 @@
using namespace std;
using namespace mfem;
class VisServer
{
const char *path{};
int port{-1};
struct Deleter { void operator()(FILE *); };
std::unique_ptr<FILE, Deleter> fglvis;
void Open();
public:
VisServer(const char *path_, int port_ = 19916)
: path(path_), port(port_) { Open(); }
explicit VisServer() = default;
inline const char *GetPath() const { return path; }
inline int GetPort() const { return port; }
inline bool IsOpen() const { return (fglvis != nullptr); }
};
int main(int argc, char *argv[])
{
// 1. Initialize MPI and HYPRE.
@@ -82,6 +102,7 @@ int main(int argc, char *argv[])
bool fa = false;
const char *device_config = "cpu";
bool visualization = true;
const char *visserver = "";
bool algebraic_ceed = false;
OptionsParser args(argc, argv);
@@ -106,6 +127,8 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&visserver, "-vs", "--visualization-server",
"Path to GLVis binary to start own server.");
args.Parse();
if (!args.Good())
{
@@ -301,6 +324,14 @@ int main(int argc, char *argv[])
{
char vishost[] = "localhost";
int visport = 19916;
VisServer server;
if (strlen(visserver) > 0)
{
server = VisServer(visserver, visport);
visport = server.GetPort();
}
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
@@ -315,3 +346,66 @@ int main(int argc, char *argv[])
return 0;
}
void VisServer::Open()
{
if (!path || strlen(path) <= 0) { return; }
#ifdef MFEM_USE_MPI
if (Mpi::Root())
#endif // MFEM_USE_MPI
{
// Open a log file
FILE *ftmp = popen("mktemp --tmpdir glvis-log.XXXXXX", "r");
constexpr size_t ssize = 256;
char stmp[ssize];
fgets(stmp, ssize, ftmp);
pclose(ftmp);
int len = strlen(stmp);
if (len > 0 && stmp[len-1] == '\n') { stmp[--len] = '\0'; }
std::cout << "Starting GLVis log in: " << stmp << std::endl;
// Start the server
std::stringstream ss;
ss << "trap '' SIGPIPE && " << path <<
" -no-pr -no-ex 2>&1 | tee \"" << stmp <<
"\" 2> /dev/null | grep -m 1 ^GLVIS_SERVER_PORT";
fglvis.reset(popen(ss.str().c_str(), "r"));
// Capture the port number
char line[ssize];
bool captured = false;
while (fgets(line, ssize, fglvis.get()))
{
if (strncmp(line, "GLVIS_SERVER_PORT=", 18) == 0)
{
sscanf(line, "GLVIS_SERVER_PORT=%d", &port);
captured = true;
break;
}
}
if (captured)
{
std::cout << "Started GLVis server at port: " << port << std::endl;
}
else
{
std::cerr << "GLVis server did not start normally." << std::endl;
}
}
#ifdef MFEM_USE_MPI
MPI_Bcast(&port, 1, MPI_INT, 0, MPI_COMM_WORLD);
#endif // MFEM_USE_MPI
}
void VisServer::Deleter::operator()(FILE *f)
{
if (f != nullptr)
{
int ierr = pclose(f);
if (ierr != 0)
{
std::cerr << "GLVis server pclose() returns: " << ierr << std::endl;
}
}
}
+9 -27
View File
@@ -302,21 +302,15 @@ int main(int argc, char *argv[])
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_r(vishost, visport);
socketstream sol_sock_i(vishost, visport);
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_r.precision(8);
sol_sock_i.precision(8);
sol_sock_r << "solution\n" << *pmesh << u_exact->real()
<< "window_title 'Exact: Real Part'" << flush;
// Make sure all ranks have sent their real solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
socketstream sol_sock_i(vishost, visport);
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i.precision(8);
sol_sock_i << "solution\n" << *pmesh << u_exact->imag()
<< "window_title 'Exact: Imaginary Part'" << flush;
// Make sure all ranks have sent their imaginary solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
}
// 11. Set up the parallel sesquilinear form a(.,.) on the finite element
@@ -540,21 +534,15 @@ int main(int argc, char *argv[])
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_r(vishost, visport);
socketstream sol_sock_i(vishost, visport);
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_r.precision(8);
sol_sock_i.precision(8);
sol_sock_r << "solution\n" << *pmesh << u.real()
<< "window_title 'Solution: Real Part'" << flush;
// Make sure all ranks have sent their real solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
socketstream sol_sock_i(vishost, visport);
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i.precision(8);
sol_sock_i << "solution\n" << *pmesh << u.imag()
<< "window_title 'Solution: Imaginary Part'" << flush;
// Make sure all ranks have sent their imaginary solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
}
if (visualization && exact_sol)
{
@@ -563,21 +551,15 @@ int main(int argc, char *argv[])
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_r(vishost, visport);
socketstream sol_sock_i(vishost, visport);
sol_sock_r << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_r.precision(8);
sol_sock_i.precision(8);
sol_sock_r << "solution\n" << *pmesh << u_exact->real()
<< "window_title 'Error: Real Part'" << flush;
// Make sure all ranks have sent their real solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
socketstream sol_sock_i(vishost, visport);
sol_sock_i << "parallel " << num_procs << " " << myid << "\n";
sol_sock_i.precision(8);
sol_sock_i << "solution\n" << *pmesh << u_exact->imag()
<< "window_title 'Error: Imaginary Part'" << flush;
// Make sure all ranks have sent their imaginary solution before initiating
// another set of GLVis connections (one from each rank):
MPI_Barrier(pmesh->GetComm());
}
if (visualization)
{
+8 -2
View File
@@ -97,7 +97,13 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.ParseCheck();
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the mesh file.
const char *mesh_file = "../data/disc-nurbs.mesh";
@@ -122,7 +128,7 @@ int main(int argc, char *argv[])
*nodes /= scale;
// 4. Define the necessary finite element spaces on the mesh.
H1Bubble_FECollection H1fec(order, order - 1, dim);
H1_FECollection H1fec(order+1, dim);
FiniteElementSpace H1fes(&mesh, &H1fec);
L2_FECollection L2fec(order-1, dim);
+14 -2
View File
@@ -103,7 +103,19 @@ int main(int argc, char *argv[])
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.ParseCheck();
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 2. Read the mesh from the mesh file.
const char *mesh_file = "../data/disc-nurbs.mesh";
@@ -131,7 +143,7 @@ int main(int argc, char *argv[])
mesh.Clear();
// 4. Define the necessary finite element spaces on the mesh.
H1Bubble_FECollection H1fec(order, order - 1, dim);
H1_FECollection H1fec(order+1, dim);
ParFiniteElementSpace H1fes(&pmesh, &H1fec);
L2_FECollection L2fec(order-1, dim);
+1 -3
View File
@@ -73,7 +73,6 @@ set(SRCS
fe/fe_base.cpp
fe/fe_fixed_order.cpp
fe/fe_h1.cpp
fe/fe_h1_bubble.cpp
fe/fe_l2.cpp
fe/fe_nd.cpp
fe/fe_nurbs.cpp
@@ -134,7 +133,7 @@ set(SRCS
tmop/assemble/diag2.cpp
tmop/assemble/grad2_limit.cpp
tmop/assemble/grad2.cpp
tmop/assemble/diag3_limit.cpp
tmop/assemble/diag3_limit.cpp
tmop/assemble/diag3.cpp
tmop/assemble/grad3_limit.cpp
tmop/assemble/grad3.cpp
@@ -222,7 +221,6 @@ set(HDRS
fe/fe_base.hpp
fe/fe_fixed_order.hpp
fe/fe_h1.hpp
fe/fe_h1_bubble.hpp
fe/fe_l2.hpp
fe/fe_nd.hpp
fe/fe_nurbs.hpp
+3 -7
View File
@@ -729,8 +729,7 @@ void BilinearForm::Assemble(int skip_zeros)
tr = mesh -> GetBdrFaceTransformations (i);
if (tr != NULL)
{
mfem::DofTransformation doftrans;
fes -> GetElementVDofs (tr -> Elem1No, vdofs, doftrans);
fes -> GetElementVDofs (tr -> Elem1No, vdofs);
fe1 = fes -> GetFE (tr -> Elem1No);
// The fe2 object is really a dummy and not used on the boundaries,
// but we can't dereference a NULL pointer, and we don't want to
@@ -744,7 +743,6 @@ void BilinearForm::Assemble(int skip_zeros)
boundary_face_integs[k] -> AssembleFaceMatrix (*fe1, *fe2, *tr,
elemmat);
doftrans.TransformDual(elemmat);
mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros);
}
}
@@ -1725,7 +1723,6 @@ void MixedBilinearForm::Assemble(int skip_zeros)
}
}
DofTransformation dom_dof_trans, ran_dof_trans;
for (int i = 0; i < trial_fes -> GetNBE(); i++)
{
const int bdr_attr = mesh->GetBdrAttribute(i);
@@ -1734,8 +1731,8 @@ void MixedBilinearForm::Assemble(int skip_zeros)
ftr = mesh -> GetBdrFaceTransformations (i);
if (ftr != NULL)
{
trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs, dom_dof_trans);
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs, ran_dof_trans);
trial_fes->GetElementVDofs(ftr->Elem1No, trial_vdofs);
test_fes->GetElementVDofs(ftr->Elem1No, test_vdofs);
trial_fe1 = trial_fes->GetFE(ftr->Elem1No);
test_fe1 = test_fes->GetFE(ftr->Elem1No);
// The test_fe2 object is really a dummy and not used on the
@@ -1751,7 +1748,6 @@ void MixedBilinearForm::Assemble(int skip_zeros)
boundary_face_integs[k]->AssembleFaceMatrix(*trial_fe1, *test_fe1, *trial_fe2,
*test_fe2,
*ftr, elemmat);
TransformDual(ran_dof_trans, dom_dof_trans, elemmat);
mat->AddSubMatrix(test_vdofs, trial_vdofs, elemmat, skip_zeros);
}
}
+1 -1
View File
@@ -2710,7 +2710,7 @@ public:
/** Integrator for $(-Q u, \nabla v)$ for Nedelec ($u$) and $H^1$ ($v$) elements.
This is equivalent to a weak divergence of the $H(curl)$ basis functions. */
This is equivalent to a weak divergence of the $H(curl$ basis functions. */
class VectorFEWeakDivergenceIntegrator: public BilinearFormIntegrator
{
protected:
-1
View File
@@ -20,7 +20,6 @@
#include "fe/fe_base.hpp"
#include "fe/fe_fixed_order.hpp"
#include "fe/fe_h1.hpp"
#include "fe/fe_h1_bubble.hpp"
#include "fe/fe_nd.hpp"
#include "fe/fe_rt.hpp"
#include "fe/fe_l2.hpp"
-973
View File
@@ -1,973 +0,0 @@
// Copyright (c) 2010-2025, 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.
// H1 Finite Element classes
#include "fe_h1_bubble.hpp"
namespace mfem
{
using namespace std;
H1Bubble_TriangleElement::H1Bubble_TriangleElement(int p, int q, int btype)
: NodalFiniteElement(2, Geometry::TRIANGLE, 3*p + ((q+1)*(q+2))/2,
max(p, 3 + q), FunctionSpace::Pk),
base_order(p), bubble_order(q)
{
const real_t *cp = poly1d.ClosedPoints(p, VerifyNodal(VerifyClosed(btype)));
const real_t *cp2 = poly1d.ClosedPoints(
q + 3, VerifyNodal(VerifyClosed(btype)));
const int n1d = max(p + 1, q + 1);
const int npq = ((p+1)*(p+2))/2 + ((q+1)*(q+2))/2;
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(n1d);
shape_y.SetSize(n1d);
shape_l.SetSize(n1d);
dshape_x.SetSize(n1d);
dshape_y.SetSize(n1d);
dshape_l.SetSize(n1d);
u.SetSize(npq);
du.SetSize(npq, dim);
#endif
// vertices
Nodes.IntPoint(0).Set2(cp[0], cp[0]);
Nodes.IntPoint(1).Set2(cp[p], cp[0]);
Nodes.IntPoint(2).Set2(cp[0], cp[p]);
// edges
int o = 3;
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set2(cp[i], cp[0]);
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set2(cp[p-i], cp[i]);
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set2(cp[0], cp[p-i]);
}
// Interior P_{q+3} nodes
for (int j = 1; j < q + 3; j++)
{
for (int i = 1; i + j < q + 3; i++)
{
const real_t w = cp2[i] + cp2[j] + cp2[q+3-i-j];
Nodes.IntPoint(o++).Set2(cp2[i]/w, cp2[j]/w);
}
}
#ifdef MFEM_THREAD_SAFE
Vector shape_x(n1d), shape_y(n1d), shape_l(n1d);
#endif
DenseMatrix Tt(dof, npq);
for (int k = 0; k < dof; ++k)
{
const IntegrationPoint &ip = Nodes.IntPoint(k);
poly1d.CalcBasis(p, ip.x, shape_x);
poly1d.CalcBasis(p, ip.y, shape_y);
poly1d.CalcBasis(p, 1. - ip.x - ip.y, shape_l);
o = 0;
for (int j = 0; j <= p; j++)
{
for (int i = 0; i + j <= p; i++)
{
Tt(k, o++) = shape_x[i]*shape_y[j]*shape_l[p-i-j];
}
}
poly1d.CalcBasis(q, ip.x, shape_x);
poly1d.CalcBasis(q, ip.y, shape_y);
poly1d.CalcBasis(q, 1. - ip.x - ip.y, shape_l);
const real_t b_T = ip.x * ip.y * (1 - ip.x - ip.y);
for (int j = 0; j <= q; j++)
{
for (int i = 0; i + j <= q; i++)
{
Tt(k, o++) = b_T*shape_x[i]*shape_y[j]*shape_l[q-i-j];
}
}
}
// Compute left inverse of T (given Tt = T^T).
DenseMatrix TtT(dof, dof);
MultAAt(Tt, TtT);
DenseMatrixInverse TtT_inv(TtT);
T_pinv.SetSize(dof, dof);
TtT_inv.Mult(Tt, T_pinv);
}
void H1Bubble_TriangleElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = base_order;
const int q = bubble_order;
#ifdef MFEM_THREAD_SAFE
const int n1d = max(p + 1, q + 1);
const int npq = ((p+1)*(p+2))/2 + ((q+1)*(q+2))/2;
Vector shape_x(n1d), shape_y(n1d), shape_l(n1d), u(npq);
#endif
poly1d.CalcBasis(p, ip.x, shape_x);
poly1d.CalcBasis(p, ip.y, shape_y);
poly1d.CalcBasis(p, 1. - ip.x - ip.y, shape_l);
int o = 0;
for (int j = 0; j <= p; j++)
{
for (int i = 0; i + j <= p; i++)
{
u(o++) = shape_x[i]*shape_y[j]*shape_l[p-i-j];
}
}
poly1d.CalcBasis(q, ip.x, shape_x);
poly1d.CalcBasis(q, ip.y, shape_y);
poly1d.CalcBasis(q, 1. - ip.x - ip.y, shape_l);
const real_t b_T = ip.x * ip.y * (1 - ip.x - ip.y);
for (int j = 0; j <= q; j++)
{
for (int i = 0; i + j <= q; i++)
{
u(o++) = b_T*shape_x[i]*shape_y[j]*shape_l[q-i-j];
}
}
T_pinv.Mult(u, shape);
}
void H1Bubble_TriangleElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = base_order;
const int q = bubble_order;
#ifdef MFEM_THREAD_SAFE
const int n1d = max(p + 1, q + 1);
const int npq = ((p+1)*(p+2))/2 + ((q+1)*(q+2))/2;
Vector shape_x(n1d), shape_y(n1d), shape_l(n1d);
Vector dshape_x(n1d), dshape_y(n1d), dshape_l(n1d);
DenseMatrix du(npq, dim);
#endif
const real_t lambda = 1.0 - ip.x - ip.y;
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
poly1d.CalcBasis(p, lambda, shape_l, dshape_l);
int o = 0;
for (int j = 0; j <= p; j++)
{
for (int i = 0; i + j <= p; i++)
{
int k = p - i - j;
du(o,0) = (dshape_x[i]*shape_l[k] - shape_x[i]*dshape_l[k])*shape_y[j];
du(o,1) = (dshape_y[j]* shape_l[k] - shape_y[j]*dshape_l[k])*shape_x[i];
o++;
}
}
poly1d.CalcBasis(q, ip.x, shape_x, dshape_x);
poly1d.CalcBasis(q, ip.y, shape_y, dshape_y);
poly1d.CalcBasis(q, lambda, shape_l, dshape_l);
const real_t b_T = ip.x * ip.y * lambda;
const real_t dxb_T = ip.y * (lambda - ip.x);
const real_t dyb_T = ip.x * (lambda - ip.y);
for (int j = 0; j <= q; j++)
{
for (int i = 0; i + j <= q; i++)
{
int k = q - i - j;
du(o,0) = shape_y[j]*(dxb_T*shape_x[i]*shape_l[k]
+ b_T*dshape_x[i]*shape_l[k]
- b_T*shape_x[i]*dshape_l[k]);
du(o,1) = shape_x[i]*(dyb_T*shape_y[j]*shape_l[k]
+ b_T*dshape_y[j]*shape_l[k]
- b_T*shape_y[j]*dshape_l[k]);
o++;
}
}
Mult(T_pinv, du, dshape);
}
H1Bubble_QuadrilateralElement::H1Bubble_QuadrilateralElement(
int p, int q, int btype)
: NodalFiniteElement(2, Geometry::SQUARE, 4*p + (q+1)*(q+1),
max(p, 2 + q), FunctionSpace::Qk),
base_order(p), bubble_order(q)
{
const real_t *cp = poly1d.ClosedPoints(p, VerifyNodal(VerifyClosed(btype)));
const real_t *cp2 = poly1d.ClosedPoints(
q + 2, VerifyNodal(VerifyClosed(btype)));
const int n1d = max(p + 1, q + 1);
const int npq = (p+1)*(p+1) + (q+1)*(q+1);
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(n1d);
shape_y.SetSize(n1d);
dshape_x.SetSize(n1d);
dshape_y.SetSize(n1d);
u.SetSize(npq);
du.SetSize(npq, dim);
#endif
// vertices
Nodes.IntPoint(0).Set2(cp[0], cp[0]);
Nodes.IntPoint(1).Set2(cp[p], cp[0]);
Nodes.IntPoint(2).Set2(cp[p], cp[p]);
Nodes.IntPoint(3).Set2(cp[0], cp[p]);
// edges
int o = 4;
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set2(cp[i], cp[0]);
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set2(cp[p], cp[i]);
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set2(cp[p-i], cp[p]);
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set2(cp[0], cp[p-i]);
}
// interior P_{q+2} nodes
for (int j = 1; j < q+2; j++)
{
for (int i = 1; i < q+2; i++)
{
Nodes.IntPoint(o++).Set2(cp2[i], cp2[j]);
}
}
#ifdef MFEM_THREAD_SAFE
Vector shape_x(n1d), shape_y(n1d);
#endif
DenseMatrix Tt(dof, npq);
for (int k = 0; k < dof; ++k)
{
const IntegrationPoint &ip = Nodes.IntPoint(k);
poly1d.CalcBasis(p, ip.x, shape_x);
poly1d.CalcBasis(p, ip.y, shape_y);
o = 0;
for (int j = 0; j <= p; j++)
{
for (int i = 0; i <= p; i++)
{
Tt(k, o++) = shape_x[i]*shape_y[j];
}
}
poly1d.CalcBasis(q, ip.x, shape_x);
poly1d.CalcBasis(q, ip.y, shape_y);
const real_t b_T = ip.x*(1.0 - ip.x)*ip.y*(1.0 - ip.y);
for (int j = 0; j <= q; j++)
{
for (int i = 0; i <= q; i++)
{
Tt(k, o++) = b_T*shape_x[i]*shape_y[j];
}
}
}
// Compute left inverse of T (given Tt = T^T).
DenseMatrix TtT(dof, dof);
MultAAt(Tt, TtT);
DenseMatrixInverse TtT_inv(TtT);
T_pinv.SetSize(dof, dof);
TtT_inv.Mult(Tt, T_pinv);
}
void H1Bubble_QuadrilateralElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = base_order;
const int q = bubble_order;
#ifdef MFEM_THREAD_SAFE
const int n1d = max(p + 1, q + 1);
const int npq = (p+1)*(p+1) + (q+1)*(q+1);
Vector shape_x(n1d), shape_y(n1d), u(npq);
#endif
poly1d.CalcBasis(p, ip.x, shape_x);
poly1d.CalcBasis(p, ip.y, shape_y);
int o = 0;
for (int j = 0; j <= p; j++)
{
for (int i = 0; i <= p; i++)
{
u(o++) = shape_x[i]*shape_y[j];
}
}
poly1d.CalcBasis(q, ip.x, shape_x);
poly1d.CalcBasis(q, ip.y, shape_y);
const real_t b_T = ip.x*(1.0 - ip.x)*ip.y*(1.0 - ip.y);
for (int j = 0; j <= q; j++)
{
for (int i = 0; i <= q; i++)
{
u(o++) = b_T*shape_x[i]*shape_y[j];
}
}
T_pinv.Mult(u, shape);
}
void H1Bubble_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = base_order;
const int q = bubble_order;
#ifdef MFEM_THREAD_SAFE
const int n1d = max(p + 1, q + 1);
const int npq = (p+1)*(p+1) + (q+1)*(q+1);
Vector shape_x(n1d), shape_y(n1d), dshape_x(n1d), dshape_y(n1d);
DenseMatrix du(npq, dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
int o = 0;
for (int j = 0; j <= p; j++)
{
for (int i = 0; i <= p; i++)
{
du(o,0) = dshape_x[i]*shape_y[j];
du(o,1) = shape_x[i]*dshape_y[j];
o += 1;
}
}
poly1d.CalcBasis(q, ip.x, shape_x, dshape_x);
poly1d.CalcBasis(q, ip.y, shape_y, dshape_y);
const real_t b_T = ip.x*(1.0 - ip.x)*ip.y*(1.0 - ip.y);
const real_t dxb_T = (1.0 - 2*ip.x)*ip.y*(1.0 - ip.y);
const real_t dyb_T = ip.x*(1.0 - ip.x)*(1.0 - 2*ip.y);
for (int j = 0; j <= q; j++)
{
for (int i = 0; i <= q; i++)
{
du(o,0) = (dxb_T*shape_x[i] + b_T*dshape_x[i])*shape_y[j];
du(o,1) = (dyb_T*shape_y[j] + b_T*dshape_y[j])*shape_x[i];
o += 1;
}
}
Mult(T_pinv, du, dshape);
}
H1Bubble_TetrahedronElement::H1Bubble_TetrahedronElement(
int p, int q, int btype)
: NodalFiniteElement(3, Geometry::TETRAHEDRON,
2*(p*p + 1) + ((q+1)*(q+2)*(q+3))/6,
max(p, 4 + q), FunctionSpace::Pk),
base_order(p), bubble_order(q)
{
const real_t *cp = poly1d.ClosedPoints(p, VerifyNodal(VerifyClosed(btype)));
const real_t *cp2 = poly1d.ClosedPoints(
q + 4, VerifyNodal(VerifyClosed(btype)));
const int n1d = max(p+1, q+1);
const int npq = ((p+1)*(p+2)*(p+3))/6 + ((q+1)*(q+2)*(q+3))/6;
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(n1d);
shape_y.SetSize(n1d);
shape_z.SetSize(n1d);
shape_l.SetSize(n1d);
dshape_x.SetSize(n1d);
dshape_y.SetSize(n1d);
dshape_z.SetSize(n1d);
dshape_l.SetSize(n1d);
u.SetSize(npq);
du.SetSize(npq, dim);
#else
Vector shape_x(n1d), shape_y(n1d), shape_z(n1d), shape_l(n1d);
#endif
// vertices
Nodes.IntPoint(0).Set3(cp[0], cp[0], cp[0]);
Nodes.IntPoint(1).Set3(cp[p], cp[0], cp[0]);
Nodes.IntPoint(2).Set3(cp[0], cp[p], cp[0]);
Nodes.IntPoint(3).Set3(cp[0], cp[0], cp[p]);
// edges (see Tetrahedron::edges in mesh/tetrahedron.cpp)
int o = 4;
for (int i = 1; i < p; i++) // (0,1)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[0], cp[0]);
}
for (int i = 1; i < p; i++) // (0,2)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[i], cp[0]);
}
for (int i = 1; i < p; i++) // (0,3)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[0], cp[i]);
}
for (int i = 1; i < p; i++) // (1,2)
{
Nodes.IntPoint(o++).Set3(cp[p-i], cp[i], cp[0]);
}
for (int i = 1; i < p; i++) // (1,3)
{
Nodes.IntPoint(o++).Set3(cp[p-i], cp[0], cp[i]);
}
for (int i = 1; i < p; i++) // (2,3)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[p-i], cp[i]);
}
// faces (see Mesh::GenerateFaces in mesh/mesh.cpp)
for (int j = 1; j < p; j++)
{
for (int i = 1; i + j < p; i++) // (1,2,3)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(cp[p-i-j]/w, cp[i]/w, cp[j]/w);
}
}
for (int j = 1; j < p; j++)
{
for (int i = 1; i + j < p; i++) // (0,3,2)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(cp[0], cp[j]/w, cp[i]/w);
}
}
for (int j = 1; j < p; j++)
{
for (int i = 1; i + j < p; i++) // (0,1,3)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(cp[i]/w, cp[0], cp[j]/w);
}
}
for (int j = 1; j < p; j++)
{
for (int i = 1; i + j < p; i++) // (0,2,1)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(cp[j]/w, cp[i]/w, cp[0]);
}
}
// Interior P_{q+4} nodes
for (int k = 1; k < q + 4; k++)
{
for (int j = 1; j + k < q + 4; j++)
{
for (int i = 1; i + j + k < q + 4; i++)
{
real_t w = cp2[i] + cp2[j] + cp2[k] + cp2[q+4-i-j-k];
Nodes.IntPoint(o++).Set3(cp2[i]/w, cp2[j]/w, cp2[k]/w);
}
}
}
DenseMatrix Tt(dof, npq);
for (int m = 0; m < dof; ++m)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
poly1d.CalcBasis(p, ip.x, shape_x);
poly1d.CalcBasis(p, ip.y, shape_y);
poly1d.CalcBasis(p, ip.z, shape_z);
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z, shape_l);
o = 0;
for (int k = 0; k <= p; k++)
{
for (int j = 0; j + k <= p; j++)
{
for (int i = 0; i + j + k <= p; i++)
{
Tt(m, o++) = shape_x[i]*shape_y[j]*shape_z[k]*shape_l[p-i-j-k];
}
}
}
poly1d.CalcBasis(q, ip.x, shape_x);
poly1d.CalcBasis(q, ip.y, shape_y);
poly1d.CalcBasis(q, ip.z, shape_z);
poly1d.CalcBasis(q, 1. - ip.x - ip.y - ip.z, shape_l);
const real_t b_T = ip.x * ip.y * ip.z * (1 - ip.x - ip.y - ip.z);
for (int k = 0; k <= q; k++)
{
for (int j = 0; j + k <= q; j++)
{
for (int i = 0; i + j + k <= q; i++)
{
Tt(m, o++) = b_T*shape_x[i]*shape_y[j]*shape_z[k]*shape_l[q-i-j-k];
}
}
}
}
// Compute left inverse of T (given Tt = T^T).
DenseMatrix TtT(dof, dof);
MultAAt(Tt, TtT);
DenseMatrixInverse TtT_inv(TtT);
T_pinv.SetSize(dof, dof);
TtT_inv.Mult(Tt, T_pinv);
}
void H1Bubble_TetrahedronElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = base_order;
const int q = bubble_order;
#ifdef MFEM_THREAD_SAFE
const int n1d = max(p + 1, q + 1);
const int npq = ((p+1)*(p+2)*(p+3))/6 + ((q+1)*(q+2)*(q+3))/6;
Vector shape_x(n1d), shape_y(n1d), shape_z(n1d), shape_l(n1d), u(npq);
#endif
poly1d.CalcBasis(p, ip.x, shape_x);
poly1d.CalcBasis(p, ip.y, shape_y);
poly1d.CalcBasis(p, ip.z, shape_z);
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z, shape_l);
int o = 0;
for (int k = 0; k <= p; k++)
{
for (int j = 0; j + k <= p; j++)
{
for (int i = 0; i + j + k <= p; i++)
{
u[o++] = shape_x[i]*shape_y[j]*shape_z[k]*shape_l[p-i-j-k];
}
}
}
poly1d.CalcBasis(q, ip.x, shape_x);
poly1d.CalcBasis(q, ip.y, shape_y);
poly1d.CalcBasis(q, ip.z, shape_z);
poly1d.CalcBasis(q, 1. - ip.x - ip.y - ip.z, shape_l);
const real_t b_T = ip.x * ip.y * ip.z * (1 - ip.x - ip.y - ip.z);
for (int k = 0; k <= q; k++)
{
for (int j = 0; j + k <= q; j++)
{
for (int i = 0; i + j + k <= q; i++)
{
u(o++) = b_T*shape_x[i]*shape_y[j]*shape_z[k]*shape_l[q-i-j-k];
}
}
}
T_pinv.Mult(u, shape);
}
void H1Bubble_TetrahedronElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = base_order;
const int q = bubble_order;
#ifdef MFEM_THREAD_SAFE
const int n1d = max(p+1, q+1);
const int npq = ((p+1)*(p+2)*(p+3))/6 + ((q+1)*(q+2)*(q+3))/6;
Vector shape_x(n1d), shape_y(n1d), shape_z(n1d), shape_l(n1d);
Vector dshape_x(n1d), dshape_y(n1d), dshape_z(n1d), dshape_l(n1d);
DenseMatrix du(npq, dim);
#endif
const real_t lambda = 1.0 - ip.x - ip.y - ip.z;
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z);
poly1d.CalcBasis(p, lambda, shape_l, dshape_l);
int o = 0;
for (int k = 0; k <= p; k++)
{
for (int j = 0; j + k <= p; j++)
{
for (int i = 0; i + j + k <= p; i++)
{
int l = p - i - j - k;
du(o,0) = (dshape_x[i]*shape_l[l] - shape_x[i]*dshape_l[l])
*shape_y[j]*shape_z[k];
du(o,1) = (dshape_y[j]*shape_l[l] - shape_y[j]*dshape_l[l])
*shape_x[i]*shape_z[k];
du(o,2) = (dshape_z[k]*shape_l[l] - shape_z[k]*dshape_l[l])
*shape_x[i]*shape_y[j];
o++;
}
}
}
poly1d.CalcBasis(q, ip.x, shape_x, dshape_x);
poly1d.CalcBasis(q, ip.y, shape_y, dshape_y);
poly1d.CalcBasis(q, ip.z, shape_z, dshape_z);
poly1d.CalcBasis(q, lambda, shape_l, dshape_l);
const real_t b_T = ip.x * ip.y * ip.z * (1 - ip.x - ip.y - ip.z);
const real_t dxb_T = ip.y * ip.z * (lambda - ip.x);
const real_t dyb_T = ip.x * ip.z * (lambda - ip.y);
const real_t dzb_T = ip.x * ip.y * (lambda - ip.z);
for (int k = 0; k <= q; k++)
{
for (int j = 0; j + k <= q; j++)
{
for (int i = 0; i + j + k <= q; i++)
{
int l = q - i - j - k;
du(o,0) = shape_y[j]*shape_z[k]*(dxb_T*shape_x[i]*shape_l[l]
+ b_T*dshape_x[i]*shape_l[l]
- b_T*shape_x[i]*dshape_l[l]);
du(o,1) = shape_x[i]*shape_z[k]*(dyb_T*shape_y[j]*shape_l[l]
+ b_T*dshape_y[j]*shape_l[l]
- b_T*shape_y[j]*dshape_l[l]);
du(o,2) = shape_x[i]*shape_y[j]*(dzb_T*shape_z[k]*shape_l[l]
+ b_T*dshape_z[k]*shape_l[l]
- b_T*shape_z[k]*dshape_l[l]);
o++;
}
}
}
Mult(T_pinv, du, dshape);
}
H1Bubble_HexahedronElement::H1Bubble_HexahedronElement(
int p, int q, int btype)
: NodalFiniteElement(3, Geometry::CUBE, (2 + 6*p*p) + (q+1)*(q+1)*(q+1),
max(p, 2 + q), FunctionSpace::Qk),
base_order(p), bubble_order(q)
{
const real_t *cp = poly1d.ClosedPoints(p, VerifyNodal(VerifyClosed(btype)));
const real_t *cp2 = poly1d.ClosedPoints(
q + 2, VerifyNodal(VerifyClosed(btype)));
const int n1d = max(p + 1, q + 1);
const int npq = (p+1)*(p+1)*(p+1) + (q+1)*(q+1)*(q+1);
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(n1d);
shape_y.SetSize(n1d);
shape_z.SetSize(n1d);
dshape_x.SetSize(n1d);
dshape_y.SetSize(n1d);
dshape_z.SetSize(n1d);
u.SetSize(npq);
du.SetSize(npq, dim);
#endif
// vertices
Nodes.IntPoint(0).Set3(cp[0], cp[0], cp[0]);
Nodes.IntPoint(1).Set3(cp[p], cp[0], cp[0]);
Nodes.IntPoint(2).Set3(cp[p], cp[p], cp[0]);
Nodes.IntPoint(3).Set3(cp[0], cp[p], cp[0]);
Nodes.IntPoint(4).Set3(cp[0], cp[0], cp[p]);
Nodes.IntPoint(5).Set3(cp[p], cp[0], cp[p]);
Nodes.IntPoint(6).Set3(cp[p], cp[p], cp[p]);
Nodes.IntPoint(7).Set3(cp[0], cp[p], cp[p]);
int o = 8;
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[0], cp[0]); // (0,1)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[p], cp[i], cp[0]); // (1,2)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[p], cp[0]); // (3,2)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[i], cp[0]); // (0,3)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[0], cp[p]); // (4,5)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[p], cp[i], cp[p]); // (5,6)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[p], cp[p]); // (7,6)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[i], cp[p]); // (4,7)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[0], cp[i]); // (0,4)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[p], cp[0], cp[i]); // (1,5)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[p], cp[p], cp[i]); // (2,6)
}
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[p], cp[i]); // (3,7)
}
// faces
for (int j = 1; j < p; j++)
{
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[p-j], cp[0]); // (3,2,1,0)
}
}
for (int j = 1; j < p; j++)
{
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[0], cp[j]); // (0,1,5,4)
}
}
for (int j = 1; j < p; j++)
{
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[p], cp[i], cp[j]); // (1,2,6,5)
}
}
for (int j = 1; j < p; j++)
{
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[p-i], cp[p], cp[j]); // (2,3,7,6)
}
}
for (int j = 1; j < p; j++)
{
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[p-i], cp[j]); // (3,0,4,7)
}
}
for (int j = 1; j < p; j++)
{
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[j], cp[p]); // (4,5,6,7)
}
}
// interior P_{q+2} nodes
for (int k = 1; k < q+2; k++)
{
for (int j = 1; j < q+2; j++)
{
for (int i = 1; i < q+2; i++)
{
Nodes.IntPoint(o++).Set3(cp2[i], cp2[j], cp2[k]);
}
}
}
#ifdef MFEM_THREAD_SAFE
Vector shape_x(n1d), shape_y(n1d), shape_z(n1d);
#endif
DenseMatrix Tt(dof, npq);
for (int m = 0; m < dof; ++m)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
poly1d.CalcBasis(p, ip.x, shape_x);
poly1d.CalcBasis(p, ip.y, shape_y);
poly1d.CalcBasis(p, ip.z, shape_z);
o = 0;
for (int k = 0; k <= p; k++)
{
for (int j = 0; j <= p; j++)
{
for (int i = 0; i <= p; i++)
{
Tt(m, o++) = shape_x[i]*shape_y[j]*shape_z[k];
}
}
}
poly1d.CalcBasis(q, ip.x, shape_x);
poly1d.CalcBasis(q, ip.y, shape_y);
poly1d.CalcBasis(q, ip.z, shape_z);
const real_t b_T = ip.x*(1.0 - ip.x)*ip.y*(1.0 - ip.y)*ip.z*(1.0 - ip.z);
for (int k = 0; k <= q; k++)
{
for (int j = 0; j <= q; j++)
{
for (int i = 0; i <= q; i++)
{
Tt(m, o++) = b_T*shape_x[i]*shape_y[j]*shape_z[k];
}
}
}
}
// Compute left inverse of T (given Tt = T^T).
DenseMatrix TtT(dof, dof);
MultAAt(Tt, TtT);
DenseMatrixInverse TtT_inv(TtT);
T_pinv.SetSize(dof, dof);
TtT_inv.Mult(Tt, T_pinv);
}
void H1Bubble_HexahedronElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = base_order;
const int q = bubble_order;
#ifdef MFEM_THREAD_SAFE
const int n1d = max(p + 1, q + 1);
const int npq = (p+1)*(p+1)*(p+1) + (q+1)*(q+1)*(q+1);
Vector shape_x(n1d), shape_y(n1d), shape_z(n1d), u(npq);
#endif
poly1d.CalcBasis(p, ip.x, shape_x);
poly1d.CalcBasis(p, ip.y, shape_y);
poly1d.CalcBasis(p, ip.z, shape_z);
int o = 0;
for (int k = 0; k <= p; k++)
{
for (int j = 0; j <= p; j++)
{
for (int i = 0; i <= p; i++)
{
u(o++) = shape_x[i]*shape_y[j]*shape_z[k];
}
}
}
poly1d.CalcBasis(q, ip.x, shape_x);
poly1d.CalcBasis(q, ip.y, shape_y);
poly1d.CalcBasis(q, ip.z, shape_z);
const real_t b_T = ip.x*(1.0 - ip.x)*ip.y*(1.0 - ip.y)*ip.z*(1.0 - ip.z);
for (int k = 0; k <= q; k++)
{
for (int j = 0; j <= q; j++)
{
for (int i = 0; i <= q; i++)
{
u(o++) = b_T*shape_x[i]*shape_y[j]*shape_z[k];
}
}
}
T_pinv.Mult(u, shape);
}
void H1Bubble_HexahedronElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = base_order;
const int q = bubble_order;
#ifdef MFEM_THREAD_SAFE
const int n1d = max(p + 1, q + 1);
const int npq = (p+1)*(p+1)*(p+1) + (q+1)*(q+1)*(q+1);
Vector shape_x(n1d), shape_y(n1d), shape_z(n1d), dshape_x(n1d),
dshape_y(n1d), dshape_z(n1d);
DenseMatrix du(npq, dim);
#endif
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z);
int o = 0;
for (int k = 0; k <= p; k++)
{
for (int j = 0; j <= p; j++)
{
for (int i = 0; i <= p; i++)
{
du(o,0) = dshape_x[i]*shape_y[j]*shape_z[k];
du(o,1) = shape_x[i]*dshape_y[j]*shape_z[k];
du(o,2) = shape_x[i]*shape_y[j]*dshape_z[k];
o += 1;
}
}
}
poly1d.CalcBasis(q, ip.x, shape_x, dshape_x);
poly1d.CalcBasis(q, ip.y, shape_y, dshape_y);
poly1d.CalcBasis(q, ip.z, shape_z, dshape_z);
const real_t b_T = ip.x*(1.0 - ip.x)*ip.y*(1.0 - ip.y)*ip.z*(1.0 - ip.z);
const real_t dxb_T = (1.0 - 2*ip.x)*ip.y*(1.0 - ip.y)*ip.z*(1.0 - ip.z);
const real_t dyb_T = ip.x*(1.0 - ip.x)*(1.0 - 2*ip.y)*ip.z*(1.0 - ip.z);
const real_t dzb_T = ip.x*(1.0 - ip.x)*ip.y*(1.0 - ip.y)*(1.0 - 2*ip.z);
for (int k = 0; k <= q; k++)
{
for (int j = 0; j <= q; j++)
{
for (int i = 0; i <= q; i++)
{
du(o,0) = (dxb_T*shape_x[i] + b_T*dshape_x[i])*shape_y[j]*shape_z[k];
du(o,1) = (dyb_T*shape_y[j] + b_T*dshape_y[j])*shape_x[i]*shape_z[k];
du(o,2) = (dzb_T*shape_z[k] + b_T*dshape_z[k])*shape_x[i]*shape_y[j];
o += 1;
}
}
}
Mult(T_pinv, du, dshape);
}
}
-109
View File
@@ -1,109 +0,0 @@
// Copyright (c) 2010-2025, 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_FE_H1_BUBBLE
#define MFEM_FE_H1_BUBBLE
#include "fe_base.hpp"
namespace mfem
{
/// Arbitrary order H1 plus bubble elements in 2D on a triangle
class H1Bubble_TriangleElement : public NodalFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_l, dshape_x, dshape_y, dshape_l, u;
mutable DenseMatrix du;
#endif
int base_order;
int bubble_order;
DenseMatrix T_pinv;
public:
/// @brief Construct the triangular bubble element with degree-p polynomials,
/// enriched with cubic bubble times degree q polynomial.
H1Bubble_TriangleElement(int p, int q, int btype = BasisType::GaussLobatto);
void CalcShape(const IntegrationPoint &ip, Vector &shape) const override;
void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const override;
};
/// Arbitrary order H1 plus bubble elements in 2D on a quadrilateral
class H1Bubble_QuadrilateralElement : public NodalFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, dshape_x, dshape_y, u;
mutable DenseMatrix du;
#endif
int base_order;
int bubble_order;
DenseMatrix T_pinv;
public:
/// @brief Construct the quadrilateral bubble element with degree-p
/// polynomials, enriched with biquadratic bubble times degree q polynomial.
H1Bubble_QuadrilateralElement(
int p, int q, int btype = BasisType::GaussLobatto);
void CalcShape(const IntegrationPoint &ip, Vector &shape) const override;
void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const override;
};
/// Arbitrary order H1 plus bubble elements in 3D on a tetrahedron
class H1Bubble_TetrahedronElement : public NodalFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z, shape_l;
mutable Vector dshape_x, dshape_y, dshape_z, dshape_l, u;
mutable DenseMatrix du;
#endif
int base_order;
int bubble_order;
DenseMatrix T_pinv;
public:
/// @brief Construct the tetrahedral bubble element with degree-p
/// polynomials, enriched with quartic bubble times degree q polynomial.
H1Bubble_TetrahedronElement(int p, int q, int btype = BasisType::GaussLobatto);
void CalcShape(const IntegrationPoint &ip, Vector &shape) const override;
void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const override;
};
/// Arbitrary order H1 plus bubble elements in 3D on a hexahedron
class H1Bubble_HexahedronElement : public NodalFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z, u;
mutable DenseMatrix du;
#endif
int base_order;
int bubble_order;
DenseMatrix T_pinv;
public:
/// @brief Construct the hexahedral bubble element with degree-p polynomials,
/// enriched with triquadratic bubble times degree q polynomial.
H1Bubble_HexahedronElement(int p, int q, int btype = BasisType::GaussLobatto);
void CalcShape(const IntegrationPoint &ip, Vector &shape) const override;
void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const override;
};
} // namespace mfem
#endif
-177
View File
@@ -243,21 +243,11 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
{
fec = new H1Ser_FECollection(atoi(name + 10), atoi(name + 6));
}
else if (!strncmp(name, "H1Bubble_", 9))
{
fec = new H1Bubble_FECollection(atoi(name + 13), atoi(name + 16),
atoi(name + 9));
}
else if (!strncmp(name, "H1@", 3))
{
fec = new H1_FECollection(atoi(name + 9), atoi(name + 5),
BasisType::GetType(name[3]));
}
else if (!strncmp(name, "H1Bubble@", 9))
{
fec = new H1Bubble_FECollection(atoi(name + 15), atoi(name + 18),
atoi(name + 11), BasisType::GetType(name[9]));
}
else if (!strncmp(name, "L2_T", 4))
fec = new L2_FECollection(atoi(name + 10), atoi(name + 6),
atoi(name + 4));
@@ -2132,173 +2122,6 @@ H1_FECollection::~H1_FECollection()
}
}
static int GetBubbleSpaceOrder(int p, int q, int dim)
{
switch (dim)
{
case 0: return 0;
case 1: return std::max(p, q + 2);
case 2: return std::max(p, q + 3);
case 3: return std::max(p, q + 4);
}
MFEM_ABORT("Unsupported dimension.");
}
H1Bubble_FECollection::H1Bubble_FECollection(const int p, const int q,
const int dim, const int btype)
: FiniteElementCollection(GetBubbleSpaceOrder(p, q, dim)),
dim(dim),
b_type(BasisType::Check(btype)),
h1_order(p),
bubble_order(q)
{
MFEM_VERIFY(p >= 1, "H1Bubble_FECollection requires order >= 1.");
MFEM_VERIFY(dim >= 0 && dim <= 3, "Unsupported dimension.");
switch (btype)
{
case BasisType::GaussLobatto:
{
snprintf(fec_name, 32, "H1Bubble_%dD_P%d_P%d", dim, p, q);
break;
}
default:
{
const int pt_type = BasisType::GetQuadrature1D(btype);
MFEM_VERIFY(Quadrature1D::CheckClosed(pt_type) != Quadrature1D::Invalid,
"unsupported BasisType: " << BasisType::Name(btype));
snprintf(fec_name, 32, "H1Bubble@%c_%dD_P%d_P%d",
(int)BasisType::GetChar(btype), dim, p, q);
}
}
dofs[Geometry::POINT] = 1;
elements[Geometry::POINT] = make_unique<PointFiniteElement>();
if (dim >= 1)
{
dofs[Geometry::SEGMENT] = p - 1;
elements[Geometry::SEGMENT] = make_unique<H1_SegmentElement>(p, btype);
}
if (dim == 2)
{
dofs[Geometry::TRIANGLE] = ((q+1)*(q+2))/2;
dofs[Geometry::SQUARE] = (q+1)*(q+1);
elements[Geometry::TRIANGLE] =
make_unique<H1Bubble_TriangleElement>(p, q, btype);
elements[Geometry::SQUARE] =
make_unique<H1Bubble_QuadrilateralElement>(p, q, btype);
}
if (dim == 3)
{
dofs[Geometry::TRIANGLE] = ((p-1)*(p-2))/2;
dofs[Geometry::SQUARE] = (p-1)*(p-1);
dofs[Geometry::TETRAHEDRON] = ((q+1)*(q+2)*(q+3))/6;
dofs[Geometry::CUBE] = (q+1)*(q+1)*(q+1);
elements[Geometry::TRIANGLE] = make_unique<H1_TriangleElement>(p, btype);
elements[Geometry::SQUARE] = make_unique<H1_QuadrilateralElement>(p, btype);
elements[Geometry::TETRAHEDRON] =
make_unique<H1Bubble_TetrahedronElement>(p, q, btype);
elements[Geometry::CUBE] =
make_unique<H1Bubble_HexahedronElement>(p, q, btype);
}
// DOF orderings. Need only for lower-dimensional entities.
// Segment DOF orderings in 2D.
if (dim >= 2)
{
seg_dof_ord[0].resize(p - 1);
seg_dof_ord[1].resize(p - 1);
for (int i = 0; i < p - 1; i++)
{
seg_dof_ord[0][i] = i;
seg_dof_ord[1][i] = p - 2 - i;
}
}
// Face (triangle or quadrilateral) DOF orderings in 3D.
if (dim == 3)
{
const int n_tri_dof = dofs[Geometry::TRIANGLE];
for (int i = 0; i < 6; i++)
{
tri_dof_ord[i].resize(n_tri_dof);
}
// see Mesh::GetTriOrientation in mesh/mesh.cpp
const int pm1 = p - 1;
const int pm2 = p - 2;
for (int j = 0; j < pm2; j++)
{
for (int i = 0; i + j < pm2; i++)
{
int o = n_tri_dof - ((pm1 - j)*(pm2 - j))/2 + i;
int k = (p - 3) - j - i;
tri_dof_ord[0][o] = o; // (0,1,2)
tri_dof_ord[1][o] = n_tri_dof - ((pm1-j)*(pm2-j))/2 + k; // (1,0,2)
tri_dof_ord[2][o] = n_tri_dof - ((pm1-i)*(pm2-i))/2 + k; // (2,0,1)
tri_dof_ord[3][o] = n_tri_dof - ((pm1-k)*(pm2-k))/2 + i; // (2,1,0)
tri_dof_ord[4][o] = n_tri_dof - ((pm1-k)*(pm2-k))/2 + j; // (1,2,0)
tri_dof_ord[5][o] = n_tri_dof - ((pm1-i)*(pm2-i))/2 + j; // (0,2,1)
}
}
const int n_quad_dof = dofs[Geometry::SQUARE];
for (int i = 0; i < 8; i++)
{
quad_dof_ord[i].resize(n_quad_dof);
}
for (int j = 0; j < pm1; j++)
{
for (int i = 0; i < pm1; i++)
{
int o = i + j*pm1;
quad_dof_ord[0][o] = i + j*pm1; // (0,1,2,3)
quad_dof_ord[1][o] = j + i*pm1; // (0,3,2,1)
quad_dof_ord[2][o] = j + (pm2 - i)*pm1; // (1,2,3,0)
quad_dof_ord[3][o] = (pm2 - i) + j*pm1; // (1,0,3,2)
quad_dof_ord[4][o] = (pm2 - i) + (pm2 - j)*pm1; // (2,3,0,1)
quad_dof_ord[5][o] = (pm2 - j) + (pm2 - i)*pm1; // (2,1,0,3)
quad_dof_ord[6][o] = (pm2 - j) + i*pm1; // (3,0,1,2)
quad_dof_ord[7][o] = i + (pm2 - j)*pm1; // (3,2,1,0)
}
}
}
}
const FiniteElement *
H1Bubble_FECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
{
return elements[GeomType].get();
}
const int *H1Bubble_FECollection::DofOrderForOrientation(
Geometry::Type GeomType, int Or) const
{
if (GeomType == Geometry::SEGMENT)
{
return (Or > 0) ? seg_dof_ord[0].data() : seg_dof_ord[1].data();
}
else if (GeomType == Geometry::TRIANGLE)
{
return tri_dof_ord[Or%6].data();
}
else if (GeomType == Geometry::SQUARE)
{
return quad_dof_ord[Or%8].data();
}
return nullptr;
}
FiniteElementCollection *H1Bubble_FECollection::GetTraceCollection() const
{
return (dim < 0) ? NULL : new H1_Trace_FECollection(h1_order, dim, b_type);
}
H1_Trace_FECollection::H1_Trace_FECollection(const int p, const int dim,
const int btype)
-55
View File
@@ -111,8 +111,6 @@ public:
| :------: | :---: | :---: | :-------: | :-----: | :---: |
| H1_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements |
| H1@[BTYPE]_[DIM]_[ORDER] | H1 | * | * | VALUE | H1 nodal elements |
| H1Bubble_[DIM]_[ORDER]_[BUBBLE_ORDER] | H1 | * | 1 | VALUE | H1 nodal elements enriched with bubble functions |
| H1Bubble@[BTYPE]_[DIM]_[ORDER]_[BUBBLE_ORDER] | H1 | * | 1 | VALUE | H1 nodal elements enriched with bubble functions |
| H1Pos_[DIM]_[ORDER] | H1 | * | 2 | VALUE | H1 nodal elements |
| H1Pos_Trace_[DIM]_[ORDER] | H^{1/2} | * | 2 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
| H1_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
@@ -319,59 +317,6 @@ public:
virtual ~H1_FECollection();
};
/// @brief Arbitrary order $H^1$-conforming (continuous) finite elements
/// enriched with bubble functions.
///
/// The bubble space consists of the standard $P_p$ or $Q_p$ space, enriched
/// with bubble functions, which are degree-$q$ polynomials times $b$, where $b$
/// is the lowest-order bubble function.
///
/// The traces are the same as the standard $H^1$ traces.
class H1Bubble_FECollection : public FiniteElementCollection
{
protected:
int dim;
int b_type;
int h1_order;
int bubble_order;
char fec_name[32];
std::array<int, Geometry::NumGeom> dofs{}; // zero initialize
std::array<std::unique_ptr<FiniteElement>, Geometry::NumGeom> elements;
std::array<std::vector<int>, 2> seg_dof_ord;
std::array<std::vector<int>, 6> tri_dof_ord;
std::array<std::vector<int>, 8> quad_dof_ord;
std::array<std::vector<int>, 24> tet_dof_ord;
public:
/// Construct the $H^1$ bubble collection consisting of degree-$p$
/// polynomials enriched with the bubble function times degree-$q$
/// polynomials.
explicit H1Bubble_FECollection(const int p, const int q, const int dim = 3,
const int btype = BasisType::GaussLobatto);
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
int DofForGeometry(Geometry::Type GeomType) const override
{ return dofs[GeomType]; }
const int *DofOrderForOrientation(Geometry::Type GeomType,
int Or) const override;
const char *Name() const override { return fec_name; }
int GetContType() const override { return CONTINUOUS; }
int GetBasisType() const { return b_type; }
FiniteElementCollection *GetTraceCollection() const override;
FiniteElementCollection *Clone(int p) const override
{ return new H1Bubble_FECollection(p, bubble_order, dim, b_type); }
};
/** @brief Arbitrary order H1-conforming (continuous) finite elements with
positive basis functions. */
class H1Pos_FECollection : public H1_FECollection
+3 -6
View File
@@ -3877,12 +3877,9 @@ const FiniteElement *FiniteElementSpace::GetFE(int i) const
else
{
#ifdef MFEM_DEBUG
// Consistency check: fec->GetOrder() and FE->GetOrder() should return
// the same value (for standard, constant-order spaces). Skip this check
// even for constant-order bubble spaces, since the bubble functions on
// different geometries have different orders.
if (!IsVariableOrder() && FE->GetDim() > 0 &&
dynamic_cast<const H1Bubble_FECollection*>(fec) == nullptr)
// consistency check: fec->GetOrder() and FE->GetOrder() should return
// the same value (for standard, constant-order spaces)
if (!IsVariableOrder() && FE->GetDim() > 0)
{
MFEM_ASSERT(FE->GetOrder() == fec->GetOrder(),
"internal error: " <<
+44 -43
View File
@@ -3137,29 +3137,52 @@ void GridFunction::ProjectBdrCoefficient(Coefficient *coeff[],
}
void GridFunction::ProjectBdrCoefficientNormal(
Coefficient *coeff, VectorCoefficient *vcoeff, const Array<int> &bdr_attr)
VectorCoefficient &vcoeff, const Array<int> &bdr_attr)
{
if (fes->GetNBE() > 0)
{
// TODO: Replace this by GetTypicalBdrElement() once implemented
const FiniteElement *be = fes->GetBE(0);
MFEM_VERIFY(be->GetRangeType() == FiniteElement::SCALAR &&
be->GetMapType() == FiniteElement::INTEGRAL, "Not an RT FE space!");
}
#if 0
// implementation for the case when the face dofs are integrals of the
// normal component.
const FiniteElement *fe;
ElementTransformation *T;
Array<int> dofs;
int dim = vcoeff.GetVDim();
Vector vc(dim), nor(dim), lvec, shape;
for (int i = 0; i < fes->GetNBE(); i++)
{
if (bdr_attr[fes->GetBdrAttribute(i)-1] == 0)
{
continue;
}
fe = fes->GetBE(i);
T = fes->GetBdrElementTransformation(i);
int intorder = 2*fe->GetOrder(); // !!!
const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), intorder);
int nd = fe->GetDof();
lvec.SetSize(nd);
shape.SetSize(nd);
lvec = 0.0;
for (int j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T->SetIntPoint(&ip);
vcoeff.Eval(vc, *T, ip);
CalcOrtho(T->Jacobian(), nor);
fe->CalcShape(ip, shape);
lvec.Add(ip.weight * (vc * nor), shape);
}
fes->GetBdrElementDofs(i, dofs);
SetSubVector(dofs, lvec);
}
#else
// implementation for the case when the face dofs are scaled point
// values of the normal component.
const FiniteElement *fe;
ElementTransformation *T;
Array<int> dofs;
Vector vc, nor, lvec;
int dim = vcoeff.GetVDim();
Vector vc(dim), nor(dim), lvec;
DofTransformation doftrans;
if (vcoeff)
{
const int dim = vcoeff->GetVDim();
vc.SetSize(dim);
nor.SetSize(dim);
}
for (int i = 0; i < fes->GetNBE(); i++)
{
@@ -3175,22 +3198,15 @@ void GridFunction::ProjectBdrCoefficientNormal(
{
const IntegrationPoint &ip = ir.IntPoint(j);
T->SetIntPoint(&ip);
if (coeff)
{
const real_t c = coeff->Eval(*T, ip);
lvec(j) = c * T->Weight();
}
else if (vcoeff)
{
vcoeff->Eval(vc, *T, ip);
CalcOrtho(T->Jacobian(), nor);
lvec(j) = (vc * nor);
}
vcoeff.Eval(vc, *T, ip);
CalcOrtho(T->Jacobian(), nor);
lvec(j) = (vc * nor);
}
fes->GetBdrElementDofs(i, dofs, doftrans);
doftrans.TransformPrimal(lvec);
SetSubVector(dofs, lvec);
}
#endif
}
void GridFunction::ProjectBdrCoefficientTangent(
@@ -4991,14 +5007,6 @@ real_t ExtrudeCoefficient::Eval(ElementTransformation &T,
return sol_in.Eval(*T_in, ip);
}
void VectorExtrudeCoefficient::Eval(Vector &v, ElementTransformation &T,
const IntegrationPoint &ip)
{
ElementTransformation *T_in =
mesh_in->GetElementTransformation(T.ElementNo / n);
T_in->SetIntPoint(&ip);
sol_in.Eval(v, *T_in, ip);
}
GridFunction *Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d,
GridFunction *sol, const int ny)
@@ -5049,17 +5057,10 @@ GridFunction *Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d,
return NULL;
}
FiniteElementSpace *solfes2d;
const int vdim = sol->FESpace()->GetVDim();
solfes2d = new FiniteElementSpace(mesh2d, solfec2d, vdim);
// assuming sol is scalar
solfes2d = new FiniteElementSpace(mesh2d, solfec2d);
sol2d = new GridFunction(solfes2d);
sol2d->MakeOwner(solfec2d);
if (vdim > 1)
{
VectorGridFunctionCoefficient vcsol(sol);
VectorExtrudeCoefficient vc2d(mesh, vcsol, ny);
sol2d->ProjectCoefficient(vc2d);
}
else
{
GridFunctionCoefficient csol(sol);
ExtrudeCoefficient c2d(mesh, csol, ny);
+9 -62
View File
@@ -532,9 +532,6 @@ public:
std::unique_ptr<GridFunction> ProlongateToMaxOrder() const;
protected:
void ProjectBdrCoefficientNormal(Coefficient *coeff, VectorCoefficient *vcoeff,
const Array<int> &attr);
/** @brief Accumulates (depending on @a type) the values of @a coeff at all
shared vdofs and counts in how many zones each vdof appears. */
void AccumulateAndCountZones(Coefficient &coeff, AvgType type,
@@ -659,26 +656,15 @@ public:
virtual void ProjectBdrCoefficient(Coefficient *coeff[],
const Array<int> &attr);
/** @brief Project the normal component of the given VectorCoefficient on
the boundary. */
/** Only boundary attributes that are marked in @a bdr_attr are
projected. Assumes RT-type vector finite element GridFunction. */
/** Project the normal component of the given VectorCoefficient on
the boundary. Only boundary attributes that are marked in
'bdr_attr' are projected. Assumes RT-type VectorFE GridFunction. */
void ProjectBdrCoefficientNormal(VectorCoefficient &vcoeff,
const Array<int> &bdr_attr)
{ ProjectBdrCoefficientNormal(NULL, &vcoeff, bdr_attr); }
/** @brief Project the given Coefficient in the normal direction on the
boundary. */
/** Only boundary attributes that are marked in @a bdr_attr are projected.
Assumes RT-type vector finite element GridFunction. */
void ProjectBdrCoefficientNormal(Coefficient &coeff,
const Array<int> &bdr_attr)
{ ProjectBdrCoefficientNormal(&coeff, NULL, bdr_attr); }
const Array<int> &bdr_attr);
/** @brief Project the tangential components of the given VectorCoefficient
on the boundary. */
/** Only boundary attributes that are marked in @a bdr_attr
are projected. Assumes ND-type vector finite element GridFunction. */
on the boundary. Only boundary attributes that are marked in @a bdr_attr
are projected. Assumes ND-type VectorFE GridFunction. */
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
const Array<int> &bdr_attr);
@@ -1928,7 +1914,7 @@ real_t ComputeElementLpDistance(real_t p, int i,
GridFunction& gf1, GridFunction& gf2);
/// Class used for extruding a scalar coefficient
/// Class used for extruding scalar GridFunctions
class ExtrudeCoefficient : public Coefficient
{
private:
@@ -1936,52 +1922,13 @@ private:
Mesh *mesh_in;
Coefficient &sol_in;
public:
/// Constructs an instance of VectorExtrudeCoefficient
/**
* @param m 1D mesh
* @param s 1D vector coefficient
* @param n_ number of transverse elements of the extruded mesh
*/
ExtrudeCoefficient(Mesh *m, Coefficient &s, int n_)
: n(n_), mesh_in(m), sol_in(s)
{ MFEM_VERIFY(n > 0, "Number of transverse elements must be positive!"); }
: n(n_), mesh_in(m), sol_in(s) { }
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override;
virtual ~ExtrudeCoefficient() { }
};
/// Class used for extruding a vector coefficient
class VectorExtrudeCoefficient : public VectorCoefficient
{
private:
int n;
Mesh *mesh_in;
VectorCoefficient &sol_in;
public:
/// Constructs an instance of VectorExtrudeCoefficient
/**
* @param m 1D mesh
* @param s 1D vector coefficient
* @param n_ number of transverse elements of the extruded mesh
*/
VectorExtrudeCoefficient(Mesh *m, VectorCoefficient &s, int n_)
: VectorCoefficient(s.GetVDim()), n(n_), mesh_in(m), sol_in(s)
{ MFEM_VERIFY(n > 0, "Number of transverse elements must be positive!"); }
void Eval(Vector &v, ElementTransformation &T,
const IntegrationPoint &ip) override;
virtual ~VectorExtrudeCoefficient() { }
};
/// Extrude a 1D GridFunction, after extruding the mesh with Extrude1D()
/**
* @param mesh 1D mesh
* @param mesh2d extruded mesh
* @param sol grid function
* @param ny number of transverse elements of the extruded mesh
*/
/// Extrude a scalar 1D GridFunction, after extruding the mesh with Extrude1D.
GridFunction *Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d,
GridFunction *sol, const int ny);
+8 -18
View File
@@ -197,21 +197,15 @@ static void EAHdivAssemble3D(const int NE,
// Assemble (one row per thread)
MFEM_FOREACH_THREAD(idx_i, x, NDOF)
{
// NOTE: due to an llvm backend bug, usage of the modulus operator
// has been removed from this foreach section.
const int ic = idx_i / NDOF_C;
const int idx_ii = idx_i - ic * NDOF_C; // idx_i % NDOF_C
const int idx_ii = idx_i % NDOF_C;
const int nx_i = (ic == 0) ? D1D : D1D-1;
const int ny_i = (ic == 1) ? D1D : D1D-1;
const int qx_i = idx_ii / nx_i;
const int ix = idx_ii - qx_i * nx_i; // idx_ii % nx_i
const int qy_i = qx_i / ny_i;
const int iy = qx_i - qy_i * ny_i; // (idx_ii / nx_i) % ny_i
const int iz = qy_i; // (idx_ii / nx_i) / ny_i
const int ix = idx_ii % nx_i;
const int iy = (idx_ii / nx_i) % ny_i;
const int iz = (idx_ii / nx_i) / ny_i;
const real_t (&Bi1)[MQ1][MD1] = (ic == 0) ? r_Bc : r_Bo;
const real_t (&Bi2)[MQ1][MD1] = (ic == 1) ? r_Bc : r_Bo;
@@ -220,18 +214,14 @@ static void EAHdivAssemble3D(const int NE,
for (int idx_j = 0; idx_j < NDOF; ++idx_j)
{
const int jc = idx_j / NDOF_C;
const int idx_jj = idx_j - jc * NDOF_C; // idx_j % NDOF_C
const int idx_jj = idx_j % NDOF_C;
const int nx_j = (jc == 0) ? D1D : D1D-1;
const int ny_j = (jc == 1) ? D1D : D1D-1;
const int qx_j = idx_jj / nx_j;
const int jx = idx_jj - qx_j * nx_j; // idx_jj % nx_j
const int qy_j = qx_j / ny_j;
const int jy = qx_j - qy_j * ny_j; // (idx_jj / nx_j) % ny_j
const int jz = qy_j; // (idx_jj / nx_j) / ny_j
const int jx = idx_jj % nx_j;
const int jy = (idx_jj / nx_j) % ny_j;
const int jz = (idx_jj / nx_j) / ny_j;
const real_t (&Bj1)[MQ1][MD1] = (jc == 0) ? r_Bc : r_Bo;
const real_t (&Bj2)[MQ1][MD1] = (jc == 1) ? r_Bc : r_Bo;
+327 -811
View File
File diff suppressed because it is too large Load Diff
+27 -30
View File
@@ -125,6 +125,18 @@ private:
void AddTriPoints3b(const int off, const real_t b, const real_t weight)
{ AddTriPoints3(off, (1. - b)/2., b, weight); }
void AddTriPoints3R(const int off, const real_t a, const real_t b,
const real_t c, const real_t weight)
{
IntPoint(off + 0).Set2w(a, b, weight);
IntPoint(off + 1).Set2w(c, a, weight);
IntPoint(off + 2).Set2w(b, c, weight);
}
void AddTriPoints3R(const int off, const real_t a, const real_t b,
const real_t weight)
{ AddTriPoints3R(off, a, b, 1. - a - b, weight); }
void AddTriPoints6(const int off, const real_t a, const real_t b,
const real_t c, const real_t weight)
{
@@ -171,6 +183,14 @@ private:
AddTetPoints3(off + 1, a, 1. - 3.*a, weight);
}
// given b, add the permutations of (a,a,a,b), where 3*a + b = 1
void AddTetPoints4b(const int off, const real_t b, const real_t weight)
{
const real_t a = (1. - b)/3.;
IntPoint(off).Set(a, a, a, weight);
AddTetPoints3(off + 1, a, b, weight);
}
// add the permutations of (a,a,b,b), 2*(a + b) = 1
void AddTetPoints6(const int off, const real_t a, const real_t weight)
{
@@ -189,37 +209,14 @@ private:
AddTetPoints6(off + 6, a, bc, cb, weight);
}
// add all 24 permutations of (a,b,c,d) where a+b+c+d = 1, all distinct
void AddTetPoints24(const int off, const real_t a, const real_t b,
const real_t c, const real_t weight)
// given (b,c), add the permutations of (a,a,b,c), 2*a + b + c = 1
void AddTetPoints12bc(const int off, const real_t b, const real_t c,
const real_t weight)
{
const real_t d = 1. - a - b - c;
// all 24 permutations of 4 distinct barycentric coordinates
// permuting which coordinate goes to x, y, z (4th is 1-x-y-z)
IntPoint(off + 0).Set(a, b, c, weight);
IntPoint(off + 1).Set(a, b, d, weight);
IntPoint(off + 2).Set(a, c, b, weight);
IntPoint(off + 3).Set(a, c, d, weight);
IntPoint(off + 4).Set(a, d, b, weight);
IntPoint(off + 5).Set(a, d, c, weight);
IntPoint(off + 6).Set(b, a, c, weight);
IntPoint(off + 7).Set(b, a, d, weight);
IntPoint(off + 8).Set(b, c, a, weight);
IntPoint(off + 9).Set(b, c, d, weight);
IntPoint(off + 10).Set(b, d, a, weight);
IntPoint(off + 11).Set(b, d, c, weight);
IntPoint(off + 12).Set(c, a, b, weight);
IntPoint(off + 13).Set(c, a, d, weight);
IntPoint(off + 14).Set(c, b, a, weight);
IntPoint(off + 15).Set(c, b, d, weight);
IntPoint(off + 16).Set(c, d, a, weight);
IntPoint(off + 17).Set(c, d, b, weight);
IntPoint(off + 18).Set(d, a, b, weight);
IntPoint(off + 19).Set(d, a, c, weight);
IntPoint(off + 20).Set(d, b, a, weight);
IntPoint(off + 21).Set(d, b, c, weight);
IntPoint(off + 22).Set(d, c, a, weight);
IntPoint(off + 23).Set(d, c, b, weight);
const real_t a = (1. - b - c)/2.;
AddTetPoints3(off, a, b, weight);
AddTetPoints3(off + 3, a, c, weight);
AddTetPoints6(off + 6, a, b, c, weight);
}
public:
+1 -3
View File
@@ -297,8 +297,7 @@ void LinearForm::Assemble()
tr = mesh->GetBdrFaceTransformations(i);
if (tr != NULL)
{
mfem::DofTransformation doftrans;
fes -> GetElementVDofs (tr -> Elem1No, vdofs, doftrans);
fes -> GetElementVDofs (tr -> Elem1No, vdofs);
for (int k = 0; k < boundary_face_integs.Size(); k++)
{
if (boundary_face_integs_marker[k] &&
@@ -308,7 +307,6 @@ void LinearForm::Assemble()
boundary_face_integs[k]->
AssembleRHSElementVect(*fes->GetFE(tr->Elem1No),
*tr, elemvect);
doftrans.TransformDual(elemvect);
AddElementVector (vdofs, elemvect);
}
}
+5 -11
View File
@@ -321,17 +321,12 @@ void ParL2FaceRestriction::DoubleValuedConformingMult(
const int vd = vdim;
const bool t = byvdim;
const int threshold = ndofs;
const int nsdofs = pfes.GetFaceNbrVSize() / vd;
const int nsdofs = pfes.GetFaceNbrVSize();
auto d_indices1 = scatter_indices1.Read();
auto d_indices2 = scatter_indices2.Read();
auto d_x = Reshape(x.Read(), t?vd:ndofs, t?ndofs:vd);
const int ne_shared = nsdofs / elem_dofs;
const int nedof = elem_dofs;
// Note: the shape of face_nbr_data, as determined by
// ParFiniteElementSpace::ExchangeFaceNbrData, is (elem_dofs, vdim,
// ne_shared), independent of the ordering (byNODES or byVDIM) of the finite
// element space.
auto d_x_shared = Reshape(face_nbr_data.Read(), elem_dofs, vd, ne_shared);
auto d_x_shared = Reshape(face_nbr_data.Read(),
t?vd:nsdofs, t?nsdofs:vd);
auto d_y = Reshape(y.Write(), nface_dofs, vd, 2, nf);
mfem::forall(nfdofs, [=] MFEM_HOST_DEVICE (int i)
{
@@ -351,9 +346,8 @@ void ParL2FaceRestriction::DoubleValuedConformingMult(
}
else if (idx2>=threshold) // shared boundary
{
const int e_shared = (idx2 - threshold) / nedof;
const int i_shared = (idx2 - threshold) % nedof;
d_y(dof, c, 1, face) = d_x_shared(i_shared,c,e_shared);
d_y(dof, c, 1, face) = d_x_shared(t?c:(idx2-threshold),
t?(idx2-threshold):c);
}
else // true boundary
{
+6 -3
View File
@@ -1398,17 +1398,20 @@ void L2FaceRestriction::PermuteAndSetSharedFaceDofsScatterIndices2(
const int dim = fes.GetMesh()->Dimension();
const int dof1d = fes.GetTypicalFE()->GetOrder()+1;
fes.GetTypicalFE()->GetFaceMap(face_id2, face_map);
Array<int> face_nbr_dofs;
const ParFiniteElementSpace &pfes =
static_cast<const ParFiniteElementSpace&>(this->fes);
pfes.GetFaceNbrElementVDofs(elem_index, face_nbr_dofs);
for (int face_dof_elem1 = 0; face_dof_elem1 < face_dofs; ++face_dof_elem1)
{
const int face_dof_elem2 = PermuteFaceL2(dim, face_id1, face_id2,
orientation, dof1d, face_dof_elem1);
const int volume_dof_elem2 = face_map[face_dof_elem2];
// Encode the volume DOF index and element index
const int global_dof_elem2 = elem_index*elem_dofs + volume_dof_elem2;
const int global_dof_elem2 = face_nbr_dofs[volume_dof_elem2];
const int restriction_dof_elem2 = face_dofs*face_index + face_dof_elem1;
// Trick to differentiate dof location inter/shared
scatter_indices2[restriction_dof_elem2] = ndofs + global_dof_elem2;
scatter_indices2[restriction_dof_elem2] = ndofs+global_dof_elem2;
}
#endif
}
+3 -12
View File
@@ -278,18 +278,9 @@ void ArraysByName<T>::Load(std::istream &in)
q1 = ArrayLine.find(' ');
ArrayName = ArrayLine.substr(0,q1-1);
}
if (q1+2 < ArrayLine.size())
{
// Read the remainder of the line which contains the array data
std::istringstream ArrayDataStream(ArrayLine.substr(q1+2,
ArrayLine.size()));
data[ArrayName].Load(ArrayDataStream, 0);
}
else
{
// Read the array data starting on the next line
data[ArrayName].Load(in, 0);
}
// Ignore the remainder of the line which may contain explanatory comments
data[ArrayName].Load(in, 0);
}
}
+4 -4
View File
@@ -726,16 +726,16 @@ std::string Device::GetUUID(const int device_id)
MFEM_GPU_CHECK(cudaGetDeviceProperties(&prop, device_id));
for (int i = 0; i < 16; ++i)
{
const unsigned b = static_cast<unsigned char>(prop.uuid.bytes[i]);
res << std::setfill('0') << std::setw(2) << std::hex << b;
res << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<unsigned>(prop.uuid.bytes[i]);
}
#elif defined(MFEM_USE_HIP)
hipUUID uuid;
MFEM_GPU_CHECK(hipDeviceGetUuid(&uuid, device_id));
for (int i = 0; i < 16; ++i)
{
const unsigned b = static_cast<unsigned char>(uuid.bytes[i]);
res << std::setfill('0') << std::setw(2) << std::hex << b;
res << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<unsigned>(uuid.bytes[i]);
}
#endif
return res.str();
-3
View File
@@ -317,9 +317,6 @@ void HypreParVector::WrapHypreParVector(hypre_ParVector *y, bool owner)
Vector * HypreParVector::GlobalVector() const
{
MFEM_VERIFY(size > 0,
"GlobalVector method can only be called on vectors wherein each "
"process owns one or more entries");
hypre_Vector *hv = hypre_ParVectorToVectorAll(*this);
Vector *v = new Vector(hv->data, internal::to_int(hv->size));
v->MakeDataOwner();
-12
View File
@@ -3206,22 +3206,10 @@ public:
/// Extrude a 1D mesh
/**
* @param mesh 1D mesh
* @param ny number of transverse elements of the extruded mesh
* @param sy physical size in the direction of extrusion
* @param closed if false, only the original boundaries are extruded,
* otherwise boundaries are generated all around the domain
*/
Mesh *Extrude1D(Mesh *mesh, const int ny, const real_t sy,
const bool closed = false);
/// Extrude a 2D mesh
/**
* @param mesh 2D mesh
* @param nz number of transverse elements of the extruded mesh
* @param sz physical size in the direction of extrusion
*/
Mesh *Extrude2D(Mesh *mesh, const int nz, const real_t sz);
/** @brief Constructs the smallest possible [0,1]^dim serial mesh that can be
+3 -6
View File
@@ -1516,15 +1516,12 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
{
string buff;
string version;
real_t version;
int binary, dsize;
input >> version >> binary >> dsize;
if (version != "2.2")
if (version < 2.2)
{
MFEM_ABORT("Gmsh file version must be 2.2, found version "
<< version << ".\n"
"To convert your mesh to the required format, use:\n"
" gmsh -format msh22 -save -o output.msh input.msh");
MFEM_ABORT("Gmsh file version < 2.2");
}
if (dsize != sizeof(double))
{
-49
View File
@@ -117,52 +117,3 @@ TEST_CASE("Vector FE Face Restriction", "[FaceRestriction]")
gf2 -= gf;
REQUIRE(gf2.Normlinf() == MFEM_Approx(0.0));
}
#ifdef MFEM_USE_MPI
TEST_CASE("L2 Face Restriction", "[FaceRestriction][Parallel]")
{
const int dim = GENERATE(2, 3);
constexpr int nx = 3;
constexpr int order = 2;
constexpr int vdim = 2;
const Ordering::Type ordering = GENERATE(Ordering::byNODES, Ordering::byVDIM);
Mesh serial_mesh = MakeCartesianMesh(nx, dim);
ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
L2_FECollection fec(order, dim, BasisType::GaussLobatto);
ParFiniteElementSpace fes(&mesh, &fec, vdim, ordering);
auto *R = fes.GetFaceRestriction(ElementDofOrdering::LEXICOGRAPHIC,
FaceType::Interior);
Vector vals({1.0, 2.0});
VectorConstantCoefficient coeff(vals);
ParGridFunction gf(&fes);
gf.ProjectCoefficient(coeff);
Vector face_vec(R->Height());
R->Mult(gf, face_vec);
const int nf = mesh.GetNFbyType(FaceType::Interior);
const int face_dofs = fes.GetTypicalTraceElement()->GetDof();
auto h_face_vec = Reshape(face_vec.HostRead(), face_dofs, vdim, 2, nf);
for (int f = 0; f < nf; ++f)
{
for (int m = 0; m < 2; ++m)
{
for (int c = 0; c < vdim; ++c)
{
for (int i = 0; i < face_dofs; ++i)
{
REQUIRE(h_face_vec(i, c, m, f) == vals[c]);
}
}
}
}
}
#endif
+7 -47
View File
@@ -105,39 +105,39 @@ TEST_CASE("Integration rule order initialization", "[IntegrationRules]")
SECTION("Segment rule constructed by accessing square rule")
{
auto &quad5_ir = intrules.Get(Geometry::SQUARE, 5);
REQUIRE(quad5_ir.GetOrder() >= 5);
REQUIRE(quad5_ir.GetOrder() == 5);
// The segment integration rule of order 5 is lazy constructed when we get
// the square integration rule of order 5. Make sure its order was
// properly set:
auto &line5_ir = intrules.Get(Geometry::SEGMENT, 5);
REQUIRE(line5_ir.GetOrder() >= 5);
REQUIRE(line5_ir.GetOrder() == 5);
}
SECTION("Segment rule constructed by accessing cube rule")
{
auto &hex7_ir = intrules.Get(Geometry::CUBE, 7);
REQUIRE(hex7_ir.GetOrder() >= 7);
REQUIRE(hex7_ir.GetOrder() == 7);
// The segment integration rule of order 7 is lazy constructed when we get
// the cube integration rule of order 7. Make sure its order was properly
// set:
auto &line7_ir = intrules.Get(Geometry::SEGMENT, 7);
REQUIRE(line7_ir.GetOrder() >= 7);
REQUIRE(line7_ir.GetOrder() == 7);
}
SECTION("Segment and triangle rules constructed by accessing prism rule")
{
auto &prism3_ir = intrules.Get(Geometry::PRISM, 3);
REQUIRE(prism3_ir.GetOrder() >= 3);
REQUIRE(prism3_ir.GetOrder() == 3);
// The segment integration rule of order 3 is lazy constructed when we get
// the prism integration rule of order 3. Make sure its order was properly
// set:
auto &line3_ir = intrules.Get(Geometry::SEGMENT, 3);
REQUIRE(line3_ir.GetOrder() >= 3);
REQUIRE(line3_ir.GetOrder() == 3);
// The triangle integration rule of order 3 is lazy constructed when we
// get the prism integration rule of order 3. Make sure its order was
// properly set:
auto &tri3_ir = intrules.Get(Geometry::TRIANGLE, 3);
REQUIRE(tri3_ir.GetOrder() >= 3);
REQUIRE(tri3_ir.GetOrder() == 3);
}
}
@@ -271,43 +271,3 @@ TEST_CASE("Simplex integration rules", "[SimplexRules]")
}
}
}
// Monomial exactness is tested by [SimplexRules] above, which now uses
// positive-weight rules by default. The tests below verify properties
// specific to the positive-weight rules: weight positivity, stability,
// and interior point placement.
TEST_CASE("Simplex rule positivity", "[IntegrationRules]")
{
IntegrationRules rules;
SECTION("triangle rules have all positive weights for orders 0-25")
{
for (int order = 0; order <= 25; order++)
{
const IntegrationRule &ir = rules.Get(Geometry::TRIANGLE, order);
for (int i = 0; i < ir.GetNPoints(); i++)
{
INFO("order=" << order << ", point=" << i);
REQUIRE(ir.IntPoint(i).weight > 0.0);
}
}
}
SECTION("tet rules have all positive weights for orders 0-20")
{
for (int order = 0; order <= 20; order++)
{
const IntegrationRule &ir =
rules.Get(Geometry::TETRAHEDRON, order);
for (int i = 0; i < ir.GetNPoints(); i++)
{
INFO("order=" << order << ", point=" << i);
REQUIRE(ir.IntPoint(i).weight > 0.0);
}
}
}
}
+4 -190
View File
@@ -25,201 +25,15 @@ void Func_3D_lin(const Vector &x, Vector &v)
v[2] = -2.572 * x[0] + 1.321 * x[1] + 3.234 * x[2];
}
TEST_CASE("3D ProjectBdrCoefficientNormal Vector",
"[GridFunction]"
"[VectorGridFunctionCoefficient]")
{
const int n = 1;
const int dim = 3;
const int order = 1;
const double tol = 1e-6;
for (int type = (int)Element::TETRAHEDRON;
type <= (int)Element::HEXAHEDRON; type++)
{
Mesh mesh = Mesh::MakeCartesian3D(
n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
VectorFunctionCoefficient funcCoef(dim, Func_3D_lin);
SECTION("3D GetVectorValue tests for element type " +
std::to_string(type))
{
RT_FECollection rt_fec(order+1, dim);
FiniteElementSpace rt_fespace(&mesh, &rt_fec);
GridFunction rt_x( &rt_fespace);
VectorGridFunctionCoefficient rt_xCoef( &rt_x);
Array<int> bdr_marker(6);
Vector normal(dim);
Vector f_val(dim);
Vector rt_val(dim);
for (int b = 1; b<=6; b++)
{
bdr_marker = 0;
bdr_marker[b-1] = 1;
rt_x = 0.0;
rt_x.ProjectBdrCoefficientNormal(funcCoef, bdr_marker);
for (int be = 0; be < mesh.GetNBE(); be++)
{
Element *e = mesh.GetBdrElement(be);
if (e->GetAttribute() != b) { continue; }
ElementTransformation *T = mesh.GetBdrElementTransformation(be);
const FiniteElement *fe = rt_fespace.GetBE(be);
const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(),
2*order + 2);
double rt_err = 0.0;
for (int j=0; j<ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T->SetIntPoint(&ip);
CalcOrtho(T->Jacobian(), normal);
funcCoef.Eval(f_val, *T, ip);
rt_xCoef.Eval(rt_val, *T, ip);
rt_val -= f_val;
double rt_dist = rt_val * normal;
rt_err += rt_dist;
if (verbose_tests && rt_dist > tol)
{
mfem::out << be << ":" << j << " rt ("
<< f_val[0] << "," << f_val[1] << "," << f_val[2]
<< ") vs. ("
<< rt_val[0] << "," << rt_val[1] << ","
<< rt_val[2] << ") " << rt_dist << std::endl;
}
}
rt_err /= ir.GetNPoints();
REQUIRE( rt_err == MFEM_Approx(0.0));
}
}
}
}
}
TEST_CASE("3D ProjectBdrCoefficientNormal Scalar",
"[GridFunction]"
"[VectorGridFunctionCoefficient]")
{
const int n = 1;
const int dim = 3;
const int order = 1;
const double tol = 1e-6;
const char bdrs_axis[] = {2, 1, 0, 1, 0, 2};
const char bdrs_sign[] = {-1, -1, +1, +1, -1, +1};
for (int type = (int)Element::TETRAHEDRON;
type <= (int)Element::HEXAHEDRON; type++)
{
Mesh mesh = Mesh::MakeCartesian3D(
n, n, n, (Element::Type)type, 2.0, 3.0, 5.0);
VectorFunctionCoefficient funcCoef(dim, Func_3D_lin);
SECTION("3D GetVectorValue tests for element type " +
std::to_string(type))
{
RT_FECollection rt_fec(order+1, dim);
FiniteElementSpace rt_fespace(&mesh, &rt_fec);
GridFunction rt_x( &rt_fespace);
VectorGridFunctionCoefficient rt_xCoef( &rt_x);
Array<int> bdr_marker(6);
Vector normal(dim);
Vector f_val(dim);
Vector rt_val(dim);
for (int b = 1; b<=6; b++)
{
bdr_marker = 0;
bdr_marker[b-1] = 1;
rt_x = 0.0;
normal = 0.;
normal(bdrs_axis[b-1]) = (bdrs_sign[b-1] > 0)?(+1.):(-1.);
VectorConstantCoefficient normCoef(normal);
InnerProductCoefficient prodCoef(funcCoef, normCoef);
rt_x.ProjectBdrCoefficientNormal(prodCoef, bdr_marker);
for (int be = 0; be < mesh.GetNBE(); be++)
{
Element *e = mesh.GetBdrElement(be);
if (e->GetAttribute() != b) { continue; }
ElementTransformation *T = mesh.GetBdrElementTransformation(be);
const FiniteElement *fe = rt_fespace.GetBE(be);
const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(),
2*order + 2);
double rt_err = 0.0;
for (int j=0; j<ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
T->SetIntPoint(&ip);
CalcOrtho(T->Jacobian(), normal);
funcCoef.Eval(f_val, *T, ip);
rt_xCoef.Eval(rt_val, *T, ip);
rt_val -= f_val;
double rt_dist = rt_val * normal;
rt_err += rt_dist;
if (verbose_tests && rt_dist > tol)
{
mfem::out << be << ":" << j << " rt ("
<< f_val[0] << "," << f_val[1] << "," << f_val[2]
<< ") vs. ("
<< rt_val[0] << "," << rt_val[1] << ","
<< rt_val[2] << ") " << rt_dist << std::endl;
}
}
rt_err /= ir.GetNPoints();
REQUIRE( rt_err == MFEM_Approx(0.0));
}
}
}
}
}
TEST_CASE("3D ProjectBdrCoefficientTangent",
"[GridFunction]"
"[VectorGridFunctionCoefficient]")
{
const int n = 1;
const int dim = 3;
const int order = 1;
int n = 1;
int dim = 3;
int order = 1;
const double tol = 1e-6;
double tol = 1e-6;
for (int type = (int)Element::TETRAHEDRON;
type <= (int)Element::HEXAHEDRON; type++)
@@ -200,39 +200,3 @@ TEST_CASE("ArraysByName Sort/Unique Methods", "[ArraysByName]")
}
}
}
TEST_CASE("ArraysByName Print/Load Methods", "[ArraysByName]")
{
ArraysByName<int> abn;
FillArraysByName(abn);
// Print object to string using default format
std::ostringstream oss1;
abn.Print(oss1);
// Load new object from printed output
ArraysByName<int> abn_load1;
std::istringstream iss1(oss1.str());
abn_load1.Load(iss1);
REQUIRE(abn == abn_load1);
// Print object to string using one line per array
std::ostringstream oss2;
oss2 << abn.Size() << '\n';
for (auto a : abn)
{
oss2 << '"' << a.first << "\" " << a.second.Size();
for (auto d : a.second)
{
oss2 << ' ' << d;
}
oss2 << '\n';
}
// Load new object from printed output
ArraysByName<int> abn_load2;
std::istringstream iss2(oss2.str());
abn_load2.Load(iss2);
REQUIRE(abn == abn_load2);
}