Compare commits

...
Author SHA1 Message Date
Matthew Meeker 2b01646b7a Rearranged file 2025-07-17 15:33:13 -04:00
Matthew Meeker 8104f3f5aa Removed No-pen check 2025-07-17 13:57:34 -04:00
Matthew Meeker ceb6032407 Fix style; remove large data file 2025-07-16 21:15:35 -04:00
Matthew Meeker f60dc802ac VTI wind field is correctly read in 2025-07-15 19:35:17 -04:00
Matthew Meeker 2c878bb1a0 std::max template fix 2025-07-04 14:05:01 -04:00
Matthew Meeker 70c5482f11 Added VTK output to Windtunnel example 2025-07-03 16:47:17 -04:00
Matthew Meeker ccaab0b1e8 Logarithmic profile fix to avoid log of zero = NaN 2025-07-03 12:46:39 -04:00
Matthew Meeker 8c2f69a39b Fixed style, test errors and added several profiles as CLI options 2025-07-03 10:46:41 -04:00
Matthew Meeker 94cb24e0ea Triaging example 2025-07-01 16:53:39 -04:00
Matthew Meeker 982f17726b Draft still 2025-06-30 12:55:33 -04:00
Matthew Meeker ff3014588c Draft solver 2025-06-30 12:23:51 -04:00
Matthew Meeker 26b1019d51 Set up correct boundary conditions 2025-06-30 12:23:42 -04:00
Matthew Meeker c465d9f142 Update comments to reflect source 2025-06-08 12:31:46 +02:00
Matthew Meeker a474074525 Fix style 2025-06-07 19:04:42 +02:00
Matthew Meeker fca203a579 Fix tests and maintain component-wise DBC functionality 2025-06-07 18:26:53 +02:00
Tzanio Kolev 0fed4cb6a1 Merge branch 'master' into MDMeeker_NS_DRD 2025-05-27 14:25:18 -07:00
Matthew Meeker ffd51d8212 Satisfy build 2025-05-27 17:23:00 -04:00
Tzanio Kolev 59267d1cc4 Merge pull request #4838 from mfem/subvector-device
make some subvector functions work on device
2025-05-27 12:09:31 -07:00
Matthew Meeker 4959a7dc81 Satisfy astyle 2025-05-27 13:56:22 -04:00
Matthew Meeker 8fc7f260de First draft implementation. Possible memory leak 2025-05-27 13:36:09 -04:00
Tzanio Kolev e4337d10e1 Merge pull request #3837 from mfem/sjg/mfem-device-fixes
Fixes for `mfem::Device`
2025-05-25 12:30:00 -07:00
Tzanio Kolev f81695df71 Merge branch 'master' into subvector-device 2025-05-25 12:28:58 -07:00
Tzanio Kolev 41b76c0eba Merge pull request #4849 from mfem/tmop-targets-PA2D
TMOP PA 2D kernel for size adaptivity
2025-05-25 12:24:03 -07:00
Matthew Meeker 1825fa356f Split Kovasznay off into new example for no-pen BC 2025-05-21 13:52:57 -04:00
Will Pazner 6329213cbb Use device in constant Vector::SetSubVector, add Vector::SetSubVectorHost 2025-05-20 15:08:39 -07:00
Tzanio Kolev a87cc08116 Merge branch 'master' into sjg/mfem-device-fixes 2025-05-19 16:52:09 -07:00
Veselin Dobrev 8c6c49bd1a Fix preprocessor check 2025-05-18 20:44:44 -07:00
Veselin Dobrev 4987074377 Formatting and other small tweaks 2025-05-18 19:46:13 -07:00
Tzanio Kolev b68a2d4929 Merge branch 'master' into subvector-device 2025-05-18 14:08:43 -07:00
Tzanio Kolev 9f945a5863 Merge pull request #4847 from adam-sim-dev/typo
Fix typos
2025-05-16 11:52:59 -07:00
John Camier 96b35e0067 Merge branch 'master' into tmop-targets-PA2D 2025-05-13 08:28:10 -07:00
Veselin Dobrev 2b3c9ad149 Merge pull request #4806 from mfem/bugfix/chapman39/find-petsc-cmp0126
Fix mfem4.8 about petsc config
2025-05-07 09:53:15 -07:00
victor-decaria-nnlandWill Pazner 62992c0005 Update linalg/vector.cpp
Add forgotten `use_dev` argument.

Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2025-05-07 12:37:24 -04:00
victor-decaria-nnlandWill Pazner c004a77cab Update linalg/vector.cpp
Add forgotten `use_dev` argument.

Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2025-05-07 12:37:13 -04:00
Vladimir Z Tomov ce93704976 2D kernel for DiscreteAdaptTC::ComputeAllElementTargets() 2025-05-05 15:23:23 -07:00
adam-sim-dev 95204e94a7 Fix typos 2025-05-05 20:10:40 +08:00
Tzanio Kolev c63602dc00 Merge branch 'master' into subvector-device 2025-05-03 13:28:32 -07:00
Tzanio Kolev 5bb00767ef Merge pull request #4814 from mfem/dgmassinv-1d
Support 1D in DGMassInverse
2025-05-02 11:41:46 -07:00
Tzanio Kolev 000af14c09 Merge pull request #4828 from mfem/tmop-energy-kernels
Extra TMOP PA energy kernels.
2025-05-02 11:41:27 -07:00
Mittal, Ketan 3f81c6ca26 minor fix for combomet case 2025-04-30 10:07:45 -07:00
Tzanio Kolev 43aa4fccb0 Merge pull request #4809 from mfem/gpu-hybridization-tweaks
Some tweaks in class HybridizationExtension
2025-04-30 08:47:25 -07:00
Tzanio Kolev 6ceeafaa83 Merge pull request #4826 from mfem/chain-asan-sigaction
Chain sigaction in memory manager
2025-04-30 08:46:53 -07:00
Tzanio Kolev 836a9ec10d Merge pull request #4830 from mfem/quadinterp-phys-vals
Use physical values in QuadratureFunction::ProjectGridFunction
2025-04-30 08:40:56 -07:00
Mittal, Ketan 840bb685ed add id for mu_56 2025-04-29 14:08:07 -07:00
Mittal, Ketan 06a0d49a23 minor 2025-04-29 13:10:08 -07:00
camierjs a3ca3a7b58 Simplify ComputeNormalizationEnergies comment 2025-04-29 10:48:58 -07:00
Will PaznerandYohann 82b9dc5e32 Update fem/dgmassinv_kernels.hpp
Co-authored-by: Yohann <dudouit1@llnl.gov>
2025-04-29 10:07:15 -07:00
Tzanio Kolev f10d4c175a Merge pull request #4285 from mfem/moonolith_h1_bugfix
Moonolith h1 bugfix
2025-04-29 08:21:41 -07:00
Victor DeCaria ad99d96067 make some subvector functions work on device 2025-04-29 08:45:53 -06:00
Patrick Zulian 64108af968 Added new ParMoonolith related features in CHANGELOG 2025-04-29 08:06:44 +02:00
Veselin Dobrev b3147f05f4 Fix a comment 2025-04-27 19:22:22 -07:00
Tzanio Kolev 6d743d862d Merge branch 'master' into dgmassinv-1d 2025-04-26 12:22:47 -07:00
Will PaznerandVeselin Dobrev 24be7bca7b Support Q1D < D1D in EvalHDiv2D
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2025-04-25 08:16:24 -07:00
camierjs c21460e89e Tighten linsol rtol for all TMOP tests to pass 2025-04-24 18:05:37 -07:00
camierjs 54eea15b77 Meld toward tmop-energy-kernels 2025-04-24 16:52:33 -07:00
camierjs 5750f09a1d Fix ComputeNormalizationEnergies with non-linear iterations 2025-04-24 16:49:27 -07:00
Will Pazner a5e62babfd Change name to QuadratureInterpolator::PhysValues 2025-04-24 13:14:01 -07:00
Will Pazner a05fce3e00 Evaluate values in non-H(div) QuadratureInterpolator with PHYSICAL_VALUES 2025-04-24 13:08:08 -07:00
Will Pazner 0270187325 Use physical values in QuadratureFunction::ProjectGridFunction
This ensures correct evaluation of H(div) grid functions
2025-04-24 12:27:36 -07:00
camierjs f0826d5f8e TMOP wip diffs 2025-04-24 12:05:57 -07:00
camierjs 26cc4698f5 Combo tests 2025-04-24 11:24:54 -07:00
camierjs db2a272a38 Combo with balance tests 2025-04-24 11:05:24 -07:00
camierjs 527f1b9631 Merge branch 'tmop-energy-kernels' into tmop-weights 2025-04-24 09:21:19 -07:00
Patrick Zulian 960d31f17b Merge branch 'master' into moonolith_h1_bugfix 2025-04-24 12:17:05 +02:00
Vladimir Z Tomov 6ae95a8c1f minor 2025-04-23 17:56:54 -07:00
Vladimir Z Tomov 34a8c77c43 style 2025-04-23 17:52:07 -07:00
Vladimir Z Tomov 9bb600a87c Kernels for ComputeBalancedWeights in combo metrics. 2025-04-23 17:51:27 -07:00
camierjs d723d05b8f Debug traces & ComputeAllElementTargets 2025-04-23 17:49:48 -07:00
camierjs f34f4600b7 TMOP tests update & sync 2025-04-23 16:29:13 -07:00
Victor DeCaria 626284bc29 make windows compatible 2025-04-23 16:35:04 -06:00
victor-decaria-nnl 3a80136f70 Merge branch 'master' into chain-asan-sigaction 2025-04-23 18:11:41 -04:00
Vladimir Z Tomov 9dbf656433 PA kernels for EnableNormalization. 2025-04-23 15:08:04 -07:00
Victor DeCaria 3612f1e978 make original behavior fall through correctly 2025-04-23 16:07:04 -06:00
Victor DeCaria 0563180e55 formatting 2025-04-23 15:30:38 -06:00
Victor DeCaria fb8c6eb0fe chain memory manager sigaction with asan. Print more signal information 2025-04-23 15:29:32 -06:00
Alex Tyler Chapman 3b42070ad0 Merge branch 'master' into bugfix/chapman39/find-petsc-cmp0126 2025-04-23 12:09:57 -07:00
Tzanio Kolev f690d3956a Merge pull request #4816 from mfem/tmop-combo-ir
TMOP - optional IntRule in ComputeBalancedWeights.
2025-04-23 08:01:54 -07:00
chapman39 7f77e267fd unset cached _lib var 2025-04-22 14:26:27 -07:00
Hugh Carson a6cb7f98f0 Merge remote-tracking branch 'origin/master' into sjg/mfem-device-fixes 2025-04-22 14:24:39 -04:00
Patrick Zulian e8464c77da Make style on example_utils 2025-04-22 08:52:36 +02:00
Patrick Zulian 182f2e16a7 Added custom plot options for moonolith examples 2025-04-22 08:21:28 +02:00
Patrick Zulian f89ef2f04d Added custom plot options for moonolith examples 2025-04-22 08:12:38 +02:00
Will Pazner aac94d0f67 Add error message 2025-04-21 16:19:35 -07:00
Patrick Zulian c96273e7a0 continued 2025-04-20 11:32:27 +02:00
Patrick Zulian ce54c08b50 fixed include path 2025-04-20 11:28:40 +02:00
Patrick Zulian 3b506facdc Fixed compilation issues arisen after merge with master 2025-04-20 11:14:13 +02:00
Patrick Zulian 01f8360f8f fixed whitespace conflicts 2025-04-20 10:52:36 +02:00
Vladimir Z Tomov 12bf4a450d Merge branch 'master' into tmop-combo-ir 2025-04-19 23:10:19 -07:00
Vladimir Z Tomov 74ed3102d2 minor 2025-04-19 23:03:49 -07:00
Vladimir Z Tomov 7b083081dc Option IntRule to ComputeBalancedWeights(). 2025-04-19 23:01:54 -07:00
Will Pazner 2204bc003f Supress Doxygen warnings 2025-04-19 13:58:27 -07:00
Will Pazner eec41dd6c0 Use kernel dispatch in DGMassInverse 2025-04-19 12:16:36 -07:00
Will Pazner 113b446634 Support member functions in kernel dispatch 2025-04-19 12:16:15 -07:00
Tzanio Kolev 90a68678f4 Merge pull request #4797 from mfem/vtkhdf
VTKHDF format writer
2025-04-19 11:30:37 -07:00
Will Pazner 56ae55580c Const correctness in DGMassInverse 2025-04-19 10:52:19 -07:00
Tzanio Kolev 9f2d103b4b Merge pull request #4799 from mfem/najlkin/fix-sol-ctrlr
Fixed iterative solvers for solution-based controllers
2025-04-18 13:12:12 -07:00
Tzanio Kolev b9452cf300 Merge pull request #4802 from mfem/fix-warn-extra-clang-17
Suppress two warnings from newer Clang versions when using `-Wextra`
2025-04-18 13:11:33 -07:00
Will Pazner 7e3b442102 Use unique_ptr in DGMassInverse 2025-04-17 16:30:55 -07:00
Will Pazner 081635ffd3 Support 1D in DGMassInverse 2025-04-17 16:26:57 -07:00
Veselin DobrevandAaron Skinner 488927e6c1 Some tweaks in class HybridizationExtension
Co-authored-by: Aaron Skinner <aaronskinner@users.noreply.github.com>
2025-04-16 12:54:48 -07:00
Tzanio Kolev 2d87af4491 Merge pull request #4808 from mfem/github-actions-ompi
Use Open MPI instead of MPICH in Build Analysis action
2025-04-16 12:53:38 -07:00
Tzanio Kolev 1fe5baac92 Merge branch 'master' into najlkin/fix-sol-ctrlr 2025-04-15 13:46:08 -07:00
Tzanio Kolev 4e320842a5 Merge branch 'master' into github-actions-ompi 2025-04-15 13:45:29 -07:00
Tzanio Kolev 922d89dd62 Merge branch 'master' into vtkhdf 2025-04-15 13:40:41 -07:00
Will Pazner ac66d17c67 Add more options to GridFunction::SaveVTKHDF 2025-04-15 12:48:33 -07:00
Will Pazner 5b9286caec Fix high-order VTK prism ordering
This was a bug in the VTK library, fixed in:
https://gitlab.kitware.com/vtk/vtk/-/merge_requests/6600
2025-04-15 12:48:18 -07:00
Will PaznerandSebastian Grimberg c645b1d486 Fix bug in refined low-order VTK prism ordering
Co-authored-by: Sebastian Grimberg <sjg@amazon.com>
2025-04-15 12:47:45 -07:00
Will Pazner 11a53d4359 Explicitly use uint64_t for MPI communication
Make sure correct MPITypeMap template is found
2025-04-15 12:46:37 -07:00
Will Pazner 31a811ad1c Fix Doxygen comment for Hypre::InitDevice 2025-04-15 11:08:32 -07:00
Hugh Carson aa06e17686 Merge branch 'master' into sjg/mfem-device-fixes 2025-04-15 14:01:21 -04:00
Will Pazner 839cd667ac Use Open MPI instead of MPICH in Build Analysis action 2025-04-15 10:29:22 -07:00
Will Pazner be968b3f52 Enabled shuffle filter in compressed VTKHDF output
Shuffle before compression can improve compression ratio
2025-04-15 09:58:59 -07:00
Will Pazner 3537ab556e Remove unused templates in VTKHDF
Use size_t instead of int64_t for offsets and sizes
2025-04-15 09:58:24 -07:00
Will Pazner c64cfd544e Add HDF5 config to defaults.mk 2025-04-15 09:57:38 -07:00
chapman39 d9c1c34fdf remove CACHE'ing of _lib variable instead of updating policy 2025-04-14 16:56:22 -07:00
chapman39 97c32689f0 update policy CMP0126 in find petsc 2025-04-14 15:32:36 -07:00
Jan Nikl 58453228f3 Fixed FGMRES update. 2025-04-14 13:05:59 -07:00
Veselin Dobrev 2366da7257 Fix two warnings from newer Clang versions when using -Wextra 2025-04-12 12:56:04 -07:00
Tzanio Kolev d07af7ce8b Merge pull request #4798 from mfem/new-dev-version-4.8.1
Update version numbers to 4.8.1 -- a new development version
2025-04-11 16:37:57 -07:00
Jan Nikl 3db3013271 Added a helper method for indication of requirement on update. 2025-04-11 13:26:02 -07:00
Jan Nikl 9c08ccf864 Renamed monitor to controller and added a setter. 2025-04-11 13:17:03 -07:00
Jan Nikl b38fa26468 Removed unnecessary final indication of final flag. 2025-04-11 12:36:43 -07:00
Jan Nikl 5330247ae8 Fixed IterativeSolverController to be able to indicate updated solution is needed. 2025-04-11 12:33:04 -07:00
Veselin Dobrev f9c67d7a9e Update version numbers to 4.8.1 -- a new development version 2025-04-11 10:57:07 -07:00
Will Pazner 713f178392 Add options for HDF5 in CMake build system 2025-04-11 10:22:03 -07:00
Will Pazner c0ce07fb2d Enable VTKHDF functionality only when HDF5 is enabled 2025-04-11 10:22:03 -07:00
Will Pazner 71f7398979 Add unit test for ParaViewHDFDataCollection 2025-04-11 10:22:03 -07:00
Will Pazner 943461a328 Fix signed unsigned comparisons in VTKHDF 2025-04-11 10:22:03 -07:00
Will Pazner 9c27d41fbe Handle empty prefix path in ParaViewHDFDataCollection 2025-04-11 10:22:03 -07:00
Will Pazner 1909fcc489 Update VTU file format to version 2.2, update hex node ordering 2025-04-11 10:22:03 -07:00
Will Pazner 754cc7a4f8 Handle HDF5 built without parallel support 2025-04-11 10:22:03 -07:00
Will Pazner 5b57ce88dd Minor VTKHDF simplifications 2025-04-11 10:22:03 -07:00
Will Pazner 4807e96c73 Prevent type error writing Offsets in VTKHDF 2025-04-11 10:22:03 -07:00
Will Pazner 379aafca6c Support parallel restart mode in VTKHDF 2025-04-11 10:22:03 -07:00
Will Pazner 1f91051e55 Use anonymous namespace 2025-04-11 10:22:03 -07:00
Will Pazner b321442fab Fix bug in VTKHDF::EnsureGroup 2025-04-11 10:22:03 -07:00
Will Pazner 171fafc021 Disable locking mode in VTKHDF, refactor slightly 2025-04-11 10:22:03 -07:00
Will Pazner 3aa19b7a3f Create prefix path in ParaViewHDFDataCollection 2025-04-11 10:22:03 -07:00
Will Pazner 019da753cd Support restart mode in ParaViewHDFDataCollection 2025-04-11 10:22:03 -07:00
Will Pazner 9359f0b10a Support restart mode in VTKHDF (in serial) 2025-04-11 10:22:03 -07:00
Will Pazner 0524c5b012 Flush HDF5 output in ParaViewHDFDataCollection::Save 2025-04-11 10:22:03 -07:00
Will Pazner e1a18c2868 Add Mesh::SaveVTKHDF and GridFunction::SaveVTKHDF member functions 2025-04-11 10:22:03 -07:00
Will Pazner a700036428 VTKHDF Doxygen 2025-04-11 10:22:03 -07:00
Will Pazner c9e6c6e74a Improve VTKHDF chunking 2025-04-11 10:22:03 -07:00
Will Pazner 0dfe9eaff8 High-order output in ParaViewHDFDataCollection 2025-04-11 10:22:03 -07:00
Will Pazner dc578cc8d3 VTKHDF output in 32 and 64 bits 2025-04-11 10:22:03 -07:00
Will Pazner c0444b07f5 Support vdim > 1 in VTKHDF 2025-04-11 10:22:03 -07:00
Will Pazner cc2c00946d Support high-order VTKHDF output 2025-04-11 10:22:03 -07:00
Will Pazner 18ff1d4772 Add ParaViewHDFDataCollection
Add abstract base class ParaViewDataCollectionBase inherited from by both
ParaViewDataCollection and ParaViewHDFDataCollection.
2025-04-11 10:22:03 -07:00
Will Pazner a447d0bfbd More improvements 2025-04-11 10:22:03 -07:00
Will Pazner 1318146a27 VTKHDF simplifications, documentation 2025-04-11 10:22:03 -07:00
Will Pazner 22dffb6326 VTK-HDF5 format writer 2025-04-11 10:22:03 -07:00
Will Pazner ce19020781 Add build system options for HDF5 2025-04-11 10:22:03 -07:00
Tzanio Kolev a017191010 Merge pull request #4681 from mfem/mfem-4.8-dev
Final changes for mfem-4.8
2025-04-09 16:16:44 -07:00
Tzanio Kolev b02893686a Final fix before mfem-4.8 2025-04-09 15:40:18 -07:00
Tzanio Kolev 008ac526d1 Final fixes in INSTALL before mfem-4.8 2025-04-09 15:34:54 -07:00
Veselin Dobrev 22fe453fda In CHANGELOG, remove new bullets accidentally added in the section for
version 4.7
2025-04-09 15:26:58 -07:00
Tzanio Kolev 4d39303ad9 Update CHANGELOG 2025-04-09 15:11:38 -07:00
Andrew Ho a87dadb8b3 updated HIP install instructions. 2025-04-07 22:08:28 -07:00
Tzanio Kolev cb78abf671 Merge branch 'master' into mfem-4.8-dev 2025-04-06 11:33:39 -07:00
Tzanio Kolev 5e32ae87b4 Merge pull request #4783 from mfem/github-actions-ompi
Use Open MPI instead of MPICH in GitHub Actions
2025-04-06 11:33:05 -07:00
Tzanio Kolev 1963a63075 minor 2025-04-06 11:25:43 -07:00
Tzanio Kolev 6e36cbfb5f minor 2025-04-06 10:35:14 -07:00
Will Pazner 253f578ae4 Use Open MPI instead of MPICH in GitHub Actions
The Ubuntu 24.04 MPICH package is broken, causing CI failures, see
https://bugs.launchpad.net/ubuntu/+source/mpich/+bug/2072338
2025-04-06 09:08:14 -07:00
Veselin Dobrev 52ff1fdbaf Add GitHub CI test on macOS with single precision 2025-04-05 10:49:20 -07:00
Veselin Dobrev ac53af01ef Fix errors with clang in the single precision build 2025-04-05 10:41:23 -07:00
Veselin Dobrev 5f5b15b5f6 Small tweaks: compilation warnings, PUMI link path, lsf_integral is
serial (not parallel) miniapp.
2025-04-05 08:28:36 -07:00
Andrew Ho d17263e7e5 revert CMake HIP changes
After further testing I suspect the original issue I ran into must
have been some unexpected transient configuration issue that I am no
longer able to reproduce.
2025-04-04 15:32:50 -07:00
Andrew Ho 2f852723f8 Merge remote-tracking branch 'base/mfem-4.8-dev' into mfem-4.8-dev 2025-04-04 12:49:59 -07:00
Andrew Ho e41811ad7f Fixed specifying the HIP_ARCH for CMake >= 3.21.
Added CMake HIP build instructions.
2025-04-04 12:48:22 -07:00
Tzanio Kolev 37034f28a6 Merge pull request #4780 from mfem/fix-pyramid-thread-safe
Fix compilation errors for pyramid elements with MFEM_THREAD_SAFE
2025-04-04 12:21:17 -07:00
Will Pazner 43f8ea13dd Fix compilation errors for pyramid elements with MFEM_THREAD_SAFE 2025-04-04 09:19:12 -07:00
Tzanio Kolev c5363ebaaf Merge branch 'master' into mfem-4.8-dev 2025-04-03 13:00:19 -07:00
Tzanio Kolev c11d9acab8 Merge pull request #4750 from mfem/avoid-uninitialized-buffer-ops
Avoid uninitialized memory use
2025-04-03 12:58:52 -07:00
Tzanio Kolev f0525f62e3 Merge branch 'master' into avoid-uninitialized-buffer-ops 2025-04-03 12:22:31 -07:00
Veselin Dobrev ae478a45cd Fix memory leak 2025-04-03 07:09:12 -07:00
Veselin Dobrev 9e66156622 Fix the case of vdim > 1 in the method EAL2ProjectionH1Space() in
class L2ProjectionGridTransfer::L2ProjectionH1Space.
2025-04-03 06:44:23 -07:00
Tzanio KolevandJan Nikl 09df072897 Update doc/CodeDocumentation.dox
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2025-04-03 06:38:38 -07:00
Patrick Zulian ff9467c07d Merge branch 'master' into moonolith_h1_bugfix 2025-04-03 14:37:24 +02:00
Tzanio Kolev 0641035fb9 Merge branch 'master' into mfem-4.8-dev 2025-04-02 14:54:37 -07:00
Tzanio Kolev b5ff969e5f Merge pull request #4774 from mfem/cmake4-fix
Tweaks for CMake 4 and GitHub CI
2025-04-02 14:53:48 -07:00
Chris Vogl 67b5011d50 Update CHANGELOG
minor whitespace change
2025-04-02 12:15:48 -07:00
Veselin Dobrev 29f26a96ea In CHANGELOG, add a bullet with the new CMake version requirements 2025-04-02 11:07:56 -07:00
Tzanio Kolev e5ae0c8b61 Merge branch 'master' into mfem-4.8-dev 2025-04-02 10:27:18 -07:00
Veselin Dobrev bd074035ae Fix typo 2025-04-02 10:02:53 -07:00
Tzanio Kolev aad3a6be39 Merge pull request #4766 from tepperly/mma-with-fewer-raw-pointers
Remove many of the raw pointers from the new MMA solver
2025-04-02 09:50:13 -07:00
Veselin Dobrev 1d3ffaa0bd Fix the CUDA build with older versions of CMake, e.g. v3.20.
Update the CMake version requirement when building with CUDA to 3.17
which is the version where the CUDAToolkit module was added.

Fix CUDA warnings.
2025-04-02 05:00:40 -07:00
Veselin Dobrev 42774a1e21 In CMake, remove logic for CMake < 3.12 and move the logic for the
CUDA architectures before 'enable_language(CUDA)' to allow us to
initialize 'CMAKE_CUDA_ARCHITECTURES' (if not alreasy set by the user)
based on 'CUDA_ARCH'.
2025-04-02 00:29:06 -07:00
Tzanio Kolev ac2beeb4ed Merge branch 'master' into cmake4-fix 2025-04-01 17:41:48 -07:00
Tzanio Kolev b44d75655e Small fixes for mfem-4.8 2025-04-01 17:14:58 -07:00
Tzanio Kolev b8fcc35cbc Merge branch 'master' into mfem-4.8-dev 2025-04-01 16:44:23 -07:00
Veselin Dobrev 5588024a50 Merge pull request #4741 from mfem/tmop-periodic
TMOP for periodic meshes
2025-04-01 16:35:03 -07:00
Vladimir Z Tomov 48a270679c Merge branch 'master' into tmop-periodic 2025-04-01 16:18:06 -07:00
Veselin Dobrev 3d99a9962a In CMakeLists.txt, add a comment about the requirement for CMake 3.12 2025-04-01 16:11:49 -07:00
Veselin Dobrev c6d495ac37 Update cmake4.patch so it can be applied after the other patches 2025-04-01 15:53:15 -07:00
Vladimir Z Tomov 9ad90f4491 Updated the LEXICOGRAPHIC comment in fespace.hpp. 2025-04-01 15:40:30 -07:00
Veselin Dobrev 8c0a137dae Update the CMake minimum version to 3.12.0 and add policy version.
Add a patch for CMake 4 for the "metis-mfem" vcpkg in config/vcpkg.
2025-04-01 15:39:36 -07:00
Tzanio Kolev 8315140852 Merge branch 'master' into mfem-4.8-dev
Conflicts:
	CHANGELOG
	makefile
2025-04-01 12:31:58 -07:00
Veselin Dobrev 3118e38912 Merge pull request #4701 from mfem/dev-inverse-transform
GPU Batch Inverse Element Transform
2025-04-01 12:14:54 -07:00
Tzanio Kolev c34ab2dd69 Renamed hpref_serial/hpref to hpref/phpref in miniapps/meshing 2025-04-01 10:06:44 -07:00
Tzanio Kolev 8a474b7365 Renamed Laplace to Poisson where appropriate 2025-03-31 20:56:40 -07:00
Tzanio Kolev b3e19a2e7a Typos and styling 2025-03-31 18:48:43 -07:00
Tzanio Kolev 54b85f7a1e CHANGELOG changes for mfem-4.8 2025-03-31 16:02:39 -07:00
Arturo Vargas 835b0b72cf Merge branch 'master' into avoid-uninitialized-buffer-ops 2025-03-31 15:31:24 -07:00
Arturo Vargas 25fa866918 fix bugs when having MPI available 2025-03-31 15:31:02 -07:00
Tzanio Kolev ea56560951 CHANGELOG changes for mfem-4.8 2025-03-31 15:23:18 -07:00
Tzanio Kolev e2e497bece CHANGELOG changes for mfem-4.8 2025-03-31 15:06:44 -07:00
Arturo Vargas d77ce29bd6 first pass at fixing bugs 2025-03-31 13:49:57 -07:00
Tzanio Kolev 6e3a32574b Merge branch 'master' into mfem-4.8-dev 2025-03-31 12:46:15 -07:00
Tom Epperly e2b2df0345 Change raw pointers/new/delete in LUSolve to unique_ptr equivalents 2025-03-31 10:04:41 -07:00
Tom Epperly a63be294bd Fix MFEM_ABORT, so MFEM_USE_LAPACK can be true 2025-03-31 08:16:38 -07:00
Tom Epperly e66f6b239f Fix LAPACK calls 2025-03-31 07:35:54 -07:00
Tom Epperly 3ab6b3af2d Merge remote-tracking branch 'origin/master' into mma-with-fewer-raw-pointers 2025-03-31 06:54:11 -07:00
Patrick Zulian 8c85525be5 Moonolith: fixes based on PR 4285 comments. 2025-03-31 10:52:52 +02:00
Patrick Zulian 8a15086e1a Merge branch 'master' into moonolith_h1_bugfix 2025-03-31 08:42:26 +02:00
Tzanio Kolev 38c199008f Merge pull request #4571 from mfem/hybridization-gpu
GPU hybridization
2025-03-30 09:44:57 -07:00
Tzanio Kolev fa28a928e4 Merge branch 'master' into mfem-4.8-dev 2025-03-29 13:22:14 -07:00
Tzanio Kolev 24365aa14d Merge pull request #4660 from mfem/reduction
Reduction framework
2025-03-29 13:00:21 -07:00
Tzanio Kolev 2b7360ecab Merge pull request #4666 from mfem/par-sub-transfer-fix
Bug fix and improvements to (Par)TransferMap
2025-03-29 12:57:40 -07:00
Andrew Ho c6159ef184 Merge remote-tracking branch 'base/dev-inverse-transform' into dev-inverse-transform 2025-03-28 16:04:45 -07:00
Andrew Ho 537112ebb8 cleaned up kernel specialization registration
Added assert for unsupported NewtonSegmentProject
2025-03-28 16:03:33 -07:00
Tom Epperly 956da4de04 Fix style 2025-03-28 15:22:35 -07:00
Tom Epperly 6699fc9ab0 Fix parallel methods that I hadn't built yet. 2025-03-28 15:15:12 -07:00
Andrew Ho 1912c74587 Merge branch 'master' into dev-inverse-transform 2025-03-28 15:12:21 -07:00
Tom Epperly 45747103f1 Another missing header 2025-03-28 14:59:04 -07:00
Tom Epperly dbd8d3d7d3 Fix #include 2025-03-28 14:30:25 -07:00
Tom Epperly bbc7658395 Fix one pointer to reference mistake 2025-03-28 14:02:12 -07:00
Tom Epperly a1dedbb916 Remove many of the raw pointers from the new MMA solver 2025-03-28 13:46:37 -07:00
Andrew Ho 06234a875f More cleanup
assert on unsupported ClosestRefNode
fix warning on trying to use | for bools
2025-03-28 13:06:41 -07:00
Andrew Ho 2ce31f6841 one more old code comment 2025-03-28 13:01:10 -07:00
Andrew Ho 6859612af9 cleanup old code 2025-03-28 12:58:47 -07:00
Andrew Ho d9d963cc88 Address review comments
- changed use_dev to use_device
- added a way to directly set initial guess order rather than have
  relative order only
- cleanup newton solves
- updated some documentation
2025-03-28 12:47:49 -07:00
Andrew Ho 669b6e6e49 Cleanup eltrans_basis.hpp
Use segment project for square/cube project, updated doc on what
project returns
2025-03-28 12:44:46 -07:00
Will Pazner 070c9f2787 Update CHANGELOG 2025-03-28 11:49:10 -07:00
Will Pazner 631792da83 Merge remote-tracking branch 'origin/master' into hybridization-gpu 2025-03-28 11:46:53 -07:00
Will Pazner 001f6e6137 Fix H(div) Element Assembly unit test with CUDA 2025-03-28 11:34:28 -07:00
Tzanio Kolev d5a0e90e11 Merge branch 'master' into reduction 2025-03-28 08:41:23 -07:00
Tzanio Kolev 99f88877e6 Merge pull request #4764 from mfem/lor-markers-fix
Fix dereferencing LOR markers
2025-03-28 08:23:00 -07:00
Andrew Ho dd38d5fb80 unused label 2025-03-27 16:10:05 -07:00
Andrew Ho 9434bb5a8e moved goto from reduce 2025-03-27 16:09:26 -07:00
Andrew Ho bcbd52a318 need workspaces and reducers to share common code 2025-03-27 15:42:53 -07:00
Andrew Ho a0fd156f64 cleanup execution paths
cuda/hip/cpu/debug should take very similar execution paths now.

Added missing HostRead to Vector::operator*(const real_t*) and updated
documentation
2025-03-27 15:39:07 -07:00
Andrew Ho 458348a217 revert all mem_manager changes from dynamic shared memory stuff 2025-03-27 14:44:29 -07:00
Andrew Ho 746ff7813b Merge remote-tracking branch 'base/master' into reduction 2025-03-27 14:40:05 -07:00
Andrew Ho 0120b8d50a Fixed doxygen errors 2025-03-27 14:34:24 -07:00
Veselin Dobrev 91b624b9ec Merge pull request #4746 from mfem/umpire-with-external-fmt
Support Umpire with external FMT
2025-03-27 13:56:13 -07:00
Will Pazner 359387131d Merge pull request #4738 from mfem/external-macros
External macros
2025-03-27 13:30:50 -07:00
Will Pazner ad3c02a99c Fix dereferencing LOR markers 2025-03-27 10:18:29 -07:00
Vladimir Z Tomov af8fd2bdb8 minor 2025-03-27 09:50:20 -07:00
Vladimir Z Tomov 640042d6f9 style 2025-03-27 09:39:04 -07:00
Vladimir Z Tomov a954093bad Fixed MinDetJpr() for displacements (it was forgotten). 2025-03-27 09:37:51 -07:00
Vladimir Z Tomov 94d7d2fd0a Merge branch 'master' into tmop-periodic 2025-03-27 09:08:04 -07:00
Will Pazner b91255d889 Allow RAJA kernels with zero size 2025-03-26 17:05:13 -07:00
Will Pazner 4979dc1701 Small style fixes 2025-03-26 15:03:05 -07:00
Tzanio Kolev 98834ea898 Synchronize the list of source direcrtories in the following files:
1. CONTRIBUTING.md
2. doc/CodeDocumentation.conf.in
3. makefile

Adding fem/moonolith in the last one exposed building issues that were fixed
(the MOONOLITH sources were not skipped when building without it).
2025-03-26 14:35:27 -07:00
Tzanio Kolev 6558b84cb2 Merge branch 'master' into hybridization-gpu 2025-03-26 13:44:31 -07:00
Tzanio Kolev 6b23a6bb26 Merge pull request #4739 from mfem/hybridization-gpu-ext-bdr-int
Restored external boundary constraints integrators in [gpu-hybridization]
2025-03-26 13:43:12 -07:00
Tzanio Kolev dc7c8fb6d7 Merge branch 'master' into mfem-4.8-dev 2025-03-26 12:20:40 -07:00
Tzanio Kolev d1b85413f5 Merge pull request #4691 from mfem/issue_4403
Small fixes for (ND,RT)_R(1,2)D visualization [issue_4403]
2025-03-26 10:23:41 -07:00
Tzanio Kolev 25c2975d86 Merge pull request #4038 from mfem/ppr
Parallel p-refinement
2025-03-25 20:13:44 -07:00
Tzanio Kolev 53b047c906 Merge pull request #4460 from mfem/pyramid-dev
Arbitrary order bases on Pyramids [pyramid-dev]
2025-03-25 19:27:57 -07:00
Tzanio Kolev d43343b629 Merge branch 'master' into ppr 2025-03-25 19:03:59 -07:00
Tzanio Kolev 157de7e776 Merge pull request #4486 from mfem/MMA_PR
Method of Moving Asymptotes
2025-03-25 19:02:33 -07:00
Will Pazner 337ad6b26d Merge remote-tracking branch 'origin/master' into hybridization-gpu
# Conflicts:
#	tests/unit/fem/test_bilinearform.cpp
2025-03-25 11:38:02 -07:00
Will Pazner 6dfb871840 Remove unneeded virtual 2025-03-25 11:32:44 -07:00
Will Pazner 5bc8702b6d Fix typo 2025-03-25 11:32:37 -07:00
Stowell, Mark L. 4f1bcca3b1 Updating CHANGELOG 2025-03-25 11:25:22 -07:00
Tzanio Kolev 3afd220361 styling 2025-03-24 18:50:50 -07:00
Andrew Ho bd91fb1317 Merge branch 'master' into external-macros 2025-03-24 13:10:21 -07:00
Will Pazner a5f883bf12 Merge pull request #4755 from mfem/sli-cheby-additions
Small additions in `SLISolver` and `OperatorChebyshevSmoother`
2025-03-24 12:57:45 -07:00
Will Pazner 8524697c43 Merge pull request #4737 from mfem/fix-4732
fix for #4732
2025-03-24 12:57:32 -07:00
Will Pazner d98920592c Merge pull request #4743 from mfem/fix-mpi_integer
Fix MPI data types
2025-03-24 12:57:19 -07:00
Vladimir Z Tomov ae400812cf style 2025-03-24 12:39:38 -07:00
Vladimir Z Tomov 31c50b0df8 Aded periodic-tri.mesh. 2025-03-24 12:35:18 -07:00
Vladimir Z Tomov 6bef88f661 Allow NodalFiniteElements in ElementRestriction. 2025-03-24 11:14:16 -07:00
Tzanio Kolev 565829126e Merge branch 'master' into pyramid-dev 2025-03-24 09:28:24 -07:00
Tzanio Kolev 589403aae2 Merge branch 'master' into ppr 2025-03-24 09:27:52 -07:00
Andrew Ho 8cc350380b Merge branch 'master' into dev-inverse-transform 2025-03-24 06:30:52 -07:00
Andrew Ho 979cf18e6c Merge branch 'master' into external-macros 2025-03-24 06:29:46 -07:00
Andrew Ho fce20d5b0a Merge branch 'master' into reduction 2025-03-24 06:29:18 -07:00
Vladimir Z Tomov beb78bfddd Review comments. 2025-03-23 23:02:13 -07:00
dylan-copeland 1c6e0a6cf8 Increase tolerance for single precision build. 2025-03-20 20:21:56 -07:00
Veselin Dobrev 0a0117d4bc In SLISolver::Mult, support optimized handling of the case b = 0 by
providing empty b (i.e. b.Size() == 0) as the input; this is allowed
only in iterative mode where it makes sense for smoothing operations.

In class OperatorChebyshevSmoother, in the constructor using the
power method to estimate the maximal eigenvalue, add an optional
random seed parameter used to initialize the starting random vector.

Fix a warning in mfem::internal::sqrt for dual numbers.

Fix a doxygen warning in the definition of SparseMatrix::handle.
2025-03-20 19:55:47 -07:00
Andrew Ho f8c68782b6 update changelog 2025-03-19 15:44:19 -07:00
Tom StittandVeselin Dobrev cf821ea682 Update config/defaults.mk
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2025-03-19 12:14:27 -07:00
Mittal, Ketan fd451123c9 Merge branch 'master' of https://github.com/mfem/mfem into tmop-periodic 2025-03-19 09:11:04 -07:00
Tzanio Kolev eb39463b86 Merge pull request #4702 from mfem/VectorDiffusionIntegrator
VectorDivergenceIntegrator on surface meshes
2025-03-18 20:06:39 -07:00
Tzanio Kolev b8da77edd5 Merge branch 'master' into mfem-4.8-dev 2025-03-18 19:37:25 -07:00
Tzanio Kolev 5a5be923a3 Merge branch 'master' into VectorDiffusionIntegrator 2025-03-18 18:58:05 -07:00
Tzanio Kolev 3fcceb4aeb Merge pull request #4694 from mfem/tmop-delta
TMOP - solve for displacements
2025-03-18 18:57:27 -07:00
Tom Stitt fc807c84d7 Use fes_lor_scalar instead of fes_lor so that we don't do operations on uninitialzed memory, which may lead to floating point exceptions 2025-03-18 13:48:48 -07:00
Tom Stitt 7abbfe3846 also include FMT_DIR/lib64 2025-03-18 12:19:07 -07:00
linke2 1634aa538e consistent constructors, MMASubSvanberg renaming 2025-03-18 09:51:21 -07:00
Andrew Ho ffee08a1ac Merge branch 'master' into reduction 2025-03-18 09:49:17 -07:00
linke2 8a1640725b changed constructor list 2025-03-17 20:19:42 -07:00
linke2 3b536d765c added parallel constructor (unconstrained) 2025-03-17 17:46:52 -07:00
linke2 d47b17c968 enhanced documentation 2025-03-17 17:26:27 -07:00
linke2 f78553cc86 updated unit test 2025-03-17 17:07:49 -07:00
Tom Stitt f3d0946c5e When Umpire is configured with an external fmt we need to specify FMT_DIR and include extra include and link flags for Umpire 2025-03-17 15:21:56 -07:00
Andrew Ho 46f27fc8bb Merge remote-tracking branch 'base/master' into dev-inverse-transform 2025-03-17 14:46:55 -07:00
Andrew Ho a2949dc8fd revert forall changes
the 1D batching was only used for initial testing, could be in a separate
PR if needed.
2025-03-17 14:45:59 -07:00
Mathias Rainer Schmidt 04e70e9c7c - changed comments 2025-03-17 14:18:48 -07:00
Andrew Ho 8b103e1215 changed tests to pass mesh directly 2025-03-17 13:51:17 -07:00
Andrew Ho e386c1a655 Default to closed uniform points for edgescan if btype is invalid
Update documentation
2025-03-17 13:33:07 -07:00
Andrew Ho 52eb4ff76e Added more tests 2025-03-17 11:14:54 -07:00
linke2 4d648556e6 - added verbosity level
- corrected unit test
- correct error reporting
2025-03-16 20:20:15 -07:00
linke2 29276d0b0c fixed typo 2025-03-14 20:34:26 -07:00
linke2 ade5ef80f4 commit checks 2025-03-14 19:37:32 -07:00
linke2 03d23a3fcf - finalized header file
- updated comments in .cpp, .hpp, unit-test
2025-03-14 18:42:19 -07:00
Vladimir Z Tomov 0ccc9b7346 comment 2025-03-14 17:48:30 -07:00
Andrew Ho 7344659f4b added comment explaining not using MPI_CXX_BOOL directly 2025-03-14 17:28:54 -07:00
Vladimir Z Tomov 26f4d3927c Changes in mesh-optimizer.cpp.
Fixed a bug in serial + PA + CG advector.
2025-03-14 17:28:03 -07:00
Mathias Rainer Schmidt f21d9518ac - updated unit tests
- moved iteration counter into MMA
2025-03-14 16:18:02 -07:00
Andrew Ho f3360ac118 switch to MFEM_MPI_CXX_BOOL
This is an internal macro which switches between MPI_CXX_BOOL and
MPI_C_BOOL if MPI_CXX_BOOL happens to not be defined (ex.: in Windows).
2025-03-14 14:19:17 -07:00
Mathias Rainer Schmidt a2046cc42e - deleted MMAOpt
- added function call for un-constraint optimization
- added unit test for un-contraint optimizaiton
2025-03-14 12:39:40 -07:00
dylan-copeland 7caef9cb33 CUDA build bug fix. 2025-03-14 10:24:42 -07:00
Andrew Ho 940943268b replace MPI_C_BOOL with MPI_CXX_BOOL 2025-03-14 10:06:57 -07:00
Andrew Ho bbdcb2a70f Merge branch 'master' into external-macros 2025-03-14 08:52:52 -07:00
Andrew Ho 0790d37990 Merge branch 'master' into fix-4732 2025-03-14 08:52:42 -07:00
Brendan Keith cfe9f14900 Merge branch 'master' into VectorDiffusionIntegrator 2025-03-14 11:05:34 -04:00
Brendan Keith cd0b3e23ee revert ex40.cpp 2025-03-14 11:04:08 -04:00
adam-sim-dev a2c2292ff2 Merge branch 'master' into ppr 2025-03-14 11:49:55 +08:00
Mark L. Stowell 7c7aed6764 Merge branch 'master' into pyramid-dev 2025-03-13 17:15:10 -07:00
Andrew Ho 1fc980db10 Change MPI_INTEGER to MPI_INT
MPI_INTEGER is intended to represent Fortran integers. MPI_INT is for
C/C++, which may be different.
2025-03-13 17:14:23 -07:00
Stowell, Mark L. 36204b0668 Removing unused variable from integration rule special case 2025-03-13 15:05:10 -07:00
Stowell, Mark L. 9cf6b614d5 Fixing integration point for 1 point quadrature 2025-03-13 15:01:12 -07:00
Vladimir Z Tomov f6e8d72851 minor 2025-03-12 19:25:26 -07:00
Vladimir Z Tomov f71553f6db minor 2025-03-12 18:28:27 -07:00
Vladimir Z Tomov ee0aa9bca7 renamed variables 2025-03-12 18:12:09 -07:00
Vladimir Z Tomov c604c9a098 renamed d -> dx 2025-03-12 18:03:04 -07:00
Andrew Ho 2ced1ceb84 Re-arranged interface to UpdateNodes from a GridFunction
Added tests for 2D embedded in 3D and 3D mesh
2025-03-12 17:42:45 -07:00
Vladimir Z Tomov edf2614651 minor 2025-03-12 17:33:57 -07:00
Vladimir Z Tomov 36a687fcb1 style 2025-03-12 16:59:15 -07:00
Vladimir Z Tomov 3cf8d47182 unused function 2025-03-12 16:39:29 -07:00
Vladimir Z Tomov 6210ea712d changed some L2-H1p transitions. 2025-03-12 16:35:00 -07:00
Dylan Copeland 9fd16ab65d Another bug fix for mixed meshes. 2025-03-12 16:32:12 -07:00
Stowell, Mark L. 66a543a91a Merge branch 'pyramid-dev' of github.com:mfem/mfem into pyramid-dev 2025-03-12 16:29:39 -07:00
Stowell, Mark L. cc7c996425 Adjusting pyramid integration rules and related data 2025-03-12 16:27:58 -07:00
Stowell, Mark L. ac39347119 Reducing the size of the inline-pyramid mesh 2025-03-12 16:26:39 -07:00
Dylan Copeland b56959d59e Merge branch 'ppr' of github.com:mfem/mfem into ppr 2025-03-12 13:50:21 -07:00
Dylan Copeland 62323926b0 Bug fix for mixed meshes. 2025-03-12 13:49:45 -07:00
Andrew Ho 3b1e054c71 revert MFEM_GPU_CHECK
this change is now in a separate PR
2025-03-12 13:32:57 -07:00
Andrew Ho 0ba5eb8422 MFEM_GPU_CHECK fixes
Spelling out ::mfem enables use of this macro (and macros that call
MFEM_GPU_CHECK) in external codes.

Changed the internal variable name to something somewhat obfuscated as
before MFEM_GPU_CHECK(err) would cause compiler errors.
2025-03-12 13:25:42 -07:00
Tzanio Kolev f737d30630 Merge branch 'master' into reduction 2025-03-12 13:14:03 -07:00
Tzanio Kolev b6a0ef770a Merge branch 'master' into issue_4403 2025-03-12 13:13:53 -07:00
Tzanio Kolev 70557e1f14 Merge branch 'master' into VectorDiffusionIntegrator 2025-03-12 13:13:47 -07:00
Andrew Ho e58c14da9c ensure that hypre cmake vars are correctly set 2025-03-12 13:13:27 -07:00
Tzanio Kolev 080ee85544 Merge branch 'master' into dev-inverse-transform 2025-03-12 13:13:17 -07:00
Tzanio Kolev 780d2be2d8 Merge branch 'master' into MMA_PR 2025-03-12 13:13:07 -07:00
Tzanio Kolev b42e537101 Merge branch 'master' into pyramid-dev 2025-03-12 13:13:04 -07:00
Tzanio Kolev f99c7feb53 Merge branch 'master' into ppr 2025-03-12 13:12:51 -07:00
Tzanio Kolev dd43d1fa3c Merge branch 'master' into hybridization-gpu 2025-03-12 13:12:18 -07:00
Andrew Ho 2635018243 explicitly spell out ::mfem namespace in macro
this allows external codes to use MFEM_REGISTER_KERNELS without
injecting into the mfem namespace or having using namespace mfem;
2025-03-12 12:56:34 -07:00
Andrew Ho daa2fe7c98 forall is no longer required in gslib
was only used for test tracking of number of iterations
2025-03-12 11:50:11 -07:00
Vladimir Z Tomov 98ae71ab6d Updated PA.XO in AssemblePA 2025-03-12 11:40:31 -07:00
Andrew Ho cd799dba86 removed ::mfem in batchitrans
isn't needed here
2025-03-12 11:32:21 -07:00
Andrew Ho 00008800b8 fixed typo 2025-03-12 11:11:29 -07:00
Stowell, Mark L. d2cce0a4e5 Merge branch 'pyramid-dev' of github.com:mfem/mfem into pyramid-dev 2025-03-12 10:20:12 -07:00
Stowell, Mark L. 6c1cd2f64b Improvements to comments 2025-03-12 10:19:22 -07:00
Vladimir Z Tomov 52e5d573bf Merge branch 'tmop-delta' into tmop-periodic 2025-03-12 10:06:36 -07:00
Vladimir Z Tomov e7f8bbbd85 Merge branch 'master' into tmop-delta 2025-03-12 09:46:19 -07:00
Vladimir Z Tomov 60eb10c5d7 reviewer comments. 2025-03-12 09:45:50 -07:00
Vladimir Z Tomov 63b141992d minor 2025-03-12 09:28:38 -07:00
Jan Nikl 3086f877c2 Changed extern bdr constr integs to std::vector. 2025-03-11 22:58:13 -07:00
Jan Nikl c35eee7742 Reverted the changes of external bdr constraint integrators. 2025-03-11 22:23:51 -07:00
Tzanio Kolev 56bd1da125 Updated CHANGELOG 2025-03-11 18:15:29 -07:00
Tzanio Kolev dc5e0b0c63 Merge branch 'master' into mfem-4.8-dev 2025-03-11 18:09:34 -07:00
dylan-copeland 64688f369f CHANGELOG 2025-03-11 17:13:02 -07:00
Vladimir Z Tomov e46c3929d1 periodic sample runs and 3D mesh. 2025-03-11 16:01:53 -07:00
Tzanio Kolev fc53b03b5c Merge branch 'master' into mfem-4.8-dev
Conflicts:
	CHANGELOG
2025-03-11 14:59:24 -07:00
Andrew Ho b938d99486 revert change made for tracking step count 2025-03-11 12:19:37 -07:00
Vladimir Z Tomov 859f15088c aborted periodic fitting, fixed the adaptive limiting. 2025-03-11 10:45:10 -07:00
Vladimir Z Tomov 53c1a9de7d Periodic PA. 2025-03-10 10:55:45 -07:00
adam-sim-dev 3dae59b3df Merge branch 'master' into ppr 2025-03-10 16:48:20 +08:00
Patrick Zulian 4c8174c71c Merge branch 'master' into moonolith_h1_bugfix 2025-03-07 18:58:26 -06:00
Dylan Copeland f97b4339d8 Merge branch 'master' of github.com:mfem/mfem into ppr 2025-03-06 20:37:56 -08:00
Dylan Copeland fc63c5e90b Documentation and some simplifications. 2025-03-06 20:37:44 -08:00
Jan Nikl 9212cd91d3 Merge pull request #4731 from mfem/issue_4403-glvis
Fixes for GLVis support of RT/ND_R1/2D elements.
2025-03-06 16:01:09 -08:00
Mittal, Ketan 3aed767737 update findpts miniapp for new interface, and set want_transform to true by default in PRefineAndUpdate 2025-03-06 14:19:37 -08:00
Jan Nikl 0354670dab Cleaned decoding of dofs in GridFunction::ProjectVectorFieldOn. 2025-03-06 02:24:28 -08:00
Jan Nikl dea5c1ef15 Fixed Mesh::SetCurvature() to update vertices when space dimensions change. 2025-03-05 19:21:18 -08:00
Ketan Mittal d7f3fde747 Merge branch 'master' into tmop-delta 2025-03-05 09:43:30 -06:00
Brendan Keith 87e9aacde3 Merge branch 'master' into VectorDiffusionIntegrator 2025-03-03 20:46:28 -05:00
Stowell, Mark L. 97b2561289 Adding comments with paper citations to new basis function classes 2025-03-03 15:55:22 -08:00
Andrew Ho 98b1a68c59 Merge branch 'master' into dev-inverse-transform 2025-03-03 15:11:23 -08:00
Andrew Ho cba0b592ca don't optionally track num steps in gslib
this has extra cost even when not used
2025-03-03 15:09:30 -08:00
adam-sim-dev b5ad6241e2 Merge branch 'master' into pyramid-dev 2025-03-03 03:22:22 +08:00
Jan Nikl 06e6cdc94d Updated GridFunction::ProjectVectorFieldOn() for RT/ND_R1/2D elements. 2025-03-01 12:16:07 -08:00
Jan Nikl c1d0e50948 Revert "Modify examples 31 and 32 to produce surface meshes"
This reverts commit af30acae94.
2025-03-01 11:58:39 -08:00
Dylan Copeland 4153ae8584 Made UpdatePRef a protected function. 2025-02-28 09:51:39 -08:00
Vladimir Z Tomov e024892d8e abort InterpolatorFP for periodic meshes. 2025-02-27 18:21:50 -08:00
Andrew Ho c633d5bf0e fixed name overloading and use of block_id 2025-02-27 15:52:09 -08:00
Andrew Ho 83efa2e336 use integral_constant to sneak a host-only constexpr function call
into device code
2025-02-27 15:45:58 -08:00
Andrew Ho 416ed22555 changed to use a fixed max buffer size, removed dynamic shared memory forall 2025-02-27 15:18:35 -08:00
Vladimir Z Tomov 88be18f03c Periodic advective adaptivity. 2025-02-27 13:22:41 -08:00
Mittal, Ketan b2a50919b9 remove numbering from comments in tmop miniapps 2025-02-27 10:45:34 -08:00
Mittal, Ketan edd8bd98f0 Fix ComputeMinDet for variable order in TMOP 2025-02-27 09:40:18 -08:00
adam-sim-dev add0e99d9d Merge branch 'master' into ppr 2025-02-27 22:27:34 +08:00
Andrew Ho 67850da1f7 inline static internal device functions 2025-02-26 19:23:55 -08:00
adam-sim-dev 57e99ba620 Merge branch 'master' into ppr 2025-02-27 08:38:32 +08:00
Dylan Copeland 8bb331cefa Check for variable-order space in ElementRestriction. 2025-02-26 16:11:16 -08:00
Vladimir Z Tomov 92fa66c5d4 restored HR-adapt and FD for non-periodic. 2025-02-26 16:02:34 -08:00
Vladimir Z Tomov f671f7c453 restored surface fitting for non-periodic meshes 2025-02-26 13:56:09 -08:00
Andrew Ho a9ebb665f7 merged reduction cpu and gpu unit tests 2025-02-26 12:39:41 -08:00
Andrew Ho 051fc969ab change reduction API
reducer.join -> reducer.Join
reducer.init_val -> reducer.SetInitialValue

Changed the default reducers Join and SetInitialValue to static member
functions, but still allow calling these as member functions for LpReducer
2025-02-26 12:39:29 -08:00
Andrew Ho 253ebf4e2f fix compiler error in Device which also defines the symbol err 2025-02-26 12:34:57 -08:00
Andrew Ho 5a65c4ee58 Merge branch 'master' into reduction 2025-02-26 10:50:46 -08:00
Stowell, Mark L. acb01b6e29 Fix for negative Jacobians 2025-02-25 11:44:13 -08:00
Andrew Ho 52c1a3c0b8 fixed element dof indexing 2025-02-24 12:16:38 -08:00
Andrew Ho b360a4e68b Merge branch 'master' into dev-inverse-transform 2025-02-24 07:03:05 -08:00
Andrew Ho 83f553f4a9 fixed non-power of 2 team sizes
these fail during the tree reduction steps
2025-02-24 02:14:44 -08:00
Andrew Ho 5f4d49691b added tests for batch inverse element transform 2025-02-23 23:54:21 -08:00
adam-sim-dev 632c6e34e1 Merge branch 'master' into ppr 2025-02-23 08:34:32 +08:00
Vladimir Z Tomov 012036d007 Periodic limiting. 2025-02-21 17:35:58 -08:00
Andrew Ho a7676c6443 Merge branch 'master' into dev-inverse-transform 2025-02-21 09:12:10 -08:00
Andrew Ho bcde2ec4f1 fixed step counting in findpts for some cases 2025-02-21 06:51:50 -08:00
Rick 19507830f0 Add [RT|ND]_R[2|3]D to Doxygen for FiniteElementCollection::New
As suggested by @paul-hilscher
2025-02-21 10:18:14 +01:00
adam-sim-dev 777efb0582 Merge branch 'master' into ppr 2025-02-21 16:53:50 +08:00
Vladimir Z Tomov 8f42d760fc initial working version for periodic meshes. 2025-02-20 22:38:38 -08:00
Andrew Ho cdbc8c710c implemented iteration count tracking in findpts and batch element transformations 2025-02-20 18:57:47 -08:00
Andrew Ho 76525c8ce3 working towards adding diagnostic for number of steps required in gslib
I think MPI support still needs to be added?
2025-02-20 13:27:46 -08:00
Will Pazner f6d100b119 Merge remote-tracking branch 'origin/master' into hybridization-gpu 2025-02-20 12:18:05 -08:00
Will Pazner f7a5a79d34 Add missing include 2025-02-20 10:06:45 -08:00
Stowell, Mark L. 63022c131a Lowering integration rule order 2025-02-20 09:48:38 -08:00
Will Pazner 53365490b7 Merge remote-tracking branch 'origin/master' into hybridization-gpu
# Conflicts:
#	tests/unit/fem/test_assembly_levels.cpp
2025-02-20 09:12:41 -08:00
Andrew Ho c75c5f2ea8 added optimization for guesses co-located at dofs
this matches findpts, seems like a worthwhile performance upgrade in
most situations over center
2025-02-20 05:15:46 -08:00
Vladimir Z Tomov c97450809d Switched TMOPNewtonSolver::x_0 to a GridFunction. 2025-02-19 22:08:37 -08:00
Andrew Ho 34ea1d5b07 fixed batch edgescan
Adding a native nodal DOFs init guess type would work well for some elements
2025-02-19 20:58:58 -08:00
Andrew Ho d1f560d652 implemented batch edgescan
Could have a smarter traversal order
2025-02-19 17:29:40 -08:00
Dylan Copeland cbe0582fe3 Merge branch 'ppr' of github.com:mfem/mfem into ppr 2025-02-19 17:01:22 -08:00
Dylan Copeland 7fe4c3c199 Bug fixes. 2025-02-19 17:01:09 -08:00
adam-sim-dev 779c17c86d Merge branch 'master' into ppr 2025-02-20 08:27:38 +08:00
Andrew Ho 8048e1d433 return the element result from InvTNewtonSolver
this allows an EdgeScan to re-use the same solver code
2025-02-19 15:10:22 -08:00
Stowell, Mark L. ced77961a5 Removing unnecessary argument assignments 2025-02-19 11:18:39 -08:00
Stowell, Mark L. 68eb708311 Hiding pyramid option in display-basis 2025-02-19 10:59:41 -08:00
Andrew Ho 5144997003 Merge branch 'master' into dev-inverse-transform 2025-02-19 10:32:25 -08:00
Andrew Ho c322d7cbb0 using max_q1d speeds up physnode initial guess finder 2025-02-19 01:59:17 -08:00
Andrew Ho baa2c246f9 changed newtonsolve parallelization strategy
uses a lot less shared memory, hopefully performs better. Need to tune
max_team_x.
2025-02-18 17:57:47 -08:00
adam-sim-dev 1a32b51338 Merge branch 'master' into ppr 2025-02-19 08:36:55 +08:00
Stowell, Mark L. ca1915983d Removing old commented special cases for pyramids 2025-02-18 15:38:12 -08:00
Stowell, Mark L. d1cbdf0766 Removing commented code 2025-02-18 15:35:45 -08:00
Stowell, Mark L. ba63e32ded Reverting makefile changes 2025-02-18 15:30:12 -08:00
Stowell, Mark L. 82e260ab3a Cleaning up argument alignments 2025-02-18 15:15:13 -08:00
Andrew Ho 337dd7c274 changed loop order
try to improve memory access pattern
2025-02-15 08:26:58 -08:00
Andrew Ho 6f3ecfe129 fixed 3d cube linsolve 2025-02-14 20:27:40 -08:00
Andrew Ho 7514594c32 fixed documentation 2025-02-14 12:58:54 -08:00
Andrew Ho ccdaa48f69 batch inverse element transformation should now work for all square and cube element geometries
assumes that evaluating at GLL nodes is equivalent, which I think for
NURBS meshes is not true
2025-02-14 12:32:09 -08:00
Andrew Ho 5b3cbad98c Merge branch 'master' into dev-inverse-transform 2025-02-14 09:01:57 -08:00
Andrew Ho 490b60c272 re-arrangement to make doxygen happy 2025-02-14 00:01:53 -08:00
Andrew Ho 3b5c10c1b3 documentation and formatting 2025-02-13 20:00:27 -08:00
Andrew Ho 9aaa7f13a3 fixed -Wall -Werror for some config options 2025-02-13 16:46:51 -08:00
adam-sim-dev 71f45d285c Merge branch 'master' into ppr 2025-02-14 08:40:57 +08:00
Brendan Keith 8c1dd9faca _r 2025-02-13 19:00:52 -05:00
Brendan Keith 4fea4ee7f6 support for VectorDiffusionIntegrator on surface meshes 2025-02-13 18:05:17 -05:00
Andrew Ho 07605d3097 fixed compile bugs wtih various configurations 2025-02-13 14:58:55 -08:00
Andrew Ho 02aed483e6 fixed newtonsolver 2025-02-13 09:20:16 -08:00
Andrew Ho facb0b5434 implemented newtonproject solves 2025-02-12 22:25:00 -08:00
Andrew Ho cb32b5ee8e implemented square element newton project solve 2025-02-12 21:00:46 -08:00
Vladimir Z Tomov 987203005d minor 2025-02-12 16:06:17 -08:00
Andrew Ho cd50b6b806 setup infrastructure for calling newtonsolve
still need to implement remaining specializations
2025-02-12 13:40:44 -08:00
Andrew Ho 74ef6490a7 implemented elementproject for segments 2025-02-12 13:09:14 -08:00
Andrew Ho f963df773c implemented raw newton solve for segments 2025-02-12 12:52:33 -08:00
Andrew Ho 31786ff0e0 enabled specifying 1D forall thread block size
left as an optional param
2025-02-12 11:15:41 -08:00
Vladimir Z Tomov 7275a2fbab Merge branch 'master' into tmop-delta 2025-02-11 15:59:16 -08:00
Vladimir Z Tomov b13fb27f7e minor 2025-02-11 15:57:49 -08:00
Vladimir Z Tomov e55d0882c3 Reverted testing code. 2025-02-11 15:52:22 -08:00
Dylan Copeland 4d21ab6a4d Type fix. 2025-02-11 15:49:21 -08:00
Vladimir Z Tomov 34fb676fd5 reverted testing code. 2025-02-11 15:42:33 -08:00
Dylan Copeland a55d495f1f Verify that space can be p-refined. 2025-02-11 15:39:51 -08:00
Vladimir Z Tomov f6efa8ea54 Fixed the FD displacements. 2025-02-11 15:24:43 -08:00
Dylan Copeland f0c0994a4e Unused variables. 2025-02-11 13:35:37 -08:00
Dylan Copeland e192397308 Merge branch 'master' of github.com:mfem/mfem into ppr 2025-02-11 13:13:22 -08:00
Dylan Copeland f519d59644 More documentation. Simplified ProlongateToMaxOrder and GridFunction updates. 2025-02-11 13:12:57 -08:00
Andrew Ho 3c17ed88c5 fixed some bugs
switched qaud1d type with basis type
fixed computing coordinate interpolation not summing basis values
2025-02-11 11:56:25 -08:00
Andrew Ho 159f8a1404 changed copyright years 2025-02-11 11:12:26 -08:00
Andrew Ho 0a754a78b9 implemented tensor basis optimization 2025-02-11 11:11:34 -08:00
Vladimir Z Tomov 3cf27e9243 It's better to separated x_0 and x_limiting. 2025-02-11 10:57:09 -08:00
Vladimir Z Tomov a3cf3f4bb2 Full support for solving displacements, including PA, with old interface. 2025-02-11 09:31:51 -08:00
Andrew Ho 35f508ca8c fixed bugs in batch closestphysnode kernel
still could perform better...
2025-02-11 00:31:06 -08:00
adam-sim-dev a9f4652335 Merge branch 'master' into ppr 2025-02-11 14:23:22 +08:00
Tzanio Kolev a2de8287c7 Merge branch 'master' into mfem-4.8-dev 2025-02-10 19:10:35 -08:00
Andrew Ho acea00376b fixed serial reduction save index
should be the thread x id, not just i
2025-02-10 12:36:27 -08:00
Andrew Ho 13fed2e691 implemented PhysNodeFinder for tensor elements 2025-02-10 12:25:19 -08:00
Andrew Ho 1332ba5ee7 stride_sdim needs all element dofs, not just ndof1d 2025-02-10 12:17:14 -08:00
Andrew Ho a252286472 implemented ClosestPhysNodeImpl for segments in SDim 2025-02-10 12:10:31 -08:00
Andrew Ho 8bab223de4 switched init condition kernels to template on geometry instead of dim 2025-02-10 11:52:33 -08:00
Andrew Ho 96392055d6 think I want separate kernels per geometry shape 2025-02-10 10:13:53 -08:00
Andrew Ho 36f1b769c5 specialize on device vs. non-device 2025-02-09 08:36:30 -08:00
Andrew Ho 3e074b3c7e implemented refinement points for batch itransform 2025-02-09 08:31:24 -08:00
Andrew Ho d8773cad73 initialize batch inverse transformation kernels in setup
this is guaranteed to be called before the kernels are used
2025-02-09 07:44:14 -08:00
Andrew Ho 773606139c Merge remote-tracking branch 'base/master' into dev-inverse-transform 2025-02-09 07:35:58 -08:00
Andrew Ho b1f7cb2766 moved batch inverse transform implementation into separate cpp file 2025-02-09 07:34:37 -08:00
Vladimir Z Tomov df47dd65c1 TMOP_Integrator defined w.r.t. displacements. 2025-02-08 09:32:41 -08:00
Rick af30acae94 Modify examples 31 and 32 to produce surface meshes
In the examples where ND_R1D / ND_R2D spaces are used, make sure
that the mesh that is being written for glvis visualization is
embedded in 3D space.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch issue_4403
# Your branch is up to date with 'origin/issue_4403'.
#
# Changes to be committed:
#	modified:   examples/ex31.cpp
#	modified:   examples/ex31p.cpp
#	modified:   examples/ex32p.cpp
#
# Untracked files:
#	.vscode/
#
2025-02-08 15:56:31 +01:00
Andrew Ho c102d5ecf6 use HUGE_VAL in findpts_local_2
CUDA requires --expt-relaxed-constexpr to call host only constexpr
functions from device code
2025-02-08 01:06:11 -08:00
Will Pazner b1cf2dfe9a Update copyright year 2025-02-07 16:32:57 -08:00
bslazarov c0479e88fc solver interface 2025-02-07 14:47:19 -08:00
Will Pazner e797278779 Merge remote-tracking branch 'origin/master' into hybridization-gpu
# Conflicts:
#	fem/integ/bilininteg_mass_pa.cpp
#	tests/unit/fem/test_assembly_levels.cpp
2025-02-07 14:24:06 -08:00
Andrew Ho 422a752600 Working on GPU-callable code for implementing inverse element transforms 2025-02-07 01:03:27 -08:00
Andrew Ho 2ab1ae4ff6 changed EdgeScan to repeat solve for multiple initial guesses
NewtonElementProject is actually really good, make use of it
2025-02-06 22:01:59 -08:00
Vladimir Z Tomov b5826ff9d5 pass initial positions to integrators. 2025-02-06 16:45:09 -08:00
Stowell, Mark L. a7dcc17d63 Updating copyright dates to 2025 2025-02-06 14:52:52 -08:00
Stowell, Mark L. f5b73dbaeb Merge remote-tracking branch 'origin/master' into pyramid-dev 2025-02-06 14:48:03 -08:00
Andrew Ho df3be0125c working on finding good guesses which can make progress 2025-02-06 12:14:03 -08:00
Vladimir Z Tomov 10c6c8ad22 Simpler computation of x_loc. 2025-02-05 14:35:14 -08:00
Dylan Copeland 4c62788e60 Merge branch 'master' of github.com:mfem/mfem into ppr 2025-02-04 16:18:17 -08:00
Andrew Ho ab36b3caae style 2025-02-04 15:33:23 -08:00
Andrew Ho be659ae4b6 implemented EdgeScan guesser for inverse transforms 2025-02-04 15:32:18 -08:00
Andrew Ho 5ceda33e57 implemented edgescan
fixed hash finalization infinite recursion
2025-02-04 15:13:29 -08:00
Tzanio Kolev 2189509521 Merge branch 'master' into MMA_PR 2025-02-04 14:53:58 -08:00
Tzanio Kolev 2ceee164c5 Merge branch 'master' into pyramid-dev 2025-02-04 14:53:54 -08:00
Tzanio Kolev 1f3790ba2c Merge branch 'master' into reduction 2025-02-04 14:53:21 -08:00
Andrew Ho 38aaa74b52 added API for retrieving underlying array in Poly_1D 2025-02-04 11:49:26 -08:00
Andrew Ho f6e0903d60 changed how bases_container stores the cache 2025-02-04 11:16:52 -08:00
Tzanio Kolev a077bb3a43 Update CHANGELOG 2025-02-03 11:11:03 -08:00
Tzanio Kolev 828dee43f6 Merge branch 'master' into mfem-4.8-dev 2025-02-03 11:04:57 -08:00
Tzanio Kolev 907213b3aa Initial CHANGELOG for mfem-4.8 2025-02-03 09:51:49 -08:00
Tzanio Kolev 3eae5645ae Initial changes for mfem-4.8 2025-02-03 09:24:31 -08:00
Andrew Ho 2f6c1d9b6a added helpers for evauating basis functions on device 2025-01-31 16:29:58 -08:00
Andrew Ho 7717cc5e6c cleanup 2025-01-31 16:17:29 -08:00
Andrew Ho a6da18db40 changed GetPoints so you can request device or host pointers 2025-01-31 15:18:35 -08:00
Andrew Ho 4c491ae4a7 Added a helper for constructing non-cryptographic hashes for use in
hash tables
2025-01-31 15:08:51 -08:00
Stowell, Mark L. 142528c55d Removing outdated comments 2025-01-31 09:34:47 -08:00
Andrew Ho 21590c1e60 testing out increased boundary seed points in 2D
need to add configurable options for seeding, implement in 3D
2025-01-27 14:41:26 -08:00
Andrew Ho c07d124c4c Merge branch 'master' into reduction 2025-01-24 11:17:17 -08:00
Will Pazner cf69527e0a Merge remote-tracking branch 'origin/master' into par-sub-transfer-fix 2025-01-23 09:54:02 -08:00
Will Pazner 945b88c1a8 Restrict (Par)TransferMap::Transfer to grid functions 2025-01-23 09:52:56 -08:00
adam-sim-dev e186ca4e30 Merge branch 'master' into ppr 2025-01-23 21:37:14 +08:00
Dylan Copeland add7281658 Changed R to interpolate minimum order among local neighboring elements. 2025-01-22 18:09:27 -08:00
Andrew Ho 98c6b0e32f all indices should be ints 2025-01-22 17:59:58 -08:00
Andrew Ho 506c34719a should be signed int 2025-01-22 17:03:17 -08:00
Dylan Copeland 2a035e92d2 Merge branch 'master' of github.com:mfem/mfem into ppr 2025-01-22 15:12:49 -08:00
Andrew Ho eccb30bdfe unused variable warning 2025-01-22 14:24:34 -08:00
Andrew Ho 160a52a55e added reduction unit tests, fixed some bugs in reducers 2025-01-22 11:34:59 -08:00
Andrew Ho 83440de8cd also split mesh on non-tensor basis 2025-01-21 15:53:56 -08:00
Hugh Carson 6e4b512b41 Merge remote-tracking branch 'origin/master' into sjg/mfem-device-fixes 2025-01-21 14:57:17 -05:00
Andrew Ho 26ba53a52e More clearly ensure all bits are set, especially for signed integral types. 2025-01-21 11:54:54 -08:00
Tzanio Kolev 2cde33b8dd Merge branch 'master' into pyramid-dev 2025-01-21 11:47:30 -08:00
Will Pazner e2815c1864 Bug fix and improvements to (Par)TransferMap
- Fixes a bug in ParSubMesh-to-ParSubMesh ParTransferMap.
   - Implement submesh-to-submesh transfer using composition of transfer maps.
- Allow creation of transfer maps from finite element spaces (rather than grid functions).
- Allow transfer of L-vectors (rather than just grid functions).
2025-01-16 10:54:48 -08:00
Andrew Ho 0f1880a9da added documentation 2025-01-14 10:54:57 -08:00
Andrew Ho 25cfc0991d missing header includes 2025-01-13 14:32:14 -08:00
Andrew Ho cbd035e06d use compiler min/max macros instead of manual values 2025-01-13 14:08:23 -08:00
Andrew Ho 242703e266 Implemented all vector norms to run on GPU
changed to void ptr for dynamic shared memory to reduce templates
2025-01-09 23:26:12 -08:00
Andrew Ho 7ced559b0d GPU accelerate L1 and L-infinity norms 2025-01-09 17:13:08 -08:00
Andrew Ho 06d1cd025f Cleanup CPU code paths for Vector reductions 2025-01-09 16:47:09 -08:00
Andrew Ho 40f8216355 missing headers 2025-01-09 16:30:03 -08:00
Andrew Ho fc8ee486b6 allow user to specify a kernel label (for RAJA) 2025-01-09 15:12:10 -08:00
Andrew Ho 3dae2a01dc added a slightly more descriptive label for the RAJA kernels 2025-01-09 15:02:32 -08:00
Andrew Ho 3b5068ca79 missing header, formatting 2025-01-09 14:49:30 -08:00
Andrew Ho 5b145be17d implemented forall_smem for RAJA GPU backends 2025-01-09 14:17:56 -08:00
Andrew Ho 76f382eba6 make sure forall_smem cpu backup works on cuda and hip 2025-01-09 05:58:17 -08:00
Andrew Ho 6f9cbed618 fixed reduce accidentally always running the CPU backup 2025-01-08 20:26:45 -08:00
Andrew Ho aab40b23d2 implemented reduction framework
still need to add RAJA implementation for dynamic shared memory
2025-01-08 19:02:12 -08:00
adam-sim-dev b211337360 Merge branch 'master' into pyramid-dev 2025-01-09 06:10:56 +08:00
Stowell, Mark L. 6c40c5b643 Updating comment related to pyramid integration rules 2025-01-07 11:19:30 -08:00
Stowell, Mark L. 1aa9e65cfb Cleanup of experimental class 2025-01-07 11:11:04 -08:00
Brendan Keith e05523f36e Merge branch 'master' into pyramid-dev 2024-12-30 19:09:26 -05:00
Arturo Vargas 090cdf3135 Merge branch 'master' into hybridization-gpu 2024-12-18 10:14:59 -08:00
Hugh Carson dc162a194d Merge branch 'master' into sjg/mfem-device-fixes 2024-12-13 15:45:59 -05:00
Arturo Vargas dba53a19a2 Merge branch 'master' into hybridization-gpu 2024-12-12 14:58:03 -08:00
Dylan Copeland 7295d1414f Refactor using GetNumBorderDofs. 2024-12-12 13:00:36 -08:00
Dylan Copeland de1d7406ed Merge branch 'master' of github.com:mfem/mfem into ppr 2024-12-12 10:30:03 -08:00
Dylan Copeland 6c7679f7c4 Shadowed variable 2024-12-12 10:29:49 -08:00
Dylan Copeland 9139e09a30 Projection option for hpref_serial. 2024-12-12 09:55:34 -08:00
Dylan Copeland c2bde81c14 CI error 2024-12-11 16:05:51 -08:00
Dylan Copeland c6d30c5c82 Limiting non-boolean R to H1 spaces, and fixing a bug. 2024-12-11 15:50:58 -08:00
Dylan Copeland 47f6ca5693 Fix CI error. 2024-12-10 21:54:41 -08:00
Dylan Copeland 3f30c5b970 Remove unused variables. 2024-12-10 21:45:40 -08:00
Dylan Copeland 80df37426f Merge branch 'master' of github.com:mfem/mfem into ppr 2024-12-10 21:29:51 -08:00
Dylan Copeland 36be48efa9 Minor clean up 2024-12-10 21:11:37 -08:00
Dylan Copeland d2a94aa354 Eliminated non-local DOFs in parallel variable-order spaces. Implemented non-boolean restriction matrix Rvar. Added option to test vector coefficient projection in hpref miniapp. 2024-12-10 21:09:01 -08:00
Mark L. Stowell bb44da48dd Fixing more uninitialized data 2024-12-04 14:58:03 -08:00
Mark L. Stowell 6bec321019 Try that again... 2024-12-04 14:28:57 -08:00
Mark L. Stowell 62def1c528 Fixing compiler warning 2024-12-04 11:39:25 -08:00
Mark L. Stowell faf44555ba Merge branch 'pyramid-dev' of github.com:mfem/mfem into pyramid-dev 2024-12-04 11:22:56 -08:00
Mark L. Stowell 7d74666511 Adjusting error estimates in finite difference unit tests on pyramids 2024-12-04 11:21:25 -08:00
Mark L. Stowell 8046bb2cd6 Adding unit test for symmetry of pyramid finite elements 2024-12-04 11:20:13 -08:00
Mark L. Stowell 030e4b00d1 Fixing direction used for interior Nedelec DoFs 2024-12-04 11:17:30 -08:00
Will Pazner 6c2269d817 Merge remote-tracking branch 'origin/master' into hybridization-gpu
# Conflicts:
#	linalg/batched/native.cpp
2024-11-21 13:16:47 -08:00
adam-sim-dev d0b1f3f816 Merge branch 'master' into ppr 2024-11-13 10:22:48 +08:00
adam-sim-dev be444d4b38 Merge branch 'master' into ppr 2024-11-13 05:28:31 +08:00
Mark L. Stowell e62696f749 Merge branch 'master' into pyramid-dev 2024-11-11 22:16:41 -08:00
Mark L. Stowell 12d1dcb155 Attempting to resolve issue in cmake build on Windows 2024-11-11 21:15:43 -08:00
dylan-copeland 07d59a1843 Prolongate GridFunction for glvis output. 2024-11-11 19:20:53 -08:00
Mark L. Stowell ec5ad279e7 Fixing memory leak in unit test 2024-11-11 16:47:33 -08:00
Mark L. Stowell 522dc28e5a Loosening a unit test tolerance slightly 2024-11-11 16:47:12 -08:00
Mark L. Stowell 1c47f03aba Alternative to PR #4578 2024-11-11 16:01:58 -08:00
Mark L. Stowell 6fd0e8e50a Minor unit test clean-up 2024-11-11 15:49:54 -08:00
Mark L. Stowell 841df1a9bf Making use of new CheckZ function 2024-11-11 15:40:35 -08:00
Mark L. Stowell 0b49ea9594 Removing type ambiguity flagged by Ubuntu 2024-11-11 11:41:56 -08:00
Mark L. Stowell fba17c6579 Testing solution to type ambiguity flagged by Ubuntu runs 2024-11-11 11:02:19 -08:00
Mark L. Stowell 789f5d2e49 double -> real_t 2024-11-11 10:13:02 -08:00
Mark L. Stowell 07b543000f Fixing face dof order in H1 pyramids 2024-11-11 09:57:32 -08:00
adam-sim-dev f89aba61ca Merge branch 'master' into ppr 2024-11-11 08:45:48 +08:00
Mark L. Stowell 8cae2c313e Switching to tighter, more problem specific, tolerances in product interpolator unit tests 2024-11-09 14:40:23 -08:00
Mark L. Stowell 888651e796 Adding unit test of the curl using finite differences 2024-11-08 11:49:06 -08:00
Mark L. Stowell def1a9938d Merge remote-tracking branch 'origin/master' into pyramid-dev 2024-11-08 10:21:16 -08:00
Mark L. Stowell 7b12197e94 Replacing scattered tolerances with a centrally defined one 2024-11-08 10:16:25 -08:00
adam-sim-dev e50c543dde Merge branch 'master' into ppr 2024-11-08 08:48:45 +08:00
Will Pazner 4317659edc Use unique_ptr for MixedBilinearFormExtension 2024-11-07 13:06:26 -08:00
Will Pazner 29b78f70e9 Early return to prevent division by zero 2024-11-07 12:07:04 -08:00
Will Pazner ae9ee68c82 Fix shadowed variable warning 2024-11-07 11:35:56 -08:00
Will Pazner 7c417d7f47 Fix warning 'comparison of integer expressions of different signedness' 2024-11-07 11:30:21 -08:00
Will Pazner f22201a855 Fix shadowed variable warning 2024-11-07 11:17:53 -08:00
Will Pazner 4d5426a314 Merge remote-tracking branch 'origin/master' into hybridization-gpu
# Conflicts:
#	fem/bilinearform_ext.hpp
#	fem/bilininteg.hpp
#	linalg/batched/native.cpp
2024-11-07 10:37:38 -08:00
Dylan Copeland 6baa15afba Merge branch 'master' of github.com:mfem/mfem into ppr 2024-10-16 17:38:47 -07:00
Dylan Copeland b936a27147 offdiagonal -> off-diagonal 2024-10-16 17:38:18 -07:00
Dylan Copeland 05fef0a0d2 Documentation and minor changes. 2024-10-16 16:06:10 -07:00
Mark L. Stowell 2927be94bf Merge branch 'master' into pyramid-dev 2024-10-14 10:38:15 -04:00
Stowell, Mark L f181ceb58d Correcting polynomial space 2024-10-14 10:37:28 -04:00
Stowell, Mark L e160e5cfaf Missed one "double" -> "real_t" 2024-10-09 11:39:32 -04:00
Stowell, Mark L 5b4ae30871 Replacing "double" with "real_t" 2024-10-09 11:29:46 -04:00
Stowell, Mark L 862eb07599 Fixing shadowed variables in RT basis 2024-10-09 11:18:17 -04:00
Stowell, Mark L b4c814efd4 Fixing shadowed variables in H1 basis 2024-10-09 10:47:04 -04:00
Stowell, Mark L 8a15099f67 Fixing display of math formulae in doxygen 2024-10-09 10:37:32 -04:00
Stowell, Mark L 5272fbf7fa Removing VerifyNodal from L2 basis on pyramids 2024-10-09 09:48:39 -04:00
Stowell, Mark L 10de3a3f34 Moving internal methods to protected member functions 2024-10-09 09:48:05 -04:00
Stowell, Mark L bd49a2d320 Fixing unit test issues with scalar pyramid basis functions 2024-10-08 15:31:12 -04:00
Stowell, Mark L a0d509fed6 Adding positive pyramid basis functions to finite element collections 2024-10-08 15:30:38 -04:00
Stowell, Mark L 127867dc00 Adding H1 and L2 Positive basis functions on pyramids 2024-10-08 15:29:54 -04:00
Will Pazner 5e2bac632f Bugfix in HybridizationExtension::MultAhatInv 2024-10-02 18:07:09 -07:00
Will Pazner cba6871889 Exclude essential DOFs in HybridizationExtension::FactorElementMatrices 2024-10-02 16:37:00 -07:00
Will Pazner cf0ad68faa Fix boundary indexing in EABilinearFormExtension::GetElementMatrices 2024-10-01 11:17:48 -07:00
Dylan Copeland ef386590ad Print -> ParPrint for pmesh in hpref and ex6p. 2024-09-27 17:33:26 -07:00
Will Pazner e199da273e Essential BCs in HybridizationExtension::FactorElementMatrices 2024-09-27 14:08:49 -07:00
adam-sim-dev 5b928c919e Merge branch 'master' into ppr 2024-09-26 19:42:20 +08:00
dylan-copeland 8464b3d1e7 cmake fix 2024-09-25 21:12:04 -07:00
dylan-copeland 40f20d1da5 Fixed a memory bug. 2024-09-25 20:45:34 -07:00
dylan-copeland 7e1bccc757 Fix serial build. 2024-09-25 20:22:02 -07:00
Dylan Copeland 89b7c48cf7 Update makefile 2024-09-25 20:10:06 -07:00
Dylan Copeland 351afd3fbb Serial version of UpdatePRef in FiniteElementSpace (now virtual), with a serial miniapp. 2024-09-25 19:31:01 -07:00
Dylan Copeland 68abff7ce2 Merge branch 'master' of github.com:mfem/mfem into ppr 2024-09-25 12:23:32 -07:00
Dylan Copeland 4dc9708669 Address some PR comments. 2024-09-25 12:20:55 -07:00
dylan-copeland a2f32603f8 Simplified interface for p-refinement. 2024-09-20 17:39:21 -07:00
dylan-copeland 8532980ef8 Changed PTh to shared_ptr. 2024-09-20 15:12:08 -07:00
dylan-copeland c7f632e548 Merge branch 'master' of github.com:mfem/mfem into ppr 2024-09-18 10:04:58 -07:00
dylan-copeland c99bd6515e Added a function to p-refine an array of elements. 2024-09-18 10:04:38 -07:00
Stowell, Mark L c659a98754 Implementing Bernstein basis for H1 pyramids 2024-09-18 10:47:13 -04:00
Stowell, Mark L 05ef2ea97d Adding derivatives of binomials without assumptions on the relation between the monomials 2024-09-18 10:46:42 -04:00
Stowell, Mark L 350e235920 Change limiting values on the gradients of pyramid affine parameters 2024-09-18 10:45:31 -04:00
Hugh Carson 1043d3db04 Merge branch 'master' into sjg/mfem-device-fixes 2024-09-13 13:15:29 -04:00
Will Pazner a79aaeac07 Minor Doxygen fix 2024-09-12 13:32:03 -07:00
Stowell, Mark L 8ab27a16cc Removing unnecessary vector size 2024-09-11 16:38:41 -04:00
Stowell, Mark L 04691da19a Further memory leak testing 2024-09-11 12:34:22 -04:00
Stowell, Mark L 89fa1e05b2 Test of memory leak issue 2024-09-11 12:08:02 -04:00
Stowell, Mark L 0685ed9e49 Reverting null test 2024-09-10 19:52:32 -04:00
Stowell, Mark L 00de67dd3a Testing memory leak work-around 2024-09-10 13:22:59 -04:00
linke2 c8d39a3090 Code Style 2024-09-09 14:45:46 -07:00
linke2 2e4bb12589 Updated MMA variable 2024-09-09 13:16:56 -07:00
Will Pazner 0a683fdcfd Add LocalMemory template allowing zero-sized data 2024-09-09 13:00:53 -07:00
Will Pazner 7e1d57f8b1 Add specializations for HybridizationExtension::FactorElementMatrices 2024-09-09 12:46:12 -07:00
linke2 38abb9bee4 Updated to real_t 2024-09-09 10:07:41 -07:00
Will Pazner 455d279c3d Add HybridizationExtension::FactorElementMatrices
This changes the element matrix factorization kernel to use local memory instead
of global memory
2024-09-09 10:07:20 -07:00
linke2 e0569296e7 fix MMA test 2024-09-09 09:47:03 -07:00
linke2 0b6881390f remove unused variable in test 2024-09-09 09:46:25 -07:00
Will Pazner 3655d08ca3 Make HybridizationExtension::DofType public
This is a requirement for host-device lambdas with nvcc
2024-09-07 15:00:22 -07:00
Will Pazner 35041601d4 In hybridization, use i-dof and b-dof Schur complement on device 2024-09-07 13:52:20 -07:00
Will Pazner 4caffa2ebe Move some dense linear algebra functionality to host-device functions 2024-09-07 09:27:31 -07:00
Stowell, Mark L 0bea92acf0 Improving comments 2024-09-06 15:53:53 -07:00
Stowell, Mark L 0ba784d08f Resolving limiting case problems found with fixed order comparison 2024-09-06 15:30:00 -07:00
Stowell, Mark L 8b41801be5 Using new function space where appropriate 2024-09-06 15:28:56 -07:00
Stowell, Mark L c622f40713 Adding new function space for rational polynomials 2024-09-06 15:27:37 -07:00
Stowell, Mark L d79e2af2e3 Adding unit test to compare fixed and arbitrary order pyramid finite elements 2024-09-06 15:26:11 -07:00
Mark L. Stowell 7b5a0a42d1 Merge branch 'master' into pyramid-dev 2024-09-06 09:18:14 -07:00
Stowell, Mark L f89f0eaad4 Fixing quad face dof order in pyramid finite elements 2024-09-05 16:10:49 -07:00
Stowell, Mark L 2758154175 Updating weak operator unit tests 2024-09-05 13:39:03 -07:00
Will Pazner 0aec7595bd AtomicAdd in EABilinearFormExtension::GetElementMatrices 2024-09-05 12:03:34 -07:00
Will Pazner c5064e1884 Handle case of no domain integrators in EABilinearFormExtension::Assemble 2024-09-05 12:03:27 -07:00
Will Pazner ce48acbf30 Temporary: use ib-dof Schur complement LU factorization 2024-09-05 12:02:58 -07:00
Will Pazner 25d80486e0 Hybridization extension fixes and improvements
- Add HybridizationExtension::Reset to clear the element matrices
- Distinguish between interior and boundary free DOFs
2024-09-05 12:02:07 -07:00
linke2 9a1baddd61 fixed shadowed variables 2024-09-04 11:58:25 -07:00
linke2 01eab3864d removed subcommunicator 2024-09-04 11:28:49 -07:00
linke2 455c52f520 MMA Final 2024-09-03 16:42:04 -07:00
Dylan Copeland 95e00dec12 Merge branch 'master' of github.com:mfem/mfem into ppr 2024-08-31 22:34:15 -07:00
Dylan Copeland e27726337c Minor improvements. 2024-08-31 22:33:48 -07:00
Stowell, Mark L 0b82b5b4cb Adding skipped unit tests 2024-08-27 14:33:14 -07:00
Stowell, Mark L a501fd9571 Adding unit test for CurlGrad=0 and DivCurl=0 2024-08-27 11:10:35 -07:00
Stowell, Mark L 6933b983a6 Adding pyramids to Calc*Shape unit tests 2024-08-26 09:59:09 -07:00
Stowell, Mark L ab024fa6b1 Updating copyright statement in new unit test 2024-08-20 09:23:20 -07:00
Stowell, Mark L b0efc18e0f Adding 2 sample pyramid meshes 2024-08-20 09:18:28 -07:00
Stowell, Mark L 4d40cc2152 Removing unnecessary files 2024-08-20 09:13:41 -07:00
Stowell, Mark L 3d9d7a9915 Missed one test code 2024-08-20 08:58:28 -07:00
Stowell, Mark L e19a00f18a Removing test codes 2024-08-20 08:57:45 -07:00
Stowell, Mark L 9548a87a66 Merge remote-tracking branch 'origin/master' into pyramid-dev 2024-08-20 08:37:17 -07:00
dylan-copeland a589ae90b9 Restore communication of all element orders. 2024-08-20 07:54:20 -07:00
dylan-copeland 47bbba2f5c Fix ubuntu build. 2024-08-19 22:56:14 -07:00
dylan-copeland 3553f91f44 Fix mac build. 2024-08-19 22:51:17 -07:00
Dylan Copeland 45f32fb9c6 Eliminated communication of orders greater than base order. 2024-08-19 22:44:06 -07:00
Dylan Copeland 41807f5444 Minor fixes. 2024-08-19 20:41:45 -07:00
dylan-copeland 659559d43b Updating ex6p. 2024-08-19 19:53:51 -07:00
Dylan Copeland c00f044824 Documented and cleaned up various things. Added the new miniapp hpref. 2024-08-19 17:24:52 -07:00
Stowell, Mark L 238cd67d5e Increasing integration order used with pyramids 2024-08-19 17:17:29 -07:00
Stowell, Mark L 96d9068077 Adjusting interpolation vectors for ND and RT pyramids 2024-08-19 17:16:01 -07:00
Stowell, Mark L e91f9b6e0c Augmenting interpolation vectors for ND pyramids 2024-08-19 16:50:28 -07:00
Stowell, Mark L 81f990cc8e Adding unit test for finite element compatibility 2024-08-19 16:28:28 -07:00
Dylan Copeland 70fca5a453 Minor fixes. 2024-08-16 21:26:23 -07:00
dylan-copeland 00a7f10b95 Cleaning up and fixing some minor issues. 2024-08-16 20:28:38 -07:00
Dylan Copeland a4c097f47c Merge branch 'master' of github.com:mfem/mfem into ppr 2024-08-16 18:15:41 -07:00
Dylan Copeland 7198ad8872 Eliminated some discontinuities by fixing a bug in PackDofVar, calling VariableOrderMinimumRule before applying h-refinement constraints, and propagating minimum order from master to slave entities. Added H1 continuity check in unit tests. 2024-08-16 16:40:46 -07:00
Will Pazner 52b00a08a9 Update to new batched linear algebra interface 2024-08-16 12:29:17 -07:00
Will Pazner 9a6048658b Merge remote-tracking branch 'origin/master' into hybridization-gpu
# Conflicts:
#	fem/hybridization.cpp
#	fem/hybridization.hpp
#	linalg/CMakeLists.txt
#	linalg/densemat.cpp
#	linalg/densemat.hpp
2024-08-16 12:29:07 -07:00
Rick Budé d16dae3366 Format source files 2024-07-25 16:22:06 +02:00
Rick Budé ee84d9e365 Load ND_R<1,2>D and RT_R<1,2>D spaces correctly
Resolves a crash when attempting to load a gridfunction from file,
expressed on ND_R1D, ND_R2D, RT_R1D and RT_R2D spaces. See
issue #4403
2024-07-23 17:14:42 +02:00
Patrick Zulian ed49e3eabc Merge branch 'moonolith_h1_vector_space' into moonolith_h1_bugfix 2024-06-26 10:01:00 +02:00
Patrick Zulian a7efe17b0b Merge branch 'master' into moonolith_h1_bugfix 2024-06-26 09:59:38 +02:00
Will Pazner a0d2d4ab3d Implement HybridizationExtension::AssembleBdrMatrix
Note: this is slow, it is not the recommended way to use the
HybridizationExtension. Batched Element Assembly should be used instead.
2024-06-24 10:53:37 -07:00
Will Pazner 0a08801004 Remove unused variable 2024-06-24 10:33:57 -07:00
Will Pazner 4af565819e Adjustments to matrix assembly interface in HybridizationExtension 2024-06-24 10:33:53 -07:00
Will Pazner bcd5ef92c6 Add batched.{cpp,hpp} to CMakeLists.txt 2024-06-19 16:53:10 -07:00
Will Pazner bb271475ea GPU hybridization optimizations
This commit includes two optimizations:

 - Use CuBLAS for batched linear algebra. Compute Ahat^{-1} Ct using
   batched LU with multiple right-hand sides.
 - After forming face-to-face connectivity, expose more parallelism
   in matrix-matrix kernels.
2024-06-16 22:42:07 -07:00
Stowell, Mark L 97f8b1b16b Adding more bounds checking to pyramid functions 2024-06-14 13:56:25 -07:00
Stowell, Mark L 488e93ad74 Updating meshgen and mesh_geoms flags following pyramid refinement 2024-06-14 13:55:54 -07:00
Will Pazner d448fd0811 Support element and boundary markers in Element Assembly 2024-06-14 10:37:57 -07:00
Stowell, Mark L c0fee4482a Adding pyramid type to DofTrans creation code 2024-06-13 17:47:06 -07:00
Will Pazner 098bb72f34 Fix bug in EABilinearFormExtension 2024-06-12 09:50:37 -04:00
Patrick Zulian 8a6d972814 Merge branch 'moonolith_h1_bugfix' into moonolith_h1_vector_space 2024-06-12 11:30:30 +02:00
Patrick Zulian 5706c247a4 Merge branch 'master' into moonolith_h1_bugfix 2024-06-12 11:07:52 +02:00
Will Pazner 51961fe66d Add option to add boundary elements to element matrices in EABilinearFormExtension 2024-06-11 17:11:08 -04:00
Will Pazner 14011b604f Add BilinearFormIntegrator::AssembleEABoundary, implement mass
Add unit test for mass EA and legacy boundary integrators.
2024-06-11 17:11:08 -04:00
Will Pazner c9233a2045 Use unique_ptr for BilinearFormExtension 2024-06-11 17:11:08 -04:00
Will Pazner ce9a500498 Fix nvcc 'partially overridden' warnings 2024-06-11 17:11:08 -04:00
Will Pazner 6edf26214c Expose more parallelism in HybridizationExtension kernels 2024-06-11 17:11:08 -04:00
Will Pazner b008b0b8da Minor changes to grad-div timings 2024-06-11 17:11:08 -04:00
Will Pazner 8b8e7b47c8 Host/device memory management 2024-06-11 17:11:08 -04:00
Will Pazner 1ef48cd785 Adjust shared memory H(div) EA kernels 2024-06-11 17:11:08 -04:00
Will Pazner a8c681b67c Enable element assembly with hybridization in grad-div miniapp 2024-06-11 17:11:08 -04:00
Will Pazner a2002aa05b Parallelize HybridizationExtension 2024-06-11 17:11:08 -04:00
Will Pazner 59ef835780 Fix bug in BilinearForm::RecoverFEMSolution with EA hybridization 2024-06-11 17:11:08 -04:00
Will Pazner 857f10f6a4 EA assembly kernels for 3D H(div) 2024-06-11 17:11:08 -04:00
Will Pazner a68de24413 Unify H(div) mass and div-div EA kernels 2024-06-11 17:11:08 -04:00
Will Pazner 177fee04e5 3D element assembly for NormalTraceJumpIntegrator 2024-06-11 17:11:08 -04:00
Will Pazner 5be94b463d real_t instead of double 2024-06-11 17:11:08 -04:00
Will Pazner 045cbad46f CUDA fixes in HybridizationExtension 2024-06-11 17:11:08 -04:00
Will Pazner af482bdbcc HybridizationExtension nvcc limitation 2024-06-11 17:11:08 -04:00
Will Pazner c1e587a504 Fix NormalTraceJumpIntegrator Element Assembly unit test 2024-06-11 17:11:08 -04:00
Will Pazner 2aad85ca57 More device execution in HybridizationExtension::ConstructH 2024-06-11 17:11:08 -04:00
Will Pazner c505933d7f Deep copy when accessing the DOF map on device
Reading reading the DOF map on GPU can cause issues in other parts of the code
when using the debug device. The DOF map is accessed in other places without
explicitly calling HostRead, which fails on non-const access if the device
pointer is valid.
2024-06-11 17:11:08 -04:00
Will Pazner a96222708d Add host device kernel AddMultAtB 2024-06-11 17:11:08 -04:00
Will Pazner 0addaa7342 Check A.Empty() instead of A == NULL in SparseMatrix::PrintMatlab
Otherwise this can fail with the debug device if the host pointer is not valid.
2024-06-11 17:11:08 -04:00
Will Pazner 5218b40945 Call HostRead in ElementRestriction::ElementRestriction
Avoid issues with debug device if device pointer is valid
2024-06-11 17:11:08 -04:00
Will Pazner 5b5af88f32 HybridizationExtension::MultAhatInv on device 2024-06-11 17:11:08 -04:00
Will Pazner 51037a7724 Return lexicographic ordering from element assembly
Convert to native ordering in HybridizationExtension
2024-06-11 17:11:08 -04:00
Will Pazner e325b07545 Add element assembly option to ex4, enable device hybridization 2024-06-11 17:11:07 -04:00
Will Pazner 6083094f16 Eliminate essential DOFs when adding element matrices to hybridized system 2024-06-11 17:11:07 -04:00
Will Pazner bb07ec79f4 Fix batched solve 2024-06-11 17:11:07 -04:00
Will Pazner 33157ddb60 Fix constraint matrices 2024-06-11 17:11:07 -04:00
Will Pazner 2a4e4b7d5a Hybridization device bug fixes and improvements 2024-06-11 17:11:07 -04:00
Will Pazner d160b52f49 Add DenseTensor::NewMemoryAndSize 2024-06-11 17:11:07 -04:00
Will Pazner dd153bcf7a Small refactor 2024-06-11 17:11:07 -04:00
Will Pazner fb4659bc32 Don't need to distinguish between interior and boundary free DOFs 2024-06-11 17:11:07 -04:00
Will Pazner 3344049b13 Eliminate essential DOFs on device 2024-06-11 17:11:07 -04:00
Will Pazner 4a49b90052 Factor out HybridizationExtension::MultR 2024-06-11 17:11:07 -04:00
Will Pazner 18af2042c7 Use element assembly in HybridizationExtension::ConstructC 2024-06-11 17:11:07 -04:00
Will Pazner 6be8650f71 Improve H(div) Element Assembly unit test 2024-06-11 17:11:07 -04:00
Will Pazner 4f9686bd8b Port NormalTraceJumpIntegrator::AssembleEAInteriorFaces to mfem::forall device kernels 2024-06-11 17:11:07 -04:00
Will Pazner 9b54f750c9 Add NormalTraceJumpIntegrator::AssembleEAInteriorFaces
Uses existing EA kernels for mass integrator.

Add unit test to compare with legacy assembly.

Also, fixes bug in EA mass kernel in 1D (r_Bi and r_Bj need to be set inside a
MFEM_FOREACH_THREAD loop).
2024-06-11 17:11:07 -04:00
Will Pazner fa552415d3 Add BilinearFormIntegrator::AssembleEAInteriorFaces for mixed trace integrators 2024-06-11 17:11:07 -04:00
Will Pazner 5ced2e61ff Doxygen fix 2024-06-11 17:11:07 -04:00
Will Pazner e954950e6d Combine AssemblyLevel::ELEMENT with hybridization 2024-06-11 17:11:07 -04:00
Will Pazner 7e589d7ee8 Add Hybridization::AssembleElementMatrices and HybridizationExtension::AssembleElementMatrices 2024-06-11 17:11:07 -04:00
Will Pazner 94ae58fa83 Add BilinearForm::GetElementMatrices
Also add unit test
2024-06-11 17:11:07 -04:00
Will Pazner 69a0b82c89 Support reordering in EABilinearFormExtension::GetElementMatrices 2024-06-11 17:11:07 -04:00
Will Pazner 6d297c8ec0 Add EABilinearFormExtension::GetElementMatrices 2024-06-11 17:11:07 -04:00
Will Pazner d00b172172 Small Doxygen edits for L2InterfaceFaceRestriction 2024-06-11 17:11:07 -04:00
Will Pazner 6b802a0ec0 Element assembly for div-div in 2D 2024-06-11 17:11:07 -04:00
Will Pazner 31f4f5b2bb Element assembly for 2D H(div) mass matrix 2024-06-11 17:11:07 -04:00
Will Pazner 0e135ff1d0 Enable "Serial H1 Full Assembly" unit test without MPI 2024-06-11 17:11:07 -04:00
Will Pazner 2b95924226 Use unique_ptr in BilinearForm for element_matrices, static_cond and hybridization 2024-06-11 17:11:07 -04:00
Will Pazner 9ff6c53ace Don't fall back on legacy Schur complement assembly in HybridizationExtension
Don't need to set up Af_offsets and Af_f_offsets
2024-06-11 17:11:07 -04:00
Will Pazner e3b013c3e8 Device assembly of Schur complement in HybridizationExtension 2024-06-11 17:11:07 -04:00
Will Pazner 2b8ef63bc1 Construct Schur complement in HybridizationExtension 2024-06-11 17:11:07 -04:00
Will Pazner 67e3b289b6 Provide access to gather map in L2InterfaceFaceRestriction 2024-06-11 17:11:07 -04:00
Will Pazner 8d1b7f061a Expose more parallelism in hybridization kernels 2024-06-11 17:11:07 -04:00
Will Pazner 6f9c761bfa Port some hybridization operations to forall kernels 2024-06-11 17:11:07 -04:00
Will Pazner 0ce2e7551c Implement HybridizationExtension::ReduceRHS 2024-06-11 17:11:07 -04:00
Will Pazner c07e081832 Implement L2InterfaceFaceRestriction::AddMultTranspose 2024-06-11 17:11:07 -04:00
Will Pazner 528bd5a5a3 Fix typo in comment in Hybridization 2024-06-11 17:11:07 -04:00
Will Pazner a994abd7d3 Implement A_hat^{-1} in HybridizationExtension 2024-06-11 17:11:07 -04:00
Will Pazner 4566dc299d Minor cleanup in HybridizationExtension 2024-06-11 17:11:07 -04:00
Will Pazner 352403bfc5 Store constraint matrix in EA format in hybridization extension 2024-06-11 17:11:07 -04:00
Will Pazner 0c10a41589 Add L2InterfaceFaceRestriction 2024-06-11 17:11:07 -04:00
Will Pazner ddd54fc459 Reduce transitive includes 2024-06-11 17:11:07 -04:00
Will Pazner 5ef5b333e5 Device execution in HybridizationExtension::ComputeSolution
For now, use ElementDofOrdering::NATIVE. This will need to be changed to
LEXICOGRAPHIC once device assembly of the element matrices is supported.

Also, represent hat DOF types (free interior, free boundary, essential) with
enum instead of raw integer.
2024-06-11 17:11:07 -04:00
Will Pazner cd5feebfe5 Device execution in HybridizationExtension::Init 2024-06-11 17:11:07 -04:00
Will Pazner 4c1e6e91f2 Doxygen for HybridizationExtension 2024-06-11 17:11:07 -04:00
Will Pazner fcba41be04 Initial setup for device execution for hybridization 2024-06-11 17:11:07 -04:00
Will Pazner 82e55c8aea More Doxygen 2024-06-11 17:11:07 -04:00
Will Pazner 9d1f84d81a Add hybridization extension source files 2024-06-11 17:11:07 -04:00
Will Pazner befd4656fc More Doxygen for Hybridization class 2024-06-11 17:11:07 -04:00
Will Pazner 81cd6e8fe6 RAII in Hybridization class 2024-06-11 17:11:07 -04:00
Stowell, Mark L 347d0e6384 Fixing bug in implementation of Jacobi polynomials 2024-06-06 13:51:09 -07:00
Stowell, Mark L eafeb15cd0 Correcting sizes of polynomial arrays 2024-06-05 16:20:07 -07:00
Stowell, Mark L 9178cb687a Small and medium sized bug fixes 2024-06-05 16:19:19 -07:00
Stowell, Mark L 83a34a3e77 Adding access to H1 polynomials 2024-06-05 16:17:15 -07:00
Stowell, Mark L 95705c8121 Nodes implemented but now the real debugging begins 2024-05-29 17:52:08 -07:00
Stowell, Mark L 09222e3313 Adding curls of ND basis functions on pyramids 2024-05-29 13:43:03 -07:00
Dylan Copeland ebbf706a55 Minor fixes. 2024-05-28 13:21:37 -07:00
Dylan Copeland f1f683061d ProlongToMaxOrder is now a member of (Par)GridFunction. 2024-05-28 12:12:47 -07:00
dylan-copeland 26f0dad6fa make clean 2024-05-26 13:22:56 -07:00
dylan-copeland 808b83c282 Ignore (git) examples/order files. 2024-05-26 12:27:59 -07:00
dylan-copeland ef9d32f1a4 Fix the previous fix. 2024-05-26 11:13:52 -07:00
Dylan Copeland 9130cb06e1 Fixed an MPI communication issue. 2024-05-25 21:43:06 -07:00
Dylan Copeland 90bc48532f Changed argument type in MakeDofTable. 2024-05-24 15:09:49 -07:00
dylan-copeland 21360beede Smart pointers 2024-05-24 13:08:43 -07:00
Dylan Copeland e878db0fee Bug fix 2024-05-24 10:23:55 -07:00
Dylan Copeland ce386c1409 Using PR 2854 for GridFunction updates after refinement. Added option for hp-refinement in ex6p. Improved interface for p-refinement. 2024-05-23 21:13:34 -07:00
Stowell, Mark L 06f892e457 Implementation of Nedelec basis on pyramids 2024-05-23 12:55:33 -07:00
Stowell, Mark L 2f894ef8fa Adding functions to support Nedelec basis on pyramids 2024-05-23 12:54:37 -07:00
Dylan Copeland e63ba7dd04 Fixing enum shadow. 2024-05-22 19:58:42 -07:00
Dylan Copeland 232642b5d3 Merge branch 'master' of github.com:mfem/mfem into ppr 2024-05-22 19:32:22 -07:00
Dylan Copeland c668bb6fa2 Enum for VarMessage tags. 2024-05-22 19:31:43 -07:00
Stowell, Mark L ea655797da Generalizing ND_DofTransformation to support pyramids 2024-05-22 13:23:11 -07:00
Dylan Copeland b309b6d789 Refactoring 2024-05-21 21:53:41 -07:00
Dylan Copeland 6956e10323 New struct VarOrderElemInfo. 2024-05-21 20:36:01 -07:00
Dylan Copeland e8dc1eb31c Eliminated inefficient table search. Cleaned up some things. 2024-05-20 21:22:32 -07:00
Stowell, Mark L 2f4f06d549 Switching to more robust rational polynomials for RT basis functions on triangular faces 2024-05-16 14:41:37 -07:00
Stowell, Mark L e9352448f1 Adding alternate rational polynomial which avoids 0/0 on pyramid surface 2024-05-16 14:40:40 -07:00
Stowell, Mark L 6db2519021 Adding finite difference based unit test of CalcDivShape 2024-05-16 14:39:32 -07:00
Stowell, Mark L 230d8830c5 make style 2024-05-14 13:17:08 -07:00
Stowell, Mark L 3373ee5c34 Improving/implementing gradients of H1 and L2 pyramid basis functions 2024-05-14 13:16:06 -07:00
Stowell, Mark L 1ecdd8e7b0 Adding pyramids to unit tests of CalcDShape 2024-05-14 13:14:44 -07:00
Stowell, Mark L 8f0398d330 Adding divergence of HDiv basis functions 2024-05-08 11:55:07 -07:00
Dylan Copeland d208f6a951 Removed some obsolete code. 2024-05-07 18:18:19 -07:00
Stowell, Mark L 29662bf5c6 Adding comment 2024-05-07 15:53:07 -07:00
Stowell, Mark L 59ccdced1a Changing default L2 basis on pyramids to Fuentes version 2024-05-07 15:52:52 -07:00
Stowell, Mark L fb149d7d12 Fixing ordering bug in RT_FuentesPyramid basis 2024-05-07 15:52:13 -07:00
Stowell, Mark L 15ff1a42cd Removing unused code from RT_FunetesPyramid basis 2024-05-07 15:51:46 -07:00
Stowell, Mark L 09fcd3ecca Switching L2_FuentesPyramid basis to use common polynomials with other Fuentes bases 2024-05-07 15:50:32 -07:00
Stowell, Mark L 35857b5379 Fixing bug in L2 basis with closed points (as used in GLVis) 2024-05-07 15:49:37 -07:00
Stowell, Mark L 1450a58374 Removing debugging code 2024-05-07 15:48:28 -07:00
Sebastian Grimberg 2be6e5a074 Merge branch 'master' into sjg/mfem-device-fixes 2024-05-06 12:16:09 -07:00
Patrick Zulian 278b33942a Merge branch 'moonolith_h1_bugfix' into moonolith_h1_vector_space 2024-05-06 16:48:00 +02:00
Patrick Zulian 080163deac Merge branch 'master' into moonolith_h1_bugfix 2024-05-06 10:05:43 +02:00
Dylan Copeland d398bac010 Bug fix 2024-05-03 10:41:48 -07:00
Stowell, Mark L c5be56264c Pre-update commit containing much temporary code 2024-05-02 09:40:33 -07:00
Dylan Copeland d3c669d482 Merge branch 'master' of github.com:mfem/mfem into ppr 2024-05-01 19:46:28 -07:00
Dylan Copeland 270f83bd35 Fixed a bug by adding some changed edges to parallel order propagation. 2024-05-01 17:02:27 -07:00
Dylan Copeland e327a173da Remove unused variables. 2024-04-18 21:23:05 -07:00
Dylan Copeland e6c48e3987 Merge branch 'master' of github.com:mfem/mfem into ppr 2024-04-18 17:00:47 -07:00
Dylan Copeland c9ad580d33 Added parallel order propagation with communication of shared entity orders. 2024-04-18 16:37:38 -07:00
Dylan Copeland 040c337ce7 Using local edof and communicating order, instead of encoding order in edof. Fixed an issue with ghost faces having edges without the face order. 2024-04-12 12:15:26 -07:00
Stowell, Mark L 1d46fbba57 Cleaning up deprecation warnings 2024-04-08 13:22:15 -07:00
Stowell, Mark L 4804824873 Merge remote-tracking branch 'origin/master' into pyramid-dev
# Conflicts:
#	fem/fe/fe_base.cpp
#	fem/fe/fe_base.hpp
#	fem/gridfunc.cpp
2024-04-08 12:09:46 -07:00
Stowell, Mark L 1a2b8291f5 Switching to new pyramid polynomial functions 2024-04-08 12:06:45 -07:00
Stowell, Mark L 8f3eafd251 Adding pyramid specific polynomial functions in separate source files 2024-04-08 12:04:15 -07:00
Sebastian Grimberg 559e4e20a6 Merge branch 'master' into sjg/mfem-device-fixes 2024-04-04 11:32:11 -07:00
Dylan Copeland 3ec7ae873d Allowing for ghost master faces with inconsistent ghost edge orders. 2024-03-20 15:28:34 -07:00
dylan-copeland 1acaa833b6 -Wunused-but-set-variable 2024-03-16 20:18:34 -07:00
dylan-copeland a07f893b03 Remove unused variables. 2024-03-16 20:03:18 -07:00
Dylan Copeland f0f1885090 Fixed some issues with parallel hp-refinement. Added more unit tests. 2024-03-16 17:46:37 -07:00
Patrick Zulian 42d0c95bc8 moonolith (new experimental feature): Added support for H1 vector space. ex1p can run examples with such spaces by passing the flag --use_vector_space 2024-03-14 10:36:54 +01:00
Patrick Zulian 947c8c9be9 Merge branch 'master' into moonolith_h1_bugfix 2024-03-12 11:24:00 +01:00
Patrick Zulian cf82f2830c bug fix: Switched to TrueDofs when assembling the coupling matrices. This change resolves the inconsistent dof numbering that led to wrong results when using H1 collections in parallel. ran make style. 2024-03-12 11:20:16 +01:00
Sebastian Grimberg cad2293df6 Merge branch 'master' into sjg/mfem-device-fixes 2024-03-07 15:24:09 -08:00
dylan-copeland 604cb61b00 Another pedantic error. 2024-02-09 16:42:44 -08:00
dylan-copeland ff6546dd8f Fix shadowed variable. 2024-02-09 16:35:18 -08:00
dylan-copeland 10c9adf8c8 Remove unused variables. 2024-02-09 16:29:22 -08:00
Dylan Copeland 786caf20c3 Extended to support parallel hp-refinement, with unit tests in H1 for 2D and 3D. 2024-02-09 16:21:10 -08:00
Dylan Copeland 4430df415a Remove unused variables. 2024-01-31 20:00:08 -08:00
Dylan Copeland 5acdaf28a5 Generalized for ND and RT face DOFs in parallel. Added parallel ND and RT unit tests on quad and hex meshes. 2024-01-31 19:37:43 -08:00
Sebastian Grimberg c416ac9fff Clean up mfem::Device to add a few docstrings and make CUDA/HIP device setup consistent 2024-01-29 10:47:13 -08:00
Sebastian Grimberg 48e6b88370 Remove unneeded mfem::Device::mode member 2024-01-29 10:46:41 -08:00
Sebastian Grimberg a00d2610e3 Fix bug in mfem::Device when multiple device options are specified, for example cuda:uvm in addition to a libCEED backend option 2024-01-29 10:46:41 -08:00
Sebastian Grimberg bc9e624ce8 Add mfem::Device::GetDeviceCount method to query number of available CUDA or HIP devices before initializing an mfem::Device 2024-01-29 10:46:41 -08:00
Stowell, Mark L b482ce2880 Prototype 2nd order Nedelec basis on pyramid shaped elements (incomplete) 2024-01-26 23:11:56 -08:00
Stowell, Mark L 5ab2c0b6e3 Adding temporary test functions for convergence of pyramid bases 2024-01-24 18:41:22 -08:00
Stowell, Mark L ce900ec687 Adding Bergot pyramid bases to finite element collections 2024-01-24 18:40:38 -08:00
Stowell, Mark L 19df0ed57d Adding scalar basis on pyramids from Bergot paper with fewer interior DoFs 2024-01-24 18:38:51 -08:00
Stowell, Mark L a5cd125342 Adding Jacobi polynomials 2024-01-24 18:37:35 -08:00
Dylan Copeland 220e76ec83 Bug fixes. 2024-01-22 12:00:40 -08:00
dylan-copeland c5af057556 Remove unused variables. 2024-01-19 21:58:00 -08:00
dylan-copeland 60f281ddad Fix merge. 2024-01-19 21:45:07 -08:00
dylan-copeland 2408687812 Style 2024-01-19 21:36:38 -08:00
dylan-copeland f054912423 Merge branch 'master' of github.com:mfem/mfem into ppr 2024-01-19 21:35:33 -08:00
Dylan Copeland dca045d48a More general implementation for face DOFs, with more general testing. 2024-01-19 21:01:00 -08:00
Stowell, Mark L c35ca25dfa Adding a mixed tests mesh resembling a butterfly mesh with six pyramids meeting at the origin 2024-01-19 17:27:12 -08:00
Dylan Copeland cea73f8a02 Merge branch 'master' of github.com:mfem/mfem into ppr 2023-12-18 19:07:23 -08:00
Dylan Copeland bf4f411d9c Initial implementation of parallel p-refinement, for 2D and 3D H1 spaces, with unit tests. 2023-12-18 19:04:18 -08:00
Stowell, Mark L a50ef7f774 Resolving post-merge build issues related to pyramid classes 2023-10-06 11:03:40 -07:00
Stowell, Mark L a897af7764 make style 2023-10-06 10:49:28 -07:00
Stowell, Mark L e6ce209f64 Merge remote-tracking branch 'origin/master' into pyramid-dev
# Conflicts:
#	fem/fe.cpp
#	fem/fe.hpp
#	fem/fe_coll.cpp
#	fem/fe_coll.hpp
#	fem/geom.hpp
#	fem/intrules.cpp
#	mesh/mesh.cpp
#	mesh/mesh.hpp
#	mesh/mesh_headers.hpp
#	mesh/pyramid.cpp
#	mesh/pyramid.hpp
#	miniapps/common/mesh_extras.cpp
#	miniapps/tools/display-basis.cpp
#	tests/unit/fem/test_3d_bilininteg.cpp
#	tests/unit/fem/test_get_value.cpp
2023-10-06 10:48:38 -07:00
Stowell, Mark L 3c40606626 Merge branch 'pyramid-dev' of github.com:mfem/mfem into pyramid-dev
# Conflicts:
#	fem/fe.cpp
#	fem/geom.cpp
#	mesh/mesh.cpp
#	tests/unit/fem/test_calcshape.cpp
2023-10-06 10:17:45 -07:00
Stowell, Mark L 23f808fa9d make style 2023-10-06 10:08:05 -07:00
Stowell, Mark L 54cb4f7ce0 Adding tests of H1 bases on additional element types 2023-10-06 10:07:36 -07:00
Stowell, Mark L 576c5d26d6 Merge remote-tracking branch 'origin/no-tet-reorder-dev' into pyramid-dev
# Conflicts:
#	examples/test_eigs.cpp
#	fem/fe_coll.cpp
#	tests/unit/fem/test_domain_int.cpp
2021-07-08 12:42:13 -07:00
Stowell, Mark L c3c983d1e3 Adding H1 and L2 pyramids to domain integration unit test 2021-04-23 22:03:46 -07:00
Stowell, Mark L c97a82b14c Fixing pyramid uniform refinement 2021-04-23 22:02:50 -07:00
Stowell, Mark L 44d2e66858 Fixing interior dof number for pyramid in H1_FECollection 2021-03-10 13:14:32 -08:00
Stowell, Mark L 53728d12d9 Fixing pyramid integration rule 2021-03-10 13:13:39 -08:00
Stowell, Mark L e8a356baf8 Implementing L2_PyramidElement::CalcDShape for DG 2021-03-10 13:13:17 -08:00
Stowell, Mark L 482854800a Expanding unit test comment 2021-03-09 15:20:21 -08:00
Stowell, Mark L d417a515d2 Fixing pyramid cartesian mesh construction 2021-03-09 15:20:02 -08:00
Stowell, Mark L b39cfbfaa3 Implementing L2 on Pyramids 2021-03-09 15:19:26 -08:00
Stowell, Mark L cb5d07181f Implementing H1 on Pyramids 2021-03-09 15:18:59 -08:00
Stowell, Mark L 920099da20 First draft of H1 pyramids from Fuentes et al 2021-03-06 17:03:27 -08:00
Stowell, Mark L 004fb5757d Expanding tests for H1 pyramids 2021-03-06 17:02:58 -08:00
Stowell, Mark L 0783faddd4 Adding Pyramid option to Mesh::Make3D 2021-03-06 17:02:34 -08:00
Stowell, Mark L 9123848ff4 make style 2021-03-06 17:01:53 -08:00
Stowell, Mark L bfffaa3171 Fixing element count when adding pyramids 2021-03-04 16:58:24 -08:00
Stowell, Mark L a3e894ec50 Adding pyramid case to test_eigs 2021-03-04 16:58:04 -08:00
Stowell, Mark L d99c508a68 Updating legalese 2021-03-04 16:57:46 -08:00
Stowell, Mark L 053c71a885 Merge remote-tracking branch 'origin/no-tet-reorder-dev' into pyramid-dev
# Conflicts:
#	fem/fe.hpp
#	fem/intrules.cpp
#	mesh/mesh.cpp
#	mesh/mesh.hpp
#	mesh/mesh_readers.cpp
2021-03-04 16:21:34 -08:00
Stowell, Mark L 59c44959b3 Adding support for wedges and pyramids in display-basis 2020-01-19 23:14:27 -08:00
Stowell, Mark L 1beab25885 Changing reference element in H1_Pyramid 2020-01-19 23:13:53 -08:00
Stowell, Mark L 3835b45427 Tweaks in support of pyramids 2020-01-19 23:13:24 -08:00
Stowell, Mark L 7af8a82cc2 Merge remote-tracking branch 'origin/no-tet-reorder-dev' into pyramid-dev 2020-01-19 20:12:33 -08:00
Stowell, Mark L 3376d6d744 Add polynomial tests and pyramid mesh 2019-12-28 13:32:50 -08:00
Stowell, Mark L 93c87515ab Adding pyramid support to some Mesh methods 2019-12-28 13:28:29 -08:00
Stowell, Mark L 3769f8d788 Merge remote-tracking branch 'origin/no-tet-reorder-dev' into pyramid-dev 2019-12-28 10:02:34 -08:00
Stowell, Mark L e62a12af26 Starting pyramid support in Mesh class 2019-12-27 22:29:08 -08:00
Stowell, Mark L e9e0cd2af3 Adding arbitrary order H1 pyramid elements 2019-12-27 22:28:42 -08:00
Stowell, Mark L c285a77bf1 Fixing typos and adding implementation for new virtual function 2019-12-22 16:16:12 -08:00
Stowell, Mark L de179042a2 Merge remote-tracking branch 'origin/no-tet-reorder-dev' into pyramid-dev
# Conflicts:
#	makefile
#	mesh/mesh.cpp
2019-12-22 16:15:34 -08:00
Stowell, Mark L 6f5396fe11 Adding miniapps/common objects to separate library file 2019-04-17 11:10:16 -07:00
Stowell, Mark L 2b12687eb6 Merge remote-tracking branch 'origin/master' into pyramid-dev 2019-04-12 15:02:33 -07:00
Stowell, Mark L 777ad30e16 Merge remote-tracking branch 'origin/master' into pyramid-dev 2019-04-09 14:14:32 -07:00
Stowell, Mark L e25c40abaa Merge remote-tracking branch 'origin/master' into pyramid-dev
# Conflicts:
#	mesh/mesh.cpp
2019-04-01 10:57:34 -07:00
Stowell, Mark L 97f794057e Merge remote-tracking branch 'origin/master' into pyramid-dev 2019-03-31 14:53:10 -07:00
Stowell, Mark L de171f2751 Merge remote-tracking branch 'origin/master' into pyramid-dev 2019-03-28 21:57:51 -07:00
Stowell, Mark L 183569f3b7 Merge remote-tracking branch 'origin/master' into pyramid-dev 2019-01-20 00:03:24 -08:00
Stowell, Mark L c428ad7ae1 Mixed meshes can no longer assume uniform refinement produces eight times as many elements 2018-12-13 15:46:13 -08:00
Stowell, Mark L 50eef85cd5 Adding initial support for uniform refinement of Pyramid meshes 2018-12-13 11:29:44 -08:00
Stowell, Mark L 7792ced114 Using correct refined element type in Mesh c'tor with refinement option 2018-12-13 00:04:29 -08:00
Stowell, Mark L 4109c06129 Adding RefinedGeometry info for Pyramids 2018-12-13 00:03:12 -08:00
Stowell, Mark L bdb1afeb74 Bugfix: incorrect number of interior dofs 2018-12-11 16:21:12 -08:00
Stowell, Mark L fc556b7c08 Adding integration rule for pyramids 2018-12-11 15:02:24 -08:00
Stowell, Mark L 06bfe53f55 Adding inline pyramid mesh 2018-12-11 11:30:19 -08:00
Stowell, Mark L a38bda120c Adding inline pyramid mesh support 2018-12-11 11:29:03 -08:00
Stowell, Mark L 0a99b6fa99 make style 2018-12-11 11:28:34 -08:00
Stowell, Mark L 84fd3097a7 Bugfix related to precedence of '?' operator 2018-12-11 10:16:00 -08:00
Stowell, Mark L ac6efafd94 Adding pyramid comments to mesh files and vtk cell types for pyramids 2018-12-11 00:58:41 -08:00
Stowell, Mark L 7bf66519a4 Adding a piece-wise constant FE for pyramids 2018-12-11 00:57:34 -08:00
Stowell, Mark L f8c2878969 Supplying Geometry data for Pyramids 2018-12-10 22:12:10 -08:00
Stowell, Mark L 197698dc02 Adding pyramids to various classes 2018-11-25 01:18:05 -08:00
Stowell, Mark L 2e37747182 Forgot to adjust VertToVert::I array for pyramid elements 2018-11-24 21:01:01 -08:00
Stowell, Mark L c57e3b7d50 Adding initial support for pyramid shaped elements 2018-11-24 20:56:05 -08:00
297 changed files with 32941 additions and 4553 deletions
+10 -2
View File
@@ -114,6 +114,13 @@ jobs:
build-system: make
hypre-target: int32
precision: fp32
- os: macos-latest
target: opt
codecov: NO
mpi: par
build-system: make
hypre-target: int32
precision: fp32
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}-${{ matrix.precision }}
runs-on: ${{ matrix.os }}
@@ -154,7 +161,8 @@ jobs:
- name: get MPI (Linux)
if: matrix.mpi == 'par' && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get install mpich libmpich-dev
sudo apt-get install openmpi-bin libopenmpi-dev
export OMPI_MCA_rmaps_base_oversubscribe=1
- name: get lcov (Linux)
if: matrix.codecov == 'YES' && matrix.os == 'ubuntu-latest'
@@ -191,7 +199,7 @@ jobs:
uses: actions/cache@v4
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-${{ matrix.precision }}-v2.5
key: ${{ runner.os }}-ompi-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-${{ matrix.precision }}-v2.5
- name: get hypre
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-latest'
+3 -2
View File
@@ -45,14 +45,15 @@ jobs:
- name: Get MPI (Linux)
run: |
sudo apt-get install mpich libmpich-dev
sudo apt-get install openmpi-bin libopenmpi-dev
export OMPI_MCA_rmaps_base_oversubscribe=1
- name: Cache Hypre Install
id: hypre-cache
uses: actions/cache@v4
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.5
key: ${{ runner.os }}-ompi-build-${{ env.HYPRE_TOP_DIR }}-v2.5
- name: Get Hypre
if: steps.hypre-cache.outputs.cache-hit != 'true'
+9
View File
@@ -80,6 +80,7 @@ examples/sol_p.*
examples/sol_r.*
examples/sol_i.*
examples/ex6p-checkpoint.*
examples/order.*
examples/ex9.mesh
examples/ex9-mesh.*
examples/ex9-init.*
@@ -235,6 +236,8 @@ miniapps/meshing/minimal-surface
miniapps/meshing/pminimal-surface
miniapps/meshing/polar-nc
miniapps/meshing/mesh-quality
miniapps/meshing/hpref
miniapps/meshing/phpref
miniapps/meshing/mobius-strip.mesh
miniapps/meshing/klein-bottle.mesh
miniapps/meshing/toroid-*.mesh
@@ -252,6 +255,10 @@ miniapps/meshing/sol.gf
miniapps/meshing/optimized*
miniapps/meshing/perturbed*
miniapps/meshing/polar-nc.mesh
miniapps/meshing/mesh.*
miniapps/meshing/order.*
miniapps/meshing/sol.*
miniapps/meshing/refined.mesh
miniapps/mtop/parheat
miniapps/mtop/ParHeat*
@@ -274,8 +281,10 @@ miniapps/navier/navier_shear
miniapps/navier/navier_3dfoc
miniapps/navier/navier_turbchan
miniapps/navier/navier_cht
miniapps/navier/navier_windtunnel
miniapps/navier/tgv_out*.txt
miniapps/navier/*_output
miniapps/navier/inputs/
miniapps/nurbs/nurbs_ex1
miniapps/nurbs/nurbs_ex1p
+159 -107
View File
@@ -8,159 +8,225 @@
https://mfem.org
Version 4.7.1 (development)
Version 4.8.1 (development)
===========================
- Refactored ALGOIM cut integration rules. The interface is unified with
the interface for moment based cut integration rules.
- Altered (Par)GridFunction::Compute*Error functions to ensure they return
non-negative values and therefore behave as "norms".
- Added support for variational resampling of H1 vector fields to ParMoonolith
integration.
- The function Vector::SetSubVector(const Array<int> &, const real_t) now
executes on device if either the vector or the array have the device flag
set. This is most often used for setting constant essential boundary
conditions. A new function Vector::SetSubVectorHost has been added in cases
where host execution is always needed (e.g. when the DOFs array is small).
Version 4.8, released on Apr 9, 2025
====================================
Discretization improvements
---------------------------
- Added NURBS-based H(div) and H(curl) elements in 2D and 3D. Only on single
patch meshes. Only implemented for serial computations.
- Added high-order basis functions on pyramid-shaped elements for all spaces in
the de Rham complex based on the paper "Orientation embedded high order shape
functions for the exact sequence elements of all shapes" by Fuentes, Keith,
Demkowicz and Nagaraj (doi.org/10.1016/j.camwa.2015.04.027). Positive basis
functions (Bernstein basis) for H1 and L2 on pyramids were also added.
- Added support for boundary constraints to the hybridization class.
- Added support for parallel p- and hp-refinement on quad/hex meshes. For hp, we
currently support only isotropic refinement with L2 or H1 spaces. See the new
miniapps hpref and phpref in the miniapps/meshing/ directory.
- Added support for external boundary submeshes with nonconformal mesh adaptation.
- Added several improvements for hyperbolic problems:
* Assembly of Jacobians in HyperbolicFormIntegrator
* Component-wise upwinded flux (ComponentwiseUpwindFlux)
* Average fluxes in NumericalFlux (formerly RiemannSolver) and FluxFunction
- Added assembly of Jacobians to `HyperbolicFormIntegrator`.
- Added convenience methods to class FiniteElementSpace to directly identify all
degrees of freedom on the exterior faces of the domain, without referencing
boundary element attributes (GetExteriorVDofs and GetExteriorTrueDofs).
- Added average fluxes to `NumericalFlux` (formerly `RiemannSolver`)
and `FluxFunction`.
- Altered (Par)GridFunction::Compute*Error functions to ensure they return
non-negative values and therefore behave as "norms".
- Added component-wise upwinded flux (`ComponentwiseUpwindFlux`).
- SubMesh and ParSubMesh have been extended to work on nonconforming meshes.
Extracting volume and exterior surface submeshes are both supported.
- Added support for H(div) spaces in class QuadratureInterpolator. For now, only
- LinearFormIntegrator, BilinearFormIntegrator and NonlinearFormIntegrator now
inherit from a base class Integrator that centralizes the logic for selecting
quadrature rules. This includes a virtual method GetDefaultIntegrationRule,
which should be favored over directly defining a default integration rule in
the element-level assembly routines. The latter is still possible, by leaving
the new virtual method as its default base implementation of returning NULL.
- Added NURBS-based H(div) and H(curl) elements in 2D and 3D. Currently only for
single patch meshes in serial.
- Refactored ALGOIM cut integration rules. The interface is unified with the
interface for moment based cut integration rules.
- FiniteElementSpace has new methods to directly set the prolongation and
restriction operators to user-specified sparse matrices.
- Added support for H(div) spaces in class QuadratureInterpolator. Currently only
(vector) VALUES, (vector) PHYSICAL_VALUES, and PHYSICAL_MAGNITUDES evaluations
are implemented. [PR #4669]
are implemented.
- Added support for boundary constraints to class Hybridization.
- Added support for custom interpolation procedure in FindPointsGSLIB.
- Added GSLIB-based gather-scatter operator.
Meshing improvements
--------------------
- Added native AD support for numerous TMOP metrics that didn't have first or
second derivative implementations.
- Added support for nonuniform anisotropic mesh refinement on serial quad/hex
meshes with arbitrary spacing in each direction. This enables in particular
3:1 refinement, as demonstrated in the new meshing miniapp ref321.
- The ExodusII reader now handles pyramid and wedge element types. Mixed meshes
are also supported.
- Added capabilities for optimization and adaptation of periodic meshes with
TMOP. The internals of TMOP were modified so that the optimization problem is
always solved with respect to mesh displacements.
- Added support for nonuniform anisotropic (nonconforming) mesh refinement with
arbitrary spacing in each direction, for quadrilateral (2D) and hexahedral
(3D) meshes. This enables in particular 3:1 refinement, as demonstrated in the
new meshing miniapp ref321.
- New convenience methods for manipulating boundary attribute markers in class
Mesh: MarkExternalBoundaries, MarkNamedBoundaries, UnmarkInternalBoundaries
and UnmarkNamedBoundaries. See Examples 1/1p and 11p for basic usage.
New and updated examples and miniapps
-------------------------------------
- Added miniapps to demonstrate the H(div) and H(curl) NURBS elements.
- Added a new method, GetExteriorFaceMarker, to the serial and parallel mesh
classes for identifying faces on the exterior of the mesh irrespective of
their presence in the list of "boundary elements".
- Added an MFEM example for the eikonal equation. This new solver is based on
the proximal Galerkin method introduced by Keith and Surowiec.
- Added native AD support for computing the derivatives of numerous TMOP metrics
that didn't have first or second derivative implementations.
- Added a new toy miniapp that animates an interesting fidget spiral cone toy.
See miniapps/toys/spiral.cpp.
- Added ExodusII output capability which can handle in particular pyramid and
wedge element types. Mixed meshes are also supported.
- Added a command line option to all miniapps (`-p` or `--send-port`) for
specifying the GLVis server socket port (19916 by default).
- Added InverseElementTransformation::InitGuessType::EdgeScan as an alternative
initial guess type. This guess type tries solving with multiple initial guesses
along the r/s/t=0 edges of the element until a valid solution is found or all
initial guess points are exhausted.
- Added new convenience constructors for NURBS patches and knot vectors.
GPU computing
-------------
- Extended FindPointsGSLIB to support general field interpolation on GPUs. Note
that this requires that switch from gslib v1.0.7 to v1.0.9.
- Added support for GPU-accelerated batched linear algebra (using cuBLAS,
hipBLAS, MAGMA, or native MFEM functionality) through the BatchedLinAlg class.
- A new GPU kernel dispatch mechanism was introduced. Users can instantiate
specialized kernels for specific combinations of (for example) polynomial
degree and number of quadrature points using
`DiffusionIntegrator::AddSpecialization` and
`MassIntegrator::AddSpecialization` (this functionality may be added to more
integrators in the future).
degree and number of quadrature points using method AddSpecialization in
classes DiffusionIntegrator and MassIntegrator (this functionality may be
added to more integrators in the future).
- Calls to slower fallback kernels can be reported to `mfem::err` by setting
the environment variable `MFEM_REPORT_KERNELS` to any value other than `NO`
or by explicitly calling `KernelReporter::Enable`. Users can then add
specializations for these kernels to achieve higher performance.
- Added BatchInverseElementTransformation to batch InverseElementTransformation
searches. Batch searches are currently limited to meshes with a single element
geometry type of SEGMENT, SQUARE, or CUBE. Additional element geometry types
may be added in the future. Mixed element order meshes are supported. Batch
searches can be performed on the CPU (serial per MPI rank) or GPU. Embedded
elements (SEGMENT in 2D/3D space or SQUARE in 3D space) are supported, however
the existing solvers may struggle to find a valid solution.
- Element assembly kernels have been added for low-order refined to
high-order transfer operators. New kernels can be offloaded as device
kernels. Example usage may be found in lor-transfer.cpp under miniapps/tools.
- Calls to slower fallback kernels can be reported to mfem::err by setting the
environment variable MFEM_REPORT_KERNELS to any value other than NO or by
explicitly calling KernelReporter::Enable. For higher performance, users can
then add specializations for these kernels.
- Added support for GPU accelerated FindPointsGSLIB. Note that this will require
the users to switch from gslib v1.0.7 to v1.0.9.
- Element assembly kernels have been added for low-order refined -> high-order
transfer operators. New kernels can be offloaded as device kernels. Example
usage may be found in lor-transfer.cpp in the miniapps/tools/ directory.
- Added GPU acceleration and element assembly for DivDivIntegrator and
NormalTraceJumpIntegrator.
- Allow BlockLowerTriangularPreconditioner to run on GPU.
- Use device vectors in GMRES, FGMRES and other iterative methods.
Miscellaneous
-------------
Linear and nonlinear solvers
----------------------------
- Added GPU acceleration of the algebraic hybridization solver for grad-div
problems in H(div). See Example 4.
- Added a self-contained implementation of the Method of Moving Asymptotes (MMA)
for solving optimization problems.
- Added support for SUNDIALS v7. See the section "API changes" for some small
changes related to this new version.
- Refactored the `ARKStepSolver` class (ARKODE interface) to use
`TimeDependentOperator::Mult` only when the associated ODE operator is
expressed in explicit form (i.e., `TimeDependentOperator::isExplicit()`),
otherwise `TimeDependentOperator::ExplicitMult` is used. A check has been
added to `ARKStepSolver` to verify that the associated ODE operator is not in
explicit form when a mass matrix solver is enabled via a call to either the
`UseMFEMMassLinearSolver` or `UseSundialsMassLinearSolver` methods. This is
because enabling a mass matrix solver assumes that F(u,k,t) = M k in the
associated ODE operator.
- Changed the name of class IterativeSolverMonitor to IterativeSolverController,
which now allows for specifying convergence by a user defined criterion. For
backward compatibility, the old name is still available.
- Added support for custom interpolation procedure in FindPointsGSLIB.
- Refactored the ARKStepSolver class (ARKODE interface) to use the Mult() method
of TimeDependentOperator only when the associated ODE operator is expressed in
explicit form (i.e., TimeDependentOperator::isExplicit()), otherwise the
method ExplicitMult() is used. A check has been added to ARKStepSolver to
verify that the associated ODE operator is not in explicit form when a mass
matrix solver is enabled via a call to either the UseMFEMMassLinearSolver or
UseSundialsMassLinearSolver methods. This is because enabling a mass matrix
solver assumes that F(u,k,t) = M k in the associated ODE operator.
- `FiniteElementSpace` has new methods to directly set prolongation and
restriction operators to arbitrary sparse matrices.
- Added ODE solvers selection routines. This creates a uniformity across
examples, miniapps and other executables in regard to ODE (time-integrator)
selection.
- There are new convenience constructors for NURBS patches and knot vectors.
- Added new mechanism for retrieving and setting state vectors in ODE solvers.
This is relevant for AB/AM and gen-alpha solvers.
- Added convenience methods for manipulating boundary attribute marker arrays;
`(Par)Mesh::MarkExternalBoundaries`, `(Par)Mesh::UnmarkInternalBoundaries`,
`(Par)Mesh::MarkNamedBoundaries`, and `(Par)Mesh::UnmarkNamedBoundaries`.
See examples `ex1.cpp`, `ex1p.cpp`, and `ex11p.cpp` for basic usage.
- Added ODEsolver/ODEsolver2 unit tests to verify order of convergence and
read/write functionality.
- Added `(Par)Mesh::GetExteriorFaceMarker` for identifying faces on the
exterior of the mesh irrespective of their presence in the list of "boundary
elements".
New and updated examples and miniapps
-------------------------------------
- Added an MFEM example for the eikonal equation (examples/ex40) based on the
proximal Galerkin method introduced by Keith and Surowiec.
- Added methods to `(Par)FiniteElementSpace` to identify all degrees of freedom
located on the exterior of the domain without reference to the list of
"boundary elements"; `GetExteriorVDofs` and `GetExteriorTrueDofs`.
- Added miniapps to demonstrate the H(div) and H(curl) NURBS elements.
- `LinearFormIntegrator` and `NonlinearFormIntegrator` (including
`BilinearFormIntegrator`) now all inherit from a base class `Integrator`
that combines some logic related to selecting quadrature rules. This includes
a virtual method `Integrator::GetDefaultIntegrationRule`, which should be
favored over directly defining a default integration rule in the element-level
assembly routines (although the latter is still possible, by leaving the new
virtual method as its default base implementation of returning `NULL`).
- Fixed element visualization in the Mesh explorer miniapp.
- Added a command line option to all miniapps (-p or --send-port) for
specifying the GLVis server socket port (19916 by default).
- Added a new toy miniapp that animates an interesting fidget spiral cone toy.
See miniapps/toys/spiral.cpp.
Miscellaneous
-------------
- Updated the benchmarks (in tests/benchmarks) to work with the latest Google
Benchmarks classes (version 1.9.1). Renamed the MFEM_ENABLE_GOOGLE_BENCHMARKS
CMake option to just MFEM_ENABLE_BENCHMARKS.
- Changed the name of `IterativeSolverMonitor` to `IterativeSolverController`
which now allows for declaring convergence by a user defined criterion. For
backward compatibility, the old name is still available.
- Updated the minimum CMake version requirements:
* CMake >= 3.12 for CPU builds,
* CMake >= 3.17 for CUDA builds, and
* CMake >= 3.14 for HIP builds (CMake >= 3.12 may work as well, not tested).
- Various other simplifications, extensions, and bugfixes in the code.
API changes
-----------
- API change: 'TMOP_Metric_skew2D' has been marked as deprecated.
- In class GridFunction, fec was renamed to fec_owned.
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
- RiemannSolver was renamed to NumericalFlux (the old name has been deprecated
through typedef).
- API change: `RiemannSolver` was renamed to `NumericalFlux` (the old name has
been been deprecated through typedef)
- API change: support for SUNDIALS v7:
* the SUNDIALS types `realtype` and `booleantype` are no longer defined by v7
and therefore MFEM now uses the new type names `sunrealtype` and
`sunbooleantype`, respectively, which MFEM defines when using SUNDIALS < v6
- API changes due to SUNDIALS v7:
* the SUNDIALS types realtype and booleantype are no longer defined by v7
and therefore MFEM now uses the new type names sunrealtype and
sunbooleantype, respectively, which MFEM defines when using SUNDIALS < v6
where these types were not defined.
* The SUNDIALS macro `SUNLS_SUCCESS` and some other `*_SUCCESS` macros were
removed and replaced by `SUN_SUCCESS` in v7, so to avoid tedious checks for
SUNDIALS versions, MFEM now defines and uses the constant `SUN_SUCCESS` when
* The SUNDIALS macro SUNLS_SUCCESS and some other *_SUCCESS macros were
removed and replaced by SUN_SUCCESS in v7, so to avoid tedious checks for
SUNDIALS versions, MFEM now defines and uses the constant SUN_SUCCESS when
using SUNDIALS < v7.
* The constants `SUN_PREC_*`, introduced by SUNDIALS v6 are now introduced by
* The constants SUN_PREC_*, introduced by SUNDIALS v6 are now introduced by
MFEM when using SUNDIALS < v6 to avoid tedious version checks.
- TMOP_Metric_skew2D has been marked as deprecated.
Version 4.7, released on May 7, 2024
====================================
@@ -185,9 +251,6 @@ Meshing improvements
- Added support for internal boundary elements in nonconforming meshes.
- Added ExodusII output capability. The writer can handle first-order (Pyramid5,
Wedge6, Hex8, Tet4) and second-order FE types (Pyramid14, Wedge18, Hex27, Tet10).
- The ReadCubit Genesis mesh importer has been rewritten to improve readability.
Discretization improvements
@@ -247,15 +310,6 @@ New and updated examples and miniapps
- Added two new example codes: 38 and 39/39p described above. Substantially
updated Example 18/18p.
- Added ODE solvers selection routines. This creates a uniformity across examples,
miniapps and other executables in regard to ODE(time-integrator) selection.
- Added new mechanism for retrieving and setting state vectors in ODE solvers.
This is relevant for AB/AM and gen-alpha solvers.
- Added ODEsolver/ODEsolver2 unit tests to verify order of convergence and
read/write functionality.
Miscellaneous
-------------
- Updated the Doxygen documentation style, which now requires Doxygen version
@@ -269,8 +323,6 @@ Miscellaneous
- Various other simplifications, extensions, and bugfixes in the code.
- Added GSLIB-based gather-scatter operator.
Version 4.6, released on September 27, 2023
===========================================
+30 -24
View File
@@ -12,7 +12,8 @@
# The variable CMAKE_CXX_STANDARD and related were introduced in CMake v3.1
# Version 3.8 fixes the handling of CMAKE_CXX_STANDARD for try_compile.
# Version 3.8 or newer is required for direct CUDA support.
cmake_minimum_required(VERSION 3.8)
# Version 3.12 or newer is required for setting maximum policy version.
cmake_minimum_required(VERSION 3.12.0...4.0.0)
message(STATUS "CMake version: ${CMAKE_VERSION}")
set(USER_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/config/user.cmake" CACHE PATH
"Path to optional user configuration file.")
@@ -58,7 +59,7 @@ project(mfem NONE)
# Current version of MFEM, see also `makefile`.
# mfem_VERSION = (string)
# MFEM_VERSION = (int) [automatically derived from mfem_VERSION]
set(${PROJECT_NAME}_VERSION 4.7.1)
set(${PROJECT_NAME}_VERSION 4.8.1)
# Prohibit in-source build
if (${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR})
@@ -104,6 +105,13 @@ endif()
# Include xSDK default CMake file.
include("${CMAKE_CURRENT_SOURCE_DIR}/config/XSDKDefaults.cmake")
# Path to MFEM's CMake modules and utilities.
set(MFEM_CMAKE_PATH ${PROJECT_SOURCE_DIR}/config)
set(CMAKE_MODULE_PATH ${MFEM_CMAKE_PATH}/cmake/modules)
# Load MFEM CMake utilities.
include(MfemCmakeUtilities)
# Enable languages.
enable_language(CXX)
if (MINGW)
@@ -116,16 +124,15 @@ if (MFEM_USE_CUDA)
if (MFEM_USE_HIP)
message(FATAL_ERROR " *** MFEM_USE_HIP cannot be combined with MFEM_USE_CUDA.")
endif()
# CUDAToolkit was added in CMake 3.17, so we require at least CMake 3.17 when
# CUDA is enabled:
if (CMAKE_VERSION VERSION_LESS 3.17.0)
message(FATAL_ERROR "CUDA support requires CMake >= 3.17")
endif()
# Use ${CMAKE_CXX_COMPILER} as the cuda host compiler.
if (NOT CMAKE_CUDA_HOST_COMPILER)
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER})
endif()
enable_language(CUDA)
set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD} CACHE STRING
"CUDA standard to use.")
set(CMAKE_CUDA_STANDARD_REQUIRED ON CACHE BOOL
"Force the use of the chosen CUDA standard.")
set(CMAKE_CUDA_EXTENSIONS OFF CACHE BOOL "Enable CUDA standard extensions.")
set(CUDA_FLAGS "--expt-extended-lambda")
if (CMAKE_VERSION VERSION_LESS 3.18.0)
set(CUDA_FLAGS "-arch=${CUDA_ARCH} ${CUDA_FLAGS}")
@@ -140,18 +147,19 @@ if (MFEM_USE_CUDA)
set(CUDA_ARCH "CMAKE_CUDA_ARCHITECTURES: ${CMAKE_CUDA_ARCHITECTURES}")
endif()
message(STATUS "Using CUDA architecture: ${CUDA_ARCH}")
if (CMAKE_VERSION VERSION_LESS 3.12.0)
# CMake versions 3.8 and 3.9 require this to work; 3.10 and 3.11 are not
# tested and may not actually need this (but should be ok to keep).
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
endif()
enable_language(CUDA)
set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD} CACHE STRING
"CUDA standard to use.")
set(CMAKE_CUDA_STANDARD_REQUIRED ON CACHE BOOL
"Force the use of the chosen CUDA standard.")
set(CMAKE_CUDA_EXTENSIONS OFF CACHE BOOL "Enable CUDA standard extensions.")
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${CUDA_FLAGS}")
find_package(CUDAToolkit REQUIRED)
set(CUSPARSE_FOUND TRUE)
set(CUBLAS_FOUND TRUE)
get_target_property(CUSPARSE_LIBRARIES CUDA::cusparse LOCATION)
get_target_property(CUBLAS_LIBRARIES CUDA::cublas LOCATION)
# Initialize CUSPARSE_LIBRARIES and CUBLAS_LIBRARIES:
mfem_culib_set_libraries(CUSPARSE cusparse)
mfem_culib_set_libraries(CUBLAS cublas)
endif()
if (XSDK_ENABLE_C)
@@ -164,13 +172,6 @@ endif()
# Suppress warnings about MACOSX_RPATH
set(CMAKE_MACOSX_RPATH OFF CACHE BOOL "")
# CMake needs to know where to find things
set(MFEM_CMAKE_PATH ${PROJECT_SOURCE_DIR}/config)
set(CMAKE_MODULE_PATH ${MFEM_CMAKE_PATH}/cmake/modules)
# Load MFEM CMake utilities.
include(MfemCmakeUtilities)
string(TOUPPER "${PROJECT_NAME}" PROJECT_NAME_UC)
mfem_version_to_int(${${PROJECT_NAME}_VERSION} ${PROJECT_NAME_UC}_VERSION)
set(${PROJECT_NAME_UC}_VERSION_STRING ${${PROJECT_NAME}_VERSION})
@@ -387,6 +388,11 @@ if (MFEM_USE_GSLIB)
find_package(GSLIB REQUIRED)
endif()
# HDF5
if (MFEM_USE_HDF5)
find_package(HDF5 REQUIRED)
endif()
# NetCDF
if (MFEM_USE_NETCDF)
find_package(NetCDF REQUIRED)
@@ -568,7 +574,7 @@ find_package(Threads REQUIRED)
# integers, the METIS header (with 32-bit indices, as used by mfem) needs to
# be before SuiteSparse.
set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB
SUNDIALS PETSC SLEPC MUMPS AXOM FMS CONDUIT Ginkgo GNUTLS GSLIB HDF5
NETCDF MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE
ADIOS2 MKL_CPARDISO MKL_PARDISO AMGX MAGMA CUSPARSE CUBLAS CALIPER CODIPACK
BENCHMARK PARELAG TRIBOL MPI_CXX HIP HIPBLAS HIPSPARSE MOONOLITH BLITZ
+3
View File
@@ -120,7 +120,9 @@ The MFEM source code has the following structure:
| └── superlu
├── fem
│ ├── ceed
│ ├── eltrans
│ ├── fe
│ ├── gslib
│ ├── integ
│ ├── lor
│ ├── moonolith
@@ -128,6 +130,7 @@ The MFEM source code has the following structure:
│ └── tmop
├── general
├── linalg
│ ├── batched
│ └── simd
├── mesh
│ └── submesh
+30 -4
View File
@@ -122,9 +122,14 @@ Parallel build:
(For METIS 5, see https://mfem.org/building/#parallel-build-using-metis-5)
CUDA build:
(this build requires CMake 3.8 or newer)
(this build requires CMake 3.17 or newer)
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
cmake <mfem-source-dir> -DMFEM_USE_CUDA=YES
cmake <mfem-source-dir> -DMFEM_USE_CUDA=YES -DCUDA_ARCH=sm_70
make -j 4
HIP build:
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
cmake <mfem-source-dir> -DMFEM_USE_HIP=YES -DHIP_ARCH=gfx942 -DCMAKE_CXX_COMPILER=amdclang++ -DCMAKE_HIP_COMPILER=amdclang++
make -j 4
Example codes (serial/parallel, depending on the build):
@@ -418,6 +423,10 @@ MFEM_USE_GNUTLS = YES/NO
When MFEM_USE_GNUTLS is enabled, the additional build options, GNUTLS_*, are
also used, see below.
MFEM_USE_HDF5 = YES/NO
The HDF5 library is used for input and output of HDF5 files, for example
Cubit mesh files or VTKHDF files for ParaView.
MFEM_USE_NETCDF = YES/NO
NetCDF is the library that is used by the SNL Cubit mesh generator to create
Genesis mesh files. This option enables a reader for these files, which
@@ -728,6 +737,9 @@ The specific libraries and their options are:
Options: GNUTLS_OPT, GNUTLS_LIB.
Versions: GnuTLS >= 2.12.0, older versions may work too.
- HDF5 (optional), used when MFEM_USE_HDF5 = YES, required for reading and
writing files in VTKHDF format.
- NetCDF (optional), used when MFEM_USE_NETCDF = YES, required for reading Cubit
mesh files. Also requires installation of HDF5 and ZLIB, as explained at the
NetCDF web site. Note that we use the plain vanilla "C" version of NetCDF, you
@@ -1002,7 +1014,7 @@ Configuration variables (CMake)
===============================
See the configuration file config/defaults.cmake for the default settings.
Note: the option MFEM_USE_CUDA requires CMake version 3.8 or newer!
Note: the option MFEM_USE_CUDA requires CMake version 3.17 or newer!
Non-standard CMake variables for compilers:
CXX - If set, overwrite the auto-detected C++ compiler, serial build
@@ -1033,6 +1045,7 @@ MFEM_USE_STRUMPACK
MFEM_USE_GINKGO
MFEM_USE_AMGX
MFEM_USE_GNUTLS
MFEM_USE_HDF5
MFEM_USE_NETCDF
MFEM_USE_MPFR
MFEM_USE_ZLIB
@@ -1161,6 +1174,19 @@ larger problems, there are two options:
1. Building hypre with '--enable-bigint' defines the local and global indices to
be 64-bit. This is convenient, but requires more memory than necessary.
2. Building hypre with '--enable-mixedint' defines the local indiced to be
2. Building hypre with '--enable-mixedint' defines the local indices to be
32-bit, while using a 64-bit storage for global indices. This option is
currently tested only in ex1p, and may not work in more general settings.
Specific options for HIP
========================
MFEM expects the `ROCM_PATH` environment variable to be set to the path of the
ROCM install, as well as having `$ROCM_PATH/bin` in `PATH`.
Specific options for RAJA+HIP+MPI
=================================
RAJA uses CMake's built-in HIP support (added in CMake 3.21), while MFEM uses
the older HIP C++ library build/linkage. To ensure proper build and linkage
check that `CMAKE_CXX_COMPILER` and `CMAKE_HIP_COMPILER` are set to the same
compiler. This is especially important when using an MPI compiler (for example
crayCC) where some linker flags may get dropped if these two are not identical.
+1
View File
@@ -41,6 +41,7 @@ set(MFEM_USE_MAGMA @MFEM_USE_MAGMA@)
set(MFEM_USE_HIOP @MFEM_USE_HIOP@)
set(MFEM_USE_GNUTLS @MFEM_USE_GNUTLS@)
set(MFEM_USE_GSLIB @MFEM_USE_GSLIB@)
set(MFEM_USE_HDF5 @MFEM_USE_HDF5@)
set(MFEM_USE_NETCDF @MFEM_USE_NETCDF@)
set(MFEM_USE_PETSC @MFEM_USE_PETSC@)
set(MFEM_USE_SLEPC @MFEM_USE_SLEPC@)
+3
View File
@@ -132,6 +132,9 @@
// Enable Conduit support.
#cmakedefine MFEM_USE_CONDUIT
// Enable functionality based on the HDF5 library (reading VTKHDF files).
#cmakedefine MFEM_USE_HDF5
// Enable functionality based on the NetCDF library (reading CUBIT files).
#cmakedefine MFEM_USE_NETCDF
+14 -4
View File
@@ -25,7 +25,12 @@ if (HYPRE_FOUND)
find_package(rocsparse REQUIRED)
find_package(rocrand REQUIRED)
endif()
return()
if (HYPRE_LIBRARIES AND HYPRE_INCLUDE_DIRS AND HYPRE_VERSION)
find_package_handle_standard_args(HYPRE
REQUIRED_VARS HYPRE_LIBRARIES HYPRE_INCLUDE_DIRS HYPRE_VERSION
)
return()
endif()
endif()
include(MfemCmakeUtilities)
@@ -77,9 +82,10 @@ endif()
if (HYPRE_FOUND AND HYPRE_USING_CUDA)
find_package(CUDAToolkit REQUIRED)
get_target_property(CUSPARSE_LIBRARIES CUDA::cusparse LOCATION)
get_target_property(CURAND_LIBRARIES CUDA::curand LOCATION)
get_target_property(CUBLAS_LIBRARIES CUDA::cublas LOCATION)
# Initialize CUSPARSE_LIBRARIES, CURAND_LIBRARIES, and CUBLAS_LIBRARIES:
mfem_culib_set_libraries(CUSPARSE cusparse)
mfem_culib_set_libraries(CURAND curand)
mfem_culib_set_libraries(CUBLAS cublas)
list(APPEND HYPRE_LIBRARIES ${CUSPARSE_LIBRARIES} ${CURAND_LIBRARIES}
${CUBLAS_LIBRARIES})
set(HYPRE_LIBRARIES ${HYPRE_LIBRARIES} CACHE STRING
@@ -95,3 +101,7 @@ if (HYPRE_FOUND AND HYPRE_USING_HIP)
"HYPRE libraries + dependencies." FORCE)
message(STATUS "Updated HYPRE_LIBRARIES: ${HYPRE_LIBRARIES}")
endif()
find_package_handle_standard_args(HYPRE
REQUIRED_VARS HYPRE_LIBRARIES HYPRE_INCLUDE_DIRS HYPRE_VERSION
)
+4 -2
View File
@@ -19,8 +19,10 @@ mfem_find_package(MAGMA MAGMA MAGMA_DIR "include" "magma.h" "lib" "magma"
"Paths to headers required by MAGMA." "Libraries required by MAGMA.")
if (MAGMA_FOUND AND MFEM_USE_CUDA)
get_target_property(CUSPARSE_LIBRARIES CUDA::cusparse LOCATION)
get_target_property(CUBLAS_LIBRARIES CUDA::cublas LOCATION)
find_package(CUDAToolkit REQUIRED)
# Initialize CUSPARSE_LIBRARIES and CUBLAS_LIBRARIES:
mfem_culib_set_libraries(CUSPARSE cusparse)
mfem_culib_set_libraries(CUBLAS cublas)
list(APPEND MAGMA_LIBRARIES ${CUSPARSE_LIBRARIES} ${CUBLAS_LIBRARIES})
set(MAGMA_LIBRARIES ${MAGMA_LIBRARIES} CACHE STRING
"MAGMA libraries + dependencies." FORCE)
+20 -11
View File
@@ -123,16 +123,9 @@ macro(add_mfem_miniapp MFEM_EXE_NAME)
# If CUDA is enabled, tag source files to be compiled with nvcc.
if (MFEM_USE_CUDA)
set_source_files_properties(${MAIN_LIST} ${EXTRA_SOURCES_LIST} PROPERTIES LANGUAGE CUDA)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
else()
set(LIST_)
foreach(item IN LISTS EXTRA_OPTIONS_LIST)
list(APPEND LIST_ "-Xcompiler=${item}")
endforeach()
set(EXTRA_OPTIONS_LIST ${LIST_})
endif()
set_source_files_properties(${MAIN_LIST} ${EXTRA_SOURCES_LIST}
PROPERTIES LANGUAGE CUDA)
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
endif()
# Actually add the executable
@@ -157,6 +150,21 @@ macro(add_mfem_miniapp MFEM_EXE_NAME)
endif()
endmacro()
# Macro for setting variables like '<culib>_LIBRARIES' where <culib> is a CUDA
# library like cublas. This macro assumes that the CUDAToolkit module was loaded
# successfully. Example usage:
# mfem_culib_set_libraries(CUBLAS cublas)
macro(mfem_culib_set_libraries _CULIB _culib)
# The following command does not work with older CMake versions, e.g. 3.20:
# get_target_property(${_CULIB}_LIBRARIES CUDA::${_culib} LOCATION)
# Therefore, we use the respective internal variable:
set(${_CULIB}_LIBRARIES ${CUDA_${_culib}_LIBRARY})
if (NOT ${_CULIB}_LIBRARIES)
message(FATAL_ERROR
"Error setting ${_CULIB}_LIBRARIES: ${${_CULIB}_LIBRARIES}")
endif()
endmacro()
# Auxiliary function, used in mfem_find_package().
function(mfem_find_component Prefix DirVar IncSuffixes Header LibSuffixes Lib
@@ -869,7 +877,8 @@ function(mfem_export_mk_files)
MFEM_USE_OCCA MFEM_USE_CEED MFEM_USE_CALIPER MFEM_USE_UMPIRE MFEM_USE_SIMD
MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_MKL_PARDISO
MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_BENCHMARK MFEM_USE_PARELAG
MFEM_USE_TRIBOL MFEM_USE_MOONOLITH MFEM_USE_ALGOIM MFEM_USE_ENZYME)
MFEM_USE_TRIBOL MFEM_USE_MOONOLITH MFEM_USE_ALGOIM MFEM_USE_ENZYME
MFEM_USE_HDF5)
foreach(var ${CONFIG_MK_BOOL_VARS})
if (${var})
set(${var} YES)
@@ -93,17 +93,17 @@ macro (RESOLVE_LIBRARIES LIBS LINK_LINE)
set (_directory_list ${_directory_list} ${libpath})
set (token ${libname})
endif (token MATCHES "^/")
set (_lib "NOTFOUND" CACHE FILEPATH "Cleared" FORCE)
set (_lib "NOTFOUND")
find_library (_lib ${token} HINTS ${_directory_list} ${_root})
if (_lib)
string (REPLACE "//" "/" _lib ${_lib})
string (REPLACE "//" "/" _lib ${_lib})
list (APPEND _libs_found ${_lib})
else (_lib)
message (STATUS "Unable to find library ${token}")
endif (_lib)
unset(_lib CACHE)
endif (token MATCHES "-L([^\" ]+|\"[^\"]+\")")
endforeach (token)
set (_lib "NOTFOUND" CACHE INTERNAL "Scratch variable" FORCE)
# only the LAST occurrence of each library is required since there should be no circular dependencies
if (_libs_found)
list (REVERSE _libs_found)
+3
View File
@@ -132,6 +132,9 @@
// Enable Conduit support.
// #define MFEM_USE_CONDUIT
// Enable functionality based on the HDF5 library
// #define MFEM_USE_HDF5
// Enable functionality based on the NetCDF library (reading CUBIT files).
// #define MFEM_USE_NETCDF
+1
View File
@@ -40,6 +40,7 @@ MFEM_USE_GINKGO = @MFEM_USE_GINKGO@
MFEM_USE_AMGX = @MFEM_USE_AMGX@
MFEM_USE_MAGMA = @MFEM_USE_MAGMA@
MFEM_USE_GNUTLS = @MFEM_USE_GNUTLS@
MFEM_USE_HDF5 = @MFEM_USE_HDF5@
MFEM_USE_NETCDF = @MFEM_USE_NETCDF@
MFEM_USE_PETSC = @MFEM_USE_PETSC@
MFEM_USE_SLEPC = @MFEM_USE_SLEPC@
+1
View File
@@ -43,6 +43,7 @@ option(MFEM_USE_AMGX "Enable AmgX usage" OFF)
option(MFEM_USE_MAGMA "Enable MAGMA usage" OFF)
option(MFEM_USE_GNUTLS "Enable GNUTLS usage" OFF)
option(MFEM_USE_GSLIB "Enable GSLIB usage" OFF)
option(MFEM_USE_HDF5 "Enable HDF5 usage" OFF)
option(MFEM_USE_NETCDF "Enable NETCDF usage" OFF)
option(MFEM_USE_PETSC "Enable PETSc support." OFF)
option(MFEM_USE_SLEPC "Enable SLEPc support." OFF)
+14 -4
View File
@@ -145,6 +145,7 @@ MFEM_USE_GINKGO = NO
MFEM_USE_AMGX = NO
MFEM_USE_MAGMA = NO
MFEM_USE_GNUTLS = NO
MFEM_USE_HDF5 = NO
MFEM_USE_NETCDF = NO
MFEM_USE_PETSC = NO
MFEM_USE_SLEPC = NO
@@ -401,9 +402,14 @@ MAGMA_LIB = -L$(MAGMA_DIR)/lib -l:libmagma.a -lcublas -lcusparse $(LAPACK_LIB)
GNUTLS_OPT =
GNUTLS_LIB = -lgnutls
# HDF5 library configuration
HDF5_DIR = $(HOME)/local
HDF5_OPT = -I$(HDF5_DIR)/include
HDF5_LIB = $(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib -lhdf5_hl -lhdf5 \
$(ZLIB_LIB)
# NetCDF library configuration
NETCDF_DIR = $(HOME)/local
HDF5_DIR = $(HOME)/local
NETCDF_OPT = -I$(NETCDF_DIR)/include -I$(HDF5_DIR)/include $(ZLIB_OPT)
NETCDF_LIB = $(XLINKER)-rpath,$(NETCDF_DIR)/lib -L$(NETCDF_DIR)/lib\
$(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib\
@@ -484,8 +490,8 @@ SIDRE_LIB = \
# Note that PUMI_DIR is needed -- it is used to check for gmi_sim.h
PUMI_DIR = @MFEM_DIR@/../pumi-2.1.0
PUMI_OPT = -I$(PUMI_DIR)/include
PUMI_LIB = -L$(PUMI_DIR)/lib -lpumi -lcrv -lma -lmds -lapf -lpcu -lgmi -lparma\
-llion -lmth -lapf_zoltan -lspr
PUMI_LIB = -L$(PUMI_DIR)/lib64 -L$(PUMI_DIR)/lib -lpumi -lcrv -lma -lmds -lapf\
-lpcu -lgmi -lparma -llion -lmth -lapf_zoltan -lspr
# HIOP
HIOP_DIR = @MFEM_DIR@/../hiop/install
@@ -568,7 +574,11 @@ RAJA_LIB = $(XLINKER)-rpath,$(RAJA_DIR)/lib -L$(RAJA_DIR)/lib -lRAJA $(CAMP_LIB)
# UMPIRE library configuration
UMPIRE_DIR = @MFEM_DIR@/../umpire
UMPIRE_OPT = -I$(UMPIRE_DIR)/include $(if $(CAMP_DIR), -I$(CAMP_DIR)/include)
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -lumpire $(CAMP_LIB)
UMPIRE_LIB = -L$(UMPIRE_DIR)/lib -L$(UMPIRE_DIR)/lib64 -lumpire $(CAMP_LIB)
ifdef FMT_DIR
UMPIRE_OPT += -I$(FMT_DIR)/include
UMPIRE_LIB += -L$(FMT_DIR)/lib -L$(FMT_DIR)/lib64 -lfmt
endif
# MKL CPardiso library configuration
MKL_CPARDISO_DIR ?=
+3 -3
View File
@@ -17,7 +17,7 @@ We provide two containers, which you can either build or use directly from
In the above, "ghcr.io" means "GitHub Container Registry" and
is the [GitHub packages](https://github.com/features/packages) registry that supports
Docker images and other OCI artifacts.
Docker images and other OCI artifacts.
### Ubuntu
@@ -132,7 +132,7 @@ examples.
> Use this build for a development environment with spack and mfem
This container is also [provided on GitHub packages](https://github.com/mfem/mfem/pkgs/container/mfem-ubuntu-base),
This container is also [provided on GitHub packages](https://github.com/mfem/mfem/pkgs/container/mfem-ubuntu-base),
however you can build it locally too:
```bash
@@ -197,7 +197,7 @@ Average reduction factor = 0.140201
This container is likely ideal for someone that wants to develop mfem itself.
For other use cases, we recommend using the slimmer image. As an example,
if you want to develop with your own code base (and mfem as is in the container)
if you want to develop with your own code base (and mfem as is in the container)
you can bind to somewhere else in the container (e.g., src)
```bash
@@ -0,0 +1,20 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 186a320..39e5356 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.12.0...4.0.0)
project(METIS)
set(GKLIB_PATH "${CMAKE_SOURCE_DIR}/GKlib" CACHE PATH "path to GKlib")
diff --git a/GKlib/CMakeLists.txt b/GKlib/CMakeLists.txt
index 67b600a..44321a6 100644
--- a/GKlib/CMakeLists.txt
+++ b/GKlib/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 3.12.0...4.0.0)
project(GKlib)
get_filename_component(abs "." ABSOLUTE)
@@ -22,6 +22,7 @@ vcpkg_extract_source_archive_ex(
fix-linux-build-error.patch
install-metisConfig.patch
fix-INT_MIN_define.patch
cmake4.patch
)
vcpkg_configure_cmake(
+38
View File
@@ -0,0 +1,38 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see fem/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.5 -0.5 0
0.5 -0.5 0
0.5 0.5 0
-0.5 0.5 0
0 0 0.7071067811865475
+108
View File
@@ -0,0 +1,108 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see fem/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
# PYRAMID = 7
#
dimension
3
elements
16
1 5 12 13 16 15 21 22 25 24
1 6 9 12 8 18 21 17
1 6 11 8 12 20 17 21
1 6 3 2 12 6 5 15
1 6 11 12 2 14 15 5
1 6 3 12 0 4 13 1
1 6 9 0 12 10 1 13
1 7 12 13 22 21 19
1 7 15 16 13 12 7
1 7 12 21 24 15 23
1 7 9 12 21 18 19
1 7 11 20 21 12 23
1 7 9 10 13 12 19
1 7 11 12 15 14 23
1 7 3 6 15 12 7
1 7 3 12 13 4 7
boundary
39
1 3 5 6 3 2
2 2 6 7 3
2 2 7 4 3
3 3 3 4 1 0
4 2 11 12 8
4 2 9 8 12
5 2 3 12 2
5 2 11 2 12
6 3 0 1 10 9
7 2 10 19 9
7 2 18 9 19
8 3 8 9 18 17
9 2 4 13 1
9 2 10 1 13
10 2 4 7 13
10 2 16 13 7
11 3 13 16 25 22
12 2 10 13 19
12 2 22 19 13
13 2 6 15 7
13 2 16 7 15
14 2 6 5 15
14 2 14 15 5
15 2 14 23 15
15 2 24 15 23
16 3 16 15 24 25
17 3 5 2 11 14
18 2 3 0 12
18 2 9 12 0
19 3 11 8 17 20
20 2 14 11 23
20 2 20 23 11
21 2 18 21 17
21 2 20 17 21
22 2 18 19 21
22 2 22 21 19
23 3 21 22 25 24
24 2 20 21 23
24 2 24 23 21
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
+3 -3
View File
@@ -1,9 +1,9 @@
MFEM INLINE mesh v1.0
type = pyramid
nx = 4
ny = 4
nz = 4
nx = 2
ny = 2
nz = 2
sx = 1.0
sy = 1.0
sz = 1.0
+8 -5
View File
@@ -48,7 +48,7 @@ PROJECT_NAME = MFEM
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = v4.7.1
PROJECT_NUMBER = v4.8.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -951,7 +951,10 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/fem/ceed/integrators/nlconvection \
@MFEM_SOURCE_DIR@/fem/ceed/interface \
@MFEM_SOURCE_DIR@/fem/ceed/solvers \
@MFEM_SOURCE_DIR@/fem/eltrans \
@MFEM_SOURCE_DIR@/fem/fe \
@MFEM_SOURCE_DIR@/fem/gslib \
@MFEM_SOURCE_DIR@/fem/integ \
@MFEM_SOURCE_DIR@/fem/lor \
@MFEM_SOURCE_DIR@/fem/moonolith \
@MFEM_SOURCE_DIR@/fem/qinterp \
@@ -969,6 +972,8 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/adjoint \
@MFEM_SOURCE_DIR@/miniapps/autodiff \
@MFEM_SOURCE_DIR@/miniapps/common \
@MFEM_SOURCE_DIR@/miniapps/dpg \
@MFEM_SOURCE_DIR@/miniapps/dpg/util \
@MFEM_SOURCE_DIR@/miniapps/electromagnetics \
@MFEM_SOURCE_DIR@/miniapps/gslib \
@MFEM_SOURCE_DIR@/miniapps/hdiv-linear-solver \
@@ -986,12 +991,10 @@ INPUT = @MFEM_SOURCE_DIR@/doc/CodeDocumentation.dox \
@MFEM_SOURCE_DIR@/miniapps/performance \
@MFEM_SOURCE_DIR@/miniapps/shifted \
@MFEM_SOURCE_DIR@/miniapps/solvers \
@MFEM_SOURCE_DIR@/miniapps/spde \
@MFEM_SOURCE_DIR@/miniapps/tools \
@MFEM_SOURCE_DIR@/miniapps/toys \
@MFEM_SOURCE_DIR@/miniapps/tribol \
@MFEM_SOURCE_DIR@/miniapps/spde \
@MFEM_SOURCE_DIR@/miniapps/dpg \
@MFEM_SOURCE_DIR@/miniapps/dpg/util
@MFEM_SOURCE_DIR@/miniapps/tribol
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+16 -16
View File
@@ -42,10 +42,10 @@ namespace mfem {
* - mfem::forall functions in forall.hpp
*
* <H3>Example codes</H3>
* - <a class="el" href="ex0_8cpp_source.html">Example 0</a>: simplest example, nodal H1 FEM for the Laplace problem
* - <a class="el" href="ex0p_8cpp_source.html">Example 0p</a>: simplest parallel example, nodal H1 FEM for the Laplace problem
* - <a class="el" href="examples_2ex1_8cpp_source.html">Example 1</a>: nodal H1 FEM for the Laplace problem (same discretization as ex0 but with more sophisticated options)
* - <a class="el" href="examples_2ex1p_8cpp_source.html">Example 1p</a>: parallel nodal H1 FEM for the Laplace problem (same discretization as ex0p but with more sophisticated options)
* - <a class="el" href="ex0_8cpp_source.html">Example 0</a>: simplest example, nodal H1 FEM for the Poisson problem
* - <a class="el" href="ex0p_8cpp_source.html">Example 0p</a>: simplest parallel example, nodal H1 FEM for the Poisson problem
* - <a class="el" href="examples_2ex1_8cpp_source.html">Example 1</a>: nodal H1 FEM for the Poisson problem (same discretization as ex0 but with more sophisticated options)
* - <a class="el" href="examples_2ex1p_8cpp_source.html">Example 1p</a>: parallel nodal H1 FEM for the Poisson problem (same discretization as ex0p but with more sophisticated options)
* - <a class="el" href="ex2_8cpp_source.html">Example 2</a>: vector FEM for linear elasticity
* - <a class="el" href="ex2p_8cpp_source.html">Example 2p</a>: parallel vector FEM for linear elasticity
* - <a class="el" href="ex3_8cpp_source.html">Example 3</a>: Nedelec H(curl) FEM for the definite Maxwell problem
@@ -54,12 +54,12 @@ namespace mfem {
* - <a class="el" href="ex4p_8cpp_source.html">Example 4p</a>: parallel Raviart-Thomas H(div) FEM for the grad-div problem
* - <a class="el" href="ex5_8cpp_source.html">Example 5</a>: mixed pressure-velocity FEM for the Darcy problem
* - <a class="el" href="ex5p_8cpp_source.html">Example 5p</a>: parallel mixed pressure-velocity FEM for the Darcy problem
* - <a class="el" href="ex6_8cpp_source.html">Example 6</a>: non-conforming adaptive mesh refinement for the Laplace problem
* - <a class="el" href="ex6p_8cpp_source.html">Example 6p</a>: parallel non-conforming adaptive mesh refinement for the Laplace problem
* - <a class="el" href="ex7_8cpp_source.html">Example 7</a>: Laplace problem on a surface (the unit sphere)
* - <a class="el" href="ex7p_8cpp_source.html">Example 7p</a>: parallel Laplace problem on a surface (the unit sphere)
* - <a class="el" href="ex8_8cpp_source.html">Example 8</a>: Discontinuous Petrov-Galerkin (DPG) for the Laplace problem
* - <a class="el" href="ex8p_8cpp_source.html">Example 8p</a>: parallel Discontinuous Petrov-Galerkin (DPG) for the Laplace problem
* - <a class="el" href="ex6_8cpp_source.html">Example 6</a>: non-conforming adaptive mesh refinement for the Poisson problem
* - <a class="el" href="ex6p_8cpp_source.html">Example 6p</a>: parallel non-conforming adaptive mesh refinement for the Poisson problem
* - <a class="el" href="ex7_8cpp_source.html">Example 7</a>: screened Poisson problem on a surface (the unit sphere)
* - <a class="el" href="ex7p_8cpp_source.html">Example 7p</a>: parallel screened Poisson problem on a surface (the unit sphere)
* - <a class="el" href="ex8_8cpp_source.html">Example 8</a>: Discontinuous Petrov-Galerkin (DPG) for the Poisson problem
* - <a class="el" href="ex8p_8cpp_source.html">Example 8p</a>: parallel Discontinuous Petrov-Galerkin (DPG) for the Poisson problem
* - <a class="el" href="ex9_8cpp_source.html">Example 9</a>: Discontinuous Galerkin (DG) time-dependent advection
* - <a class="el" href="ex9p_8cpp_source.html">Example 9p</a>: parallel Discontinuous Galerkin (DG) time-dependent advection
* - <a class="el" href="ex10_8cpp_source.html">Example 10</a>: time-dependent implicit nonlinear elasticity
@@ -67,8 +67,8 @@ namespace mfem {
* - <a class="el" href="ex11p_8cpp_source.html">Example 11p</a>: parallel Laplace eigensolver
* - <a class="el" href="ex12p_8cpp_source.html">Example 12p</a>: parallel linear elasticity eigensolver
* - <a class="el" href="ex13p_8cpp_source.html">Example 13p</a>: parallel Maxwell eigensolver
* - <a class="el" href="ex14_8cpp_source.html">Example 14</a>: Discontinuous Galerkin (DG) for the Laplace problem
* - <a class="el" href="ex14p_8cpp_source.html">Example 14p</a>: parallel Discontinuous Galerkin (DG) for the Laplace problem
* - <a class="el" href="ex14_8cpp_source.html">Example 14</a>: Discontinuous Galerkin (DG) for the Poisson problem
* - <a class="el" href="ex14p_8cpp_source.html">Example 14p</a>: parallel Discontinuous Galerkin (DG) for the Poisson problem
* - <a class="el" href="ex15_8cpp_source.html">Example 15</a>: dynamic AMR for Laplace with prescribed time-dependent source
* - <a class="el" href="ex15p_8cpp_source.html">Example 15p</a>: parallel dynamic AMR for Laplace with prescribed time-dependent source
* - <a class="el" href="ex16_8cpp_source.html">Example 16</a>: time-dependent nonlinear heat equation
@@ -90,8 +90,8 @@ namespace mfem {
* - <a class="el" href="ex24p_8cpp_source.html">Example 24p</a>: parallel mixed finite element spaces and interpolators
* - <a class="el" href="ex25_8cpp_source.html">Example 25</a>: simulation of electromagnetic wave propagation using a Perfectly Matched Layer (PML)
* - <a class="el" href="ex25p_8cpp_source.html">Example 25p</a>: parallel simulation of electromagnetic wave propagation using a Perfectly Matched Layer (PML)
* - <a class="el" href="ex26_8cpp_source.html">Example 26</a>: multigrid preconditioner for the Laplace problem using nodal H1 FEM
* - <a class="el" href="ex26p_8cpp_source.html">Example 26p</a>: parallel multigrid preconditioner for the Laplace problem using nodal H1 FEM
* - <a class="el" href="ex26_8cpp_source.html">Example 26</a>: multigrid preconditioner for the Poisson problem using nodal H1 FEM
* - <a class="el" href="ex26p_8cpp_source.html">Example 26p</a>: parallel multigrid preconditioner for the Poisson problem using nodal H1 FEM
* - <a class="el" href="ex27_8cpp_source.html">Example 27</a>: boundary conditions for the Laplace problem
* - <a class="el" href="ex27p_8cpp_source.html">Example 27p</a>: parallel boundary conditions for the Laplace problem
* - <a class="el" href="ex28_8cpp_source.html">Example 28</a>: sliding contact in elasticity
@@ -230,8 +230,8 @@ namespace mfem {
* - <a class="el" href="parheat_8cpp_source.html">Optimization gradients</a>: Gradients of PDE-constrained function
* - <a class="el" href="par__example_8cpp_source.html">Parallel AD</a>: Parallel p-Laplacian example
* - <a class="el" href="seq__example_8cpp_source.html">Serial AD</a>: Serial p-Laplacian example
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Laplace problem
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Laplace problem
* - <a class="el" href="miniapps_2performance_2ex1_8cpp_source.html">HPC Example 1</a>: high-performance nodal H1 FEM for the Poisson problem
* - <a class="el" href="miniapps_2performance_2ex1p_8cpp_source.html">HPC Example 1p</a>: high-performance parallel nodal H1 FEM for the Poisson problem
* - <a class="el" href="generate__random__field_8cpp_source.html">SPDE Solvers</a>: SPDE solver random field generation
* - <a class="el" href="contact-patch-test_8cpp_source.html">Contact</a>: mortar contact patch test for elasticity
* - <a class="el" href="multidomain_8cpp_source.html">Multidomain miniapp</a>: Multidomain and Submesh demonstration miniapp
+1 -1
View File
@@ -12,7 +12,7 @@
// ex1 --amgx-file precon.json --amgx-preconditioner -d cuda
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+1 -1
View File
@@ -10,7 +10,7 @@
// mpirun -np 4 ex1p --amgx-file amg_pcg.json
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+1 -1
View File
@@ -7,7 +7,7 @@
// ex0 -m ../data/square-disc.mesh -o 2
//
// Description: This example code demonstrates the most basic usage of MFEM to
// define a simple finite element discretization of the Laplace
// define a simple finite element discretization of the Poisson
// problem -Delta u = 1 with zero Dirichlet boundary conditions.
// General 2D/3D mesh files and finite element polynomial degrees
// can be specified by command line options.
+1 -1
View File
@@ -8,7 +8,7 @@
//
// Description: This example code demonstrates the most basic parallel usage of
// MFEM to define a simple finite element discretization of the
// Laplace problem -Delta u = 1 with zero Dirichlet boundary
// Poisson problem -Delta u = 1 with zero Dirichlet boundary
// conditions. General 2D/3D serial mesh files and finite element
// polynomial degrees can be specified by command line options.
+1 -1
View File
@@ -50,7 +50,7 @@
// ex1 -m ../data/beam-tet.mesh -pa -d ceed-cuda:/gpu/cuda/ref
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+1 -1
View File
@@ -27,7 +27,7 @@
//
// Description: This example code demonstrates the use of MFEM to define a
// discontinuous Galerkin (DG) finite element discretization of
// the Laplace problem -Delta u = 1 with homogeneous Dirichlet
// the Poisson problem -Delta u = 1 with homogeneous Dirichlet
// boundary conditions. Finite element spaces of any order,
// including zero on regular grids, are supported. The example
// highlights the use of discontinuous spaces and DG-specific face
+1 -1
View File
@@ -26,7 +26,7 @@
//
// Description: This example code demonstrates the use of MFEM to define a
// discontinuous Galerkin (DG) finite element discretization of
// the Laplace problem -Delta u = 1 with homogeneous Dirichlet
// the Poisson problem -Delta u = 1 with homogeneous Dirichlet
// boundary conditions. Finite element spaces of any order,
// including zero on regular grids, are supported. The example
// highlights the use of discontinuous spaces and DG-specific face
+2 -2
View File
@@ -159,7 +159,7 @@ int main(int argc, char *argv[])
FiniteElementSpace fespace(&mesh, &fec);
// 6. As in Example 1p, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// the Poisson problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the inner loop.
BilinearForm a(&fespace);
LinearForm b(&fespace);
@@ -446,7 +446,7 @@ real_t bdr_func(const Vector &pt, real_t t)
return composite_func(pt, t, front, ball);
}
// Laplace of the exact solution, used for the right hand side.
// Laplacian of the exact solution, used for the right hand side.
real_t rhs_func(const Vector &pt, real_t t)
{
return composite_func(pt, t, front_laplace, ball_laplace);
+2 -2
View File
@@ -181,7 +181,7 @@ int main(int argc, char *argv[])
ParFiniteElementSpace fespace(&pmesh, &fec);
// 7. As in Example 1p, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// the Poisson problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the inner loop.
ParBilinearForm a(&fespace);
ParLinearForm b(&fespace);
@@ -507,7 +507,7 @@ real_t bdr_func(const Vector &pt, real_t t)
return composite_func(pt, t, front, ball);
}
// Laplace of the exact solution, used for the right hand side.
// Laplacian of the exact solution, used for the right hand side.
real_t rhs_func(const Vector &pt, real_t t)
{
return composite_func(pt, t, front_laplace, ball_laplace);
+1 -1
View File
@@ -45,7 +45,7 @@
// mpirun -np 4 ex1p -m ../data/beam-tet.mesh -pa -d ceed-cpu
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+1 -1
View File
@@ -94,7 +94,7 @@ WaveOperator::WaveOperator(FiniteElementSpace &f,
M->AddDomainIntegrator(new MassIntegrator());
M->Assemble();
// Apply Bcs
// Apply BCs
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
K->FormSystemMatrix(ess_tdof_list, Kmat);
M->FormSystemMatrix(ess_tdof_list, Mmat);
+1 -1
View File
@@ -17,7 +17,7 @@
// ex26 -m ../data/beam-hex.mesh -d cuda
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions
// as in Example 1.
//
+1 -1
View File
@@ -14,7 +14,7 @@
// mpirun -np 4 ex26p -d ceed-cuda
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions
// as in Example 1.
//
+1 -1
View File
@@ -10,7 +10,7 @@
// Description: This example code demonstrates the use of MFEM to define a
// finite element discretization of a PDE on a 2 dimensional
// surface embedded in a 3 dimensional domain. In this case we
// solve the Laplace problem -Div(sigma Grad u) = 1, with
// solve the Poisson problem -Div(sigma Grad u) = 1, with
// homogeneous Dirichlet boundary conditions, where sigma is an
// anisotropic diffusion constant defined as a 3x3 matrix
// coefficient.
+1 -1
View File
@@ -10,7 +10,7 @@
// Description: This example code demonstrates the use of MFEM to define a
// finite element discretization of a PDE on a 2 dimensional
// surface embedded in a 3 dimensional domain. In this case we
// solve the Laplace problem -Div(sigma Grad u) = 1, with
// solve the Poisson problem -Div(sigma Grad u) = 1, with
// homogeneous Dirichlet boundary conditions, where sigma is an
// anisotropic diffusion constant defined as a 3x3 matrix
// coefficient.
+3 -3
View File
@@ -390,7 +390,7 @@ public:
/**
@brief Class for surface linearform integrator
@brief Class for surface linear form integrator
Integrator to demonstrate the use of the surface integration rule on an
implicit surface defined by a level-set.
@@ -460,7 +460,7 @@ public:
};
/**
@brief Class for subdomain linearform integrator
@brief Class for subdomain linear form integrator
Integrator to demonstrate the use of the subdomain integration rule within
an area defined by an implicit surface defined by a level-set.
@@ -546,7 +546,7 @@ int main(int argc, char *argv[])
args.AddOption(&ref_levels, "-r", "--refine", "Number of meh refinements");
args.AddOption(&method, "-m", "--method",
"Cut integration method: 0 for moments-based, 1 for Algoim.");
args.AddOption(&inttype, "-i", "--integrationtype",
args.AddOption(&inttype, "-i", "--integration-type",
"IntegrationType to demonstrate");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
+1 -1
View File
@@ -16,7 +16,7 @@
//
// The particular problem being solved here is nearly the same
// as that in example 1 i.e. a simple finite element
// discretization of the Laplace problem -Delta u = 1 with
// discretization of the Poisson problem -Delta u = 1 with
// homogeneous Dirichlet boundary conditions and, in this case,
// an inhomogeneous diffusion coefficient. The diffusion
// coefficient is given a small default value throughout the
+1 -1
View File
@@ -16,7 +16,7 @@
//
// The particular problem being solved here is nearly the same
// as that in example 1 i.e. a simple finite element
// discretization of the Laplace problem -Delta u = 1 with
// discretization of the Poisson problem -Delta u = 1 with
// homogeneous Dirichlet boundary conditions and, in this case,
// an inhomogeneous diffusion coefficient. The diffusion
// coefficient is given a small default value throughout the
+5 -7
View File
@@ -65,6 +65,7 @@ int main(int argc, char *argv[])
bool static_cond = false;
bool hybridization = false;
bool pa = false;
bool ea = false;
const char *device_config = "cpu";
bool visualization = 1;
@@ -83,18 +84,14 @@ int main(int argc, char *argv[])
"--no-hybridization", "Enable hybridization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
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);
args.ParseCheck();
kappa = freq * M_PI;
// 2. Enable hardware devices such as GPUs, and programming models such as
@@ -166,6 +163,7 @@ int main(int argc, char *argv[])
Coefficient *beta = new ConstantCoefficient(1.0);
BilinearForm *a = new BilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
if (ea) { a->SetAssemblyLevel(AssemblyLevel::ELEMENT); }
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
+5 -13
View File
@@ -71,6 +71,7 @@ int main(int argc, char *argv[])
bool static_cond = false;
bool hybridization = false;
bool pa = false;
bool ea = false;
const char *device_config = "cpu";
bool visualization = 1;
@@ -89,24 +90,14 @@ int main(int argc, char *argv[])
"--no-hybridization", "Enable hybridization.");
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
"--no-partial-assembly", "Enable Partial Assembly.");
args.AddOption(&ea, "-ea", "--element-assembly", "-no-ea",
"--no-element-assembly", "Enable Element Assembly.");
args.AddOption(&device_config, "-d", "--device",
"Device configuration string, see Device::Configure().");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
args.ParseCheck();
kappa = freq * M_PI;
// 3. Enable hardware devices such as GPUs, and programming models such as
@@ -194,6 +185,7 @@ int main(int argc, char *argv[])
Coefficient *beta = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
if (pa) { a->SetAssemblyLevel(AssemblyLevel::PARTIAL); }
if (ea) { a->SetAssemblyLevel(AssemblyLevel::ELEMENT); }
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
+2 -2
View File
@@ -25,7 +25,7 @@
// ex6 -pa -d ceed-cuda:/gpu/cuda/shared
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// refinement loop. The problem being solved is again the Poisson
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are locally refined in a conforming (triangles, tetrahedrons)
@@ -113,7 +113,7 @@ int main(int argc, char *argv[])
FiniteElementSpace fespace(&mesh, &fec);
// 6. As in Example 1, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// the Poisson problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
BilinearForm a(&fespace);
if (pa)
+104 -7
View File
@@ -3,6 +3,7 @@
// Compile with: make ex6p
//
// Sample runs: mpirun -np 4 ex6p -m ../data/star-hilbert.mesh -o 2
// mpirun -np 4 ex6p -m ../data/star-hilbert.mesh -pref
// mpirun -np 4 ex6p -m ../data/square-disc.mesh -rm 1 -o 1
// mpirun -np 4 ex6p -m ../data/square-disc.mesh -rm 1 -o 2 -h1
// mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 2 -cs
@@ -28,7 +29,7 @@
// mpirun -np 4 ex6p -pa -d ceed-cuda:/gpu/cuda/shared
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// refinement loop. The problem being solved is again the Poisson
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are locally refined in a conforming (triangles, tetrahedrons)
@@ -41,6 +42,12 @@
// from coarse to fine meshes, restarting from a checkpoint, as
// well as persistent GLVis visualization are also illustrated.
//
// There is also the option to use hp-refinement. Real
// applications should use some problem-dependent criteria for
// selecting between h- and p-refinement, but in this example, we
// simply alternate between refinement types to demonstrate the
// capabilities.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
@@ -69,6 +76,8 @@ int main(int argc, char *argv[])
bool smooth_rt = true;
bool restart = false;
bool visualization = true;
bool rebalance = true;
bool usePRefinement = false;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
@@ -90,6 +99,10 @@ int main(int argc, char *argv[])
"Stop after reaching this many degrees of freedom.");
args.AddOption(&smooth_rt, "-rt", "--smooth-rt", "-h1", "--smooth-h1",
"Represent the smooth flux in RT or vector H1 space.");
args.AddOption(&usePRefinement, "-pref", "--p-refine", "-no-pref",
"--no-p-refine", "Alternate between h- and p-refinement.");
args.AddOption(&rebalance, "-reb", "--rebalance", "-no-reb",
"--no-rebalance", "Load balance the nonconforming mesh.");
args.AddOption(&restart, "-res", "--restart", "-no-res", "--no-restart",
"Restart computation from the last checkpoint.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
@@ -109,6 +122,15 @@ int main(int argc, char *argv[])
args.PrintOptions(cout);
}
if (usePRefinement && rebalance)
{
rebalance = false;
if (myid == 0)
{
cout << "Load balancing is not performed with p-refinements.\n";
}
}
// 3. Enable hardware devices such as GPUs, and programming models such as
// CUDA, OCCA, RAJA and OpenMP based on command line options.
Device device(device_config);
@@ -186,7 +208,7 @@ int main(int argc, char *argv[])
ParFiniteElementSpace fespace(pmesh, &fec);
// 11. As in Example 1p, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// the Poisson problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
ParBilinearForm a(&fespace);
if (pa)
@@ -321,7 +343,15 @@ int main(int argc, char *argv[])
if (visualization)
{
sout << "parallel " << num_procs << " " << myid << "\n";
sout << "solution\n" << *pmesh << x << flush;
if (usePRefinement)
{
std::unique_ptr<GridFunction> vis_x = x.ProlongateToMaxOrder();
sout << "solution\n" << *pmesh << *vis_x << flush;
}
else
{
sout << "solution\n" << *pmesh << x << flush;
}
}
if (global_dofs >= max_dofs)
@@ -337,8 +367,31 @@ int main(int argc, char *argv[])
// estimator to obtain element errors, then it selects elements to be
// refined and finally it modifies the mesh. The Stop() method can be
// used to determine if a stopping criterion was met.
refiner.Apply(*pmesh);
if (refiner.Stop())
// Simply alternate between h- and p-refinement.
const bool pRefine = usePRefinement && ((it % 2) == 1);
bool stop = false;
Array<pRefinement> prefinements;
if (pRefine)
{
Array<Refinement> refinements;
refiner.MarkWithoutRefining(*pmesh, refinements);
stop = pmesh->ReduceInt(refinements.Size()) == 0LL;
prefinements.SetSize(refinements.Size());
for (int i=0; i<refinements.Size(); ++i)
{
prefinements[i].index = refinements[i].index;
prefinements[i].delta = 1; // Increase the element order by 1
}
}
else
{
refiner.Apply(*pmesh);
stop = refiner.Stop();
}
if (stop)
{
if (myid == 0)
{
@@ -352,12 +405,20 @@ int main(int argc, char *argv[])
// to any GridFunctions over the space. In this case, the update
// matrix is an interpolation matrix so the updated GridFunction will
// still represent the same function as before refinement.
fespace.Update();
if (pRefine)
{
fespace.PRefineAndUpdate(prefinements);
}
else
{
fespace.Update();
}
x.Update();
// 25. Load balance the mesh, and update the space and solution. Currently
// available only for nonconforming meshes.
if (pmesh->Nonconforming())
if (pmesh->Nonconforming() && rebalance)
{
pmesh->Rebalance();
@@ -389,6 +450,42 @@ int main(int argc, char *argv[])
}
}
// Save result
if (usePRefinement)
{
L2_FECollection fecL2(0, dim);
ParFiniteElementSpace l2fespace(pmesh, &fecL2);
ParGridFunction xo(&l2fespace); // Element order field
xo = 0.0;
for (int e=0; e<pmesh->GetNE(); ++e)
{
const int p_elem = fespace.GetElementOrder(e);
Array<int> dofs;
l2fespace.GetElementDofs(e, dofs);
xo[dofs[0]] = p_elem;
}
ostringstream mesh_name, sol_name, order_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
order_name << "order." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->ParPrint(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
std::unique_ptr<ParGridFunction> vis_x = x.ProlongateToMaxOrder();
vis_x->Save(sol_ofs);
ofstream order_ofs(order_name.str().c_str());
order_ofs.precision(8);
xo.Save(order_ofs);
}
delete smooth_flux_fes;
delete smooth_flux_fec;
delete pmesh;
+2 -2
View File
@@ -9,8 +9,8 @@
//
// Description: This example code demonstrates the use of MFEM to define a
// triangulation of a unit sphere and a simple isoparametric
// finite element discretization of the Laplace problem with mass
// term, -Delta u + u = f.
// finite element discretization of the screened Poisson problem,
// -Delta u + u = f.
//
// The example highlights mesh generation, the use of mesh
// refinement, high-order meshes and finite elements, as well as
+2 -2
View File
@@ -9,8 +9,8 @@
//
// Description: This example code demonstrates the use of MFEM to define a
// triangulation of a unit sphere and a simple isoparametric
// finite element discretization of the Laplace problem with mass
// term, -Delta u + u = f.
// finite element discretization of the screened Poisson problem,
// -Delta u + u = f.
//
// The example highlights mesh generation, the use of mesh
// refinement, high-order meshes and finite elements, as well as
+1 -1
View File
@@ -15,7 +15,7 @@
//
// Description: This example code demonstrates the use of the Discontinuous
// Petrov-Galerkin (DPG) method in its primal 2x2 block form as a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = f with homogeneous Dirichlet boundary conditions. We
// use high-order continuous trial space, a high-order interfacial
// (trace) space, and a high-order discontinuous test space
+1 -1
View File
@@ -14,7 +14,7 @@
//
// Description: This example code demonstrates the use of the Discontinuous
// Petrov-Galerkin (DPG) method in its primal 2x2 block form as a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = f with homogeneous Dirichlet boundary conditions. We
// use high-order continuous trial space, a high-order interfacial
// (trace) space, and a high-order discontinuous test space
+1 -1
View File
@@ -35,7 +35,7 @@
// ex1 -m ../../data/beam-hex.mesh -pa -d cuda
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+1 -1
View File
@@ -33,7 +33,7 @@
"id": "public-white",
"metadata": {},
"source": [
"This is the simplest MFEM example and a good starting point for new users. The example demonstrates the use of MFEM to define and solve an $H^1$ finite element discretization of the Laplace problem\n",
"This is the simplest MFEM example and a good starting point for new users. The example demonstrates the use of MFEM to define and solve an $H^1$ finite element discretization of the Poisson problem\n",
"\n",
"$$\n",
"-\\Delta u = 1\n",
+1 -1
View File
@@ -189,7 +189,7 @@ clean-build:
clean-exec:
@rm -f refined.mesh displaced.mesh mesh.* ex5.mesh ex6p-checkpoint.*
@rm -rf Example5* Example9* Example15* Example16* Example23* ParaView
@rm -f sphere_refined.* sol.* sol_u.* sol_p.* sol_r.* sol_i.*
@rm -f sphere_refined.* sol.* sol_u.* sol_p.* sol_r.* sol_i.* order.*
@rm -f ex9.mesh ex9-mesh.* ex9-init.* ex9-final.*
@rm -f deformed.* velocity.* elastic_energy.* mode_* mode_deriv_* flux.*
@rm -f ex5-p-*.bp ex9-p-*.bp ex12-p-*.bp ex16-p-*.bp
+8 -2
View File
@@ -16,10 +16,16 @@
// multi-physics applications.
//
// This particular example is only for serial runtimes.
// For non-conforming meshes please have a look at example
// "ex2p.cpp".
#include "example_utils.hpp"
#include "mfem.hpp"
#ifndef MFEM_USE_MOONOLITH
#error This example requires that MFEM is built with MFEM_USE_MOONOLITH=YES
#endif
using namespace mfem;
using namespace std;
@@ -215,8 +221,8 @@ int main(int argc, char *argv[])
mfem::out << "l2 error: src: " << src_err << ", dest: " << dest_err
<< std::endl;
plot(*src_mesh, src_fun, "source");
plot(*dest_mesh, dest_fun, "destination");
plot(*src_mesh, src_fun, "source", 0);
plot(*dest_mesh, dest_fun, "destination", 1);
}
}
else
+54 -16
View File
@@ -8,18 +8,23 @@
// mpirun -np 4 ex1p -s ../../data/inline-hex.mesh -d ../../data/inline-tet.mesh
//
// Description: This example code demonstrates the use of MFEM for transferring
// discrete fields from one finite element mesh to another. The
// discrete fields from one conforming finite element mesh to another. The
// meshes can be of arbitrary shape and completely unrelated with
// each other. This feature can be used for implementing immersed
// domain methods for fluid-structure interaction or general
// multi-physics applications.
//
// This particular example is for parallel runtimes. Vector FE is
// an experimental feature in parallel.
// an experimental feature in parallel. For non-conforming meshes
// please have a look at example "ex2p.cpp".
#include "example_utils.hpp"
#include "mfem.hpp"
#ifndef MFEM_USE_MOONOLITH
#error This example requires that MFEM is built with MFEM_USE_MOONOLITH=YES
#endif
using namespace mfem;
using namespace std;
@@ -50,6 +55,8 @@ int main(int argc, char *argv[])
int dest_fe_order = 1;
bool visualization = true;
bool use_vector_fe = false;
bool use_h1 = true;
bool use_vector_space = false;
bool verbose = false;
bool assemble_mass_and_coupling_together = true;
@@ -72,14 +79,28 @@ int main(int argc, char *argv[])
args.AddOption(&verbose, "-verb", "--verbose", "--no-verb", "--no-verbose",
"Enable/Disable verbose output");
args.AddOption(&use_vector_fe, "-vfe", "--use_vector_fe", "-no-vfe",
"--no-vector_fe", "Use vector finite elements (Experimental)");
"--no-vector_fe",
"Use RT|ND vector finite elements (Experimental)");
args.AddOption(&use_vector_space, "-vfs", "--use_vector_space", "-no-vfs",
"--no-vector_space",
"Use Lagrange vector finite elements (Experimental)");
args.AddOption(&use_h1, "-h1", "--use-h1", "-nh1", "--no-h1",
"Use H1 collection");
args.AddOption(&assemble_mass_and_coupling_together, "-act",
"--assemble_mass_and_coupling_together", "-no-act",
"--no-assemble_mass_and_coupling_together",
"Assemble mass and coupling operators together (better for non-affine elements)");
"Assemble mass and coupling operators together (better for "
"non-affine elements)");
args.Parse();
check_options(args);
if (use_vector_fe && use_vector_space)
{
mfem::err <<
"WARNING: use_vector_fe and use_vector_space options"
"are both true, ignoring use_vector_fe\n";
}
shared_ptr<Mesh> src_mesh, dest_mesh;
ifstream imesh;
@@ -169,17 +190,30 @@ int main(int argc, char *argv[])
}
else
{
src_fe_coll =
make_shared<L2_FECollection>(source_fe_order, src_mesh->Dimension());
dest_fe_coll =
make_shared<L2_FECollection>(dest_fe_order, dest_mesh->Dimension());
if (use_h1)
{
src_fe_coll =
make_shared<H1_FECollection>(source_fe_order, src_mesh->Dimension());
dest_fe_coll =
make_shared<H1_FECollection>(dest_fe_order, dest_mesh->Dimension());
}
else
{
src_fe_coll =
make_shared<L2_FECollection>(source_fe_order, src_mesh->Dimension());
dest_fe_coll =
make_shared<L2_FECollection>(dest_fe_order, dest_mesh->Dimension());
}
}
auto src_fe =
make_shared<ParFiniteElementSpace>(p_src_mesh.get(), src_fe_coll.get());
auto src_fe = make_shared<ParFiniteElementSpace>(
p_src_mesh.get(), src_fe_coll.get(),
use_vector_space ? src_mesh->Dimension() : 1);
auto dest_fe =
make_shared<ParFiniteElementSpace>(p_dest_mesh.get(), dest_fe_coll.get());
auto dest_fe = make_shared<ParFiniteElementSpace>(
p_dest_mesh.get(), dest_fe_coll.get(),
use_vector_space ? dest_mesh->Dimension() : 1);
ParGridFunction src_fun(src_fe.get());
@@ -189,7 +223,7 @@ int main(int argc, char *argv[])
// To be used with vector fe
VectorFunctionCoefficient vector_coeff(dim, &vector_fun);
if (use_vector_fe)
if (use_vector_fe || use_vector_space)
{
src_fun.ProjectCoefficient(vector_coeff);
src_fun.Update();
@@ -209,7 +243,11 @@ int main(int argc, char *argv[])
assemble_mass_and_coupling_together);
assembler.SetVerbose(verbose);
if (use_vector_fe)
if (use_vector_space)
{
assembler.AddMortarIntegrator(make_shared<LagrangeVectorL2MortarIntegrator>());
}
else if (use_vector_fe)
{
assembler.AddMortarIntegrator(make_shared<VectorL2MortarIntegrator>());
}
@@ -243,8 +281,8 @@ int main(int argc, char *argv[])
<< std::endl;
}
plot(*p_src_mesh, src_fun, "source");
plot(*p_dest_mesh, dest_fun, "destination");
plot(*p_src_mesh, src_fun, "source", 0);
plot(*p_dest_mesh, dest_fun, "destination", 1);
}
}
else
+6 -2
View File
@@ -20,6 +20,10 @@
#include "example_utils.hpp"
#include "mfem.hpp"
#ifndef MFEM_USE_MOONOLITH
#error This example requires that MFEM is built with MFEM_USE_MOONOLITH=YES
#endif
using namespace mfem;
using namespace std;
@@ -186,8 +190,8 @@ int main(int argc, char *argv[])
<< std::endl;
}
plot(*p_src_mesh, src_fun, "source");
plot(*p_dest_mesh, dest_fun, "destination");
plot(*p_src_mesh, src_fun, "source", 0);
plot(*p_dest_mesh, dest_fun, "destination", 1);
}
}
else
+15 -1
View File
@@ -84,7 +84,8 @@ void vector_fun(const mfem::Vector &x, mfem::Vector &f)
f = n;
}
inline void plot(mfem::Mesh &mesh, mfem::GridFunction &x, std::string title)
inline void plot(mfem::Mesh &mesh, mfem::GridFunction &x, std::string title,
const int plot_number = 0)
{
using namespace std;
using namespace mfem;
@@ -103,5 +104,18 @@ inline void plot(mfem::Mesh &mesh, mfem::GridFunction &x, std::string title)
sol_sock.precision(8);
sol_sock << "solution\n" << mesh << x
<< "window_title '"<< title << "'\n" << flush;
sol_sock << "window_geometry ";
sol_sock << (plot_number * 600) << " " << 0 << " " << 600 << " " << 600 <<
"\n";
if (mesh.Dimension() == 2)
{
sol_sock << "keys jRmclA\n";
}
else
{
sol_sock << "keys rmclAa\n";
}
sol_sock << flush;
}
+1 -1
View File
@@ -10,7 +10,7 @@
// mpirun -np 4 ex1p -pa -d cuda --petscopts rc_ex1p_device
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+2 -2
View File
@@ -8,7 +8,7 @@
// mpirun -np 4 ex6p -m ../../data/amr-quad.mesh -nonoverlapping
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// refinement loop. The problem being solved is again the Poisson
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are locally refined in a conforming (triangles, tetrahedrons)
@@ -131,7 +131,7 @@ int main(int argc, char *argv[])
ParFiniteElementSpace fespace(&pmesh, &fec);
// 7. As in Example 1p, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// the Poisson problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
ParBilinearForm a(&fespace);
ParLinearForm b(&fespace);
+1 -1
View File
@@ -11,7 +11,7 @@
// creating a symbolic link to the above directory in ../../data.
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+1 -1
View File
@@ -12,7 +12,7 @@
// creating a symbolic link to the above directory in ../../data.
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+1 -1
View File
@@ -6,7 +6,7 @@
// Sample runs: mpirun -np 8 ex6p
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// refinement loop. The problem being solved is again the Poisson
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are adapted in a conforming (tetrahedrons) manner according
+1 -1
View File
@@ -26,7 +26,7 @@
// mpirun -np 4 ex1p -m ../../data/mobius-strip.mesh
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// simple finite element discretization of the Poisson problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
+7
View File
@@ -35,6 +35,7 @@ set(SRCS
integ/bilininteg_mass_ea.cpp
integ/bilininteg_mixedcurl_pa.cpp
integ/bilininteg_mixedvecgrad_pa.cpp
integ/bilininteg_trace_jump_ea.cpp
integ/bilininteg_transpose_ea.cpp
integ/bilininteg_vecdiffusion_mf.cpp
integ/bilininteg_vecdiffusion_pa.cpp
@@ -46,6 +47,7 @@ set(SRCS
integ/bilininteg_diffusion_kernels.cpp
integ/bilininteg_elasticity_kernels.cpp
integ/bilininteg_hcurl_kernels.cpp
integ/bilininteg_hdiv_ea.cpp
integ/bilininteg_hdiv_kernels.cpp
integ/bilininteg_hcurlhdiv_kernels.cpp
integ/bilininteg_mass_kernels.cpp
@@ -63,6 +65,7 @@ set(SRCS
dgmassinv.cpp
doftrans.cpp
eltrans.cpp
batchitrans.cpp
estimators.cpp
fe.cpp
fe/face_map_utils.cpp
@@ -73,6 +76,7 @@ set(SRCS
fe/fe_nd.cpp
fe/fe_nurbs.cpp
fe/fe_pos.cpp
fe/fe_pyramid.cpp
fe/fe_rt.cpp
fe/fe_ser.cpp
fe_coll.cpp
@@ -80,6 +84,7 @@ set(SRCS
geom.cpp
gridfunc.cpp
hybridization.cpp
hybridization_ext.cpp
intrules.cpp
intrules_cut.cpp
ceed/interface/basis.cpp
@@ -186,6 +191,7 @@ set(HDRS
fe/fe_nd.hpp
fe/fe_nurbs.hpp
fe/fe_pos.hpp
fe/fe_pyramid.hpp
fe/fe_rt.hpp
fe/fe_ser.hpp
fe_coll.hpp
@@ -194,6 +200,7 @@ set(HDRS
geom.hpp
gridfunc.hpp
hybridization.hpp
hybridization_ext.hpp
intrules.hpp
intrules_cut.hpp
kernel_dispatch.hpp
+2035
View File
File diff suppressed because it is too large Load Diff
+75 -50
View File
@@ -71,15 +71,11 @@ BilinearForm::BilinearForm(FiniteElementSpace * f)
sequence = f->GetSequence();
mat = mat_e = NULL;
extern_bfs = 0;
element_matrices = NULL;
static_cond = NULL;
hybridization = NULL;
precompute_sparsity = 0;
diag_policy = DIAG_KEEP;
assembly = AssemblyLevel::LEGACY;
batch = 1;
ext = NULL;
}
BilinearForm::BilinearForm (FiniteElementSpace * f, BilinearForm * bf, int ps)
@@ -89,15 +85,11 @@ BilinearForm::BilinearForm (FiniteElementSpace * f, BilinearForm * bf, int ps)
sequence = f->GetSequence();
mat_e = NULL;
extern_bfs = 1;
element_matrices = NULL;
static_cond = NULL;
hybridization = NULL;
precompute_sparsity = ps;
diag_policy = DIAG_KEEP;
assembly = AssemblyLevel::LEGACY;
batch = 1;
ext = NULL;
// Copy the pointers to the integrators
domain_integs = bf->domain_integs;
@@ -127,16 +119,16 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
break;
case AssemblyLevel::FULL:
SetDiagonalPolicy( DIAG_ONE ); // Only diagonal policy supported on device
ext = new FABilinearFormExtension(this);
ext.reset(new FABilinearFormExtension(this));
break;
case AssemblyLevel::ELEMENT:
ext = new EABilinearFormExtension(this);
ext.reset(new EABilinearFormExtension(this));
break;
case AssemblyLevel::PARTIAL:
ext = new PABilinearFormExtension(this);
ext.reset(new PABilinearFormExtension(this));
break;
case AssemblyLevel::NONE:
ext = new MFBilinearFormExtension(this);
ext.reset(new MFBilinearFormExtension(this));
break;
default:
MFEM_ABORT("BilinearForm: unknown assembly level");
@@ -145,14 +137,13 @@ void BilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
void BilinearForm::EnableStaticCondensation()
{
delete static_cond;
if (assembly != AssemblyLevel::LEGACY)
{
static_cond = NULL;
static_cond.reset();
MFEM_WARNING("Static condensation not supported for this assembly level");
return;
}
static_cond = new StaticCondensation(fes);
static_cond.reset(new StaticCondensation(fes));
if (static_cond->ReducesTrueVSize())
{
bool symmetric = false; // TODO
@@ -161,8 +152,7 @@ void BilinearForm::EnableStaticCondensation()
}
else
{
delete static_cond;
static_cond = NULL;
static_cond.reset();
}
}
@@ -170,15 +160,18 @@ void BilinearForm::EnableHybridization(FiniteElementSpace *constr_space,
BilinearFormIntegrator *constr_integ,
const Array<int> &ess_tdof_list)
{
delete hybridization;
if (assembly != AssemblyLevel::LEGACY)
if (assembly != AssemblyLevel::LEGACY && assembly != AssemblyLevel::ELEMENT)
{
delete constr_integ;
hybridization = NULL;
hybridization.reset();
MFEM_WARNING("Hybridization not supported for this assembly level");
return;
}
hybridization = new Hybridization(fes, constr_space);
hybridization.reset(new Hybridization(fes, constr_space));
if (assembly == AssemblyLevel::ELEMENT)
{
hybridization->EnableDeviceExecution();
}
hybridization->SetConstraintIntegrator(constr_integ);
hybridization->Init(ess_tdof_list);
}
@@ -231,8 +224,8 @@ void BilinearForm::Finalize (int skip_zeros)
if (!static_cond) { mat->Finalize(skip_zeros); }
if (mat_e) { mat_e->Finalize(skip_zeros); }
if (static_cond) { static_cond->Finalize(); }
if (hybridization) { hybridization->Finalize(); }
}
if (hybridization) { hybridization->Finalize(); }
}
void BilinearForm::AddDomainIntegrator(BilinearFormIntegrator *bfi)
@@ -465,6 +458,10 @@ void BilinearForm::Assemble(int skip_zeros)
if (ext)
{
ext->Assemble();
if (hybridization)
{
hybridization->AssembleElementMatrices(GetElementMatrices());
}
return;
}
@@ -835,7 +832,19 @@ void BilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x,
{
if (ext)
{
ext->FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
if (hybridization)
{
FormSystemMatrix(ess_tdof_list, A);
ConstrainedOperator A_constrained(this, ess_tdof_list);
A_constrained.EliminateRHS(x, b);
hybridization->ReduceRHS(b, B);
X.SetSize(B.Size());
X = 0.0;
}
else
{
ext->FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
}
return;
}
const SparseMatrix *P = fes->GetConformingProlongation();
@@ -903,7 +912,16 @@ void BilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
{
if (ext)
{
ext->FormSystemMatrix(ess_tdof_list, A);
if (hybridization)
{
const int remove_zeros = 0;
Finalize(remove_zeros);
A.Reset(&hybridization->GetMatrix(), false);
}
else
{
ext->FormSystemMatrix(ess_tdof_list, A);
}
return;
}
@@ -944,7 +962,7 @@ void BilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
void BilinearForm::RecoverFEMSolution(const Vector &X,
const Vector &b, Vector &x)
{
if (ext)
if (ext && !hybridization)
{
ext->RecoverFEMSolution(X, b, x);
return;
@@ -1001,16 +1019,26 @@ void BilinearForm::RecoverFEMSolution(const Vector &X,
void BilinearForm::ComputeElementMatrices()
{
if (element_matrices || domain_integs.Size() == 0 || fes->GetNE() == 0)
if (element_matrices) { return; }
if (auto *ea_ext = dynamic_cast<EABilinearFormExtension*>(ext.get()))
{
element_matrices.reset(new DenseTensor);
ea_ext->GetElementMatrices(*element_matrices, ElementDofOrdering::NATIVE, true);
return;
}
if (domain_integs.Size() == 0 || fes->GetNE() == 0)
{
element_matrices.reset(new DenseTensor);
return;
}
int num_elements = fes->GetNE();
int num_dofs_per_el = fes->GetTypicalFE()->GetDof() * fes->GetVDim();
element_matrices = new DenseTensor(num_dofs_per_el, num_dofs_per_el,
num_elements);
element_matrices.reset(new DenseTensor(num_dofs_per_el, num_dofs_per_el,
num_elements));
DenseMatrix tmp;
IsoparametricTransformation eltrans;
@@ -1041,6 +1069,12 @@ void BilinearForm::ComputeElementMatrices()
}
}
const DenseTensor &BilinearForm::GetElementMatrices()
{
ComputeElementMatrices(); // Won't recompute if element_matrices exists
return *element_matrices;
}
void BilinearForm::EliminateEssentialBC(const Array<int> &bdr_attr_is_ess,
const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy)
@@ -1228,15 +1262,13 @@ void BilinearForm::Update(FiniteElementSpace *nfes)
delete mat_e;
mat_e = NULL;
FreeElementMatrices();
delete static_cond;
static_cond = NULL;
static_cond.reset();
if (full_update)
{
delete mat;
mat = NULL;
delete hybridization;
hybridization = NULL;
hybridization.reset();
sequence = fes->GetSequence();
}
else
@@ -1259,9 +1291,6 @@ BilinearForm::~BilinearForm()
{
delete mat_e;
delete mat;
delete element_matrices;
delete static_cond;
delete hybridization;
if (!extern_bfs)
{
@@ -1273,8 +1302,6 @@ BilinearForm::~BilinearForm()
for (k=0; k < boundary_face_integs.Size(); k++)
{ delete boundary_face_integs[k]; }
}
delete ext;
}
@@ -1301,7 +1328,6 @@ MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes,
mat = NULL;
mat_e = NULL;
extern_bfs = 1;
ext = NULL;
// Copy the pointers to the integrators
domain_integs = mbf->domain_integs;
@@ -1331,22 +1357,22 @@ void MixedBilinearForm::SetAssemblyLevel(AssemblyLevel assembly_level)
case AssemblyLevel::LEGACY:
break;
case AssemblyLevel::FULL:
// ext = new FAMixedBilinearFormExtension(this);
// ext.reset(new FAMixedBilinearFormExtension(this));
// Use the original BilinearForm implementation for now
break;
case AssemblyLevel::ELEMENT:
mfem_error("Element assembly not supported yet... stay tuned!");
// ext = new EAMixedBilinearFormExtension(this);
MFEM_ABORT("Element assembly not supported yet... stay tuned!");
// ext.reset(new EAMixedBilinearFormExtension(this));
break;
case AssemblyLevel::PARTIAL:
ext = new PAMixedBilinearFormExtension(this);
ext.reset(new PAMixedBilinearFormExtension(this));
break;
case AssemblyLevel::NONE:
mfem_error("Matrix-free action not supported yet... stay tuned!");
// ext = new MFMixedBilinearFormExtension(this);
MFEM_ABORT("Matrix-free action not supported yet... stay tuned!");
// ext.reset(new MFMixedBilinearFormExtension(this));
break;
default:
mfem_error("Unknown assembly level");
MFEM_ABORT("Unknown assembly level");
}
}
@@ -2343,7 +2369,6 @@ MixedBilinearForm::~MixedBilinearForm()
for (i = 0; i < boundary_trace_face_integs.Size(); i++)
{ delete boundary_trace_face_integs[i]; }
}
delete ext;
}
void DiscreteLinearOperator::SetAssemblyLevel(AssemblyLevel assembly_level)
@@ -2360,16 +2385,16 @@ void DiscreteLinearOperator::SetAssemblyLevel(AssemblyLevel assembly_level)
// Use the original implementation for now
break;
case AssemblyLevel::ELEMENT:
mfem_error("Element assembly not supported yet... stay tuned!");
MFEM_ABORT("Element assembly not supported yet... stay tuned!");
break;
case AssemblyLevel::PARTIAL:
ext = new PADiscreteLinearOperatorExtension(this);
ext.reset(new PADiscreteLinearOperatorExtension(this));
break;
case AssemblyLevel::NONE:
mfem_error("Matrix-free action not supported yet... stay tuned!");
MFEM_ABORT("Matrix-free action not supported yet... stay tuned!");
break;
default:
mfem_error("Unknown assembly level");
MFEM_ABORT("Unknown assembly level");
}
}
+19 -13
View File
@@ -83,7 +83,7 @@ protected:
/** @brief Extension for supporting Full Assembly (FA),
Element Assembly (EA),Partial Assembly (PA),
or Matrix Free assembly (MF). */
BilinearFormExtension *ext;
std::unique_ptr<BilinearFormExtension> ext;
/** Indicates if the sparse matrix is sorted after assembly when using
Full Assembly (FA). */
@@ -122,10 +122,10 @@ protected:
mutable DenseMatrix elemmat;
mutable Array<int> vdofs;
DenseTensor *element_matrices; ///< Owned.
std::unique_ptr<DenseTensor> element_matrices;
StaticCondensation *static_cond; ///< Owned.
Hybridization *hybridization; ///< Owned.
std::unique_ptr<StaticCondensation> static_cond;
std::unique_ptr<Hybridization> hybridization;
/** @brief This data member allows one to specify what should be done to the
diagonal matrix entries and corresponding RHS values upon elimination of
@@ -148,13 +148,11 @@ protected:
BilinearForm() : Matrix (0)
{
fes = NULL; sequence = -1;
mat = mat_e = NULL; extern_bfs = 0; element_matrices = NULL;
static_cond = NULL; hybridization = NULL;
mat = mat_e = NULL; extern_bfs = 0;
precompute_sparsity = 0;
diag_policy = DIAG_KEEP;
assembly = AssemblyLevel::LEGACY;
batch = 1;
ext = NULL;
}
private:
@@ -214,7 +212,7 @@ public:
/// Returns the assembly level
AssemblyLevel GetAssemblyLevel() const { return assembly; }
Hybridization *GetHybridization() const { return hybridization; }
Hybridization *GetHybridization() const { return hybridization.get(); }
/** @brief Enable the use of static condensation. For details see the
description for class StaticCondensation in fem/staticcond.hpp This
@@ -224,7 +222,7 @@ public:
/** @brief Check if static condensation was actually enabled by a previous
call to EnableStaticCondensation(). */
bool StaticCondensationIsEnabled() const { return static_cond; }
bool StaticCondensationIsEnabled() const { return static_cond != nullptr; }
/// Return the trace FE space associated with static condensation.
FiniteElementSpace *SCFESpace() const
@@ -569,12 +567,20 @@ public:
void RecoverFEMSolution(const Vector &X, const Vector &b,
Vector &x) override;
/// Compute and store internally all element matrices.
/// @brief Compute and store internally all element matrices.
///
/// If AssemblyLevel::ELEMENT is selected with SetAssemblyLevel(), this will
/// use efficient (device-accelerated) assembly of the element matrices.
void ComputeElementMatrices();
/// Free the memory used by the element matrices.
void FreeElementMatrices()
{ delete element_matrices; element_matrices = NULL; }
void FreeElementMatrices() { element_matrices.reset(); }
/// @brief Return a DenseTensor containing the assembled element matrices.
///
/// If AssemblyLevel::ELEMENT is selected with SetAssemblyLevel(), this will
/// use efficient (device-accelerated) assembly of the element matrices.
const DenseTensor &GetElementMatrices();
/// Compute the element matrix of the given element
/** The element matrix is computed by calling the domain integrators
@@ -760,7 +766,7 @@ protected:
/** Extension for supporting Full Assembly (FA), Element Assembly (EA),
Partial Assembly (PA), or Matrix Free assembly (MF). */
MixedBilinearFormExtension *ext;
std::unique_ptr<MixedBilinearFormExtension> ext;
/** @brief Indicates the BilinearFormIntegrator%s stored in
MixedBilinearForm#domain_integs, MixedBilinearForm#boundary_integs,
+288 -78
View File
@@ -16,6 +16,7 @@
#include "bilinearform.hpp"
#include "pbilinearform.hpp"
#include "pgridfunc.hpp"
#include "fe/face_map_utils.hpp"
#include "ceed/interface/util.hpp"
namespace mfem
@@ -864,52 +865,137 @@ void EABilinearFormExtension::Assemble()
ne = trial_fes->GetMesh()->GetNE();
elemDofs = trial_fes->GetTypicalFE()->GetDof();
ea_data.SetSize(ne*elemDofs*elemDofs, Device::GetMemoryType());
ea_data.UseDevice(true);
Vector ea_data_tmp;
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
const int integratorCount = integrators.Size();
if ( integratorCount == 0 )
auto add_with_markers = [&](const Vector &ea_1, Vector &ea_2, const int ne_,
const Array<int> &markers, const Array<int> &attrs,
const bool add)
{
ea_data = 0.0;
}
for (int i = 0; i < integratorCount; ++i)
if (ne_ == 0) { return; }
const int sz = ea_1.Size() / ne_;
const int *d_m = markers.Read();
const int *d_a = attrs.Read();
const auto d_ea_1 = Reshape(ea_1.Read(), sz, ne_);
auto d_ea_2 = Reshape(add ? ea_2.ReadWrite() : ea_2.Write(), sz, ne_);
mfem::forall(sz*ne_, [=] MFEM_HOST_DEVICE (int idx)
{
const int i = idx % sz;
const int e = idx / sz;
const real_t val = d_m[d_a[e] - 1] ? d_ea_1(i, e) : 0.0;
if (add)
{
d_ea_2(i, e) += val;
}
else
{
d_ea_2(i, e) = val;
}
});
};
{
integrators[i]->AssembleEA(*a->FESpace(), ea_data, i);
ea_data.SetSize(ne*elemDofs*elemDofs);
ea_data.UseDevice(true);
Array<BilinearFormIntegrator*> &integrators = *a->GetDBFI();
Array<Array<int>*> &markers_array = *a->GetDBFI_Marker();
if (integrators.Size() == 0) { ea_data = 0.0; }
for (int i = 0; i < integrators.Size(); ++i)
{
const bool add = (i > 0);
const Array<int> *markers = markers_array[i];
if (markers == nullptr)
{
integrators[i]->AssembleEA(*a->FESpace(), ea_data, add);
}
else
{
ea_data_tmp.SetSize(ea_data.Size());
integrators[i]->AssembleEA(*a->FESpace(), ea_data_tmp, false);
add_with_markers(ea_data_tmp, ea_data, ne, *markers,
elem_attributes, add);
}
}
}
faceDofs = trial_fes->GetTypicalTraceElement()->GetDof();
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
"Element assembly does not support AddBoundaryIntegrator yet.");
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
if (intFaceIntegratorCount>0)
{
nf_int = trial_fes->GetNFbyType(FaceType::Interior);
ea_data_int.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_ext.SetSize(2*nf_int*faceDofs*faceDofs, Device::GetMemoryType());
}
for (int i = 0; i < intFaceIntegratorCount; ++i)
{
intFaceIntegrators[i]->AssembleEAInteriorFaces(*a->FESpace(),
ea_data_int,
ea_data_ext,
i);
Array<BilinearFormIntegrator*> &bdr_integs = *a->GetBBFI();
Array<Array<int>*> &markers_array = *a->GetBBFI_Marker();
const int n_bdr_integs = bdr_integs.Size();
if (n_bdr_integs > 0)
{
nf_bdr = trial_fes->GetNFbyType(FaceType::Boundary);
ea_data_bdr.SetSize(nf_bdr*faceDofs*faceDofs);
}
for (int i = 0; i < n_bdr_integs; ++i)
{
const bool add = (i > 0);
const Array<int> *markers = markers_array[i];
if (markers == nullptr)
{
bdr_integs[i]->AssembleEABoundary(*a->FESpace(), ea_data_bdr, add);
}
else
{
ea_data_tmp.SetSize(ea_data_bdr.Size());
bdr_integs[i]->AssembleEABoundary(*a->FESpace(), ea_data_tmp, add);
add_with_markers(ea_data_tmp, ea_data_bdr, nf_bdr, *markers,
bdr_attributes, add);
}
}
}
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int boundFaceIntegratorCount = bdrFaceIntegrators.Size();
if (boundFaceIntegratorCount>0)
{
nf_bdr = trial_fes->GetNFbyType(FaceType::Boundary);
ea_data_bdr.SetSize(nf_bdr*faceDofs*faceDofs, Device::GetMemoryType());
ea_data_bdr = 0.0;
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
const int intFaceIntegratorCount = intFaceIntegrators.Size();
if (intFaceIntegratorCount>0)
{
nf_int = trial_fes->GetNFbyType(FaceType::Interior);
ea_data_int.SetSize(2*nf_int*faceDofs*faceDofs);
ea_data_ext.SetSize(2*nf_int*faceDofs*faceDofs);
}
for (int i = 0; i < intFaceIntegratorCount; ++i)
{
const bool add = (i > 0);
intFaceIntegrators[i]->AssembleEAInteriorFaces(*a->FESpace(),
ea_data_int,
ea_data_ext,
add);
}
}
for (int i = 0; i < boundFaceIntegratorCount; ++i)
{
bdrFaceIntegrators[i]->AssembleEABoundaryFaces(*a->FESpace(),ea_data_bdr,i);
Array<BilinearFormIntegrator*> &bdr_face_integs = *a->GetBFBFI();
Array<Array<int>*> &markers_array = *a->GetBFBFI_Marker();
const int n_bdr_face_integs = bdr_face_integs.Size();
if (n_bdr_face_integs > 0)
{
nf_bdr = trial_fes->GetNFbyType(FaceType::Boundary);
ea_data_bdr.SetSize(nf_bdr*faceDofs*faceDofs);
}
for (int i = 0; i < n_bdr_face_integs; ++i)
{
const bool add = (i > 0);
const Array<int> *markers = markers_array[i];
if (markers == nullptr)
{
bdr_face_integs[i]->AssembleEABoundaryFaces(
*a->FESpace(), ea_data_bdr, add);
}
else
{
ea_data_tmp.SetSize(ea_data_bdr.Size());
bdr_face_integs[i]->AssembleEABoundaryFaces(*a->FESpace(),
ea_data_tmp,
add);
add_with_markers(ea_data_tmp, ea_data_bdr, nf_bdr, *markers,
bdr_attributes, add);
}
}
}
if (factorize_face_terms && int_face_restrict_lex)
@@ -1021,34 +1107,29 @@ void EABilinearFormExtension::Mult(const Vector &x, Vector &y) const
}
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (!factorize_face_terms && bdr_face_restrict_lex && bFISz>0)
if (!factorize_face_terms && bdr_face_restrict_lex && ea_data_bdr.Size() > 0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, bdr_face_X);
if (bdr_face_X.Size()>0)
bdr_face_Y = 0.0;
// Apply the boundary face matrices
const int NDOFS = faceDofs;
auto X = Reshape(bdr_face_X.Read(), NDOFS, nf_bdr);
auto Y = Reshape(bdr_face_Y.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
mfem::forall(nf_bdr*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
bdr_face_Y = 0.0;
// Apply the boundary face matrices
const int NDOFS = faceDofs;
auto X = Reshape(bdr_face_X.Read(), NDOFS, nf_bdr);
auto Y = Reshape(bdr_face_Y.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
mfem::forall(nf_bdr*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
real_t res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
real_t res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(i, j, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
}
res += A(i, j, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
}
}
@@ -1149,35 +1230,164 @@ void EABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
}
// Treatment of boundary faces
Array<BilinearFormIntegrator*> &bdrFaceIntegrators = *a->GetBFBFI();
const int bFISz = bdrFaceIntegrators.Size();
if (!factorize_face_terms && bdr_face_restrict_lex && bFISz>0)
if (!factorize_face_terms && bdr_face_restrict_lex && ea_data_bdr.Size() > 0)
{
// Apply the Boundary Face Restriction
bdr_face_restrict_lex->Mult(x, bdr_face_X);
if (bdr_face_X.Size()>0)
bdr_face_Y = 0.0;
// Apply the boundary face matrices transposed
const int NDOFS = faceDofs;
auto X = Reshape(bdr_face_X.Read(), NDOFS, nf_bdr);
auto Y = Reshape(bdr_face_Y.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
mfem::forall(nf_bdr*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
{
bdr_face_Y = 0.0;
// Apply the boundary face matrices transposed
const int NDOFS = faceDofs;
auto X = Reshape(bdr_face_X.Read(), NDOFS, nf_bdr);
auto Y = Reshape(bdr_face_Y.ReadWrite(), NDOFS, nf_bdr);
auto A = Reshape(ea_data_bdr.Read(), NDOFS, NDOFS, nf_bdr);
mfem::forall(nf_bdr*NDOFS, [=] MFEM_HOST_DEVICE (int glob_j)
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
real_t res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
const int f = glob_j/NDOFS;
const int j = glob_j%NDOFS;
real_t res = 0.0;
for (int i = 0; i < NDOFS; i++)
{
res += A(j, i, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
res += A(j, i, f)*X(i, f);
}
Y(j, f) += res;
});
// Apply the Boundary Face Restriction transposed
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
}
}
void EABilinearFormExtension::GetElementMatrices(
DenseTensor &element_matrices, ElementDofOrdering ordering, bool add_bdr)
{
// Ensure the EA data is assembled
if (ea_data.Size() == 0) { Assemble(); }
const int ndofs = elemDofs;
element_matrices.SetSize(ndofs, ndofs, ne);
const int N = element_matrices.TotalSize();
const auto d_ea_data = Reshape(ea_data.Read(), ndofs, ndofs, ne);
auto d_element_matrices = Reshape(element_matrices.Write(),
ndofs, ndofs,
ne);
const int *d_dof_map = nullptr;
Array<int> dof_map;
if (ordering == ElementDofOrdering::NATIVE)
{
const TensorBasisElement* tbe =
dynamic_cast<const TensorBasisElement*>(trial_fes->GetFE(0));
if (tbe)
{
// Deep copy to avoid issues with host device (see similar comment in
// HybridizationExtension::ConstructC).
dof_map = tbe->GetDofMap();
d_dof_map = dof_map.Read();
}
}
if (d_dof_map)
{
// Reordering required
mfem::forall(N, [=] MFEM_HOST_DEVICE (int idx)
{
const int e = idx / ndofs / ndofs;
const int i = idx % ndofs;
const int j = (idx / ndofs) % ndofs;
const int ii_s = d_dof_map[i];
const int ii = (ii_s >= 0) ? ii_s : -1 - ii_s;
const int s_i = (ii_s >= 0) ? 1 : -1;
const int jj_s = d_dof_map[j];
const int jj = (jj_s >= 0) ? jj_s : -1 - jj_s;
const int s_j = (jj_s >= 0) ? 1 : -1;
d_element_matrices(ii, jj, e) = s_i*s_j*d_ea_data(j, i, e);
});
}
else
{
// No reordering required
mfem::forall(N, [=] MFEM_HOST_DEVICE (int idx)
{
const int e = idx / ndofs / ndofs;
const int i = idx % ndofs;
const int j = (idx / ndofs) % ndofs;
d_element_matrices(i, j, e) = d_ea_data(j, i, e);
});
}
if (add_bdr && ea_data_bdr.Size() > 0)
{
const int ndof_face = faceDofs;
const auto d_ea_bdr = Reshape(ea_data_bdr.Read(),
ndof_face, ndof_face, nf_bdr);
// Get all the local face maps (mapping from lexicographic face index to
// lexicographic volume index, depending on the local face index).
const Mesh &mesh = *trial_fes->GetMesh();
const int dim = mesh.Dimension();
const int n_faces_per_el = 2*dim; // assuming tensor product
Array<int> face_maps(ndof_face * n_faces_per_el);
for (int lf_i = 0; lf_i < n_faces_per_el; ++lf_i)
{
Array<int> face_map(ndof_face);
trial_fes->GetFE(0)->GetFaceMap(lf_i, face_map);
for (int i = 0; i < ndof_face; ++i)
{
face_maps[i + lf_i*ndof_face] = face_map[i];
}
}
Array<int> face_info(nf_bdr * 2);
{
int fidx = 0;
for (int f = 0; f < mesh.GetNumFaces(); ++f)
{
Mesh::FaceInformation finfo = mesh.GetFaceInformation(f);
if (!finfo.IsBoundary()) { continue; }
face_info[0 + fidx*2] = finfo.element[0].local_face_id;
face_info[1 + fidx*2] = finfo.element[0].index;
fidx++;
}
}
const auto d_face_maps = Reshape(face_maps.Read(), ndof_face, n_faces_per_el);
const auto d_face_info = Reshape(face_info.Read(), 2, nf_bdr);
const bool reorder = (ordering == ElementDofOrdering::NATIVE);
mfem::forall_2D(nf_bdr, ndof_face, ndof_face, [=] MFEM_HOST_DEVICE (int f)
{
const int lf_i = d_face_info(0, f);
const int e = d_face_info(1, f);
// Loop over face indices in "native ordering"
MFEM_FOREACH_THREAD(i_lex_face, x, ndof_face)
{
// Convert from lexicographic face DOF to volume DOF
const int i_lex = d_face_maps(i_lex_face, lf_i);
const int ii_s = d_dof_map[i_lex];
const int ii = (ii_s >= 0) ? ii_s : -1 - ii_s;
const int i = reorder ? ii : i_lex;
const int s_i = (ii_s < 0 && reorder) ? -1 : 1;
MFEM_FOREACH_THREAD(j_lex_face, y, ndof_face)
{
// Convert from lexicographic face DOF to volume DOF
const int j_lex = d_face_maps(j_lex_face, lf_i);
const int jj_s = d_dof_map[j_lex];
const int jj = (jj_s >= 0) ? jj_s : -1 - jj_s;
const int j = reorder ? jj : j_lex;
const int s_j = (jj_s < 0 && reorder) ? -1 : 1;
AtomicAdd(d_element_matrices(i, j, e),
s_i*s_j*d_ea_bdr(i_lex_face, j_lex_face, f));
}
}
});
}
}
// Data and methods for fully-assembled bilinear forms
+11
View File
@@ -154,6 +154,17 @@ public:
void Assemble() override;
void Mult(const Vector &x, Vector &y) const override;
void MultTranspose(const Vector &x, Vector &y) const override;
/// @brief Populates @a element_matrices with the element matrices.
///
/// The element matrices are converted from row-major (how they are stored in
/// @a ea_data) to column-major format.
///
/// If @a ordering is ElementDofOrdering::NATIVE, then the matrices are
/// reordered from the lexicographic ordering used internally.
void GetElementMatrices(DenseTensor &element_matrices,
ElementDofOrdering ordering,
bool add_bdr);
};
/// Data and methods for fully-assembled bilinear forms
+31 -5
View File
@@ -72,6 +72,14 @@ void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEABoundary(const FiniteElementSpace &fes,
Vector &emat,
const bool add)
{
MFEM_ABORT("BilinearFormIntegrator::AssembleEABoundary(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
&fes,
Vector &ea_data_int,
@@ -82,6 +90,16 @@ void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEAInteriorFaces(
const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes,
Vector &emat,
const bool add)
{
MFEM_ABORT("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
" is not implemented for this class.");
}
void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
&fes,
Vector &ea_data_bdr,
@@ -2829,17 +2847,18 @@ void VectorDivergenceIntegrator::AssembleElementMatrix2(
DenseMatrix &elmat)
{
dim = trial_fe.GetDim();
sdim = Trans.GetSpaceDim();
int trial_dof = trial_fe.GetDof();
int test_dof = test_fe.GetDof();
real_t c;
dshape.SetSize (trial_dof, dim);
gshape.SetSize (trial_dof, dim);
Jadj.SetSize (dim);
divshape.SetSize (dim*trial_dof);
gshape.SetSize (trial_dof, sdim);
Jadj.SetSize (dim, sdim);
divshape.SetSize (sdim*trial_dof);
shape.SetSize (test_dof);
elmat.SetSize (test_dof, dim*trial_dof);
elmat.SetSize (test_dof, sdim*trial_dof);
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
@@ -2853,13 +2872,15 @@ void VectorDivergenceIntegrator::AssembleElementMatrix2(
trial_fe.CalcDShape (ip, dshape);
test_fe.CalcPhysShape (Trans, shape);
// AdjugateJacobian = / adj(J), if J is square
// \ adj(J^t.J).J^t, otherwise
CalcAdjugate(Trans.Jacobian(), Jadj);
Mult (dshape, Jadj, gshape);
gshape.GradToDiv (divshape);
c = ip.weight;
if (dim != sdim) { c /= Trans.Weight(); }
if (Q)
{
c *= Q -> Eval (Trans, ip);
@@ -2900,6 +2921,11 @@ void DivDivIntegrator::AssembleElementMatrix(
if (ir == NULL)
{
int order = 2 * el.GetOrder() - 2; // <--- OK for RTk
if (el.Space() == FunctionSpace::Uk)
{
order += 2;
}
ir = &IntRules.Get(el.GetGeomType(), order);
}
+39 -7
View File
@@ -124,11 +124,25 @@ public:
/// Assemble diagonal and add it to Vector @a diag.
virtual void AssembleDiagonalMF(Vector &diag);
virtual void AssembleEABoundary(const FiniteElementSpace &fes,
Vector &ea_data_bdr,
const bool add = true);
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext,
const bool add = true);
/// @brief Method defining element assembly for mixed trace integrators.
///
/// This is the element assembly analogue of AssembleFaceMatrix(const
/// FiniteElement&, const FiniteElement&, const FiniteElement&,
/// FaceElementTransformations&, DenseMatrix&).
virtual void AssembleEAInteriorFaces(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes,
Vector &emat,
const bool add = true);
virtual void AssembleEABoundaryFaces(const FiniteElementSpace &fes,
Vector &ea_data_bdr,
const bool add = true);
@@ -383,6 +397,7 @@ public:
void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add) override;
using BilinearFormIntegrator::AssembleEAInteriorFaces;
void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext,
@@ -494,6 +509,7 @@ public:
void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add) override;
using BilinearFormIntegrator::AssembleEAInteriorFaces;
void AssembleEAInteriorFaces(const FiniteElementSpace &fes,
Vector &ea_data_int,
Vector &ea_data_ext,
@@ -2350,6 +2366,8 @@ protected:
const FaceGeometricFactors *face_geom; ///< Not owned
int dim, ne, nq, dofs1D, quad1D;
void AssembleEA_(Vector &ea, const bool add);
public:
using ApplyKernelType = void(*)(const int, const Array<real_t>&,
@@ -2390,7 +2408,10 @@ public:
void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add) override;
void AssembleDiagonalPA(Vector &diag) override;
virtual void AssembleEABoundary(const FiniteElementSpace &fes, Vector &emat,
const bool add) override;
virtual void AssembleDiagonalPA(Vector &diag) override;
void AssembleDiagonalMF(Vector &diag) override;
@@ -2914,6 +2935,8 @@ public:
void AddMultPA(const Vector &x, Vector &y) const override;
void AddMultTransposePA(const Vector &x, Vector &y) const override;
void AssembleDiagonalPA(Vector& diag) override;
void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add) override;
const Coefficient *GetCoefficient() const { return Q; }
};
@@ -2935,7 +2958,7 @@ private:
Vector pa_data;
const DofToQuad *trial_maps, *test_maps; ///< Not owned
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq;
int dim, sdim, ne, nq;
int trial_dofs1D, test_dofs1D, quad1D;
public:
@@ -2981,11 +3004,6 @@ class DivDivIntegrator: public BilinearFormIntegrator
protected:
Coefficient *Q;
using BilinearFormIntegrator::AssemblePA;
void AssemblePA(const FiniteElementSpace &fes) override;
void AddMultPA(const Vector &x, Vector &y) const override;
void AssembleDiagonalPA(Vector& diag) override;
private:
#ifndef MFEM_THREAD_SAFE
Vector divshape, te_divshape;
@@ -3012,6 +3030,13 @@ public:
ElementTransformation &Trans,
DenseMatrix &elmat) override;
using BilinearFormIntegrator::AssemblePA;
void AssemblePA(const FiniteElementSpace &fes) override;
void AddMultPA(const Vector &x, Vector &y) const override;
void AssembleDiagonalPA(Vector& diag) override;
void AssembleEA(const FiniteElementSpace &fes, Vector &emat,
const bool add) override;
const Coefficient *GetCoefficient() const { return Q; }
};
@@ -3311,6 +3336,7 @@ public:
void AddMultPA(const Vector&, Vector&) const override;
using BilinearFormIntegrator::AssembleEAInteriorFaces;
void AssembleEAInteriorFaces(const FiniteElementSpace& fes,
Vector &ea_data_int,
Vector &ea_data_ext,
@@ -3624,6 +3650,12 @@ public:
const FiniteElement &test_fe2,
FaceElementTransformations &Trans,
DenseMatrix &elmat) override;
using BilinearFormIntegrator::AssembleEAInteriorFaces;
void AssembleEAInteriorFaces(const FiniteElementSpace &trial_fes,
const FiniteElementSpace &test_fes,
Vector &emat,
const bool add = true) override;
};
/** Integrator for the DPG form:$ \langle v, w \rangle $ over a face (the interface) where
+7 -2
View File
@@ -240,7 +240,9 @@ public:
Vector argument instead of Vector. */
MFEM_DEPRECATED FunctionCoefficient(real_t (*f)(Vector &))
{
Function = reinterpret_cast<real_t(*)(const Vector&)>(f);
// Cast first to (void*) to suppress a warning from newer version of
// Clang when using -Wextra.
Function = reinterpret_cast<real_t(*)(const Vector&)>((void*)f);
TDFunction = NULL;
}
@@ -250,7 +252,10 @@ public:
MFEM_DEPRECATED FunctionCoefficient(real_t (*tdf)(Vector &, real_t))
{
Function = NULL;
TDFunction = reinterpret_cast<real_t(*)(const Vector&,real_t)>(tdf);
// Cast first to (void*) to suppress a warning from newer version of
// Clang when using -Wextra.
TDFunction =
reinterpret_cast<real_t(*)(const Vector&,real_t)>((void*)tdf);
}
/// Evaluate the coefficient at @a ip.
+4 -4
View File
@@ -487,7 +487,7 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
if (RealInteg() && ImagInteg())
{
// Modify RHS and offdiagonal blocks (imaginary parts of the matrix) to
// Modify RHS and off-diagonal blocks (imaginary parts of the matrix) to
// conform with standard essential BC treatment
if (A_i.Is<ConstrainedOperator>())
{
@@ -576,7 +576,7 @@ SesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
if (RealInteg() && ImagInteg())
{
// Modify offdiagonal blocks (imaginary parts of the matrix) to conform
// Modify off-diagonal blocks (imaginary parts of the matrix) to conform
// with standard essential BC treatment
if (A_i.Is<ConstrainedOperator>())
{
@@ -1236,7 +1236,7 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
d_B_r[j] = d_X_r[j];
d_B_i[j] = d_X_i[j];
});
// Modify offdiagonal blocks (imaginary parts of the matrix) to conform
// Modify off-diagonal blocks (imaginary parts of the matrix) to conform
// with standard essential BC treatment
if (A_i.Type() == Operator::Hypre_ParCSR)
{
@@ -1324,7 +1324,7 @@ ParSesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
if (RealInteg() && ImagInteg())
{
// Modify offdiagonal blocks (imaginary parts of the matrix) to conform
// Modify off-diagonal blocks (imaginary parts of the matrix) to conform
// with standard essential BC treatment
if ( A_i.Type() == Operator::Hypre_ParCSR )
{
+118 -52
View File
@@ -12,6 +12,7 @@
#include "fem.hpp"
#include "../mesh/nurbs.hpp"
#include "../mesh/vtk.hpp"
#include "../mesh/vtkhdf.hpp"
#include "../general/binaryio.hpp"
#include "../general/text.hpp"
#include "picojson.h"
@@ -758,18 +759,10 @@ void VisItDataCollection::ParseVisItRootString(const std::string& json)
}
}
ParaViewDataCollection::ParaViewDataCollection(const std::string&
collection_name,
Mesh *mesh_)
: DataCollection(collection_name, mesh_),
levels_of_detail(1),
pv_data_format(VTKFormat::BINARY),
high_order_output(false),
restart_mode(false)
ParaViewDataCollectionBase::ParaViewDataCollectionBase(
const std::string &name, Mesh *mesh) : DataCollection(name, mesh)
{
cycle = 0; // always include a valid cycle index in file names
compression_level = -1; // default zlib compression level, equivalent to 6
cycle = 0;
#ifdef MFEM_USE_ZLIB
compression = true; // if we have zlib, enable compression
#else
@@ -777,16 +770,53 @@ ParaViewDataCollection::ParaViewDataCollection(const std::string&
#endif
}
void ParaViewDataCollection::SetLevelsOfDetail(int levels_of_detail_)
void ParaViewDataCollectionBase::SetLevelsOfDetail(int levels_of_detail_)
{
levels_of_detail = levels_of_detail_;
}
void ParaViewDataCollection::Load(int )
void ParaViewDataCollectionBase::SetHighOrderOutput(bool high_order_output_)
{
MFEM_WARNING("ParaViewDataCollection::Load() is not implemented!");
high_order_output = high_order_output_;
}
void ParaViewDataCollectionBase::SetCompressionLevel(int compression_level_)
{
MFEM_ASSERT(compression_level_ >= -1 && compression_level_ <= 9,
"Compression level must be between -1 and 9 (inclusive).");
compression_level = compression_level_;
compression = compression_level_ != 0;
}
void ParaViewDataCollectionBase::SetCompression(bool compression_)
{
compression = compression_;
}
int ParaViewDataCollectionBase::GetCompressionLevel() const
{
return compression ? compression_level : 0;
}
void ParaViewDataCollectionBase::SetDataFormat(VTKFormat fmt)
{
pv_data_format = fmt;
}
bool ParaViewDataCollectionBase::IsBinaryFormat() const
{
return pv_data_format != VTKFormat::ASCII;
}
void ParaViewDataCollectionBase::UseRestartMode(bool restart_mode_)
{
restart_mode = restart_mode_;
}
ParaViewDataCollection::ParaViewDataCollection(
const std::string& collection_name, Mesh *mesh_)
: ParaViewDataCollectionBase(collection_name, mesh_) { }
std::string ParaViewDataCollection::GenerateCollectionPath()
{
return prefix_path + DataCollection::GetCollectionName();
@@ -901,7 +931,7 @@ void ParaViewDataCollection::Save()
// Initialize new pvd file.
pvd_stream.open(pvdname,std::ios::out|std::ios::trunc);
pvd_stream << "<?xml version=\"1.0\"?>\n";
pvd_stream << "<VTKFile type=\"Collection\" version=\"0.1\"";
pvd_stream << "<VTKFile type=\"Collection\" version=\"2.2\"";
pvd_stream << " byte_order=\"" << VTKByteOrder() << "\">\n";
pvd_stream << "<Collection>" << std::endl;
}
@@ -1001,7 +1031,7 @@ void ParaViewDataCollection::WritePVTUHeader(std::ostream &os)
{
os << "<?xml version=\"1.0\"?>\n";
os << "<VTKFile type=\"PUnstructuredGrid\"";
os << " version =\"0.1\" byte_order=\"" << VTKByteOrder() << "\">\n";
os << " version =\"2.2\" byte_order=\"" << VTKByteOrder() << "\">\n";
os << "<PUnstructuredGrid GhostLevel=\"0\">\n";
os << "<PPoints>\n";
@@ -1042,7 +1072,7 @@ void ParaViewDataCollection::SaveDataVTU(std::ostream &os, int ref)
{
os << " compressor=\"vtkZLibDataCompressor\"";
}
os << " version=\"0.1\" byte_order=\"" << VTKByteOrder() << "\">\n";
os << " version=\"2.2\" byte_order=\"" << VTKByteOrder() << "\">\n";
os << "<UnstructuredGrid>\n";
mesh->PrintVTU(os,ref,pv_data_format,high_order_output,GetCompressionLevel());
@@ -1115,39 +1145,6 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &os, int ref_,
os << "</DataArray>" << std::endl;
}
void ParaViewDataCollection::SetDataFormat(VTKFormat fmt)
{
pv_data_format = fmt;
}
bool ParaViewDataCollection::IsBinaryFormat() const
{
return pv_data_format != VTKFormat::ASCII;
}
void ParaViewDataCollection::SetHighOrderOutput(bool high_order_output_)
{
high_order_output = high_order_output_;
}
void ParaViewDataCollection::SetCompressionLevel(int compression_level_)
{
MFEM_ASSERT(compression_level_ >= -1 && compression_level_ <= 9,
"Compression level must be between -1 and 9 (inclusive).");
compression_level = compression_level_;
compression = compression_level_ != 0;
}
void ParaViewDataCollection::SetCompression(bool compression_)
{
compression = compression_;
}
void ParaViewDataCollection::UseRestartMode(bool restart_mode_)
{
restart_mode = restart_mode_;
}
const char *ParaViewDataCollection::GetDataFormatString() const
{
if (pv_data_format == VTKFormat::ASCII)
@@ -1172,9 +1169,78 @@ const char *ParaViewDataCollection::GetDataTypeString() const
}
}
int ParaViewDataCollection::GetCompressionLevel() const
#ifdef MFEM_USE_HDF5
ParaViewHDFDataCollection::ParaViewHDFDataCollection(
const std::string &collection_name, Mesh *mesh)
: ParaViewDataCollectionBase(collection_name, mesh)
{ }
void ParaViewHDFDataCollection::EnsureVTKHDF()
{
return compression ? compression_level : 0;
if (!vtkhdf)
{
if (!prefix_path.empty())
{
const int error_code = create_directory(prefix_path, mesh, myid);
MFEM_VERIFY(error_code == 0, "Error creating directory " << prefix_path);
}
std::string fname = prefix_path + name + ".vtkhdf";
bool use_mpi = false;
#ifdef MFEM_USE_MPI
if (ParMesh *pmesh = dynamic_cast<ParMesh*>(mesh))
{
use_mpi = true;
#ifdef MFEM_PARALLEL_HDF5
vtkhdf.reset(new VTKHDF(fname, pmesh->GetComm(), {restart_mode, time}));
#else
MFEM_ABORT("Requires HDF5 library with parallel support enabled");
#endif
}
#endif
if (!use_mpi)
{
vtkhdf.reset(new VTKHDF(fname, {restart_mode, time}));
}
}
}
template <typename FP_T>
void ParaViewHDFDataCollection::TSave()
{
EnsureVTKHDF();
if (compression)
{
vtkhdf->EnableCompression(compression_level >= 0 ? compression_level : 6);
}
else
{
vtkhdf->DisableCompression();
}
vtkhdf->SaveMesh<FP_T>(*mesh, high_order_output, levels_of_detail);
for (const auto &field : field_map)
{
vtkhdf->SaveGridFunction<FP_T>(*field.second, field.first);
}
vtkhdf->UpdateSteps(time);
vtkhdf->Flush();
}
void ParaViewHDFDataCollection::Save()
{
switch (pv_data_format)
{
case VTKFormat::BINARY32: TSave<float>(); break;
case VTKFormat::BINARY: TSave<double>(); break;
default: MFEM_ABORT("Unsupported VTK format.");
}
}
ParaViewHDFDataCollection::~ParaViewHDFDataCollection() = default;
#endif
} // end namespace MFEM
+110 -61
View File
@@ -502,59 +502,26 @@ public:
};
/// Helper class for ParaView visualization data
class ParaViewDataCollection : public DataCollection
/// Abstract base class for ParaViewDataCollection and ParaViewHDFDataCollection
class ParaViewDataCollectionBase : public DataCollection
{
private:
int levels_of_detail;
int compression_level;
std::fstream pvd_stream;
VTKFormat pv_data_format;
bool high_order_output;
bool restart_mode;
protected:
void WritePVTUHeader(std::ostream &out);
void WritePVTUFooter(std::ostream &out, const std::string &vtu_prefix);
void SaveDataVTU(std::ostream &out, int ref);
void SaveGFieldVTU(std::ostream& out, int ref_, const FieldMapIterator& it);
const char *GetDataFormatString() const;
const char *GetDataTypeString() const;
/// @brief If compression is enabled, return the compression level, otherwise
/// return 0.
int GetCompressionLevel() const;
std::string GenerateCollectionPath();
std::string GenerateVTUFileName(const std::string &prefix, int rank);
std::string GenerateVTUPath();
std::string GeneratePVDFileName();
std::string GeneratePVTUFileName(const std::string &prefix);
std::string GeneratePVTUPath();
int levels_of_detail = 1;
int compression_level = -1;
bool high_order_output = false;
bool restart_mode = false;
VTKFormat pv_data_format = VTKFormat::BINARY;
public:
/// Constructor. The collection name is used when saving the data.
/** If @a mesh_ is NULL, then the mesh can be set later by calling SetMesh().
Before saving the data collection, some parameters in the collection can
be adjusted, e.g. SetPadDigits(), SetPrefixPath(), etc. */
ParaViewDataCollection(const std::string& collection_name,
mfem::Mesh *mesh_ = NULL);
ParaViewDataCollectionBase(const std::string &name, Mesh *mesh);
/// Set refinement levels - every element is uniformly split based on
/// levels_of_detail_. The initial value is 1.
void SetLevelsOfDetail(int levels_of_detail_);
/// Save the collection - the directory name is constructed based on the
/// cycle value
void Save() override;
/// Set the data format for the ParaView output files. Possible options are
/// VTKFormat::ASCII, VTKFormat::BINARY, and VTKFormat::BINARY32.
/// The ASCII and BINARY options output double precision data, whereas the
/// BINARY32 option outputs single precision data.
/// @brief Set the refinement level.
///
/// The initial format is VTKFormat::BINARY.
void SetDataFormat(VTKFormat fmt);
/// In "low-order mode", every element is uniformly split based on the levels
/// of detail. In "high-order mode", this sets the polynomial degree for the
/// element transformations.
///
/// The initial value is 1.
void SetLevelsOfDetail(int levels_of_detail_);
/// @brief Set the zlib compression level.
///
@@ -570,28 +537,110 @@ public:
/// Any nonzero compression level will enable compression.
void SetCompressionLevel(int compression_level_);
/// Enable or disable zlib compression. If the input is true, use the default
/// zlib compression level (unless the compression level has previously been
/// set by calling SetCompressionLevel()).
/// @brief Enable or disable zlib compression.
///
/// If the input is true, use the default zlib compression level (unless the
/// compression level has previously been set by calling
/// SetCompressionLevel()).
void SetCompression(bool compression_) override;
/// @brief Sets whether or not to output the data as high-order elements
/// (false by default).
///
/// Reading high-order data requires ParaView 5.5 or later.
void SetHighOrderOutput(bool high_order_output_);
/// If compression is enabled, return the compression level, else return 0.
int GetCompressionLevel() const;
/// @brief Set the data format for the ParaView output files.
///
/// Possible options are VTKFormat::ASCII, VTKFormat::BINARY, and
/// VTKFormat::BINARY32. The ASCII and BINARY options output double precision
/// data, whereas the BINARY32 option outputs single precision data.
///
/// The initial format is VTKFormat::BINARY.
///
/// VTKFormat::ASCII is not supported by ParaViewHDFDataCollection.
void SetDataFormat(VTKFormat fmt);
/// Returns true if the output format is BINARY or BINARY32, false if ASCII.
bool IsBinaryFormat() const;
/// Sets whether or not to output the data as high-order elements (false
/// by default). Reading high-order data requires ParaView 5.5 or later.
void SetHighOrderOutput(bool high_order_output_);
/// Enable or disable restart mode. If restart is enabled, new writes will
/// preserve timestep metadata for any solutions prior to the currently
/// defined time.
/// @brief Enable or disable restart mode.
///
/// If restart is enabled, new writes will preserve timestep metadata for any
/// solutions prior to the currently defined time.
///
/// Initially, restart mode is disabled.
void UseRestartMode(bool restart_mode_);
/// Load the collection - not implemented in the ParaView writer
void Load(int cycle_ = 0) override;
};
/// Writer for ParaView visualization (PVD and VTU format)
class ParaViewDataCollection : public ParaViewDataCollectionBase
{
private:
std::fstream pvd_stream;
protected:
void WritePVTUHeader(std::ostream &out);
void WritePVTUFooter(std::ostream &out, const std::string &vtu_prefix);
void SaveDataVTU(std::ostream &out, int ref);
void SaveGFieldVTU(std::ostream& out, int ref_, const FieldMapIterator& it);
const char *GetDataFormatString() const;
const char *GetDataTypeString() const;
std::string GenerateCollectionPath();
std::string GenerateVTUFileName(const std::string &prefix, int rank);
std::string GenerateVTUPath();
std::string GeneratePVDFileName();
std::string GeneratePVTUFileName(const std::string &prefix);
std::string GeneratePVTUPath();
public:
/// Constructor. The collection name is used when saving the data.
/** If @a mesh_ is NULL, then the mesh can be set later by calling SetMesh().
Before saving the data collection, some parameters in the collection can
be adjusted, e.g. SetPadDigits(), SetPrefixPath(), etc. */
ParaViewDataCollection(const std::string& collection_name,
Mesh *mesh_ = nullptr);
/// Save the collection - the directory name is constructed based on the
/// cycle value
void Save() override;
};
#ifdef MFEM_USE_HDF5
/// Writer for ParaView visualization (%VTKHDF format)
class ParaViewHDFDataCollection : public ParaViewDataCollectionBase
{
/// The low-level VTKHDF object for I/O (pointer to implementation idiom).
std::unique_ptr<class VTKHDF> vtkhdf;
/// Create the VTKHDF object if it doesn't exist already.
void EnsureVTKHDF();
/// Save the collection (templated on floating point type).
template <typename FP_T> void TSave();
public:
/// @brief Constructor. The collection name is used when saving the data.
///
/// If @a mesh_ is NULL, then the mesh can be set later by calling SetMesh().
/// Before saving the data collection, some parameters in the collection can
/// be adjusted, e.g. SetPadDigits(), SetPrefixPath(), etc.
ParaViewHDFDataCollection(const std::string& collection_name,
Mesh *mesh_ = nullptr);
/// Save the collection.
void Save() override;
/// Destructor.
~ParaViewHDFDataCollection();
};
#endif
}
#endif
+65 -52
View File
@@ -17,7 +17,10 @@
namespace mfem
{
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_orig, Coefficient *coeff,
struct DGMassInvKernels { DGMassInvKernels(); };
DGMassInverse::DGMassInverse(const FiniteElementSpace &fes_orig,
Coefficient *coeff,
const IntegrationRule *ir,
int btype)
: Solver(fes_orig.GetTrueVSize()),
@@ -27,6 +30,8 @@ DGMassInverse::DGMassInverse(FiniteElementSpace &fes_orig, Coefficient *coeff,
fes_orig.GetTypicalFE()->GetMapType()),
fes(fes_orig.GetMesh(), &fec)
{
static DGMassInvKernels kernels;
MFEM_VERIFY(fes.IsDGSpace(), "Space must be DG.");
MFEM_VERIFY(!fes.IsVariableOrder(), "Variable orders not supported.");
@@ -46,7 +51,7 @@ DGMassInverse::DGMassInverse(FiniteElementSpace &fes_orig, Coefficient *coeff,
const FiniteElement &fe = *fes.GetTypicalFE();
d2q = &fe_orig.GetDofToQuad(fe.GetNodes(), mode);
int n = d2q->ndof;
const int n = d2q->ndof;
Array<real_t> B_inv = d2q->B; // deep copy
Array<int> ipiv(n);
// solver basis to original
@@ -71,7 +76,7 @@ DGMassInverse::DGMassInverse(FiniteElementSpace &fes_orig, Coefficient *coeff,
// Only need transformed RHS if basis is different
if (btype_orig != btype) { b2_.SetSize(height); }
M = new BilinearForm(&fes);
M.reset(new BilinearForm(&fes));
M->AddDomainIntegrator(m); // M assumes ownership of m
M->SetAssemblyLevel(AssemblyLevel::PARTIAL);
@@ -79,19 +84,19 @@ DGMassInverse::DGMassInverse(FiniteElementSpace &fes_orig, Coefficient *coeff,
Update();
}
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_, Coefficient &coeff,
DGMassInverse::DGMassInverse(const FiniteElementSpace &fes_, Coefficient &coeff,
int btype)
: DGMassInverse(fes_, &coeff, nullptr, btype) { }
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_, Coefficient &coeff,
DGMassInverse::DGMassInverse(const FiniteElementSpace &fes_, Coefficient &coeff,
const IntegrationRule &ir, int btype)
: DGMassInverse(fes_, &coeff, &ir, btype) { }
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_,
DGMassInverse::DGMassInverse(const FiniteElementSpace &fes_,
const IntegrationRule &ir, int btype)
: DGMassInverse(fes_, nullptr, &ir, btype) { }
DGMassInverse::DGMassInverse(FiniteElementSpace &fes_, int btype)
DGMassInverse::DGMassInverse(const FiniteElementSpace &fes_, int btype)
: DGMassInverse(fes_, nullptr, nullptr, btype) { }
void DGMassInverse::SetOperator(const Operator &op)
@@ -112,10 +117,7 @@ void DGMassInverse::Update()
diag_inv.Reciprocal();
}
DGMassInverse::~DGMassInverse()
{
delete M;
}
DGMassInverse::~DGMassInverse() = default;
template<int DIM, int D1D, int Q1D>
void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
@@ -269,47 +271,58 @@ void DGMassInverse::Mult(const Vector &Mu, Vector &u) const
const int d1d = m->dofs1D;
const int q1d = m->quad1D;
const int id = (d1d << 4) | q1d;
if (dim == 2)
{
switch (id)
{
case 0x11: return DGMassCGIteration<2,1,1>(Mu, u);
case 0x22: return DGMassCGIteration<2,2,2>(Mu, u);
case 0x33: return DGMassCGIteration<2,3,3>(Mu, u);
case 0x35: return DGMassCGIteration<2,3,5>(Mu, u);
case 0x44: return DGMassCGIteration<2,4,4>(Mu, u);
case 0x46: return DGMassCGIteration<2,4,6>(Mu, u);
case 0x55: return DGMassCGIteration<2,5,5>(Mu, u);
case 0x57: return DGMassCGIteration<2,5,7>(Mu, u);
case 0x66: return DGMassCGIteration<2,6,6>(Mu, u);
case 0x68: return DGMassCGIteration<2,6,8>(Mu, u);
default: return DGMassCGIteration<2>(Mu, u); // Fallback
}
}
else if (dim == 3)
{
switch (id)
{
case 0x22: return DGMassCGIteration<3,2,2>(Mu, u);
case 0x23: return DGMassCGIteration<3,2,3>(Mu, u);
case 0x33: return DGMassCGIteration<3,3,3>(Mu, u);
case 0x34: return DGMassCGIteration<3,3,4>(Mu, u);
case 0x35: return DGMassCGIteration<3,3,5>(Mu, u);
case 0x44: return DGMassCGIteration<3,4,4>(Mu, u);
case 0x45: return DGMassCGIteration<3,4,5>(Mu, u);
case 0x46: return DGMassCGIteration<3,4,6>(Mu, u);
case 0x48: return DGMassCGIteration<3,4,8>(Mu, u);
case 0x55: return DGMassCGIteration<3,5,5>(Mu, u);
case 0x56: return DGMassCGIteration<3,5,6>(Mu, u);
case 0x57: return DGMassCGIteration<3,5,7>(Mu, u);
case 0x58: return DGMassCGIteration<3,5,8>(Mu, u);
case 0x66: return DGMassCGIteration<3,6,6>(Mu, u);
case 0x67: return DGMassCGIteration<3,6,7>(Mu, u);
default: return DGMassCGIteration<3>(Mu, u); // Fallback
}
}
CGKernels::Run(dim, d1d, q1d, *this, Mu, u);
}
DGMassInvKernels::DGMassInvKernels()
{
using k = DGMassInverse::CGKernels;
// 2D
k::Specialization<2,1,1>::Add();
k::Specialization<2,2,2>::Add();
k::Specialization<2,3,3>::Add();
k::Specialization<2,3,5>::Add();
k::Specialization<2,4,4>::Add();
k::Specialization<2,4,6>::Add();
k::Specialization<2,5,5>::Add();
k::Specialization<2,5,7>::Add();
k::Specialization<2,6,6>::Add();
k::Specialization<2,6,8>::Add();
// 3D
k::Specialization<3,2,2>::Add();
k::Specialization<3,2,3>::Add();
k::Specialization<3,3,3>::Add();
k::Specialization<3,3,4>::Add();
k::Specialization<3,3,5>::Add();
k::Specialization<3,4,4>::Add();
k::Specialization<3,4,5>::Add();
k::Specialization<3,4,6>::Add();
k::Specialization<3,4,8>::Add();
k::Specialization<3,5,5>::Add();
k::Specialization<3,5,6>::Add();
k::Specialization<3,5,7>::Add();
k::Specialization<3,5,8>::Add();
k::Specialization<3,6,6>::Add();
k::Specialization<3,6,7>::Add();
}
/// @cond Suppress_Doxygen_warnings
template <int DIM, int D1D, int Q1D>
DGMassInverse::CGKernelType DGMassInverse::CGKernels::Kernel()
{
return &DGMassInverse::DGMassCGIteration<DIM,D1D,Q1D>;
}
DGMassInverse::CGKernelType DGMassInverse::CGKernels::Fallback(
int dim, int, int)
{
if (dim == 1) { return &DGMassInverse::DGMassCGIteration<1>; }
else if (dim == 2) { return &DGMassInverse::DGMassCGIteration<2>; }
else if (dim == 3) { return &DGMassInverse::DGMassCGIteration<3>; }
else { MFEM_ABORT("Unsupported dimension."); }
}
/// @endcond
} // namespace mfem
+15 -9
View File
@@ -14,6 +14,8 @@
#include "../linalg/operator.hpp"
#include "fespace.hpp"
#include "kernel_dispatch.hpp"
#include <memory>
namespace mfem
{
@@ -32,7 +34,7 @@ protected:
const DofToQuad *d2q; ///< Change of basis. Not owned.
Array<real_t> B_; ///< Inverse of change of basis.
Array<real_t> Bt_; ///< Inverse of change of basis, transposed.
class BilinearForm *M; ///< Mass bilinear form, owned.
std::unique_ptr<class BilinearForm> M; ///< Mass bilinear form.
class MassIntegrator *m; ///< Mass integrator, owned by the form @ref M.
Vector diag_inv; ///< Jacobi preconditioner.
real_t rel_tol = 1e-12; ///< Relative CG tolerance.
@@ -48,7 +50,7 @@ protected:
///
/// Custom coefficient and integration rule are used if @a coeff and @a ir
/// are non-NULL.
DGMassInverse(FiniteElementSpace &fes_, Coefficient *coeff,
DGMassInverse(const FiniteElementSpace &fes_, Coefficient *coeff,
const IntegrationRule *ir, int btype);
public:
/// @brief Construct the DG inverse mass operator for @a fes_.
@@ -61,36 +63,37 @@ public:
/// The solution and right-hand side used for the solver are not affected by
/// this basis (they correspond to the basis of @a fes_). @a btype is only
/// used internally, and only has an effect on the convergence rate.
DGMassInverse(FiniteElementSpace &fes_, int btype=BasisType::GaussLegendre);
DGMassInverse(const FiniteElementSpace &fes_,
int btype=BasisType::GaussLegendre);
/// @brief Construct the DG inverse mass operator for @a fes_ with
/// Coefficient @a coeff.
///
/// @sa DGMassInverse(FiniteElementSpace&, int) for information about @a
/// btype.
DGMassInverse(FiniteElementSpace &fes_, Coefficient &coeff,
DGMassInverse(const FiniteElementSpace &fes_, Coefficient &coeff,
int btype=BasisType::GaussLegendre);
/// @brief Construct the DG inverse mass operator for @a fes_ with
/// Coefficient @a coeff and IntegrationRule @a ir.
///
/// @sa DGMassInverse(FiniteElementSpace&, int) for information about @a
/// btype.
DGMassInverse(FiniteElementSpace &fes_, Coefficient &coeff,
DGMassInverse(const FiniteElementSpace &fes_, Coefficient &coeff,
const IntegrationRule &ir, int btype=BasisType::GaussLegendre);
/// @brief Construct the DG inverse mass operator for @a fes_ with
/// IntegrationRule @a ir.
///
/// @sa DGMassInverse(FiniteElementSpace&, int) for information about @a
/// btype.
DGMassInverse(FiniteElementSpace &fes_, const IntegrationRule &ir,
DGMassInverse(const FiniteElementSpace &fes_, const IntegrationRule &ir,
int btype=BasisType::GaussLegendre);
/// @brief Solve the system M b = u.
///
/// If @ref iterative_mode is @a true, @a u is used as an initial guess.
void Mult(const Vector &b, Vector &u) const;
void Mult(const Vector &b, Vector &u) const override;
/// Same as Mult() since the mass matrix is symmetric.
void MultTranspose(const Vector &b, Vector &u) const { Mult(b, u); }
void MultTranspose(const Vector &b, Vector &u) const override { Mult(b, u); }
/// Not implemented. Aborts.
void SetOperator(const Operator &op);
void SetOperator(const Operator &op) override;
/// Set the relative tolerance.
void SetRelTol(const real_t rel_tol_);
/// Set the absolute tolerance.
@@ -107,6 +110,9 @@ public:
/// extended lambda used in an mfem::forall kernel (nvcc limitation)
template<int DIM, int D1D = 0, int Q1D = 0>
void DGMassCGIteration(const Vector &b_, Vector &u_) const;
using CGKernelType = void(DGMassInverse::*)(const Vector &b_, Vector &u) const;
MFEM_REGISTER_KERNELS(CGKernels, CGKernelType, (int, int, int));
};
} // namespace mfem
+49 -1
View File
@@ -37,6 +37,13 @@ void DGMassApply(const int e,
constexpr bool use_smem = (D1D > 0 && Q1D > 0);
constexpr bool ACCUM = false;
constexpr int NBZ = 1;
if (DIM == 1)
{
PAMassApply1D_Element<ACCUM>(e, NE, B, Bt, pa_data, x, y, d1d, q1d);
return;
}
if (use_smem)
{
// cannot specialize functions below with D1D or Q1D equal to zero
@@ -172,6 +179,43 @@ real_t DGMassDot(const int e,
return s_dot[0];
}
template<int T_D1D = 0>
MFEM_HOST_DEVICE inline
void DGMassBasis1D(const int e,
const int NE,
const real_t *b_,
const real_t *x_,
real_t *y_,
const int d1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const auto b = Reshape(b_, D1D, D1D);
const auto x = Reshape(x_, D1D, NE);
auto y = Reshape(y_, D1D, NE);
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
real_t Y[MD1];
MFEM_FOREACH_THREAD(i,x,D1D)
{
real_t val = 0.0;
for (int j = 0; j < D1D; ++j)
{
val += b(i,j)*x(j,e);
}
Y[i] = val;
}
MFEM_SYNC_THREAD;
if (MFEM_THREAD_ID(y) == 0)
{
MFEM_FOREACH_THREAD(i,x,D1D)
{
y(i,e) = Y[i];
}
}
}
template<int T_D1D = 0>
MFEM_HOST_DEVICE inline
void DGMassBasis2D(const int e,
@@ -269,7 +313,11 @@ void DGMassBasis(const int e,
real_t *y_,
const int d1d = 0)
{
if (DIM == 2)
if (DIM == 1)
{
DGMassBasis1D<T_D1D>(e, NE, b_, x_, y_, d1d);
}
else if (DIM == 2)
{
DGMassBasis2D<T_D1D>(e, NE, b_, x_, y_, d1d);
}
+59 -19
View File
@@ -201,13 +201,16 @@ const DenseTensor ND_DofTransformation
::TInv(const_cast<real_t *>(TInv_data), 2, 2, 6);
ND_DofTransformation::ND_DofTransformation(int size, int p, int num_edges,
int num_tri_faces)
int num_faces,
int face_types[])
: StatelessDofTransformation(size)
, order(p)
, nedofs(p)
, nfdofs(p*(p-1))
, ntdofs(p*(p-1))
, nqdofs(2*p*(p-1))
, nedges(num_edges)
, nfaces(num_tri_faces)
, nfaces(num_faces)
, ftypes(face_types)
{
}
@@ -221,6 +224,7 @@ void ND_DofTransformation::TransformPrimal(const Array<int> & Fo,
"Face orientation array is shorter than the number of faces in "
"ND_DofTransformation");
int of = 0;
real_t data[2];
Vector v2(data, 2);
DenseMatrix T2;
@@ -228,11 +232,19 @@ void ND_DofTransformation::TransformPrimal(const Array<int> & Fo,
// Transform face DoFs
for (int f=0; f<nfaces; f++)
{
for (int i=0; i<nfdofs/2; i++)
if (ftypes[f] == Geometry::TRIANGLE)
{
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
T2.UseExternalData(const_cast<real_t *>(T.GetData(Fo[f])), 2, 2);
T2.Mult(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
for (int i=0; i<ntdofs/2; i++)
{
v2 = &v[nedges*nedofs + of + 2*i];
T2.UseExternalData(const_cast<real_t *>(T.GetData(Fo[f])), 2, 2);
T2.Mult(v2, &v[nedges*nedofs + of + 2*i]);
}
of += ntdofs;
}
else
{
of += nqdofs;
}
}
}
@@ -247,6 +259,7 @@ void ND_DofTransformation::InvTransformPrimal(const Array<int> & Fo,
"Face orientation array is shorter than the number of faces in "
"ND_DofTransformation");
int of = 0;
real_t data[2];
Vector v2(data, 2);
DenseMatrix T2Inv;
@@ -254,11 +267,19 @@ void ND_DofTransformation::InvTransformPrimal(const Array<int> & Fo,
// Transform face DoFs
for (int f=0; f<nfaces; f++)
{
for (int i=0; i<nfdofs/2; i++)
if (ftypes[f] == Geometry::TRIANGLE)
{
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
T2Inv.UseExternalData(const_cast<real_t *>(TInv.GetData(Fo[f])), 2, 2);
T2Inv.Mult(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
for (int i=0; i<ntdofs/2; i++)
{
v2 = &v[nedges*nedofs + of + 2*i];
T2Inv.UseExternalData(const_cast<real_t *>(TInv.GetData(Fo[f])), 2, 2);
T2Inv.Mult(v2, &v[nedges*nedofs + of + 2*i]);
}
of += ntdofs;
}
else
{
of += nqdofs;
}
}
}
@@ -272,6 +293,7 @@ void ND_DofTransformation::TransformDual(const Array<int> & Fo, real_t *v) const
"Face orientation array is shorter than the number of faces in "
"ND_DofTransformation");
int of = 0;
real_t data[2];
Vector v2(data, 2);
DenseMatrix T2Inv;
@@ -279,12 +301,21 @@ void ND_DofTransformation::TransformDual(const Array<int> & Fo, real_t *v) const
// Transform face DoFs
for (int f=0; f<nfaces; f++)
{
for (int i=0; i<nfdofs/2; i++)
if (ftypes[f] == Geometry::TRIANGLE)
{
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
T2Inv.UseExternalData(const_cast<real_t *>(TInv.GetData(Fo[f])), 2, 2);
T2Inv.MultTranspose(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
for (int i=0; i<ntdofs/2; i++)
{
v2 = &v[nedges*nedofs + of + 2*i];
T2Inv.UseExternalData(const_cast<real_t *>(TInv.GetData(Fo[f])), 2, 2);
T2Inv.MultTranspose(v2, &v[nedges*nedofs + of + 2*i]);
}
of += ntdofs;
}
else
{
of += nqdofs;
}
}
}
@@ -298,6 +329,7 @@ void ND_DofTransformation::InvTransformDual(const Array<int> & Fo,
"Face orientation array is shorter than the number of faces in "
"ND_DofTransformation");
int of = 0;
real_t data[2];
Vector v2(data, 2);
DenseMatrix T2;
@@ -305,11 +337,19 @@ void ND_DofTransformation::InvTransformDual(const Array<int> & Fo,
// Transform face DoFs
for (int f=0; f<nfaces; f++)
{
for (int i=0; i<nfdofs/2; i++)
if (ftypes[f] == Geometry::TRIANGLE)
{
v2 = &v[nedges*nedofs + f*nfdofs + 2*i];
T2.UseExternalData(const_cast<real_t *>(T.GetData(Fo[f])), 2, 2);
T2.MultTranspose(v2, &v[nedges*nedofs + f*nfdofs + 2*i]);
for (int i=0; i<ntdofs/2; i++)
{
v2 = &v[nedges*nedofs + of + 2*i];
T2.UseExternalData(const_cast<real_t *>(T.GetData(Fo[f])), 2, 2);
T2.MultTranspose(v2, &v[nedges*nedofs + of + 2*i]);
}
of += ntdofs;
}
else
{
of += nqdofs;
}
}
}
+31 -10
View File
@@ -306,13 +306,16 @@ private:
static const DenseTensor T, TInv;
protected:
const int order; // basis function order
const int nedofs; // number of DoFs per edge
const int nfdofs; // number of DoFs per face
const int nedges; // number of edges per element
const int nfaces; // number of triangular faces per element
const int order; // basis function order
const int nedofs; // number of DoFs per edge
const int ntdofs; // number of DoFs per triangular face
const int nqdofs; // number of DoFs per quadrilateral face
const int nedges; // number of edges per element
const int nfaces; // number of faces per element
const int *ftypes; // Pointer to array of Geometry::Type for each face
ND_DofTransformation(int size, int order, int num_edges, int num_tri_faces);
ND_DofTransformation(int size, int order, int num_edges, int num_faces,
int *face_types);
public:
// Return the 2x2 transformation operator for the given face orientation
@@ -322,7 +325,7 @@ public:
static const DenseMatrix & GetFaceInverseTransform(int ori)
{ return TInv(ori); }
bool IsIdentity() const override { return nfdofs < 2; }
bool IsIdentity() const override { return ntdofs < 2; }
void TransformPrimal(const Array<int> & Fo, real_t *v) const override;
void InvTransformPrimal(const Array<int> & Fo, real_t *v) const override;
@@ -334,9 +337,11 @@ public:
/// triangles
class ND_TriDofTransformation : public ND_DofTransformation
{
private:
const int face_type[1] = { Geometry::TRIANGLE };
public:
ND_TriDofTransformation(int order)
: ND_DofTransformation(order*(order + 2), order, 3, 1)
: ND_DofTransformation(order*(order + 2), order, 3, 1, (int *)face_type)
{}
};
@@ -345,7 +350,9 @@ class ND_TetDofTransformation : public ND_DofTransformation
{
public:
ND_TetDofTransformation(int order)
: ND_DofTransformation(order*(order + 2)*(order + 3)/2, order, 6, 4)
: ND_DofTransformation(order*(order + 2)*(order + 3)/2, order, 6, 4,
(int *)Geometry::Constants<Geometry::TETRAHEDRON>::
FaceTypes)
{}
};
@@ -355,7 +362,21 @@ class ND_WedgeDofTransformation : public ND_DofTransformation
public:
ND_WedgeDofTransformation(int order)
: ND_DofTransformation(3 * order * ((order + 1) * (order + 2))/2,
order, 9, 2)
order, 9, 5,
(int *)Geometry::Constants<Geometry::PRISM>::
FaceTypes)
{}
};
/// DoF transformation implementation for the Nedelec basis on pyramid elements
class ND_PyramidDofTransformation : public ND_DofTransformation
{
public:
ND_PyramidDofTransformation(int order)
: ND_DofTransformation(2 * order * (order * (order + 1) + 2),
order, 8, 5,
(int *)Geometry::Constants<Geometry::PYRAMID>::
FaceTypes)
{}
};
+53 -10
View File
@@ -11,6 +11,8 @@
#include "../mesh/mesh_headers.hpp"
#include "fem.hpp"
#include "eltrans/eltrans_basis.hpp"
#include <cmath>
namespace mfem
@@ -66,7 +68,6 @@ const DenseMatrix &ElementTransformation::EvalInverseJ()
return invJ;
}
int InverseElementTransformation::FindClosestPhysPoint(
const Vector& pt, const IntegrationRule &ir)
{
@@ -180,12 +181,13 @@ int InverseElementTransformation::NewtonSolve(const Vector &pt,
const int dim = T->GetDimension();
const int sdim = T->GetSpaceDim();
IntegrationPoint xip, prev_xip;
real_t xd[3], yd[3], dxd[3], dx_norm = -1.0, err_phys, real_dx_norm = -1.0;
Vector x(xd, dim), y(yd, sdim), dx(dxd, dim);
real_t xd[3], yd[3], dxd[3], dxpd[3], dx_norm = -1.0, err_phys,
real_dx_norm = -1.0;
Vector x(xd, dim), y(yd, sdim), dx(dxd, dim), dx_prev(dxpd, dim);
bool hit_bdr = false, prev_hit_bdr = false;
// Use ip0 as initial guess:
xip = *ip0;
xip = ip0;
xip.Get(xd, dim); // xip -> x
if (print_level >= 3)
{
@@ -342,16 +344,18 @@ int InverseElementTransformation::Transform(const Vector &pt,
switch (init_guess_type)
{
case Center:
ip0 = &Geometries.GetCenter(T->GetGeometryType());
ip0 = Geometries.GetCenter(T->GetGeometryType());
break;
case ClosestPhysNode:
case ClosestRefNode:
{
const int order = std::max(T->Order()+rel_qpts_order, 0);
const int order = qpts_order >= 0
? qpts_order
: std::max(T->Order() + rel_qpts_order, 0);
if (order == 0)
{
ip0 = &Geometries.GetCenter(T->GetGeometryType());
ip0 = Geometries.GetCenter(T->GetGeometryType());
}
else
{
@@ -359,11 +363,45 @@ int InverseElementTransformation::Transform(const Vector &pt,
int closest_idx = (init_guess_type == ClosestPhysNode) ?
FindClosestPhysPoint(pt, RefG.RefPts) :
FindClosestRefPoint(pt, RefG.RefPts);
ip0 = &RefG.RefPts.IntPoint(closest_idx);
ip0 = RefG.RefPts.IntPoint(closest_idx);
}
break;
}
case EdgeScan:
{
const int order = qpts_order >= 0
? qpts_order
: std::max(T->Order() + rel_qpts_order, 0);
if (order == 0)
{
ip0 = Geometries.GetCenter(T->GetGeometryType());
}
else
{
auto &ir = *refiner.EdgeScan(T->GetGeometryType(), order + 1);
int res = Outside;
int npts = ir.GetNPoints();
// will return Inside if any test point reports Inside, Outside if
// all points report Outside, else Unknown
for (int i = 0; i < npts; ++i)
{
ip0 = ir.IntPoint(i);
int tmp_res = NewtonSolve(pt, ip);
switch (tmp_res)
{
case Inside:
return Inside;
case Outside:
break;
case Unknown:
res = Unknown;
break;
}
}
return res;
}
break;
}
case GivenPoint:
break;
@@ -444,6 +482,8 @@ int IsoparametricTransformation::OrderJ() const
return (FElem->GetOrder()-1);
case FunctionSpace::Qk:
return (FElem->GetOrder());
case FunctionSpace::Uk:
return (FElem->GetOrder());
default:
MFEM_ABORT("unsupported finite element");
}
@@ -458,6 +498,8 @@ int IsoparametricTransformation::OrderW() const
return (FElem->GetOrder() - 1) * FElem->GetDim();
case FunctionSpace::Qk:
return (FElem->GetOrder() * FElem->GetDim() - 1);
case FunctionSpace::Uk:
return (FElem->GetOrder() * FElem->GetDim() - 1);
default:
MFEM_ABORT("unsupported finite element");
}
@@ -477,6 +519,8 @@ int IsoparametricTransformation::OrderGrad(const FiniteElement *fe) const
return ((k-1)*(d-1)+(l-1));
case FunctionSpace::Qk:
return (k*(d-1)+(l-1));
case FunctionSpace::Uk:
return (k*(d-1)+(l-1));
default:
MFEM_ABORT("unsupported finite element");
}
@@ -712,5 +756,4 @@ real_t FaceElementTransformations::CheckConsistency(int print_level,
return max_dist;
}
}
+281 -30
View File
@@ -17,9 +17,13 @@
#include "intrules.hpp"
#include "fe.hpp"
#include "kernel_dispatch.hpp"
namespace mfem
{
class GridFunction;
class ElementTransformation
{
protected:
@@ -198,40 +202,46 @@ public:
/// Algorithms for selecting an initial guess.
enum InitGuessType
{
Center = 0, ///< Use the center of the reference element.
Center = 0, ///< Use the center of the reference element.
ClosestPhysNode = 1, /**<
Use the point returned by FindClosestPhysPoint() from a reference-space
grid of type and size controlled by SetInitGuessPointsType() and
SetInitGuessRelOrder(), respectively. */
ClosestRefNode = 2, /**<
Use the point returned by FindClosestRefPoint() from a reference-space
grid of type and size controlled by SetInitGuessPointsType() and
SetInitGuessRelOrder(), respectively. */
GivenPoint = 3 ///< Use a specific point, set with SetInitialGuess().
Use the point returned by FindClosestPhysPoint() from a reference-space
grid of type and size controlled by SetInitGuessPointsType() and
SetInitGuessRelOrder(), respectively. */
ClosestRefNode = 2, /**<
Use the point returned by FindClosestRefPoint() from a reference-space
grid of type and size controlled by SetInitGuessPointsType() and
SetInitGuessRelOrder(), respectively. */
GivenPoint = 3, ///< Use a specific point, set with SetInitialGuess().
EdgeScan =
4, /**< Performs full solves on multiple points along the r/s/t=0 edges
of the element. It is recommended that SetInitGuessRelOrder() is
chosen such that max(trans_order+order,0)+1 <= 4 with
SetInitGuessPointsType() as Quadrature1D::ClosedUniform. @see
GeometryRefiner::EdgeScan */
};
/// Solution strategy.
enum SolverType
{
Newton = 0, /**<
Use Newton's algorithm, without restricting the reference-space points
(iterates) to the reference element. */
Newton = 0, /**<
Use Newton's algorithm, without restricting the reference-space points
(iterates) to the reference element. */
NewtonSegmentProject = 1, /**<
Use Newton's algorithm, restricting the reference-space points to the
reference element by scaling back the Newton increments, i.e.
projecting new iterates, x_new, lying outside the element, to the
intersection of the line segment [x_old, x_new] with the boundary. */
NewtonElementProject = 2 /**<
Use Newton's algorithm, restricting the reference-space points to the
reference element by projecting new iterates, x_new, lying outside the
element, to the point on the boundary closest (in reference-space) to
x_new. */
Use Newton's algorithm, restricting the reference-space points to the
reference element by scaling back the Newton increments, i.e.
projecting new iterates, x_new, lying outside the element, to the
intersection of the line segment [x_old, x_new] with the boundary. */
NewtonElementProject = 2, /**<
Use Newton's algorithm, restricting the reference-space points to the
reference element by projecting new iterates, x_new, lying outside the
element, to the point on the boundary closest (in reference-space) to
x_new. */
};
/// Values returned by Transform().
enum TransformResult
{
Inside = 0, ///< The point is inside the element
Inside = 0, ///< The point is inside the element
Outside = 1, ///< The point is _probably_ outside the element
Unknown = 2 ///< The algorithm failed to determine where the point is
};
@@ -241,9 +251,11 @@ protected:
ElementTransformation *T;
// Parameters of the inversion algorithms:
const IntegrationPoint *ip0;
IntegrationPoint ip0;
int init_guess_type; // algorithm to use
GeometryRefiner refiner; // geometry refiner for initial guess
int qpts_order; // num_1D_qpts = rel_qpts_order + 1, or < 0 to use
// rel_qpts_order.
int rel_qpts_order; // num_1D_qpts = max(trans_order+rel_qpts_order,0)+1
int solver_type; // solution strategy to use
int max_iter; // max. number of Newton iterations
@@ -284,19 +296,19 @@ public:
tolerances. */
InverseElementTransformation(ElementTransformation *Trans = NULL)
: T(Trans),
ip0(NULL),
init_guess_type(Center),
refiner(Quadrature1D::OpenHalfUniform),
qpts_order(-1),
rel_qpts_order(-1),
solver_type(NewtonElementProject),
max_iter(16),
#ifdef MFEM_USE_DOUBLE
ref_tol(1e-15),
phys_rtol(1e-15),
phys_rtol(4e-15),
ip_tol(1e-8),
#elif defined(MFEM_USE_SINGLE)
ref_tol(1e-7),
phys_rtol(1e-7),
ref_tol(4e-7),
phys_rtol(1e-6),
ip_tol(1e-4),
#endif
print_level(-1)
@@ -314,16 +326,28 @@ public:
/** @brief Set the initial guess for subsequent calls to Transform(),
switching to the #GivenPoint #InitGuessType at the same time. */
void SetInitialGuess(const IntegrationPoint &init_ip)
{ ip0 = &init_ip; SetInitialGuessType(GivenPoint); }
{ ip0 = init_ip; SetInitialGuessType(GivenPoint); }
/// Set the Quadrature1D type used for the `Closest*` initial guess types.
/// Set the Quadrature1D type used for the `Closest*` and `EdgeScan` initial
/// guess types.
void SetInitGuessPointsType(int q_type) { refiner.SetType(q_type); }
/// Set the relative order used for the `Closest*` initial guess types.
/** The number of points in each spatial direction is given by the formula
max(trans_order+order,0)+1, where trans_order is the order of the current
ElementTransformation. */
void SetInitGuessRelOrder(int order) { rel_qpts_order = order; }
void SetInitGuessRelOrder(int order)
{
qpts_order = -1;
rel_qpts_order = order;
}
/** The number of points in each spatial direction is given by the formula
order+1. */
void SetInitGuessOrder(int order)
{
qpts_order = order;
}
/** @brief Specify which algorithm to use for solving the transformation
equation, i.e. when calling the Transform() method. */
@@ -373,6 +397,233 @@ public:
virtual int Transform(const Vector &pt, IntegrationPoint &ip);
};
/**
* @brief Performs batch inverse element transforms. Currently only supports
* non-mixed meshes with SEGMENT, SQUARE, or CUBE geometries. Mixed
* element order meshes are projected onto an equivalent uniform order mesh.
*/
class BatchInverseElementTransformation
{
// nodes grid function, not owned
const GridFunction *gf_ = nullptr;
// initial guess algorithm to use
InverseElementTransformation::InitGuessType init_guess_type =
InverseElementTransformation::ClosestPhysNode;
int qpts_order = -1; // num_1D_qpts = rel_qpts_order + 1, or < 0 to use
// rel_qpts_order.
// num_1D_qpts = max(trans_order+rel_qpts_order,0)+1
int rel_qpts_order = 0;
// solution strategy to use
InverseElementTransformation::SolverType solver_type =
InverseElementTransformation::NewtonElementProject;
// basis type stored in points1d
int basis_type = BasisType::Invalid;
// initial guess points type. Quadrature1D::Invalid is used for match
// basis_type.
int guess_points_type = Quadrature1D::Invalid;
// max. number of Newton iterations
int max_iter = 16;
// internal element node locations cache
Vector node_pos;
#ifdef MFEM_USE_DOUBLE
// reference space tolerance
real_t ref_tol = 1e-15;
// physical space tolerance (relative)
real_t phys_rtol = 4e-15;
#else
// reference space tolerance
real_t ref_tol = 4e-7;
// physical space tolerance (relative)
real_t phys_rtol = 1e-6;
#endif
// not owned, location of tensor product basis nodes in reference space
const Array<real_t> *points1d = nullptr;
public:
/// Uninitialized BatchInverseElementTransformation. Users must call
/// UpdateNodes before Transform.
BatchInverseElementTransformation();
///
/// Constructs a BatchInverseElementTransformation given @a nodes representing
/// the mesh nodes.
///
BatchInverseElementTransformation(const GridFunction &nodes,
MemoryType d_mt = MemoryType::DEFAULT);
///
/// Constructs a BatchInverseElementTransformation for a given @a mesh.
/// mesh.GetNodes() must not be null.
///
BatchInverseElementTransformation(const Mesh &mesh,
MemoryType d_mt = MemoryType::DEFAULT);
~BatchInverseElementTransformation();
/** @brief Choose how the initial guesses for subsequent calls to Transform()
will be selected. ClosestRefNode is currently not supported. */
void SetInitialGuessType(InverseElementTransformation::InitGuessType itype)
{
MFEM_ASSERT(itype != InverseElementTransformation::ClosestRefNode,
"ClosestRefNode is currently not supported");
init_guess_type = itype;
}
/// Set the Quadrature1D type used for the `Closest*` and `EdgeScan` initial
/// guess types.
void SetInitGuessPointsType(int q_type) { guess_points_type = q_type; }
/// Set the relative order used for the `Closest*` initial guess types.
/** The number of points in each spatial direction is given by the formula
max(trans_order+order,0)+1, where trans_order is the order of the
current ElementTransformation. */
void SetInitGuessRelOrder(int order)
{
qpts_order = -1;
rel_qpts_order = order;
}
/** The number of points in each spatial direction is given by the formula
order+1. */
void SetInitGuessOrder(int order) { qpts_order = order; }
/// @b Gets the basis type nodes are projected onto, or BasisType::Invalid if
/// uninitialized.
int GetBasisType() const { return basis_type; }
/** @brief Specify which algorithm to use for solving the transformation
equation, i.e. when calling the Transform() method. NewtonSegmentProject
is currently not supported. */
void SetSolverType(InverseElementTransformation::SolverType stype)
{
MFEM_ASSERT(stype != InverseElementTransformation::NewtonSegmentProject,
"NewtonSegmentProject is currently not supported");
solver_type = stype;
}
/// Set the maximum number of iterations when solving for a reference point.
void SetMaxIter(int max_it) { max_iter = max_it; }
/// Set the reference-space convergence tolerance.
void SetReferenceTol(real_t ref_sp_tol) { ref_tol = ref_sp_tol; }
/// Set the relative physical-space convergence tolerance.
void SetPhysicalRelTol(real_t phys_rel_tol) { phys_rtol = phys_rel_tol; }
/**
* @brief Updates internal datastructures if @a nodes change. Some version
* of UpdateNodes must be called at least once before calls to Transform if
* nodes have changed.
*/
void UpdateNodes(const GridFunction &nodes,
MemoryType d_mt = MemoryType::DEFAULT);
/**
* @brief Updates internal datastructures if @a mesh nodes change. Some version
* of UpdateNodes must be called at least once before calls to Transform if
* mesh nodes have changed. mesh.GetNodes() must not be null.
*/
void UpdateNodes(const Mesh &mesh, MemoryType d_mt = MemoryType::DEFAULT);
/** @brief Performs a batch request of a set of points belonging to the given
elements.
@a pts list of physical point coordinates ordered by
Ordering::Type::byNODES.
@a elems which element index to search for each corresponding point in
@a pts
@a types output search classification (@see
InverseElementTransformation::TransformResult).
@a refs result reference point coordinates ordered by
Ordering::Type::byNODES. If using InitGuessType::GivenPoint, this should
contain the initial guess for each point.
@a use_device hint for if device acceleration should be used.
Device acceleration is currently only implemented for meshes containing
only a single tensor product basis element type.
@a iters optional array storing how many iterations was spent on each
tested point
*/
void Transform(const Vector &pts, const Array<int> &elems, Array<int> &types,
Vector &refs, bool use_device = true,
Array<int> *iters = nullptr) const;
using ClosestPhysPointKernelType = void (*)(int, int, int, int,
const real_t *, const real_t *,
const int *, const real_t *,
const real_t *, real_t *);
// specialization params: Geom, SDim, use_device
MFEM_REGISTER_KERNELS(FindClosestPhysPoint, ClosestPhysPointKernelType,
(int, int, bool));
using ClosestPhysDofKernelType = void (*)(int, int, int,
const real_t *, const real_t *,
const int *, const real_t *,
real_t *);
// specialization params: Geom, SDim, use_device
MFEM_REGISTER_KERNELS(FindClosestPhysDof, ClosestPhysDofKernelType,
(int, int, bool));
using ClosestRefDofKernelType = void (*)(int, int, int, const real_t *,
const real_t *, const int *,
const real_t *, real_t *);
// specialization params: Geom, SDim, use_device
MFEM_REGISTER_KERNELS(FindClosestRefDof, ClosestRefDofKernelType,
(int, int, bool));
using ClosestRefPointKernelType = void (*)(int, int, int, int, const real_t *,
const real_t *, const int *,
const real_t *, const real_t *,
real_t *);
// specialization params: Geom, SDim, use_device
MFEM_REGISTER_KERNELS(FindClosestRefPoint, ClosestRefPointKernelType,
(int, int, bool));
using NewtonKernelType = void (*)(real_t, real_t, int, int, int, int,
const real_t *, const real_t *,
const int *, const real_t *, int *, int*,
real_t *);
// specialization params: Geom, SDim, SolverType, use_device
MFEM_REGISTER_KERNELS(NewtonSolve, NewtonKernelType,
(int, int, InverseElementTransformation::SolverType,
bool));
using NewtonEdgeScanKernelType = void (*)(real_t, real_t, int, int, int, int,
const real_t *, const real_t *,
const int *, const real_t *,
const real_t *, int, int *, int *,
real_t *);
// specialization params: Geom, SDim, SolverType, use_device
MFEM_REGISTER_KERNELS(NewtonEdgeScan, NewtonEdgeScanKernelType,
(int, int, InverseElementTransformation::SolverType,
bool));
struct Kernels { Kernels(); };
template <int Dim, int SDim>
static void AddFindClosestSpecialization()
{
FindClosestPhysPoint::Specialization<Dim, SDim, true>::Add();
FindClosestRefPoint::Specialization<Dim, SDim, true>::Add();
FindClosestPhysPoint::Specialization<Dim, SDim, false>::Add();
FindClosestRefPoint::Specialization<Dim, SDim, false>::Add();
FindClosestPhysDof::Specialization<Dim, SDim, true>::Add();
FindClosestRefDof::Specialization<Dim, SDim, true>::Add();
FindClosestPhysDof::Specialization<Dim, SDim, false>::Add();
FindClosestRefDof::Specialization<Dim, SDim, false>::Add();
}
template <int Dim, int SDim, InverseElementTransformation::SolverType SType>
static void AddNewtonSolveSpecialization()
{
NewtonSolve::Specialization<Dim, SDim, SType, true>::Add();
NewtonEdgeScan::Specialization<Dim, SDim, SType, true>::Add();
NewtonSolve::Specialization<Dim, SDim, SType, false>::Add();
NewtonEdgeScan::Specialization<Dim, SDim, SType, false>::Add();
}
};
/// A standard isoparametric element transformation
class IsoparametricTransformation : public ElementTransformation
{
+187
View File
@@ -0,0 +1,187 @@
// 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_ELTRANS_BASIS
#define MFEM_ELTRANS_BASIS
#include "../../general/forall.hpp"
#include "../geom.hpp"
// this file contains utilities for computing nodal basis functions and their
// derivatives in device kernels
namespace mfem
{
namespace eltrans
{
/// Various utilities for working with different element geometries
template <int GeomType> struct GeometryUtils;
template <> struct GeometryUtils<Geometry::SEGMENT>
{
static constexpr MFEM_HOST_DEVICE int Dimension() { return 1; }
/// @b true if the given point x in ref space is inside the element
static bool MFEM_HOST_DEVICE inside(real_t x) { return x >= 0 && x <= 1; }
/// @b Bound the reference coordinate @a x += dx to be inside the segment.
/// @a dx is updated to be dx = project(x+dx) - x
/// @return true if x + dx hit a boundary
static bool MFEM_HOST_DEVICE project(real_t &x, real_t &dx)
{
real_t tmp = x;
x += dx;
if (x < 0)
{
x = 0;
dx = x - tmp;
return true;
}
if (x > 1)
{
x = 1;
dx = x - tmp;
return true;
}
return false;
}
};
template <> struct GeometryUtils<Geometry::SQUARE>
{
static constexpr MFEM_HOST_DEVICE int Dimension() { return 2; }
/// @b true if the given point (x,y) in ref space is inside the element
static bool MFEM_HOST_DEVICE inside(real_t x, real_t y)
{
return (x >= 0) && (x <= 1) && (y >= 0) && (y <= 1);
}
/// @b Bound the reference coordinate @a (x,y) += (dx,dy) to be inside the
/// square.
/// @a dx and @a dy are updated to be (dx,dy) = project(x+dx,y+dy) - (x,y)
/// @return true if (x,y) + (dx,dy) hit a boundary
static bool MFEM_HOST_DEVICE project(real_t &x, real_t &y, real_t &dx,
real_t &dy)
{
bool x_cond = GeometryUtils<Geometry::SEGMENT>::project(x, dx);
bool y_cond = GeometryUtils<Geometry::SEGMENT>::project(y, dy);
return x_cond || y_cond;
}
};
template <> struct GeometryUtils<Geometry::CUBE>
{
static constexpr MFEM_HOST_DEVICE int Dimension() { return 3; }
/// @b true if the given point (x,y,z) in ref space is inside the element
static bool MFEM_HOST_DEVICE inside(real_t x, real_t y, real_t z)
{
return (x >= 0) && (x <= 1) && (y >= 0) && (y <= 1) && (z >= 0) && (z <= 1);
}
/// @b Bound the reference coordinate @a (x,y,z) += (dx,dy,dz) to be inside
/// the cube.
/// @a dx, @a dy, and @ dz are updated to be
/// (dx,dy,dz) = project(x+dx,y+dy,z+dz) - (x,y,z)
/// @return true if (x,y,z) + (dx,dy,dz) hit a boundary
static bool MFEM_HOST_DEVICE project(real_t &x, real_t &y, real_t &z,
real_t &dx, real_t &dy, real_t &dz)
{
bool x_cond = GeometryUtils<Geometry::SEGMENT>::project(x, dx);
bool y_cond = GeometryUtils<Geometry::SEGMENT>::project(y, dy);
bool z_cond = GeometryUtils<Geometry::SEGMENT>::project(z, dz);
return x_cond || y_cond || z_cond;
}
};
/// 1D Lagrange basis from [0, 1]
class Lagrange
{
public:
/// interpolant node locations, in reference space
const real_t *z;
/// number of points
int pN;
/// @b Evaluates the @a i'th Lagrange polynomial at @a x
real_t MFEM_HOST_DEVICE eval(real_t x, int i) const
{
real_t u0 = 1;
real_t den = 1;
for (int j = 0; j < pN; ++j)
{
if (i != j)
{
real_t d_j = (x - z[j]);
u0 = d_j * u0;
den *= (z[i] - z[j]);
}
}
den = 1 / den;
return u0 * den;
}
/// @b Evaluates the @a i'th Lagrange polynomial and its first derivative at
/// @a x
void MFEM_HOST_DEVICE eval_d1(real_t &p, real_t &d1, real_t x, int i) const
{
real_t u0 = 1;
real_t u1 = 0;
real_t den = 1;
for (int j = 0; j < pN; ++j)
{
if (i != j)
{
real_t d_j = (x - z[j]);
u1 = d_j * u1 + u0;
u0 = d_j * u0;
den *= (z[i] - z[j]);
}
}
den = 1 / den;
p = u0 * den;
d1 = u1 * den;
}
/// @b Evaluates the @a i'th Lagrange polynomial and its first and second
/// derivatives at @a x
void MFEM_HOST_DEVICE eval_d2(real_t &p, real_t &d1, real_t &d2, real_t x,
int i) const
{
real_t u0 = 1;
real_t u1 = 0;
real_t u2 = 0;
real_t den = 1;
for (int j = 0; j < pN; ++j)
{
if (i != j)
{
real_t d_j = (x - z[j]);
u2 = d_j * u2 + u1;
u1 = d_j * u1 + u0;
u0 = d_j * u0;
den *= (z[i] - z[j]);
}
}
den = 1 / den;
p = den * u0;
d1 = den * u1;
d2 = 2 * den * u2;
}
};
} // namespace eltrans
} // namespace mfem
#endif
+2 -2
View File
@@ -623,7 +623,7 @@ private:
public:
/** @brief Construct a new KellyErrorEstimator object for a scalar field.
@param di_ The bilinearform to compute the interface flux.
@param di_ The bilinear form to compute the interface flux.
@param sol_ The solution field whose error is to be estimated.
@param flux_fes_ The finite element space for the interface flux.
@param attributes_ The attributes of the subdomain(s) for which the
@@ -635,7 +635,7 @@ public:
const Array<int> &attributes_ = Array<int>());
/** @brief Construct a new KellyErrorEstimator object for a scalar field.
@param di_ The bilinearform to compute the interface flux.
@param di_ The bilinear form to compute the interface flux.
@param sol_ The solution field whose error is to be estimated.
@param flux_fes_ The finite element space for the interface flux.
@param attributes_ The attributes of the subdomain(s) for which the
+41 -17
View File
@@ -69,16 +69,16 @@ inline int ToLexOrdering2D(const int face_id, const int size1d, const int i)
}
/// @brief Given a face DOF index on a shared face, ordered lexicographically
/// relative to element 1, return the corresponding face DOF index ordered
/// lexicographically relative to element 2.
/// relative to element the element (where the local face is face_id), and
/// return the corresponding face DOF index ordered lexicographically relative
/// to the face itself.
MFEM_HOST_DEVICE
inline int PermuteFace2D(const int face_id1, const int face_id2,
const int orientation, const int size1d,
const int index)
inline int PermuteFace2D(const int face_id, const int orientation,
const int size1d, const int index)
{
int new_index;
// Convert from element 1 lex ordering to native ordering
if (face_id1 == 2 || face_id1 == 3)
if (face_id == 2 || face_id == 3)
{
new_index = size1d-1-index;
}
@@ -91,7 +91,18 @@ inline int PermuteFace2D(const int face_id1, const int face_id2,
{
new_index = size1d-1-new_index;
}
// Covert to element 2 lex ordering
return new_index;
}
/// @brief Given a face DOF index on a shared face, ordered lexicographically
/// relative to element 1, return the corresponding face DOF index ordered
/// lexicographically relative to element 2.
MFEM_HOST_DEVICE
inline int PermuteFace2D(const int face_id1, const int face_id2,
const int orientation, const int size1d,
const int index)
{
const int new_index = PermuteFace2D(face_id1, orientation, size1d, index);
return ToLexOrdering2D(face_id2, size1d, new_index);
}
@@ -116,26 +127,22 @@ inline int ToLexOrdering3D(const int face_id, const int size1d, const int i,
}
}
/// @brief Given the index of a face DOF in lexicographic ordering relative
/// element 1, permute the index so that it is lexicographically ordered
/// relative to element 2.
///
/// The given face corresponds to local face index @a face_id1 relative to
/// element 1, and @a face_id2 (with @a orientation) relative to element 2.
/// @brief Given the index of a face DOF in lexicographic ordering relative the
/// element (where the local face id is @a face_id), permute the index so that
/// it is lexicographically ordered relative to the face itself.
MFEM_HOST_DEVICE
inline int PermuteFace3D(const int face_id1, const int face_id2,
const int orientation,
inline int PermuteFace3D(const int face_id, const int orientation,
const int size1d, const int index)
{
int i=0, j=0, new_i=0, new_j=0;
i = index%size1d;
j = index/size1d;
// Convert from lex ordering
if (face_id1==3 || face_id1==4)
if (face_id==3 || face_id==4)
{
i = size1d-1-i;
}
else if (face_id1==0)
else if (face_id==0)
{
j = size1d-1-j;
}
@@ -175,6 +182,23 @@ inline int PermuteFace3D(const int face_id1, const int face_id2,
new_j = (size1d-1-j);
break;
}
return new_i + new_j*size1d;
}
/// @brief Given the index of a face DOF in lexicographic ordering relative
/// element 1, permute the index so that it is lexicographically ordered
/// relative to element 2.
///
/// The given face corresponds to local face index @a face_id1 relative to
/// element 1, and @a face_id2 (with @a orientation) relative to element 2.
MFEM_HOST_DEVICE
inline int PermuteFace3D(const int face_id1, const int face_id2,
const int orientation,
const int size1d, const int index)
{
const int new_index = PermuteFace3D(face_id1, orientation, size1d, index);
const int new_i = new_index%size1d;
const int new_j = new_index/size1d;
return ToLexOrdering3D(face_id2, size1d, new_i, new_j);
}
+95 -62
View File
@@ -973,6 +973,22 @@ void NodalFiniteElement::ProjectDiv(
}
}
void NodalFiniteElement::ReorderLexToNative(int ncomp,
Vector &dofs) const
{
MFEM_ASSERT(lex_ordering.Size() == dof, "Permutation is not defined by FE.");
MFEM_ASSERT(dofs.Size() == ncomp * dof, "Wrong input size.");
Vector dofs_native(ncomp * dof);
for (int i = 0; i < dof; i++)
{
for (int c = 0; c < ncomp; c++)
{
dofs_native(c*dof + lex_ordering[i]) = dofs(c*dof + i);
}
}
dofs = dofs_native;
}
VectorFiniteElement::VectorFiniteElement(int D, Geometry::Type G,
int Do, int O, int M, int F)
@@ -2168,6 +2184,64 @@ void Poly_1D::CalcDBinomTerms(const int p, const real_t x, const real_t y,
}
}
void Poly_1D::CalcDxBinomTerms(const int p, const real_t x, const real_t y,
real_t *u)
{
if (p == 0)
{
u[0] = 0.;
}
else
{
int i;
const int *b = Binom(p);
real_t z = 1.;
for (i = 1; i < p; i++)
{
u[i] = i * b[i]*z;
z *= x;
}
u[p] = i * z;
z = y;
for (i--; i > 0; i--)
{
u[i] *= z;
z *= y;
}
u[0] = 0;
}
}
void Poly_1D::CalcDyBinomTerms(const int p, const real_t x, const real_t y,
real_t *u)
{
if (p == 0)
{
u[0] = 0.;
}
else
{
int i;
const int *b = Binom(p);
real_t z = x;
for (i = 1; i < p; i++)
{
u[i] = b[i]*z;
z *= x;
}
u[p] = 0.;
z = 1.;
for (i--; i > 0; i--)
{
u[i] *= (p - i) * z;
z *= y;
}
u[0] = p * z;
}
}
void Poly_1D::CalcLegendre(const int p, const real_t x, real_t *u)
{
// use the recursive definition for [-1,1]:
@@ -2267,99 +2341,58 @@ void Poly_1D::CalcChebyshev(const int p, const real_t x, real_t *u, real_t *d,
}
}
const real_t *Poly_1D::GetPoints(const int p, const int btype)
const Array<real_t>* Poly_1D::GetPointsArray(const int p, const int btype)
{
Array<real_t*> *pts;
Array<real_t> *val;
BasisType::Check(btype);
const int qtype = BasisType::GetQuadrature1D(btype);
if (qtype == Quadrature1D::Invalid) { return NULL; }
if (qtype == Quadrature1D::Invalid) { return nullptr; }
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
#pragma omp critical (Poly1DGetPoints)
#endif
{
auto it = points_container.find(btype);
if (it != points_container.end())
std::pair<int, int> key(btype, p);
auto it = points_container.find(key);
if (it == points_container.end())
{
pts = it->second;
it = points_container.emplace(key, new Array<real_t>(p + 1, h_mt)).first;
val = it->second.get();
real_t* hptr = val->HostWrite();
quad_func.GivePolyPoints(p + 1, hptr, qtype);
}
else
{
pts = new Array<real_t*>(h_mt);
points_container[btype] = pts;
}
if (pts->Size() <= p)
{
pts->SetSize(p + 1, NULL);
}
if ((*pts)[p] == NULL)
{
(*pts)[p] = new real_t[p + 1];
quad_func.GivePolyPoints(p + 1, (*pts)[p], qtype);
val = it->second.get();
}
}
return (*pts)[p];
return val;
}
Poly_1D::Basis &Poly_1D::GetBasis(const int p, const int btype)
{
Array<Basis*> *bases;
BasisType::Check(btype);
Basis* val;
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
#pragma omp critical (Poly1DGetBasis)
#endif
{
auto it = bases_container.find(btype);
if (it != bases_container.end())
{
bases = it->second;
}
else
{
// we haven't been asked for basis or points of this type yet
bases = new Array<Basis*>(h_mt);
bases_container[btype] = bases;
}
if (bases->Size() <= p)
{
bases->SetSize(p + 1, NULL);
}
if ((*bases)[p] == NULL)
std::pair<int, int> key(btype, p);
auto it = bases_container.find(key);
if (it == bases_container.end())
{
EvalType etype;
if (btype == BasisType::Positive) { etype = Positive; }
else if (btype == BasisType::IntegratedGLL) { etype = Integrated; }
else { etype = Barycentric; }
(*bases)[p] = new Basis(p, GetPoints(p, btype), etype);
it = bases_container
.emplace(key, new Basis(p, GetPoints(p, btype), etype))
.first;
}
val = it->second.get();
}
return *(*bases)[p];
}
Poly_1D::~Poly_1D()
{
for (PointsMap::iterator it = points_container.begin();
it != points_container.end() ; ++it)
{
Array<real_t*>& pts = *it->second;
for (int i = 0; i < pts.Size(); ++i)
{
delete [] pts[i];
}
delete it->second;
}
for (BasisMap::iterator it = bases_container.begin();
it != bases_container.end() ; ++it)
{
Array<Basis*>& bases = *it->second;
for (int i = 0; i < bases.Size(); ++i)
{
delete bases[i];
}
delete it->second;
}
return *val;
}
+61 -11
View File
@@ -15,8 +15,12 @@
#include "../intrules.hpp"
#include "../geom.hpp"
#include "../doftrans.hpp"
#include "../../general/hash.hpp"
#include <map>
#include <memory>
#include <unordered_map>
#include <utility>
namespace mfem
{
@@ -223,9 +227,10 @@ class FunctionSpace
public:
enum
{
Pk, ///< Polynomials of order k
Qk, ///< Tensor products of polynomials of order k
rQk ///< Refined tensor products of polynomials of order k
Pk, ///< Polynomials of order k
Qk, ///< Tensor products of polynomials of order k
rQk, ///< Refined tensor products of polynomials of order k
Uk ///< Rational polynomials of order k
};
};
@@ -794,6 +799,12 @@ public:
TensorBasisElement::GetDofMap, but it is also available for non-tensor
elements. */
const Array<int> &GetLexicographicOrdering() const { return lex_ordering; }
/// Given a lexicographically ordered Vector @a dofs, containing @a ncomp
/// components of the size of the scalar FiniteElement, reorder its entries
/// into native (H1) ordering.
/// The function assumes that GetLexicographicOrdering() is not empty.
void ReorderLexToNative(int ncomp, Vector &dofs) const;
};
/** @brief Intermediate class for finite elements whose basis functions return
@@ -1038,8 +1049,14 @@ public:
};
private:
typedef std::map<int, Array<real_t*>*> PointsMap;
typedef std::map<int, Array<Basis*>*> BasisMap;
/// key: (btype, p), value: underlying storage Array
typedef std::unordered_map<std::pair<int, int>,
std::unique_ptr<Basis>, PairHasher>
BasisMap;
/// key: (btype, p), value: underlying storage Array
typedef std::unordered_map<std::pair<int, int>,
std::unique_ptr<Array<real_t>>, PairHasher>
PointsMap;
MemoryType h_mt;
PointsMap points_container;
@@ -1073,17 +1090,40 @@ public:
@return A pointer to an array containing the `p+1` coordinates of the
points. Returns NULL if the BasisType has no associated set of
points. */
const real_t *GetPoints(const int p, const int btype);
const Array<real_t>* GetPointsArray(const int p, const int btype);
/** @brief Get the coordinates of the points of the given BasisType,
@a btype.
@param[in] p The polynomial degree; the number of points is `p+1`.
@param[in] btype The BasisType.
@param[in] on_device true if the requested pointer should be accessible
from the device.
@return A pointer to an array containing the `p+1` coordinates of the
points. Returns NULL if the BasisType has no associated set of
points. */
const real_t *GetPoints(const int p, const int btype,
bool on_device = false)
{
return GetPointsArray(p, btype)->Read(on_device);
}
/// Get coordinates of an open (GaussLegendre) set of points if degree @a p
const real_t *OpenPoints(const int p,
const int btype = BasisType::GaussLegendre)
{ return GetPoints(p, btype); }
const int btype = BasisType::GaussLegendre,
bool on_device = false)
{
return GetPoints(p, btype, on_device);
}
/// Get coordinates of a closed (GaussLegendre) set of points if degree @a p
const real_t *ClosedPoints(const int p,
const int btype = BasisType::GaussLobatto)
{ return GetPoints(p, btype); }
const int btype = BasisType::GaussLobatto,
bool on_device = false)
{
return GetPoints(p, btype, on_device);
}
/** @brief Get a Poly_1D::Basis object of the given degree and BasisType,
@a btype.
@@ -1158,6 +1198,16 @@ public:
in the already allocated @a d array.*/
static void CalcDBinomTerms(const int p, const real_t x, const real_t y,
real_t *d);
/** @brief Compute the derivatives (w.r.t. x) of the terms in the expansion
of the binomial (x + y)^p. Store the results in the already allocated
@a d array.*/
static void CalcDxBinomTerms(const int p, const real_t x, const real_t y,
real_t *d);
/** @brief Compute the derivatives (w.r.t. y) of the terms in the expansion
of the binomial (x + y)^p. Store the results in the already allocated
@a d array.*/
static void CalcDyBinomTerms(const int p, const real_t x, const real_t y,
real_t *d);
/** @brief Compute the values of the Bernstein basis functions of order
@a p at coordinate @a x and store the results in the already allocated
@@ -1186,7 +1236,7 @@ public:
static void CalcLegendre(const int p, const real_t x, real_t *u);
static void CalcLegendre(const int p, const real_t x, real_t *u, real_t *d);
~Poly_1D();
~Poly_1D() = default;
};
extern MFEM_EXPORT Poly_1D poly1d;
+573 -34
View File
@@ -1341,7 +1341,7 @@ const
LinearPyramidFiniteElement::LinearPyramidFiniteElement()
: NodalFiniteElement(3, Geometry::PYRAMID, 5, 1)
: NodalFiniteElement(3, Geometry::PYRAMID, 5, 1, FunctionSpace::Uk)
{
Nodes.IntPoint(0).x = 0.0;
Nodes.IntPoint(0).y = 0.0;
@@ -3015,7 +3015,7 @@ void P0WdgFiniteElement::CalcDShape(const IntegrationPoint &ip,
P0PyrFiniteElement::P0PyrFiniteElement()
: NodalFiniteElement(3, Geometry::PYRAMID, 1, 0, FunctionSpace::Qk)
: NodalFiniteElement(3, Geometry::PYRAMID, 1, 0, FunctionSpace::Uk)
{
Nodes.IntPoint(0).x = 0.375;
Nodes.IntPoint(0).y = 0.375;
@@ -4818,7 +4818,7 @@ void Nedelec1WdgFiniteElement::ProjectGrad(const FiniteElement &fe,
Nedelec1PyrFiniteElement::Nedelec1PyrFiniteElement()
: VectorFiniteElement(3, Geometry::PYRAMID, 8, 1, H_CURL)
: VectorFiniteElement(3, Geometry::PYRAMID, 8, 1, H_CURL, FunctionSpace::Uk)
{
// not real nodes ...
Nodes.IntPoint(0).x = 0.5;
@@ -4866,7 +4866,11 @@ void Nedelec1PyrFiniteElement::CalcVShape(const IntegrationPoint &ip,
{
// We must return the limit of the basis functions as z->1. In order to
// remain inside the pyramid in this limit the x and y coordinates must
// be approaching 0. The resulting limiting basis function values are:
// be approaching 0. Unfortunately we obtain different limits if we
// approach (0,0,1) from different directions. The values provided below
// are the limits as x->(1-z)/2 and y->(1-z)/2 i.e. along the line from
// the center of the base of the pyramid towards the apex. The resulting
// limiting basis function values are:
shape(0,0) = 0.;
shape(0,1) = 0.;
shape(0,2) = 0.;
@@ -4883,21 +4887,21 @@ void Nedelec1PyrFiniteElement::CalcVShape(const IntegrationPoint &ip,
shape(3,1) = 0.;
shape(3,2) = 0.;
shape(4,0) = 1.;
shape(4,1) = 1.;
shape(4,2) = 1.;
shape(4,0) = 0.5;
shape(4,1) = 0.5;
shape(4,2) = 0.75;
shape(5,0) = - 1.;
shape(5,1) = 0.;
shape(5,2) = 0.;
shape(5,0) = - 0.5;
shape(5,1) = 0.5;
shape(5,2) = 0.25;
shape(6,0) = 0.;
shape(6,1) = 0.;
shape(6,2) = 0.;
shape(6,0) = - 0.5;
shape(6,1) = - 0.5;
shape(6,2) = - 0.25;
shape(7,0) = 0.;
shape(7,1) = - 1.;
shape(7,2) = 0.;
shape(7,0) = 0.5;
shape(7,1) = - 0.5;
shape(7,2) = 0.25;
return;
}
@@ -4952,36 +4956,36 @@ const
// In order to remain inside the pyramid in this limit the x and y
// coordinates must be approaching 0. The resulting limiting basis
// function values are:
curl_shape(0,0) = 0.;
curl_shape(0,1) = - 2.;
curl_shape(0,0) = - 0.5;
curl_shape(0,1) = - 1.5;
curl_shape(0,2) = 1.;
curl_shape(1,0) = 0.;
curl_shape(1,1) = 0.;
curl_shape(1,0) = 0.5;
curl_shape(1,1) = - 0.5;
curl_shape(1,2) = 1.;
curl_shape(2,0) = 0.;
curl_shape(2,1) = 0.;
curl_shape(2,0) = 0.5;
curl_shape(2,1) = - 0.5;
curl_shape(2,2) = - 1.;
curl_shape(3,0) = 2.;
curl_shape(3,1) = 0.;
curl_shape(3,0) = 1.5;
curl_shape(3,1) = 0.5;
curl_shape(3,2) = - 1.;
curl_shape(4,0) = - 2.;
curl_shape(4,1) = 2.;
curl_shape(4,0) = - 1.;
curl_shape(4,1) = 1.;
curl_shape(4,2) = 0.;
curl_shape(5,0) = 0.;
curl_shape(5,1) = - 2.;
curl_shape(5,0) = - 1.;
curl_shape(5,1) = - 1.;
curl_shape(5,2) = 0.;
curl_shape(6,0) = 0.;
curl_shape(6,1) = 0.;
curl_shape(6,0) = 1.;
curl_shape(6,1) = - 1.;
curl_shape(6,2) = 0.;
curl_shape(7,0) = 2.;
curl_shape(7,1) = 0.;
curl_shape(7,0) = 1.;
curl_shape(7,1) = 1.;
curl_shape(7,2) = 0.;
return;
@@ -5119,6 +5123,540 @@ void Nedelec1PyrFiniteElement::ProjectGrad(const FiniteElement &fe,
}
Nedelec2PyrFiniteElement::Nedelec2PyrFiniteElement()
: VectorFiniteElement(3, Geometry::PYRAMID, 28, 2, H_CURL, FunctionSpace::Uk)
{
const real_t *eop = poly1d.OpenPoints(2 - 1);
const real_t fop = 1. / 3.;
// not real nodes ...
Nodes.IntPoint(0).Set3(eop[0], 0., 0.);
Nodes.IntPoint(1).Set3(eop[1], 0., 0.);
Nodes.IntPoint(2).Set3(1.0, eop[0], 0.);
Nodes.IntPoint(3).Set3(1.0, eop[1], 0.);
Nodes.IntPoint(4).Set3(eop[0], 1.0, 0.);
Nodes.IntPoint(5).Set3(eop[1], 1.0, 0.);
Nodes.IntPoint(6).Set3(0., eop[0], 0.);
Nodes.IntPoint(7).Set3(0., eop[1], 0.);
Nodes.IntPoint(8).Set3(0., 0., eop[0]);
Nodes.IntPoint(9).Set3(0., 0., eop[1]);
Nodes.IntPoint(10).Set3(eop[1], 0., eop[0]);
Nodes.IntPoint(11).Set3(eop[0], 0., eop[1]);
Nodes.IntPoint(12).Set3(eop[1], eop[1], eop[0]);
Nodes.IntPoint(13).Set3(eop[0], eop[0], eop[1]);
Nodes.IntPoint(14).Set3(0., eop[1], eop[0]);
Nodes.IntPoint(15).Set3(0., eop[0], eop[1]);
Nodes.IntPoint(16).Set3(eop[0], 0.5, 0.);
Nodes.IntPoint(17).Set3(eop[1], 0.5, 0.);
Nodes.IntPoint(18).Set3(0.5, eop[0], 0.);
Nodes.IntPoint(19).Set3(0.5, eop[1], 0.);
Nodes.IntPoint(20).Set3(fop, 0., fop);
Nodes.IntPoint(21).Set3(fop, 0., fop);
Nodes.IntPoint(22).Set3(2.*fop, fop, fop);
Nodes.IntPoint(23).Set3(2.*fop, fop, fop);
Nodes.IntPoint(24).Set3(fop, 2.*fop, fop);
Nodes.IntPoint(25).Set3(fop, 2.*fop, fop);
Nodes.IntPoint(26).Set3(0., fop, fop);
Nodes.IntPoint(27).Set3(0., fop, fop);
{
int n = 28;
DenseMatrix I(n,n);
DenseMatrix vecs(n,3);
I = 0.0;
for (int i=0; i<n; i++)
{
CalcVShape(Nodes.IntPoint(i), vecs);
for (int j=0; j<n; j++)
{
I(j,i) = vecs(j,0)*tk[i][0]+vecs(j,1)*tk[i][1]+vecs(j,2)*tk[i][2];
}
}
}
}
void Nedelec2PyrFiniteElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
shape = 0.0;
const real_t one = 1.0;
const real_t x = ip.x, y = ip.y, z = ip.z;
const real_t ox = one - x - z, oy = one - y - z, oz = one - z;
const real_t sq3 = sqrt(3.0);
const real_t tol = 1e-6;
if (oz <= tol)
{
// We must return the limit of the basis functions as z->1. In order to
// remain inside the pyramid in this limit the x and y coordinates must
// be approaching 0. The resulting limiting basis function values are:
shape(0,0) = 0.;
shape(0,1) = 0.;
shape(0,2) = 0.;
shape(1,0) = 0.;
shape(1,1) = 0.;
shape(1,2) = 0.;
shape(2,0) = 0.;
shape(2,1) = 0.;
shape(2,2) = 0.;
shape(3,0) = 0.;
shape(3,1) = 0.;
shape(3,2) = 0.;
shape(4,0) = 0.;
shape(4,1) = 0.;
shape(4,2) = 0.;
shape(5,0) = 0.;
shape(5,1) = 0.;
shape(5,2) = 0.;
shape(6,0) = 0.;
shape(6,1) = 0.;
shape(6,2) = 0.;
shape(7,0) = 0.;
shape(7,1) = 0.;
shape(7,2) = 0.;
return;
}
const real_t ozi = one / oz;
const real_t me0120[3] = {oy, 0., x * oy * ozi};
const real_t me1120[3] = {(x - ox) * oy, 0., (x - ox) * x * oy * ozi};
const real_t me0121[3] = {y, 0., x * y * ozi};
const real_t me1121[3] = {(x - ox) * y, 0., (x - ox) * x * y * ozi};
const real_t me0210[3] = {0., ox, ox * y * ozi};
const real_t me1210[3] = {0., ox * (y - oy), ox * y * (y - oy) * ozi};
const real_t me0211[3] = {0., x, x * y * ozi};
const real_t me1211[3] = {0., x * (y - oy), x * y * (y - oy) * ozi};
const real_t te01[3] = {oy * z * ozi, ox * z * ozi,
(ox * oy + (x * oy + ox * y) * z) * ozi * ozi
};
const real_t te11[3] = {oy * z * (z * oz - ox * oy) * ozi * ozi,
ox * z * (z * oz - ox * oy) * ozi * ozi,
(ox * oy + z * (x * oy + ox * y)) *
(z * oz - ox * oy) * ozi * ozi * ozi
};
const real_t te02[3] = {-oy * z * ozi, x * z * ozi,
x * (y * z + oy * oz) * ozi * ozi
};
const real_t te12[3] = {oy * z * (x * oy - z * oz) * ozi * ozi,
-x * z * (x * oy - z * oz) * ozi * ozi,
-x * (y * z + oy * oz) * (x * oy - z * oz)
* ozi * ozi * ozi
};
const real_t te03[3] = {-y * z * ozi, -x * z * ozi,
x * y * (one - 2_r * z) * ozi * ozi
};
const real_t te13[3] = {y * z * (x * y - z * oz) * ozi * ozi,
x * z * (x * y - z * oz) * ozi * ozi,
-x * y * (one - 2_r * z) * (x * y - z * oz)
* ozi * ozi * ozi
};
const real_t te04[3] = {y * z * ozi, -ox * z * ozi,
y * (x * z + ox * oz) * ozi * ozi
};
const real_t te14[3] = {-y * z * (ox * y - z * oz) * ozi * ozi,
ox * z * (ox * y - z * oz) * ozi * ozi,
-y * (x * z + ox * oz) * (ox * y - z * oz)
* ozi * ozi * ozi
};
const real_t qI02[3] = {-y * oy * ozi, 0., -x * y * oy * ozi * ozi};
const real_t qI12[3] = {-(x - ox) * y * oy * ozi * ozi, 0.,
-(x - ox) * x * y * oy * ozi * ozi * ozi
};
const real_t qII02[3] = {0., -x * ox * ozi, -x * y * ox * ozi * ozi};
const real_t qII12[3] = {0., -x * ox * (y - oy) * ozi * ozi,
-x * ox * y * (y - oy) * ozi * ozi * ozi
};
const real_t tI120[3] = {oy * z, 0., x * oy * z * ozi};
const real_t tI121[3] = {y * z, 0., x * y * z * ozi};
const real_t tI210[3] = {0., ox * z, ox * y * z * ozi};
const real_t tI211[3] = {0., x * z, x * y * z * ozi};
const real_t tII120[3] = {-ox * oy * z * ozi, 0., x * ox * oy * ozi};
const real_t tII121[3] = {-ox * y * z * ozi, 0., x * ox * y * ozi};
const real_t tII210[3] = {0., -ox * oy * z * ozi, ox * y * oy * ozi};
const real_t tII211[3] = {0., -x * oy * z * ozi, x * y * oy * ozi};
// Edge 0,1
for (int d=0; d<3; d++)
{
shape(0,d) = 0.5 * me0120[d] + qI02[d]
- sq3 * (0.5 * me1120[d] + qI12[d]) - 1.5 * tI120[d];
}
for (int d=0; d<3; d++)
{
shape(1,d) = 0.5 * me0120[d] + qI02[d]
+ sq3 * (0.5 * me1120[d] + qI12[d]) - 1.5 * tI120[d];
}
// Edge 1,2
for (int d=0; d<3; d++)
{
shape(2,d) = 0.5 * me0211[d] + qII02[d]
- sq3 * (0.5 * me1211[d] + qII12[d]) - 1.5 * tI211[d];
}
for (int d=0; d<3; d++)
{
shape(3,d) = 0.5 * me0211[d] + qII02[d]
+ sq3 * (0.5 * me1211[d] + qII12[d]) - 1.5 * tI211[d];
}
// Edge 3,2
for (int d=0; d<3; d++)
{
shape(4,d) = 0.5 * me0121[d] + qI02[d]
- sq3 * (0.5 * me1121[d] + qI12[d]) - 1.5 * tI121[d];
}
for (int d=0; d<3; d++)
{
shape(5,d) = 0.5 * me0121[d] + qI02[d]
+ sq3 * (0.5 * me1121[d] + qI12[d]) - 1.5 * tI121[d];
}
// Edge 0,3
for (int d=0; d<3; d++)
{
shape(6,d) = 0.5 * me0210[d] + qII02[d]
- sq3 * (0.5 * me1210[d] + qII12[d]) - 1.5 * tI210[d];
}
for (int d=0; d<3; d++)
{
shape(7,d) = 0.5 * me0210[d] + qII02[d]
+ sq3 * (0.5 * me1210[d] + qII12[d]) - 1.5 * tI210[d];
}
// Edge 0,4
for (int d=0; d<3; d++)
{
shape(8,d) = 0.5 * te01[d] - sq3 * 0.5 * te11[d]
- 1.5 * (tI120[d] + tII120[d] + tI210[d] + tII210[d]);
}
for (int d=0; d<3; d++)
{
shape(9,d) = 0.5 * te01[d] + sq3 * 0.5 * te11[d]
- 1.5 * (tI120[d] + tII120[d] + tI210[d] + tII210[d]);
}
// Edge 1,4
for (int d=0; d<3; d++)
{
shape(10,d) = 0.5 * te02[d] - sq3 * 0.5 * te12[d]
- 1.5 * (tII120[d] + tI211[d] + tII211[d]);
}
for (int d=0; d<3; d++)
{
shape(11,d) = 0.5 * te02[d] + sq3 * 0.5 * te12[d]
- 1.5 * (tII120[d] + tI211[d] + tII211[d]);
}
// Edge 2,4
for (int d=0; d<3; d++)
{
shape(12,d) = 0.5 * te03[d] - sq3 * 0.5 * te13[d]
- 1.5 * (tII211[d] + tII121[d]);
}
for (int d=0; d<3; d++)
{
shape(13,d) = 0.5 * te03[d] + sq3 * 0.5 * te13[d]
- 1.5 * (tII211[d] + tII121[d]);
}
// Edge 3,4
for (int d=0; d<3; d++)
{
shape(14,d) = 0.5 * te04[d] - sq3 * 0.5 * te14[d]
- 1.5 * (tI121[d] + tII121[d] + tII210[d]);
}
for (int d=0; d<3; d++)
{
shape(15,d) = 0.5 * te04[d] + sq3 * 0.5 * te14[d]
- 1.5 * (tI121[d] + tII121[d] + tII210[d]);
}
// Quadrilateral face
for (int d=0; d<3; d++)
{
shape(16,d) = -2. * qI02[d] + 2. * sq3 * qI12[d];
}
for (int d=0; d<3; d++)
{
shape(17,d) = -2. * qI02[d] - 2. * sq3 * qI12[d];
}
for (int d=0; d<3; d++)
{
shape(18,d) = 2. * qII02[d] - 2. * sq3 * qII12[d];
}
for (int d=0; d<3; d++)
{
shape(19,d) = 2. * qII02[d] + 2. * sq3 * qII12[d];
}
// Triangular face 0,1,4
for (int d=0; d<3; d++)
{
shape(20,d) = 3. * tI120[d] - 3. * tII120[d];
}
for (int d=0; d<3; d++)
{
shape(21,d) = 3. * tI120[d] + 6. * tII120[d];
}
// Triangular face 1,2,4
for (int d=0; d<3; d++)
{
shape(22,d) = 3. * tI211[d] - 3. * tII211[d];
}
for (int d=0; d<3; d++)
{
shape(23,d) = 3. * tI211[d] + 6. * tII211[d];
}
// Triangular face 2,3,4
for (int d=0; d<3; d++)
{
shape(24,d) = -6. * tI121[d] - 3. * tII121[d];
}
for (int d=0; d<3; d++)
{
shape(25,d) = 3. * tI121[d] + 6. * tII121[d];
}
// Triangular face 3,0,4
for (int d=0; d<3; d++)
{
shape(26,d) = -6. * tI210[d] - 3. * tII210[d];
}
for (int d=0; d<3; d++)
{
shape(27,d) = 3. * tI210[d] + 6. * tII210[d];
}
}
void Nedelec2PyrFiniteElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape)
const
{
const real_t one = 1.0;
const real_t x = ip.x, y = ip.y, z = ip.z, z2 = 2. * z;
const real_t ox = one - x - z, oy = one - y - z, oz = one - z;
const real_t tol = 1e-6;
if (oz <= tol)
{
// We must return the limit of the basis function derivatives as z->1.
// In order to remain inside the pyramid in this limit the x and y
// coordinates must be approaching 0. The resulting limiting basis
// function values are:
curl_shape(0,0) = 0.;
curl_shape(0,1) = - 2.;
curl_shape(0,2) = 1.;
curl_shape(1,0) = 0.;
curl_shape(1,1) = 0.;
curl_shape(1,2) = 1.;
curl_shape(2,0) = 0.;
curl_shape(2,1) = 0.;
curl_shape(2,2) = - 1.;
curl_shape(3,0) = 2.;
curl_shape(3,1) = 0.;
curl_shape(3,2) = - 1.;
curl_shape(4,0) = - 2.;
curl_shape(4,1) = 2.;
curl_shape(4,2) = 0.;
curl_shape(5,0) = 0.;
curl_shape(5,1) = - 2.;
curl_shape(5,2) = 0.;
curl_shape(6,0) = 0.;
curl_shape(6,1) = 0.;
curl_shape(6,2) = 0.;
curl_shape(7,0) = 2.;
curl_shape(7,1) = 0.;
curl_shape(7,2) = 0.;
return;
}
real_t ozi = one / oz;
curl_shape(0,0) = - x * ozi;
curl_shape(0,1) = - 2. + y * ozi;
curl_shape(0,2) = 1.;
curl_shape(1,0) = x * ozi;
curl_shape(1,1) = - y * ozi;
curl_shape(1,2) = 1.;
curl_shape(2,0) = x * ozi;
curl_shape(2,1) = - y * ozi;
curl_shape(2,2) = - 1.;
curl_shape(3,0) = (2. - x - z2) * ozi;
curl_shape(3,1) = y * ozi;
curl_shape(3,2) = - 1.;
curl_shape(4,0) = - 2. * ox * ozi;
curl_shape(4,1) = 2. * oy * ozi;
curl_shape(4,2) = 0.;
curl_shape(5,0) = - 2. * x * ozi;
curl_shape(5,1) = - 2. * oy * ozi;
curl_shape(5,2) = 0.;
curl_shape(6,0) = 2. * x * ozi;
curl_shape(6,1) = - 2. * y * ozi;
curl_shape(6,2) = 0.;
curl_shape(7,0) = 2. * ox * ozi;
curl_shape(7,1) = 2. * y * ozi;
curl_shape(7,2) = 0.;
}
const real_t Nedelec2PyrFiniteElement::tk[28][3] =
{
{1,0,0}, {1,0,0}, {0,1,0}, {0,1,0},
{1,0,0}, {1,0,0}, {0,1,0}, {0,1,0},
{0,0,1}, {0,0,1}, {-1,0,1}, {-1,0,1},
{-1,-1,1}, {-1,-1,1}, {0,-1,1}, {0,-1,1},
{1,0,0}, {1,0,0}, {0,-1,0}, {0,-1,0},
{1,0,0}, {0,0,1}, {0,1,0}, {-1,0,1},
{-1,0,0}, {-1,-1,1}, {0,-1,0}, {0,-1,1}
};
void Nedelec2PyrFiniteElement::GetLocalInterpolation (
ElementTransformation &Trans, DenseMatrix &I) const
{
int k, j;
#ifdef MFEM_THREAD_SAFE
DenseMatrix vshape(dof, dim);
#endif
#ifdef MFEM_DEBUG
for (k = 0; k < dof; k++)
{
CalcVShape (Nodes.IntPoint(k), vshape);
for (j = 0; j < dof; j++)
{
real_t d = ( vshape(j,0)*tk[k][0] + vshape(j,1)*tk[k][1] +
vshape(j,2)*tk[k][2] );
if (j == k) { d -= 1.0; }
if (fabs(d) > 1.0e-12)
{
mfem::err << "Nedelec1PyrFiniteElement::GetLocalInterpolation (...)\n"
" k = " << k << ", j = " << j << ", d = " << d << endl;
mfem_error();
}
}
}
#endif
IntegrationPoint ip;
ip.x = ip.y = ip.z = 0.0;
Trans.SetIntPoint (&ip);
// Trans must be linear
const DenseMatrix &J = Trans.Jacobian();
real_t vk[3];
Vector xk (vk, 3);
for (k = 0; k < dof; k++)
{
Trans.Transform (Nodes.IntPoint (k), xk);
ip.x = vk[0]; ip.y = vk[1]; ip.z = vk[2];
CalcVShape (ip, vshape);
// vk = J tk
vk[0] = J(0,0)*tk[k][0]+J(0,1)*tk[k][1]+J(0,2)*tk[k][2];
vk[1] = J(1,0)*tk[k][0]+J(1,1)*tk[k][1]+J(1,2)*tk[k][2];
vk[2] = J(2,0)*tk[k][0]+J(2,1)*tk[k][1]+J(2,2)*tk[k][2];
for (j = 0; j < dof; j++)
if (fabs (I(k,j) = (vshape(j,0)*vk[0]+vshape(j,1)*vk[1]+
vshape(j,2)*vk[2])) < 1.0e-12)
{
I(k,j) = 0.0;
}
}
}
void Nedelec2PyrFiniteElement::Project (
VectorCoefficient &vc, ElementTransformation &Trans,
Vector &dofs) const
{
real_t vk[3];
Vector xk (vk, 3);
for (int k = 0; k < dof; k++)
{
Trans.SetIntPoint (&Nodes.IntPoint (k));
const DenseMatrix &J = Trans.Jacobian();
vc.Eval (xk, Trans, Nodes.IntPoint (k));
// xk^t J tk
dofs(k) =
vk[0] * ( J(0,0)*tk[k][0]+J(0,1)*tk[k][1]+J(0,2)*tk[k][2] ) +
vk[1] * ( J(1,0)*tk[k][0]+J(1,1)*tk[k][1]+J(1,2)*tk[k][2] ) +
vk[2] * ( J(2,0)*tk[k][0]+J(2,1)*tk[k][1]+J(2,2)*tk[k][2] );
}
}
void Nedelec2PyrFiniteElement::ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const
{
DenseMatrix dshape(fe.GetDof(), 3);
Vector grad_k(fe.GetDof());
grad.SetSize(dof, fe.GetDof());
for (int k = 0; k < dof; k++)
{
fe.CalcDShape(Nodes.IntPoint(k), dshape);
dshape.Mult(tk[k], grad_k);
for (int j = 0; j < grad_k.Size(); j++)
{
grad(k,j) = (fabs(grad_k(j)) < 1e-12) ? 0.0 : grad_k(j);
}
}
}
RT0HexFiniteElement::RT0HexFiniteElement()
: VectorFiniteElement(3, Geometry::CUBE, 6, 1, H_DIV, FunctionSpace::Qk)
{
@@ -5950,7 +6488,8 @@ void RT0WdgFiniteElement::ProjectCurl(const FiniteElement &fe,
}
RT0PyrFiniteElement::RT0PyrFiniteElement(bool rt0tets)
: VectorFiniteElement(3, Geometry::PYRAMID, 5, 1, H_DIV), rt0(rt0tets)
: VectorFiniteElement(3, Geometry::PYRAMID, 5, 1, H_DIV, FunctionSpace::Uk),
rt0(rt0tets)
{
// not real nodes ...
Nodes.IntPoint(0).x = 0.5;
@@ -6073,7 +6612,7 @@ void RT0PyrFiniteElement::CalcDivShape(const IntegrationPoint &ip,
}
const real_t RT0PyrFiniteElement::nk[5][3] =
{{0.,0.,-1.}, {0,-.5,0}, {.5,0,.5}, {0,.5,.5}, {-.5,0,0}};
{{0.,0.,-1}, {0,-1,0}, {1,0,1}, {0,1,1}, {-1,0,0}};
void RT0PyrFiniteElement::GetLocalInterpolation (
ElementTransformation &Trans, DenseMatrix &I) const
+28
View File
@@ -1018,6 +1018,34 @@ public:
};
/// A 3D 2nd order Nedelec element on a pyramid
class Nedelec2PyrFiniteElement : public VectorFiniteElement
{
private:
static const real_t tk[28][3];
public:
/// Construct the Nedelec2PyrFiniteElement
Nedelec2PyrFiniteElement();
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 0th order Raviert-Thomas element on a cube
class RT0HexFiniteElement : public VectorFiniteElement
{
+825
View File
@@ -1040,4 +1040,829 @@ void H1_WedgeElement::CalcDShape(const IntegrationPoint &ip,
}
}
H1_FuentesPyramidElement::H1_FuentesPyramidElement(const int p, const int btype)
: NodalFiniteElement(3, Geometry::PYRAMID,
p * (p * p + 3) + 1, // Fuentes et al
p, FunctionSpace::Uk)
{
zmax = 0.0;
const real_t *cp = poly1d.ClosedPoints(p, VerifyNodal(VerifyClosed(btype)));
#ifndef MFEM_THREAD_SAFE
tmp_i.SetSize(p + 1);
tmp1_ij.SetSize(p + 1, p + 1);
tmp2_ij.SetSize(p + 1, dim);
tmp_ijk.SetSize(p + 1, p + 1, dim);
tmp_u.SetSize(dof);
tmp_du.SetSize(dof, dim);
#else
Vector tmp_i(p + 1);
DenseMatrix tmp1_ij(p + 1, p + 1);
#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]);
// edges
int o = 5;
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++) // (1,2)
{
Nodes.IntPoint(o++).Set3(cp[p], cp[i], cp[0]);
}
for (int i = 1; i < p; i++) // (3,2)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[p], cp[0]);
}
for (int i = 1; i < p; i++) // (0,3)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[i], cp[0]);
}
for (int i = 1; i < p; i++) // (0,4)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[0], cp[i]);
}
for (int i = 1; i < p; i++) // (1,4)
{
Nodes.IntPoint(o++).Set3(cp[p-i], cp[0], cp[i]);
}
for (int i = 1; i < p; i++) // (2,4)
{
Nodes.IntPoint(o++).Set3(cp[p-i], cp[p-i], cp[i]);
}
for (int i = 1; i < p; i++) // (3,4)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[p-i], cp[i]);
}
// quadrilateral face
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]);
}
}
// triangular faces
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (0,1,4)
{
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++) // (1,2,4)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3((cp[i] + 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++) // (2,3,4)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(cp[p-i-j]/w, (cp[i] + cp[p-i-j])/w, cp[j]/w);
}
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (3,0,4)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(cp[0], cp[p-i-j]/w, cp[j]/w);
}
// Points based on Fuentes' interior bubbles
for (int k = 1; k < p; k++)
{
for (int j = 1; j < p; j++)
{
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i] * (1.0 - cp[k]),
cp[j] * (1.0 - cp[k]),
cp[k]);
}
}
}
MFEM_ASSERT(o == dof,
"Number of nodes does not match the "
"number of degrees of freedom");
DenseMatrix T(dof);
for (int m = 0; m < dof; m++)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
Vector col(T.GetColumn(m), dof);
calcBasis(order, ip, tmp_i, tmp1_ij, col);
}
Ti.Factor(T);
}
void H1_FuentesPyramidElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector tmp_i(p + 1);
Vector tmp_u(dof);
DenseMatrix tmp1_ij(p + 1, p + 1);
#endif
calcBasis(p, ip, tmp_i, tmp1_ij, tmp_u);
Ti.Mult(tmp_u, shape);
}
void H1_FuentesPyramidElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector tmp_i(p + 1);
DenseMatrix tmp1_ij(p + 1, p + 1);
DenseMatrix tmp2_ij(p + 1, dim);
DenseTensor tmp_ijk(p + 1, p + 1, dim);
DenseMatrix tmp_du(dof, dim);
#endif
calcGradBasis(p, ip, tmp_i, tmp2_ij, tmp1_ij, tmp_ijk, tmp_du);
Ti.Mult(tmp_du, dshape);
}
void H1_FuentesPyramidElement::CalcRawShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector tmp_i(p + 1);
DenseMatrix tmp1_ij(p + 1, p + 1);
#endif
calcBasis(p, ip, tmp_i, tmp1_ij, shape);
}
void H1_FuentesPyramidElement::CalcRawDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector tmp_i(p + 1);
DenseMatrix tmp1_ij(p + 1, p + 1);
DenseMatrix tmp2_ij(p + 1, dim);
DenseTensor tmp_ijk(p + 1, p + 1, dim);
#endif
calcGradBasis(p, ip, tmp_i, tmp2_ij, tmp1_ij, tmp_ijk, dshape);
}
void H1_FuentesPyramidElement::calcBasis(const int p,
const IntegrationPoint &ip,
Vector &phi_i, DenseMatrix &phi_ij,
Vector &u) const
{
real_t x = ip.x;
real_t y = ip.y;
real_t z = ip.z;
Vector xy({x,y});
zmax = std::max(z, zmax);
real_t mu;
int o = 0;
// Vertices
u[0] = lam1(x, y, z);
u[1] = lam2(x, y, z);
u[2] = lam3(x, y, z);
u[3] = lam4(x, y, z);
u[4] = lam5(x, y, z);
o += 5;
// Mixed edges (base edges)
if (CheckZ(z) && p >= 2)
{
// (a,b) = (1,2), c = 0
phi_E(p, nu01(z, xy, 1), phi_i);
mu = mu0(z, xy, 2);
for (int i = 2; i <= p; i++, o++)
{
u[o] = mu * phi_i[i];
}
// (a,b) = (1,2), c = 1
mu = mu1(z, xy, 2);
for (int i = 2; i <= p; i++, o++)
{
u[o] = mu * phi_i[i];
}
// (a,b) = (2,1), c = 0
phi_E(p, nu01(z, xy, 2), phi_i);
mu = mu0(z, xy, 1);
for (int i = 2; i <= p; i++, o++)
{
u[o] = mu * phi_i[i];
}
// (a,b) = (2,1), c = 1
mu = mu1(z, xy, 1);
for (int i = 2; i <= p; i++, o++)
{
u[o] = mu * phi_i[i];
}
}
else
{
for (int i = 0; i < 4 * (p - 1); i++, o++)
{
u[o] = 0.0;
}
}
// Triangle edges (upright edges)
if (p >= 2)
{
phi_E(p, lam15(x, y, z), phi_i);
for (int i = 2; i<= p; i++, o++)
{
u[o] = phi_i[i];
}
phi_E(p, lam25(x, y, z), phi_i);
for (int i = 2; i<= p; i++, o++)
{
u[o] = phi_i[i];
}
phi_E(p, lam35(x, y, z), phi_i);
for (int i = 2; i<= p; i++, o++)
{
u[o] = phi_i[i];
}
phi_E(p, lam45(x, y, z), phi_i);
for (int i = 2; i<= p; i++, o++)
{
u[o] = phi_i[i];
}
}
// Quadrilateral face
if (CheckZ(z) && p >= 2)
{
phi_Q(p, mu01(z, xy, 1), mu01(z, xy, 2), phi_ij);
mu = mu0(z);
for (int j = 2; j <= p; j++)
{
for (int i = 2; i <= p; i++, o++)
{
u[o] = mu * phi_ij(i,j);
}
}
}
else
{
for (int j = 2; j <= p; j++)
{
for (int i = 2; i <= p; i++, o++)
{
u[o] = 0.0;
}
}
}
// Triangular faces
if (CheckZ(z) && p >= 3)
{
// (a,b) = (1,2), c = 0
phi_T(p, nu012(z, xy, 1), phi_ij);
mu = mu0(z, xy, 2);
for (int i = 2; i < p; i++)
for (int j = 1; i + j <= p; j++, o++)
{
u[o] = mu * phi_ij(i,j);
}
// (a,b) = (1,2), c = 1
mu = mu1(z, xy, 2);
for (int i = 2; i < p; i++)
for (int j = 1; i + j <= p; j++, o++)
{
u[o] = mu * phi_ij(i,j);
}
// (a,b) = (2,1), c = 0
phi_T(p, nu012(z, xy, 2), phi_ij);
mu = mu0(z, xy, 1);
for (int i = 2; i < p; i++)
for (int j = 1; i + j <= p; j++, o++)
{
u[o] = mu * phi_ij(i,j);
}
// (a,b) = (2,1), c = 1
mu = mu1(z, xy, 1);
for (int i = 2; i < p; i++)
for (int j = 1; i + j <= p; j++, o++)
{
u[o] = mu * phi_ij(i,j);
}
}
else
{
for (int i = 0; i < 2 * (p - 1) * (p - 2); i++, o++)
{
u[o] = 0.0;
}
}
// Interior
if (CheckZ(z) && p >= 2)
{
phi_Q(p, mu01(z, xy, 1), mu01(z, xy, 2), phi_ij);
phi_E(p, mu01(z), phi_i);
for (int k = 2; k <= p; k++)
{
for (int j = 2; j <= p; j++)
{
for (int i = 2; i <= p; i++, o++)
{
u[o] = phi_ij(i,j) * phi_i(k);
}
}
}
}
else
{
for (int i = 0; i < (p - 1) * (p - 1) * (p - 1); i++, o++)
{
u[o]= 0.0;
}
}
}
void H1_FuentesPyramidElement::calcGradBasis(const int p,
const IntegrationPoint &ip,
Vector &phi_i,
DenseMatrix &dphi_i,
DenseMatrix &phi_ij,
DenseTensor &dphi_ij,
DenseMatrix &du) const
{
real_t x = ip.x;
real_t y = ip.y;
real_t z = ip.z;
Vector xy({x,y});
zmax = std::max(z, zmax);
real_t mu;
Vector dmu(3);
Vector dlam(3);
int o = 0;
// Vertices
dlam = grad_lam1(x, y, z);
for (int d=0; d<3; d++) { du(0, d) = dlam(d); }
dlam = grad_lam2(x, y, z);
for (int d=0; d<3; d++) { du(1, d) = dlam(d); }
dlam = grad_lam3(x, y, z);
for (int d=0; d<3; d++) { du(2, d) = dlam(d); }
dlam = grad_lam4(x, y, z);
for (int d=0; d<3; d++) { du(3, d) = dlam(d); }
dlam = grad_lam5(x, y, z);
for (int d=0; d<3; d++) { du(4, d) = dlam(d); }
o += 5;
// Mixed edges (base edges)
if (CheckZ(z) && p >= 2)
{
// (a,b) = (1,2), c = 0
phi_E(p, nu01(z, xy, 1), grad_nu01(z, xy, 1), phi_i, dphi_i);
mu = mu0(z, xy, 2);
dmu = grad_mu0(z, xy, 2);;
for (int i = 2; i <= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_i[i] + mu * dphi_i(i, d);
}
// (a,b) = (1,2), c = 1
mu = mu1(z, xy, 2);
dmu = grad_mu1(z, xy, 2);;
for (int i = 2; i <= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_i[i] + mu * dphi_i(i, d);
}
// (a,b) = (2,1), c = 0
phi_E(p, nu01(z, xy, 2), grad_nu01(z, xy, 2), phi_i, dphi_i);
mu = mu0(z, xy, 1);
dmu = grad_mu0(z, xy, 1);;
for (int i = 2; i <= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_i[i] + mu * dphi_i(i, d);
}
// (a,b) = (2,1), c = 1
mu = mu1(z, xy, 1);
dmu = grad_mu1(z, xy, 1);;
for (int i = 2; i <= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_i[i] + mu * dphi_i(i, d);
}
}
else
{
for (int i = 0; i < 4 * (p - 1); i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = 0.0;
}
}
// Triangle edges (upright edges)
if (p >= 2)
{
phi_E(p, lam15(x, y, z), grad_lam15(x,y,z), phi_i, dphi_i);
for (int i = 2; i<= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dphi_i(i, d);
}
phi_E(p, lam25(x, y, z), grad_lam25(x, y, z), phi_i, dphi_i);
for (int i = 2; i<= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dphi_i(i, d);
}
phi_E(p, lam35(x, y, z), grad_lam35(x, y, z), phi_i, dphi_i);
for (int i = 2; i<= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dphi_i(i, d);
}
phi_E(p, lam45(x, y, z), grad_lam45(x, y, z), phi_i, dphi_i);
for (int i = 2; i<= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dphi_i(i, d);
}
}
// Quadrilateral face
if (CheckZ(z) && p >= 2)
{
phi_Q(p, mu01(z, xy, 1), grad_mu01(z, xy, 1),
mu01(z, xy, 2), grad_mu01(z, xy, 2), phi_ij, dphi_ij);
mu = mu0(z);
dmu = grad_mu0(z);
for (int j = 2; j <= p; j++)
for (int i = 2; i <= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_ij(i, j) + mu * dphi_ij(i, j, d);
}
}
else
{
for (int j = 2; j <= p; j++)
for (int i = 2; i <= p; i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = 0.0;
}
}
// Triangular faces
if (CheckZ(z) && p >= 3)
{
// (a,b) = (1,2), c = 0
phi_T(p, nu012(z, xy, 1), grad_nu012(z, xy, 1), phi_ij, dphi_ij);
mu = mu0(z, xy, 2);
dmu = grad_mu0(z, xy, 2);
for (int i = 2; i < p; i++)
for (int j = 1; i + j <= p; j++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_ij(i, j) + mu * dphi_ij(i, j, d);
}
// (a,b) = (1,2), c = 1
mu = mu1(z, xy, 2);
dmu = grad_mu1(z, xy, 2);
for (int i = 2; i < p; i++)
for (int j = 1; i + j <= p; j++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_ij(i, j) + mu * dphi_ij(i, j, d);
}
// (a,b) = (2,1), c = 0
phi_T(p, nu012(z, xy, 2), grad_nu012(z, xy, 2), phi_ij, dphi_ij);
mu = mu0(z, xy, 1);
dmu = grad_mu0(z, xy, 1);
for (int i = 2; i < p; i++)
for (int j = 1; i + j <= p; j++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_ij(i, j) + mu * dphi_ij(i, j, d);
}
// (a,b) = (2,1), c = 1
mu = mu1(z, xy, 1);
dmu = grad_mu1(z, xy, 1);
for (int i = 2; i < p; i++)
for (int j = 1; i + j <= p; j++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = dmu(d) * phi_ij(i, j) + mu * dphi_ij(i, j, d);
}
}
else
{
for (int i = 0; i < 2 * (p - 1) * (p - 2); i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = 0.0;
}
}
// Interior
if (CheckZ(z) && p >= 2)
{
phi_Q(p, mu01(z, xy, 1), grad_mu01(z, xy, 1),
mu01(z, xy, 2), grad_mu01(z, xy, 2), phi_ij, dphi_ij);
phi_E(p, mu01(z), grad_mu01(z), phi_i, dphi_i);
for (int k = 2; k <= p; k++)
for (int j = 2; j <= p; j++)
for (int i = 2; i <= p; i++, o++)
for (int d=0; d<3; d++)
du(o, d) = dphi_ij(i, j, d) * phi_i(k) +
phi_ij(i, j) * dphi_i(k, d);
}
else
{
for (int i = 0; i < (p - 1) * (p - 1) * (p - 1); i++, o++)
for (int d=0; d<3; d++)
{
du(o, d) = 0.0;
}
}
}
H1_BergotPyramidElement::H1_BergotPyramidElement(const int p, const int btype)
: NodalFiniteElement(3, Geometry::PYRAMID,
(p + 1) * (p + 2) * (2 * p + 3) / 6, // Bergot (JSC)
p, FunctionSpace::Uk)
{
const real_t *cp = poly1d.ClosedPoints(p, VerifyNodal(VerifyClosed(btype)));
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(p + 1);
shape_y.SetSize(p + 1);
shape_z.SetSize(p + 1);
dshape_x.SetSize(p + 1);
dshape_y.SetSize(p + 1);
dshape_z.SetSize(p + 1);
dshape_z_dt.SetSize(p + 1);
ddshape_x.SetSize(p + 1);
ddshape_y.SetSize(p + 1);
ddshape_z.SetSize(p + 1);
u.SetSize(dof);
du.SetSize(dof, dim);
ddu.SetSize(dof, (dim * (dim + 1)) / 2);
#else
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1);
#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]);
// edges
int o = 5;
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++) // (1,2)
{
Nodes.IntPoint(o++).Set3(cp[p], cp[i], cp[0]);
}
for (int i = 1; i < p; i++) // (3,2)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[p], cp[0]);
}
for (int i = 1; i < p; i++) // (0,3)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[i], cp[0]);
}
for (int i = 1; i < p; i++) // (0,4)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[0], cp[i]);
}
for (int i = 1; i < p; i++) // (1,4)
{
Nodes.IntPoint(o++).Set3(cp[p-i], cp[0], cp[i]);
}
for (int i = 1; i < p; i++) // (2,4)
{
Nodes.IntPoint(o++).Set3(cp[p-i], cp[p-i], cp[i]);
}
for (int i = 1; i < p; i++) // (3,4)
{
Nodes.IntPoint(o++).Set3(cp[0], cp[p-i], cp[i]);
}
// quadrilateral face
for (int j = 1; j < p; j++)
{
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o++).Set3(cp[i], cp[j], cp[0]);
}
}
// triangular faces
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (0,1,4)
{
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++) // (1,2,4)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(1.0 - cp[j]/w, cp[i]/w, cp[j]/w);
}
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (3,4,2)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(cp[j]/w, 1.0 - cp[i]/w, cp[i]/w);
}
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (0,4,3)
{
real_t w = cp[i] + cp[j] + cp[p-i-j];
Nodes.IntPoint(o++).Set3(cp[0], cp[j]/w, cp[i]/w);
}
// interior
for (int k = 1; k < p - 1; k++)
{
for (int j = 1; j < p - k; j++)
{
real_t wjk = cp[j] + cp[k] + cp[p-j-k];
for (int i = 1; i < p - k; i++)
{
real_t wik = cp[i] + cp[k] + cp[p-i-k];
real_t w = wik * wjk * cp[p-k];
Nodes.IntPoint(o++).Set3(cp[i] * (cp[j] + cp[p-j-k]) / w,
cp[j] * (cp[i] + cp[p-i-k]) / w,
cp[k] * cp[p-k] / w);
}
}
}
MFEM_ASSERT(o == dof,
"Number of nodes does not match the "
"number of degrees of freedom");
DenseMatrix T(dof);
for (int m = 0; m < dof; m++)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
o = 0;
for (int i = 0; i <= p; i++)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0, shape_z);
for (int k = 0; k <= p - maxij; k++)
{
T(o++, m) = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
}
}
}
Ti.Factor(T);
}
void H1_BergotPyramidElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(order+1);
Vector shape_y(order+1);
Vector shape_z(order+1);
Vector u(dof);
#endif
real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0), z, 1.0,
shape_z);
for (int k = 0; k <= p - maxij; k++)
u[o++] = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
Ti.Mult(u, shape);
}
void H1_BergotPyramidElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
DenseMatrix du(dof, dim);
Vector shape_x(order+1);
Vector shape_y(order+1);
Vector shape_z(order+1);
Vector dshape_x(order+1);
Vector dshape_y(order+1);
Vector dshape_z(order+1);
Vector dshape_z_dt(order+1);
#endif
real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData(), dshape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData(), dshape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0), z, 1.0,
shape_z, dshape_z, dshape_z_dt);
for (int k = 0; k <= p - maxij; k++, o++)
{
du(o,0) = dshape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,1) = shape_x(i) * dshape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,2) = shape_x(i) * shape_y(j) * dshape_z(k) *
pow(1.0 - ip.z, maxij) +
(ip.x * dshape_x(i) * shape_y(j) +
ip.y * shape_x(i) * dshape_y(j)) *
shape_z(k) * pow(1.0 - ip.z, maxij - 2) -
maxij * shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
}
}
Ti.Mult(du, dshape);
}
}
+68
View File
@@ -13,6 +13,7 @@
#define MFEM_FE_H1
#include "fe_base.hpp"
#include "fe_pyramid.hpp"
namespace mfem
{
@@ -148,6 +149,73 @@ public:
DenseMatrix &dshape) const override;
};
/** Arbitrary order H1 basis functions defined on pyramid-shaped elements
This implementation is closely based on the finite elements
described in section 9.1 of the paper "Orientation embedded high
order shape functions for the exact sequence elements of all shapes"
by Federico Fuentes, Brendan Keith, Leszek Demkowicz, and Sriram
Nagaraj, see https://doi.org/10.1016/j.camwa.2015.04.027.
*/
class H1_FuentesPyramidElement
: public NodalFiniteElement, public FuentesPyramid
{
private:
mutable real_t zmax;
#ifndef MFEM_THREAD_SAFE
mutable Vector tmp_i, tmp_u;
mutable DenseMatrix tmp1_ij, tmp2_ij, tmp_du;
mutable DenseTensor tmp_ijk;
#endif
DenseMatrixInverse Ti;
void calcBasis(const int p, const IntegrationPoint &ip,
Vector &phi_i, DenseMatrix &phi_ij, Vector &u) const;
void calcGradBasis(const int p, const IntegrationPoint &ip,
Vector &phi_i, DenseMatrix &dphi_i,
DenseMatrix &phi_ij, DenseTensor &dphi_ij,
DenseMatrix &du) const;
public:
H1_FuentesPyramidElement(const int p,
const int btype = BasisType::GaussLobatto);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
void CalcRawShape(const IntegrationPoint &ip, Vector &shape) const;
void CalcRawDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
real_t GetZetaMax() const { return zmax; }
};
/** Arbitrary order H1 basis functions defined on pyramid-shaped elements
This implementation is based on the finite elements described in the
2010 paper "Higher-Order Finite Elements for Hybrid Meshes Using New
Nodal Pyramidal Elements" by Morgane Bergot, Gary Cohen, and Marc
Durufle, see https://hal.archives-ouvertes.fr/hal-00454261.
*/
class H1_BergotPyramidElement : public NodalFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z, dshape_z_dt, u;
mutable Vector ddshape_x, ddshape_y, ddshape_z;
mutable DenseMatrix du, ddu;
#endif
DenseMatrixInverse Ti;
public:
H1_BergotPyramidElement(const int p,
const int btype = BasisType::GaussLobatto);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
} // namespace mfem
#endif
+317
View File
@@ -923,4 +923,321 @@ void L2_WedgeElement::CalcDShape(const IntegrationPoint &ip,
}
}
L2_FuentesPyramidElement::L2_FuentesPyramidElement(const int p, const int btype)
: NodalFiniteElement(3, Geometry::PYRAMID, ((p + 1)*(p + 1)*(p + 1)),
p, FunctionSpace::Uk)
{
const real_t *op = poly1d.OpenPoints(p, VerifyOpen(btype));
// These basis functions are not independent on a closed set of
// interpolation points when p >= 1. For this reason we force the points
// to be open in the z direction whenever closed points are requested.
// This should be regarded as a limitation of this choice of basis function.
// If a truly closed set of points is needed consider using
// L2_BergotPyramidElement instead.
real_t a = 1.0;
if (IsClosedType(btype) && p > 0)
{
a = (poly1d.GetPoints(p, BasisType::GaussLegendre))[p];
}
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(p + 1);
shape_y.SetSize(p + 1);
shape_z.SetSize(p + 1);
dshape_x.SetSize(p + 1);
dshape_y.SetSize(p + 1);
dshape_z.SetSize(p + 1);
u.SetSize(dof);
du.SetSize(dof, dim);
#else
Vector shape_x(p + 1);
Vector shape_y(p + 1);
Vector shape_z(p + 1);
#endif
int o = 0;
for (int k = 0; k <= p; k++)
for (int j = 0; j <= p; j++)
for (int i = 0; i <= p; i++)
{
Nodes.IntPoint(o++).Set3(op[i] * (1.0 - a * op[k]),
op[j] * (1.0 - a * op[k]),
a * op[k]);
}
MFEM_ASSERT(o == dof,
"Number of nodes does not match the "
"number of degrees of freedom");
DenseMatrix T(dof);
for (int m = 0; m < dof; m++)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
real_t x = ip.x;
real_t y = ip.y;
real_t z = ip.z;
Vector xy({x,y});
CalcHomogenizedScaLegendre(p, mu0(z, xy, 1), mu1(z, xy, 1), shape_x);
CalcHomogenizedScaLegendre(p, mu0(z, xy, 2), mu1(z, xy, 2), shape_y);
CalcHomogenizedScaLegendre(p, mu0(z), mu1(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++, o++)
{
T(o, m) = shape_x[i] * shape_y[j] * shape_z[k];
}
}
}
}
Ti.Factor(T);
}
void L2_FuentesPyramidElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1);
Vector shape_y(p + 1);
Vector shape_z(p + 1);
Vector u(dof);
#endif
real_t x = ip.x;
real_t y = ip.y;
real_t z = ip.z;
Vector xy({x,y});
if (z < 1.0)
{
CalcHomogenizedScaLegendre(p, mu0(z, xy, 1), mu1(z, xy, 1), shape_x);
CalcHomogenizedScaLegendre(p, mu0(z, xy, 2), mu1(z, xy, 2), shape_y);
}
else
{
shape_x = 0.0; shape_x(0) = 1.0;
shape_y = 0.0; shape_y(0) = 1.0;
}
CalcHomogenizedScaLegendre(p, mu0(z), mu1(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++, o++)
{
u[o] = shape_x[i] * shape_y[j] * shape_z[k];
}
Ti.Mult(u, shape);
}
void L2_FuentesPyramidElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1);
Vector shape_y(p + 1);
Vector shape_z(p + 1);
Vector dshape_x(p + 1);
Vector dshape_y(p + 1);
Vector dshape_z(p + 1);
DenseMatrix du(dof, dim);
#endif
Poly_1D::CalcLegendre(p, ip.x / (1.0 - ip.z), shape_x.GetData(),
dshape_x.GetData());
Poly_1D::CalcLegendre(p, ip.y / (1.0 - ip.z), shape_y.GetData(),
dshape_y.GetData());
Poly_1D::CalcLegendre(p, ip.z, shape_z.GetData(), dshape_z.GetData());
int o = 0;
for (int k = 0; k <= p; k++)
for (int j = 0; j <= p; j++)
for (int i = 0; i <= p; i++, o++)
{
du(o, 0) = dshape_x[i] * shape_y[j] * shape_z[k] / (1.0 - ip.z);
du(o, 1) = shape_x[i] * dshape_y[j] * shape_z[k] / (1.0 - ip.z);
du(o, 2) = shape_x[i] * shape_y[j] * dshape_z[k] +
(ip.x * dshape_x[i] * shape_y[j] +
ip.y * shape_x[i] * dshape_y[j]) *
shape_z[k] / pow(1.0 - ip.z, 2);
}
Ti.Mult(du, dshape);
}
L2_BergotPyramidElement::L2_BergotPyramidElement(const int p, const int btype)
: NodalFiniteElement(3, Geometry::PYRAMID, (p + 1)*(p + 2)*(2*p + 3)/6,
p, FunctionSpace::Pk)
{
const real_t *op = poly1d.OpenPoints(p, VerifyOpen(btype));
#ifndef MFEM_THREAD_SAFE
shape_x.SetSize(p + 1);
shape_y.SetSize(p + 1);
shape_z.SetSize(p + 1);
dshape_x.SetSize(p + 1);
dshape_y.SetSize(p + 1);
dshape_z.SetSize(p + 1);
dshape_z_dt.SetSize(p + 1);
u.SetSize(dof);
du.SetSize(dof, dim);
#else
Vector shape_x(p + 1);
Vector shape_y(p + 1);
Vector shape_z(p + 1);
Vector dshape_z_dt(p + 1);
#endif
int o = 0;
for (int k = 0; k <= p; k++)
for (int j = 0; j <= p - k; j++)
{
const real_t wjk = op[j] + op[k] + op[p-j-k];
for (int i = 0; i <= p - k; i++)
{
const real_t wik = op[i] + op[k] + op[p-i-k];
const real_t w = wik * wjk * op[p-k];
Nodes.IntPoint(o++).Set3(op[i] * (op[j] + op[p-j-k]) / w,
op[j] * (op[j] + op[p-j-k]) / w,
op[k] * op[p-k] / w);
}
}
MFEM_ASSERT(o == dof,
"Number of nodes does not match the "
"number of degrees of freedom");
DenseMatrix T(dof);
for (int m = 0; m < dof; m++)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
const real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
const real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
const real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
o = 0;
for (int i = 0; i <= p; i++)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0, shape_z);
for (int k = 0; k <= p - maxij; k++)
{
T(o++, m) = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
}
}
}
Ti.Factor(T);
}
void L2_BergotPyramidElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1);
Vector shape_y(p + 1);
Vector shape_z(p + 1);
Vector u(dof);
#endif
const real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
const real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
const real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0), z, 1.0,
shape_z);
for (int k = 0; k <= p - maxij; k++)
{
u[o++] = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
}
}
Ti.Mult(u, shape);
}
void L2_BergotPyramidElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
Vector shape_x(p + 1);
Vector shape_y(p + 1);
Vector shape_z(p + 1);
Vector dshape_x(p + 1);
Vector dshape_y(p + 1);
Vector dshape_z(p + 1);
Vector dshape_z_dt(p + 1);
DenseMatrix du(dof, dim);
#endif
const real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
const real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
const real_t z = ip.z;
Poly_1D::CalcLegendre(p, x, shape_x.GetData(), dshape_x.GetData());
Poly_1D::CalcLegendre(p, y, shape_y.GetData(), dshape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0), z, 1.0,
shape_z, dshape_z, dshape_z_dt);
for (int k = 0; k <= p - maxij; k++, o++)
{
du(o,0) = dshape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,1) = shape_x(i) * dshape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,2) = shape_x(i) * shape_y(j) * dshape_z(k) *
pow(1.0 - ip.z, maxij) +
(ip.x * dshape_x(i) * shape_y(j) +
ip.y * shape_x(i) * dshape_y(j)) *
shape_z(k) * pow(1.0 - ip.z, maxij - 2) -
((maxij > 0) ? (maxij * shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1)) : 0.0);
}
}
}
Ti.Mult(du, dshape);
}
}
+51
View File
@@ -13,6 +13,7 @@
#define MFEM_FE_L2
#include "fe_base.hpp"
#include "fe_pyramid.hpp"
namespace mfem
{
@@ -183,6 +184,56 @@ public:
DenseMatrix &dshape) const override;
};
/** Arbitrary order L2 basis functions defined on pyramid-shaped elements
This implementation is closely based on the finite elements
described in section 9.4 of the paper "Orientation embedded high
order shape functions for the exact sequence elements of all shapes"
by Federico Fuentes, Brendan Keith, Leszek Demkowicz, and Sriram
Nagaraj, see https://doi.org/10.1016/j.camwa.2015.04.027.
*/
class L2_FuentesPyramidElement
: public NodalFiniteElement, public FuentesPyramid
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z;
mutable Vector u;
mutable DenseMatrix du;
#endif
DenseMatrixInverse Ti;
public:
/// Construct the L2_PyramidElement of order @a p and BasisType @a btype
L2_FuentesPyramidElement(const int p,
const int btype = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
/// Arbitrary order L2 elements in 3D on a pyramid
class L2_BergotPyramidElement : public NodalFiniteElement
{
private:
#ifndef MFEM_THREAD_SAFE
mutable Vector shape_x, shape_y, shape_z;
mutable Vector dshape_x, dshape_y, dshape_z, dshape_z_dt;
mutable Vector u;
mutable DenseMatrix du;
#endif
DenseMatrixInverse Ti;
public:
/// Construct the L2_PyramidElement of order @a p and BasisType @a btype
L2_BergotPyramidElement(const int p,
const int btype = BasisType::GaussLegendre);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
} // namespace mfem
#endif
+948
View File
@@ -1581,6 +1581,954 @@ void ND_WedgeElement::CalcCurlShape(const IntegrationPoint &ip,
}
}
const real_t ND_FuentesPyramidElement::tk[27] =
{
1., 0., 0., 0., 1., 0., 0., 0., 1.,
-1., 0., 1., -1.,-1., 1., 0.,-1., 1.,
-1., 0., 0., 0.,-1., 0., -M_SQRT1_2,-M_SQRT1_2,M_SQRT2
};
ND_FuentesPyramidElement::ND_FuentesPyramidElement(const int p,
const int cb_type,
const int ob_type)
: VectorFiniteElement(3, Geometry::PYRAMID, p * (3 * p * p + 5), p,
H_CURL, FunctionSpace::Uk),
dof2tk(dof), doftrans(p)
{
zmax = 0.0;
const real_t *eop = poly1d.OpenPoints(p - 1);
const real_t *top = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL;
const real_t *qop = poly1d.OpenPoints(p - 1, ob_type);
const real_t *qcp = poly1d.ClosedPoints(p, cb_type);
const int pm2 = p - 2;
#ifndef MFEM_THREAD_SAFE
tmp_E_E_ij.SetSize(p, dim);
tmp_dE_E_ij.SetSize(p, dim);
tmp_E_Q1_ijk.SetSize(p, p + 1, dim);
tmp_dE_Q1_ijk.SetSize(p, p + 1, dim);
tmp_E_Q2_ijk.SetSize(p, p + 1, dim);
tmp_dE_Q2_ijk.SetSize(p, p + 1, dim);
tmp_E_T_ijk.SetSize(p - 1, p, dim);
tmp_dE_T_ijk.SetSize(p - 1, p, dim);
tmp_phi_Q1_ij.SetSize(p + 1, p + 1);
tmp_dphi_Q1_ij.SetSize(p + 1, p + 1, dim);
tmp_phi_Q2_ij.SetSize(p + 1, p + 1);
tmp_dphi_Q2_ij.SetSize(p + 1, p + 1, dim);
tmp_phi_E_i.SetSize(p + 1);
tmp_dphi_E_i.SetSize(p + 1, dim);
u.SetSize(dof, dim);
curlu.SetSize(dof, dim);
#else
DenseMatrix tmp_E_E_ij(p, dim);
DenseTensor tmp_E_Q1_ijk(p, p + 1, dim);
DenseTensor tmp_dE_Q1_ijk(p, p + 1, dim);
DenseTensor tmp_E_Q2_ijk(p, p + 1, dim);
DenseTensor tmp_dE_Q2_ijk(p, p + 1, dim);
DenseTensor tmp_E_T_ijk(p - 1, p, dim);
DenseTensor tmp_dE_T_ijk(p - 1, p, dim);
DenseMatrix tmp_phi_Q1_ij(p + 1, p + 1);
DenseTensor tmp_dphi_Q1_ij(p + 1, p + 1, dim);
DenseMatrix tmp_phi_Q2_ij(p + 1, p + 1);
Vector tmp_phi_E_i(p + 1);
DenseMatrix tmp_dphi_E_i(p + 1, dim);
DenseMatrix u(dof, dim);
#endif
int o = 0;
// edges
for (int i = 0; i < p; i++) // (0, 1)
{
Nodes.IntPoint(o).Set3(eop[i], 0., 0.);
dof2tk[o++] = 0;
}
for (int i = 0; i < p; i++) // (1, 2)
{
Nodes.IntPoint(o).Set3(1., eop[i], 0.);
dof2tk[o++] = 1;
}
for (int i = 0; i < p; i++) // (3, 2)
{
Nodes.IntPoint(o).Set3(eop[i], 1., 0.);
dof2tk[o++] = 0;
}
for (int i = 0; i < p; i++) // (0, 3)
{
Nodes.IntPoint(o).Set3(0., eop[i], 0.);
dof2tk[o++] = 1;
}
for (int i = 0; i < p; i++) // (0, 4)
{
Nodes.IntPoint(o).Set3(0., 0., eop[i]);
dof2tk[o++] = 2;
}
for (int i = 0; i < p; i++) // (1, 4)
{
Nodes.IntPoint(o).Set3(1. - eop[i], 0., eop[i]);
dof2tk[o++] = 3;
}
for (int i = 0; i < p; i++) // (2, 4)
{
Nodes.IntPoint(o).Set3(1. - eop[i], 1. - eop[i], eop[i]);
dof2tk[o++] = 4;
}
for (int i = 0; i < p; i++) // (3, 4)
{
Nodes.IntPoint(o).Set3(0., 1. - eop[i], eop[i]);
dof2tk[o++] = 5;
}
// quadrilateral face (3, 2, 1, 0)
// x-components
for (int j = 1; j < p; j++)
for (int i = 0; i < p; i++)
{
Nodes.IntPoint(o).Set3(qop[i], qcp[p-j], 0.);
dof2tk[o++] = 0; // (1 0 0)
}
// y-components
for (int j = 0; j < p; j++)
for (int i = 1; i < p; i++)
{
Nodes.IntPoint(o).Set3(qcp[i], qop[p-1-j], 0.);
dof2tk[o++] = 7; // (0 -1 0)
}
// triangular faces
for (int j = 0; j <= pm2; j++) // (0, 1, 4)
for (int i = 0; i + j <= pm2; i++)
{
real_t w = top[i] + top[j] + top[pm2-i-j];
Nodes.IntPoint(o).Set3(top[i]/w, 0., top[j]/w);
dof2tk[o++] = 0;
Nodes.IntPoint(o).Set3(top[i]/w, 0., top[j]/w);
dof2tk[o++] = 2;
}
for (int j = 0; j <= pm2; j++) // (1, 2, 4)
for (int i = 0; i + j <= pm2; i++)
{
real_t w = top[i] + top[j] + top[pm2-i-j];
Nodes.IntPoint(o).Set3((top[i] + top[pm2-i-j])/w, top[i]/w, top[j]/w);
dof2tk[o++] = 1;
Nodes.IntPoint(o).Set3((top[i] + top[pm2-i-j])/w, top[i]/w, top[j]/w);
dof2tk[o++] = 3;
}
for (int j = 0; j <= pm2; j++) // (2, 3, 4)
for (int i = 0; i + j <= pm2; i++)
{
real_t w = top[i] + top[j] + top[pm2-i-j];
Nodes.IntPoint(o).Set3(top[pm2-i-j]/w, (top[i] + top[pm2-i-j])/w,
top[j]/w);
dof2tk[o++] = 6;
Nodes.IntPoint(o).Set3(top[pm2-i-j]/w, (top[i] + top[pm2-i-j])/w,
top[j]/w);
dof2tk[o++] = 4;
}
for (int j = 0; j <= pm2; j++) // (3, 0, 4)
for (int i = 0; i + j <= pm2; i++)
{
real_t w = top[i] + top[j] + top[pm2-i-j];
Nodes.IntPoint(o).Set3(0., top[pm2-i-j]/w, top[j]/w);
dof2tk[o++] = 7;
Nodes.IntPoint(o).Set3(0., top[pm2-i-j]/w, top[j]/w);
dof2tk[o++] = 5;
}
// interior
// x-components
for (int k = 1; k < p; k++)
for (int j = 1; j < p; j++)
for (int i = 0; i < p; i++)
{
real_t w = 1.0 - qcp[k];
Nodes.IntPoint(o).Set3(qop[i]*w, qcp[j]*w, qcp[k]);
dof2tk[o++] = 0;
}
// y-components
for (int k = 1; k < p; k++)
for (int j = 0; j < p; j++)
for (int i = 1; i < p; i++)
{
real_t w = 1.0 - qcp[k];
Nodes.IntPoint(o).Set3(qcp[i]*w, qop[j]*w, qcp[k]);
dof2tk[o++] = 1;
}
// z-components
for (int k = 0; k < p; k++)
for (int j = 1; j < p; j++)
for (int i = 1; i < p; i++)
{
real_t w = 1.0 - qop[k];
Nodes.IntPoint(o).Set3(qcp[i]*w, qcp[j]*w, qop[k]);
dof2tk[o++] = 8;
}
DenseMatrix T(dof);
for (int m = 0; m < dof; m++)
{
const IntegrationPoint &ip = Nodes.IntPoint(m);
calcBasis(p, ip, tmp_E_E_ij, tmp_E_Q1_ijk, tmp_E_Q2_ijk, tmp_E_T_ijk,
tmp_phi_Q1_ij, tmp_dphi_Q1_ij, tmp_phi_Q2_ij,
tmp_phi_E_i, tmp_dphi_E_i, u);
const Vector tm({tk[3*dof2tk[m]], tk[3*dof2tk[m]+1], tk[3*dof2tk[m]+2]});
u.Mult(tm, T.GetColumn(m));
}
Ti.Factor(T);
}
void ND_FuentesPyramidElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
DenseMatrix tmp_E_E_ij(p, dim);
DenseTensor tmp_E_Q1_ijk(p, p + 1, dim);
DenseTensor tmp_E_Q2_ijk(p, p + 1, dim);
DenseTensor tmp_E_T_ijk(p - 1, p, dim);
DenseMatrix tmp_phi_Q1_ij(p + 1, p + 1);
DenseTensor tmp_dphi_Q1_ij(p + 1, p + 1, dim);
DenseMatrix tmp_phi_Q2_ij(p + 1, p + 1);
Vector tmp_phi_E_i(p + 1);
DenseMatrix tmp_dphi_E_i(p + 1, dim);
DenseMatrix u(dof, dim);
#endif
calcBasis(p, ip, tmp_E_E_ij, tmp_E_Q1_ijk, tmp_E_Q2_ijk, tmp_E_T_ijk,
tmp_phi_Q1_ij, tmp_dphi_Q1_ij, tmp_phi_Q2_ij,
tmp_phi_E_i, tmp_dphi_E_i, u);
Ti.Mult(u, shape);
}
void ND_FuentesPyramidElement::CalcCurlShape(const IntegrationPoint &ip,
DenseMatrix &curl_shape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
DenseMatrix tmp_E_E_ij(p, dim);
DenseMatrix tmp_dE_E_ij(p, dim);
DenseTensor tmp_E_Q1_ijk(p, p + 1, dim);
DenseTensor tmp_dE_Q1_ijk(p, p + 1, dim);
DenseTensor tmp_E_Q2_ijk(p, p + 1, dim);
DenseTensor tmp_dE_Q2_ijk(p, p + 1, dim);
DenseTensor tmp_E_T_ijk(p - 1, p, dim);
DenseTensor tmp_dE_T_ijk(p - 1, p, dim);
DenseMatrix tmp_phi_Q2_ij(p + 1, p + 1);
DenseTensor tmp_dphi_Q2_ij(p + 1, p + 1, dim);
Vector tmp_phi_E_i(p + 1);
DenseMatrix tmp_dphi_E_i(p + 1, dim);
DenseMatrix curlu(dof, dim);
#endif
calcCurlBasis(p, ip, tmp_E_E_ij, tmp_dE_E_ij, tmp_E_Q1_ijk, tmp_dE_Q1_ijk,
tmp_E_Q2_ijk, tmp_dE_Q2_ijk, tmp_E_T_ijk, tmp_dE_T_ijk,
tmp_phi_Q2_ij, tmp_dphi_Q2_ij, tmp_phi_E_i, tmp_dphi_E_i,
curlu);
Ti.Mult(curlu, curl_shape);
}
void ND_FuentesPyramidElement::CalcRawVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
DenseMatrix tmp_E_E_ij(p, dim);
DenseTensor tmp_E_Q1_ijk(p, p + 1, dim);
DenseTensor tmp_E_Q2_ijk(p, p + 1, dim);
DenseTensor tmp_E_T_ijk(p - 1, p, dim);
DenseMatrix tmp_phi_Q1_ij(p + 1, p + 1);
DenseTensor tmp_dphi_Q1_ij(p + 1, p + 1, dim);
DenseMatrix tmp_phi_Q2_ij(p + 1, p + 1);
Vector tmp_phi_E_i(p + 1);
DenseMatrix tmp_dphi_E_i(p + 1, dim);
#endif
calcBasis(p, ip, tmp_E_E_ij, tmp_E_Q1_ijk, tmp_E_Q2_ijk, tmp_E_T_ijk,
tmp_phi_Q1_ij, tmp_dphi_Q1_ij, tmp_phi_Q2_ij,
tmp_phi_E_i, tmp_dphi_E_i, shape);
}
void ND_FuentesPyramidElement::CalcRawCurlShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
const int p = order;
#ifdef MFEM_THREAD_SAFE
DenseMatrix tmp_E_E_ij(p, dim);
DenseMatrix tmp_dE_E_ij(p, dim);
DenseTensor tmp_E_Q1_ijk(p, p + 1, dim);
DenseTensor tmp_dE_Q1_ijk(p, p + 1, dim);
DenseTensor tmp_E_Q2_ijk(p, p + 1, dim);
DenseTensor tmp_dE_Q2_ijk(p, p + 1, dim);
DenseTensor tmp_E_T_ijk(p - 1, p, dim);
DenseTensor tmp_dE_T_ijk(p - 1, p, dim);
DenseMatrix tmp_phi_Q2_ij(p + 1, p + 1);
DenseTensor tmp_dphi_Q2_ij(p + 1, p + 1, dim);
Vector tmp_phi_E_i(p + 1);
DenseMatrix tmp_dphi_E_i(p + 1, dim);
#endif
calcCurlBasis(p, ip, tmp_E_E_ij, tmp_dE_E_ij, tmp_E_Q1_ijk, tmp_dE_Q1_ijk,
tmp_E_Q2_ijk, tmp_dE_Q2_ijk, tmp_E_T_ijk, tmp_dE_T_ijk,
tmp_phi_Q2_ij, tmp_dphi_Q2_ij, tmp_phi_E_i, tmp_dphi_E_i,
dshape);
}
void ND_FuentesPyramidElement::calcBasis(const int p,
const IntegrationPoint &ip,
DenseMatrix & E_E_ik,
DenseTensor & E_Q1_ijk,
DenseTensor & E_Q2_ijk,
DenseTensor & E_T_ijk,
DenseMatrix & phi_Q1_ij,
DenseTensor & dphi_Q1_ij,
DenseMatrix & phi_Q2_ij,
Vector & phi_E_k,
DenseMatrix & dphi_E_k,
DenseMatrix &W) const
{
real_t x = ip.x;
real_t y = ip.y;
real_t z = ip.z;
Vector xy({x,y}), dmu(3);
real_t mu, mu2;
if (std::fabs(1.0 - z) < apex_tol)
{
z = 1.0 - apex_tol;
y = 0.5 * (1.0 - z);
x = 0.5 * (1.0 - z);
xy(0) = x; xy(1) = y;
}
zmax = std::max(z, zmax);
W = 0.0;
int o = 0;
// Mixed Edges
if (z < 1.0)
{
// (a, b) = (1, 2), c = 0
mu = mu0(z, xy, 2);
E_E(p, nu01(z, xy, 1), nu01_grad_nu01(z, xy, 1), E_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_E_ik(i, k);
}
// (a, b) = (1, 2), c = 1
mu = mu1(z, xy, 2);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_E_ik(i, k);
}
// (a, b) = (2, 1), c = 0
mu = mu0(z, xy, 1);
E_E(p, nu01(z, xy, 2), nu01_grad_nu01(z, xy, 2), E_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_E_ik(i, k);
}
// (a, b) = (2, 1), c = 1
mu = mu1(z, xy, 1);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_E_ik(i, k);
}
}
// Triangle Edges
if (z < 1.0)
{
E_E(p, lam15(x, y, z), lam15_grad_lam15(x, y, z), E_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = E_E_ik(i, k);
}
E_E(p, lam25(x, y, z), lam25_grad_lam25(x, y, z), E_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = E_E_ik(i, k);
}
E_E(p, lam35(x, y, z), lam35_grad_lam35(x, y, z), E_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = E_E_ik(i, k);
}
E_E(p, lam45(x, y, z), lam45_grad_lam45(x, y, z), E_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = E_E_ik(i, k);
}
}
// Quadrilateral Face
if (z < 1.0 && p >= 2)
{
mu = mu0(z);
mu2 = mu * mu;
// Family I
E_Q(p, mu01(z, xy, 1), mu01_grad_mu01(z, xy, 1), mu01(z, xy, 2),
E_Q1_ijk);
for (int j=2; j<=p; j++)
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu2 * E_Q1_ijk(i, j, k);
}
// Family II
E_Q(p, mu01(z, xy, 2), mu01_grad_mu01(z, xy, 2), mu01(z, xy, 1),
E_Q2_ijk);
for (int j=2; j<=p; j++)
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu2 * E_Q2_ijk(i, j, k);
}
}
// Triangular Faces
if (z < 1.0 && p >= 2)
{
// Family I
// (a, b) = (1, 2), c = 0
mu = mu0(z, xy, 2);
E_T(p, nu012(z, xy, 1), nu01_grad_nu01(z, xy, 1), E_T_ijk);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_T_ijk(i, j, k);
}
// (a, b) = (1, 2), c = 1
mu = mu1(z, xy, 2);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_T_ijk(i, j, k);
}
// (a, b) = (2, 1), c = 0
mu = mu0(z, xy, 1);
E_T(p, nu012(z, xy, 2), nu01_grad_nu01(z, xy, 2), E_T_ijk);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_T_ijk(i, j, k);
}
// (a, b) = (2, 1), c = 1
mu = mu1(z, xy, 1);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_T_ijk(i, j, k);
}
// Family II
// (a, b) = (1, 2), c = 0
mu = mu0(z, xy, 2);
E_T(p, nu120(z, xy, 1), nu12_grad_nu12(z, xy, 1), E_T_ijk);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_T_ijk(i, j, k);
}
// (a, b) = (1, 2), c = 1
mu = mu1(z, xy, 2);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_T_ijk(i, j, k);
}
// (a, b) = (2, 1), c = 0
mu = mu0(z, xy, 1);
E_T(p, nu120(z, xy, 2), nu12_grad_nu12(z, xy, 2), E_T_ijk);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_T_ijk(i, j, k);
}
// (a, b) = (2, 1), c = 1
mu = mu1(z, xy, 1);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
for (int k=0; k<3; k++)
{
W(o, k) = mu * E_T_ijk(i, j, k);
}
}
// Interior
if (z < 1.0 && p >= 2)
{
// Family I
phi_Q(p, mu01(z, xy, 1), grad_mu01(z, xy, 1), mu01(z, xy, 2),
grad_mu01(z, xy, 2), phi_Q1_ij, dphi_Q1_ij);
phi_E(p, mu01(z), grad_mu01(z), phi_E_k, dphi_E_k);
for (int k=2; k<=p; k++)
for (int j=2; j<=p; j++)
for (int i=2; i<=p; i++, o++)
for (int l=0; l<3; l++)
W(o, l) = dphi_Q1_ij(i, j, l) * phi_E_k(k) +
phi_Q1_ij(i, j) * dphi_E_k(k, l);
// Family II
mu = mu0(z);
for (int k=2; k<=p; k++)
for (int j=2; j<=p; j++)
for (int i=0; i<p; i++, o++)
for (int l=0; l<3; l++)
{
W(o, l) = mu * E_Q1_ijk(i, j, l) * phi_E_k(k);
}
// Family III
for (int k=2; k<=p; k++)
for (int j=2; j<=p; j++)
for (int i=0; i<p; i++, o++)
for (int l=0; l<3; l++)
{
W(o, l) = mu * E_Q2_ijk(i, j, l) * phi_E_k(k);
}
// Family IV
// Re-using mu from Family II
dmu = grad_mu0(z);
phi_Q(p, mu01(z, xy, 2), mu01(z, xy, 1), phi_Q2_ij);
for (int j=2; j<=p; j++)
for (int i=2; i<=p; i++, o++)
{
const int n = std::max(i,j);
const real_t nmu = n * pow(mu, n-1);
for (int l=0; l<3; l++)
{
W(o, l) = nmu * phi_Q2_ij(i, j) * dmu(l);
}
}
}
}
void ND_FuentesPyramidElement::calcCurlBasis(const int p,
const IntegrationPoint &ip,
DenseMatrix & E_E_ik,
DenseMatrix & dE_E_ik,
DenseTensor & E_Q1_ijk,
DenseTensor & dE_Q1_ijk,
DenseTensor & E_Q2_ijk,
DenseTensor & dE_Q2_ijk,
DenseTensor & E_T_ijk,
DenseTensor & dE_T_ijk,
DenseMatrix & phi_Q2_ij,
DenseTensor & dphi_Q2_ij,
Vector & phi_E_k,
DenseMatrix & dphi_E_k,
DenseMatrix & dW) const
{
real_t x = ip.x;
real_t y = ip.y;
real_t z = ip.z;
Vector xy({x,y}), dmu(3);
Vector dmuxE(3), E(3), dphi(3), muphi(3);
real_t mu, mu2;
if (std::fabs(1.0 - z) < apex_tol)
{
z = 1.0 - apex_tol;
y = 0.5 * (1.0 - z);
x = 0.5 * (1.0 - z);
xy(0) = x; xy(1) = y;
}
zmax = std::max(z, zmax);
dW = 0.0;
int o = 0;
// Mixed Edges
if (z < 1.0)
{
// (a, b) = (1, 2), c = 0
mu = mu0(z, xy, 2);
dmu = grad_mu0(z, xy, 2);
E_E(p, nu01(z, xy, 1), grad_nu01(z, xy, 1), E_E_ik, dE_E_ik);
for (int i=0; i<p; i++, o++)
{
E(0) = E_E_ik(i, 0); E(1) = E_E_ik(i, 1); E(2) = E_E_ik(i, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_E_ik(i, k) + dmuxE(k);
}
}
// (a, b) = (1, 2), c = 1
mu = mu1(z, xy, 2);
dmu = grad_mu1(z, xy, 2);
for (int i=0; i<p; i++, o++)
{
E(0) = E_E_ik(i, 0); E(1) = E_E_ik(i, 1); E(2) = E_E_ik(i, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_E_ik(i, k) + dmuxE(k);
}
}
// (a, b) = (2, 1), c = 0
mu = mu0(z, xy, 1);
dmu = grad_mu0(z, xy, 1);
E_E(p, nu01(z, xy, 2), grad_nu01(z, xy, 2), E_E_ik, dE_E_ik);
for (int i=0; i<p; i++, o++)
{
E(0) = E_E_ik(i, 0); E(1) = E_E_ik(i, 1); E(2) = E_E_ik(i, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_E_ik(i, k) + dmuxE(k);
}
}
// (a, b) = (2, 1), c = 1
mu = mu1(z, xy, 1);
dmu = grad_mu1(z, xy, 1);
for (int i=0; i<p; i++, o++)
{
E(0) = E_E_ik(i, 0); E(1) = E_E_ik(i, 1); E(2) = E_E_ik(i, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_E_ik(i, k) + dmuxE(k);
}
}
}
// Triangle Edges
if (z < 1.0)
{
E_E(p, lam15(x, y, z), grad_lam15(x, y, z), E_E_ik, dE_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
dW(o, k) = dE_E_ik(i, k);
}
E_E(p, lam25(x, y, z), grad_lam25(x, y, z), E_E_ik, dE_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
dW(o, k) = dE_E_ik(i, k);
}
E_E(p, lam35(x, y, z), grad_lam35(x, y, z), E_E_ik, dE_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
dW(o, k) = dE_E_ik(i, k);
}
E_E(p, lam45(x, y, z), grad_lam45(x, y, z), E_E_ik, dE_E_ik);
for (int i=0; i<p; i++, o++)
for (int k=0; k<3; k++)
{
dW(o, k) = dE_E_ik(i, k);
}
}
// Quadrilateral Face
if (z < 1.0 && p >= 2)
{
mu = mu0(z);
mu2 = mu * mu;
dmu = grad_mu0(z);
// Family I
E_Q(p, mu01(z, xy, 1), grad_mu01(z, xy, 1),
mu01(z, xy, 2), grad_mu01(z, xy, 2), E_Q1_ijk, dE_Q1_ijk);
for (int j=2; j<=p; j++)
for (int i=0; i<p; i++, o++)
{
E(0) = E_Q1_ijk(i, j, 0);
E(1) = E_Q1_ijk(i, j, 1);
E(2) = E_Q1_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu2 * dE_Q1_ijk(i, j, k) + 2.0 * mu * dmuxE(k);
}
}
// Family II
E_Q(p, mu01(z, xy, 2), grad_mu01(z, xy, 2),
mu01(z, xy, 1), grad_mu01(z, xy, 1), E_Q2_ijk, dE_Q2_ijk);
for (int j=2; j<=p; j++)
for (int i=0; i<p; i++, o++)
{
E(0) = E_Q2_ijk(i, j, 0);
E(1) = E_Q2_ijk(i, j, 1);
E(2) = E_Q2_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu2 * dE_Q2_ijk(i, j, k) + 2.0 * mu * dmuxE(k);
}
}
}
// Triangular Faces
if (z < 1.0 && p >= 2)
{
// Family I
// (a, b) = (1, 2), c = 0
mu = mu0(z, xy, 2);
dmu = grad_mu0(z, xy, 2);
E_T(p, nu012(z, xy, 1), grad_nu012(z, xy, 1), E_T_ijk, dE_T_ijk);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
{
E(0) = E_T_ijk(i, j, 0);
E(1) = E_T_ijk(i, j, 1);
E(2) = E_T_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_T_ijk(i, j, k) + dmuxE(k);
}
}
// (a, b) = (1, 2), c = 1
mu = mu1(z, xy, 2);
dmu = grad_mu1(z, xy, 2);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
{
E(0) = E_T_ijk(i, j, 0);
E(1) = E_T_ijk(i, j, 1);
E(2) = E_T_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_T_ijk(i, j, k) + dmuxE(k);
}
}
// (a, b) = (2, 1), c = 0
mu = mu0(z, xy, 1);
dmu = grad_mu0(z, xy, 1);
E_T(p, nu012(z, xy, 2), grad_nu012(z, xy, 2), E_T_ijk, dE_T_ijk);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
{
E(0) = E_T_ijk(i, j, 0);
E(1) = E_T_ijk(i, j, 1);
E(2) = E_T_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_T_ijk(i, j, k) + dmuxE(k);
}
}
// (a, b) = (2, 1), c = 1
mu = mu1(z, xy, 1);
dmu = grad_mu1(z, xy, 1);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
{
E(0) = E_T_ijk(i, j, 0);
E(1) = E_T_ijk(i, j, 1);
E(2) = E_T_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_T_ijk(i, j, k) + dmuxE(k);
}
}
// Family II
// (a, b) = (1, 2), c = 0
mu = mu0(z, xy, 2);
dmu = grad_mu0(z, xy, 2);
E_T(p, nu120(z, xy, 1), grad_nu120(z, xy, 1), E_T_ijk, dE_T_ijk);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
{
E(0) = E_T_ijk(i, j, 0);
E(1) = E_T_ijk(i, j, 1);
E(2) = E_T_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_T_ijk(i, j, k) + dmuxE(k);
}
}
// (a, b) = (1, 2), c = 1
mu = mu1(z, xy, 2);
dmu = grad_mu1(z, xy, 2);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
{
E(0) = E_T_ijk(i, j, 0);
E(1) = E_T_ijk(i, j, 1);
E(2) = E_T_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_T_ijk(i, j, k) + dmuxE(k);
}
}
// (a, b) = (2, 1), c = 0
mu = mu0(z, xy, 1);
dmu = grad_mu0(z, xy, 1);
E_T(p, nu120(z, xy, 2), grad_nu120(z, xy, 2), E_T_ijk, dE_T_ijk);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
{
E(0) = E_T_ijk(i, j, 0);
E(1) = E_T_ijk(i, j, 1);
E(2) = E_T_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_T_ijk(i, j, k) + dmuxE(k);
}
}
// (a, b) = (2, 1), c = 1
mu = mu1(z, xy, 1);
dmu = grad_mu1(z, xy, 1);
for (int j=1; j<p; j++)
for (int i=0; i+j<p; i++, o++)
{
E(0) = E_T_ijk(i, j, 0);
E(1) = E_T_ijk(i, j, 1);
E(2) = E_T_ijk(i, j, 2);
dmu.cross3D(E, dmuxE);
for (int k=0; k<3; k++)
{
dW(o, k) = mu * dE_T_ijk(i, j, k) + dmuxE(k);
}
}
}
// Interior
if (z < 1.0 && p >= 2)
{
// Family I
// Curl is zero so skip these functions
o += (p - 1) * (p - 1) * (p - 1);
// Family II
mu = mu0(z);
dmu = grad_mu0(z);
phi_E(p, mu01(z), grad_mu01(z), phi_E_k, dphi_E_k);
for (int k=2; k<=p; k++)
{
dphi(0) = dphi_E_k(k, 0);
dphi(1) = dphi_E_k(k, 1);
dphi(2) = dphi_E_k(k, 2);
add(mu, dphi, phi_E_k(k), dmu, muphi);
for (int j=2; j<=p; j++)
for (int i=0; i<p; i++, o++)
{
E(0) = E_Q1_ijk(i, j, 0);
E(1) = E_Q1_ijk(i, j, 1);
E(2) = E_Q1_ijk(i, j, 2);
muphi.cross3D(E, dmuxE);
for (int l=0; l<3; l++)
{
dW(o, l) = mu * dE_Q1_ijk(i, j, l) * phi_E_k(k) + dmuxE(l);
}
}
}
// Family III
for (int k=2; k<=p; k++)
{
dphi(0) = dphi_E_k(k, 0);
dphi(1) = dphi_E_k(k, 1);
dphi(2) = dphi_E_k(k, 2);
add(mu, dphi, phi_E_k(k), dmu, muphi);
for (int j=2; j<=p; j++)
for (int i=0; i<p; i++, o++)
{
E(0) = E_Q2_ijk(i, j, 0);
E(1) = E_Q2_ijk(i, j, 1);
E(2) = E_Q2_ijk(i, j, 2);
muphi.cross3D(E, dmuxE);
for (int l=0; l<3; l++)
{
dW(o, l) = mu * dE_Q2_ijk(i, j, l) * phi_E_k(k) + dmuxE(l);
}
}
}
// Family IV
// Re-using mu from Family II
dmu = grad_mu0(z);
phi_Q(p, mu01(z, xy, 2), grad_mu01(z, xy, 2), mu01(z, xy, 1),
grad_mu01(z, xy, 1), phi_Q2_ij, dphi_Q2_ij);
for (int j=2; j<=p; j++)
for (int i=2; i<=p; i++, o++)
{
const int n = std::max(i,j);
const real_t nmu = n * pow(mu, n-1);
dphi(0) = dphi_Q2_ij(i, j, 0);
dphi(1) = dphi_Q2_ij(i, j, 1);
dphi(2) = dphi_Q2_ij(i, j, 2);
dphi.cross3D(dmu, muphi);
for (int l=0; l<3; l++)
{
dW(o, l) = nmu * muphi(l);
}
}
}
}
ND_R1D_PointElement::ND_R1D_PointElement(int p)
: VectorFiniteElement(1, Geometry::POINT, 2, p,
H_CURL, FunctionSpace::Pk)
+121
View File
@@ -14,6 +14,7 @@
#include "fe_base.hpp"
#include "fe_h1.hpp"
#include "fe_pyramid.hpp"
namespace mfem
{
@@ -415,6 +416,126 @@ public:
};
/** Arbitrary order H(Curl) basis functions defined on pyramid-shaped elements
This implementation is closely based on the finite elements
described in section 9.2 of the paper "Orientation embedded high
order shape functions for the exact sequence elements of all shapes"
by Federico Fuentes, Brendan Keith, Leszek Demkowicz, and Sriram
Nagaraj, see https://doi.org/10.1016/j.camwa.2015.04.027.
*/
class ND_FuentesPyramidElement
: public VectorFiniteElement, public FuentesPyramid
{
private:
static const real_t tk[27];
mutable real_t zmax;
#ifndef MFEM_THREAD_SAFE
mutable DenseMatrix tmp_E_E_ij;
mutable DenseMatrix tmp_dE_E_ij;
mutable DenseTensor tmp_E_Q1_ijk;
mutable DenseTensor tmp_dE_Q1_ijk;
mutable DenseTensor tmp_E_Q2_ijk;
mutable DenseTensor tmp_dE_Q2_ijk;
mutable DenseTensor tmp_E_T_ijk;
mutable DenseTensor tmp_dE_T_ijk;
mutable DenseMatrix tmp_phi_Q1_ij;
mutable DenseTensor tmp_dphi_Q1_ij;
mutable DenseMatrix tmp_phi_Q2_ij;
mutable DenseTensor tmp_dphi_Q2_ij;
mutable Vector tmp_phi_E_i;
mutable DenseMatrix tmp_dphi_E_i;
mutable DenseMatrix u;
mutable DenseMatrix curlu;
#endif
Array<int> dof2tk;
DenseMatrixInverse Ti;
ND_PyramidDofTransformation doftrans;
void calcBasis(const int p, const IntegrationPoint & ip,
DenseMatrix & E_E_ik,
DenseTensor & E_Q1_ijk,
DenseTensor & E_Q2_ijk,
DenseTensor & E_T_ijk,
DenseMatrix & phi_Q1_ij,
DenseTensor & dphi_Q1_ij,
DenseMatrix & phi_Q2_ij,
Vector & phi_E_k,
DenseMatrix & dphi_E_k,
DenseMatrix & W) const;
void calcCurlBasis(const int p, const IntegrationPoint & ip,
DenseMatrix & E_E_ik,
DenseMatrix & dE_E_ik,
DenseTensor & E_Q1_ijk,
DenseTensor & dE_Q1_ijk,
DenseTensor & E_Q2_ijk,
DenseTensor & dE_Q2_ijk,
DenseTensor & E_T_ijk,
DenseTensor & dE_T_ijk,
DenseMatrix & phi_Q2_ij,
DenseTensor & dphi_Q2_ij,
Vector & phi_E_k,
DenseMatrix & dphi_E_k,
DenseMatrix & dW) const;
public:
ND_FuentesPyramidElement(const int p,
const int cb_type = BasisType::GaussLobatto,
const int ob_type = BasisType::GaussLegendre);
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
{ LocalInterpolation_ND(*this, tk, dof2tk, Trans, I); }
virtual void GetLocalRestriction(ElementTransformation &Trans,
DenseMatrix &R) const
{ LocalRestriction_ND(tk, dof2tk, Trans, R); }
virtual void GetTransferMatrix(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &I) const
{ LocalInterpolation_ND(CheckVectorFE(fe), tk, dof2tk, Trans, I); }
using FiniteElement::Project;
virtual void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
virtual void ProjectMatrixCoefficient(
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
{ ProjectMatrixCoefficient_ND(tk, dof2tk, mc, T, dofs); }
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
DenseMatrix &I) const
{ Project_ND(tk, dof2tk, fe, Trans, I); }
virtual void ProjectGrad(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &grad) const
{ ProjectGrad_ND(tk, dof2tk, fe, Trans, grad); }
virtual void ProjectCurl(const FiniteElement &fe,
ElementTransformation &Trans,
DenseMatrix &curl) const
{ ProjectCurl_ND(tk, dof2tk, fe, Trans, curl); }
void CalcRawVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const;
void CalcRawCurlShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
real_t GetZetaMax() const { return zmax; }
};
/// A 0D Nedelec finite element for the boundary of a 1D domain
/** ND_R1D_PointElement provides a representation of the trace of a three
component Nedelec basis restricted to 1D.
+1 -1
View File
@@ -47,7 +47,7 @@ public:
int GetPatch () const { return patch; }
/// Set which patch should be evaluated
void SetPatch (int p) const { patch = p; }
/// Set which elemenet should be evaluated
/// Set which element should be evaluated
int GetElement () const { return elem; }
/// Get which element is currently considered
void SetElement (int e) const { elem = e; }
+752
View File
@@ -1042,6 +1042,435 @@ void H1Pos_WedgeElement::CalcDShape(const IntegrationPoint &ip,
}
}
H1Pos_PyramidElement::H1Pos_PyramidElement(const int p)
: PositiveFiniteElement(3, Geometry::PYRAMID,
((p + 1)*(p + 2)*(2 * p + 3))/6, p,
FunctionSpace::Uk),
nterms(((p + 1)*(p + 2)*(p + 3)*(p + 4))/24)
{
#ifndef MFEM_THREAD_SAFE
m_shape_1d.SetSize(order + 1);
m_shape.SetSize(nterms);
m_dshape.SetSize(nterms, dim);
#endif
Index idx;
// vertices
dof_map[idx(p,0,0,0,0)] = 0;
Nodes.IntPoint(0).Set3(0., 0., 0.);
dof_map[idx(0,p,0,0,0)] = 1;
Nodes.IntPoint(1).Set3(1., 0., 0.);
dof_map[idx(0,0,p,0,0)] = 2;
Nodes.IntPoint(2).Set3(1., 1., 0.);
dof_map[idx(0,0,0,p,0)] = 3;
Nodes.IntPoint(3).Set3(0., 1., 0.);
dof_map[idx(0,0,0,0,p)] = 4;
Nodes.IntPoint(4).Set3(0., 0., 1.);
// edges (see Geometry::Constants<Geometry::PYRAMID>::Edges
// in fem/geom.cpp)
int o = 5;
for (int i = 1; i < p; i++) // (0,1)
{
dof_map[idx(p-i,i,0,0,0)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, 0., 0.);
}
for (int i = 1; i < p; i++) // (1,2)
{
dof_map[idx(0,p-i,i,0,0)] = o;
Nodes.IntPoint(o++).Set3(1.0, real_t(i)/p, 0.);
}
for (int i = 1; i < p; i++) // (3,2)
{
dof_map[idx(0,0,i,p-i,0)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, 1., 0.);
}
for (int i = 1; i < p; i++) // (0,3)
{
dof_map[idx(p-i,0,0,i,0)] = o;
Nodes.IntPoint(o++).Set3(0., real_t(i)/p, 0.);
}
for (int i = 1; i < p; i++) // (0,4)
{
dof_map[idx(p-i,0,0,0,i)] = o;
Nodes.IntPoint(o++).Set3(0., 0., real_t(i)/p);
}
for (int i = 1; i < p; i++) // (1,4)
{
dof_map[idx(0,p-i,0,0,i)] = o;
Nodes.IntPoint(o++).Set3(real_t(p-i)/p, 0., real_t(i)/p);
}
for (int i = 1; i < p; i++) // (2,4)
{
dof_map[idx(0,0,p-i,0,i)] = o;
Nodes.IntPoint(o++).Set3(real_t(p-i)/p, real_t(p-i)/p, real_t(i)/p);
}
for (int i = 1; i < p; i++) // (3,4)
{
dof_map[idx(0,0,0,p-i,i)] = o;
Nodes.IntPoint(o++).Set3(0., real_t(p-i)/p, real_t(i)/p);
}
// faces (see Geometry::Constants<Geometry::PYRAMID>::FaceVert
// in fem/geom.cpp)
for (int j = 1; j < p; j++)
{
int i1 = j;
int i2 = 0;
int i3 = 0;
int i4 = p - j;
const int i5 = 0;
for (int i = 1; i <= p - j; i++) // (3,2,1,0)
{
i3++;
i4--;
dof_map[idx(i1,i2,i3,i4,i5)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, real_t(p-j)/p, 0);
}
for (int i = p - j + 1; i < p; i++) // (3,2,1,0)
{
i1--;
i2++;
dof_map[idx(i1,i2,i3,i4,i5)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, real_t(p-j)/p, 0);
}
}
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (0, 1, 4)
{
dof_map[idx(p-i-j,i,0,0,j)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, 0., real_t(j)/p);
}
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (1, 2, 4)
{
dof_map[idx(0,p-i-j,i,0,j)] = o;
Nodes.IntPoint(o++).Set3(real_t(p-j)/p, real_t(i)/p, real_t(j)/p);
}
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (2, 3, 4)
{
dof_map[idx(0,0,p-i-j,i,j)] = o;
Nodes.IntPoint(o++).Set3(real_t(p-i-j)/p, real_t(p-j)/p, real_t(j)/p);
}
for (int j = 1; j < p; j++)
for (int i = 1; i + j < p; i++) // (3, 0, 4)
{
dof_map[idx(i,0,0,p-i-j,j)] = o;
Nodes.IntPoint(o++).Set3(0., real_t(p-i-j)/p, real_t(j)/p);
}
// interior
for (int k = 1; k < p; k++)
for (int j = 1; j + k < p; j++)
{
int i1 = p - j - k;
int i2 = 0;
int i3 = 0;
int i4 = j;
const int i5 = k;
for (int i = 1; i <= j; i++)
{
i3++;
i4--;
dof_map[idx(i1,i2,i3,i4,i5)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, real_t(j)/p, 0);
}
for (int i = j + 1; i + k < p; i++)
{
i1--;
i2++;
dof_map[idx(i1,i2,i3,i4,i5)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, real_t(j)/p, 0);
}
}
}
// static method
void H1Pos_PyramidElement::CalcShape(const int p, const real_t x,
const real_t y, const real_t z,
real_t *shape_1d,
real_t *shape)
{
const int lshape = ((p + 1)*(p + 2)*(p + 3)*(p + 4))/24;
for (int i=0; i<lshape; i++) { shape[i] = 0.0; }
const real_t l1 = lam1(x, y, z);
const real_t l2 = lam2(x, y, z);
const real_t l3 = lam3(x, y, z);
const real_t l4 = lam4(x, y, z);
const real_t l5 = lam5(x, y, z);
// The basis functions are the terms in the expansion:
// (l1 + l2 + l3 + l4 + l5)^p =
// \sum_{l=0}^p \binom{p}{l} l5^l
// \sum_{k=0}^{p-l} \binom{p-l}{k} l4^k
// \sum_{j=0}^{p-l-k} \binom{p-l-k}{j} l3^j
// \sum_{i=0}^{p-l-k-j} \binom{p-l-k-j}{i} l2^i l1^{p-l-k-j-i}
Index idx;
const int *bp = Poly_1D::Binom(p);
real_t l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcBinomTerms(p - i5 - i4 - i3, l2, l1, shape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
shape_1d[i2] *= ei345;
shape[o] += shape_1d[i2];
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
}
// static method
void H1Pos_PyramidElement::CalcDShape(const int p, const real_t x,
const real_t y, const real_t z,
real_t *dshape_1d, real_t *dshape)
{
const int nterms = ((p + 1)*(p + 2)*(p + 3)*(p + 4))/24;
for (int i=0; i<3*nterms; i++) { dshape[i] = 0.0; }
const real_t l1 = lam1(x, y, z);
const real_t l2 = lam2(x, y, z);
const real_t l3 = lam3(x, y, z);
const real_t l4 = lam4(x, y, z);
const real_t l5 = lam5(x, y, z);
const Vector dl1 = grad_lam1(x, y, z);
const Vector dl2 = grad_lam2(x, y, z);
const Vector dl3 = grad_lam3(x, y, z);
const Vector dl4 = grad_lam4(x, y, z);
const Vector dl5 = grad_lam5(x, y, z);
// The basis functions are the terms in the expansion:
// (l1 + l2 + l3 + l4 + l5)^p
// We will compute the derivative by first computing the derivatives
// of these terms w.r.t each of the l1, l2, l3, l4, and l5 and summing
// the results together.
Index idx;
// Derivative w.r.t. l1 times grad(l1)
const int *bp = Poly_1D::Binom(p);
real_t l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcDyBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl1 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl1 * dl1[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
// Derivative w.r.t. l2 times grad(l2)
l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcDxBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl2 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl2*dl2[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
// Derivative w.r.t. l3 times grad(l3)
l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 1; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = i3*ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl3 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl3*dl3[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
// Derivative w.r.t. l4 times grad(l4)
l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 1; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = i4*ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl4 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl4*dl4[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
// Derivative w.r.t. l5 times grad(l5)
l5i5 = 1.;
for (int i5 = 1; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = i5*bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl5 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl5*dl5[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
}
void H1Pos_PyramidElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
#ifdef MFEM_THREAD_SAFE
Vector m_shape_1d(order + 1);
Vector m_shape(nterms);
#endif
CalcShape(order, ip.x, ip.y, ip.z, m_shape_1d.GetData(), m_shape.GetData());
for (auto const& it : dof_map)
{
if (it.first < m_shape.Size()) { shape[it.second] = m_shape[it.first]; }
}
}
void H1Pos_PyramidElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
#ifdef MFEM_THREAD_SAFE
Vector m_shape_1d(order + 1);
DenseMatrix m_dshape(nterms, 3);
#endif
CalcDShape(order, ip.x, ip.y, ip.z,
m_shape_1d.GetData(), m_dshape.GetData());
for (auto const& it : dof_map)
for (int d=0; d<3; d++)
{
dshape(it.second, d) = m_dshape(it.first, d);
}
}
L2Pos_SegmentElement::L2Pos_SegmentElement(const int p)
: PositiveTensorFiniteElement(1, p, L2_DOF_MAP)
{
@@ -1448,4 +1877,327 @@ void L2Pos_WedgeElement::CalcDShape(const IntegrationPoint &ip,
}
}
L2Pos_PyramidElement::L2Pos_PyramidElement(const int p)
: PositiveFiniteElement(3, Geometry::PYRAMID,
((p + 1)*(p + 2)*(2 * p + 3))/6, p,
FunctionSpace::Uk),
nterms(((p + 1)*(p + 2)*(p + 3)*(p + 4))/24)
{
#ifndef MFEM_THREAD_SAFE
m_shape_1d.SetSize(order + 1);
m_shape.SetSize(nterms);
m_dshape.SetSize(nterms, dim);
#endif
Index idx;
// interior
for (int o = 0, k = 0; k <= p; k++)
for (int j = 0; j + k <= p; j++)
{
int i1 = p - j - k;
int i2 = 0;
int i3 = -1;
int i4 = j + 1;
const int i5 = k;
for (int i = 0; i <= j; i++)
{
i3++;
i4--;
dof_map[idx(i1,i2,i3,i4,i5)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, real_t(j)/p, 0);
}
for (int i = j + 1; i + k <= p; i++)
{
i1--;
i2++;
dof_map[idx(i1,i2,i3,i4,i5)] = o;
Nodes.IntPoint(o++).Set3(real_t(i)/p, real_t(j)/p, 0);
}
}
}
// static method
void L2Pos_PyramidElement::CalcShape(const int p, const real_t x,
const real_t y, const real_t z,
real_t *shape_1d,
real_t *shape)
{
const int lshape = ((p + 1)*(p + 2)*(p + 3)*(p + 4))/24;
for (int i=0; i<lshape; i++) { shape[i] = 0.0; }
const real_t l1 = lam1(x, y, z);
const real_t l2 = lam2(x, y, z);
const real_t l3 = lam3(x, y, z);
const real_t l4 = lam4(x, y, z);
const real_t l5 = lam5(x, y, z);
// The basis functions are the terms in the expansion:
// (l1 + l2 + l3 + l4 + l5)^p =
// \sum_{l=0}^p \binom{p}{l} l5^l
// \sum_{k=0}^{p-l} \binom{p-l}{k} l4^k
// \sum_{j=0}^{p-l-k} \binom{p-l-k}{j} l3^j
// \sum_{i=0}^{p-l-k-j} \binom{p-l-k-j}{i} l2^i l1^{p-l-k-j-i}
Index idx;
const int *bp = Poly_1D::Binom(p);
real_t l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcBinomTerms(p - i5 - i4 - i3, l2, l1, shape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
shape_1d[i2] *= ei345;
shape[o] += shape_1d[i2];
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
}
// static method
void L2Pos_PyramidElement::CalcDShape(const int p, const real_t x,
const real_t y, const real_t z,
real_t *dshape_1d, real_t *dshape)
{
const int nterms = ((p + 1)*(p + 2)*(p + 3)*(p + 4))/24;
for (int i=0; i<3*nterms; i++) { dshape[i] = 0.0; }
const real_t l1 = lam1(x, y, z);
const real_t l2 = lam2(x, y, z);
const real_t l3 = lam3(x, y, z);
const real_t l4 = lam4(x, y, z);
const real_t l5 = lam5(x, y, z);
const Vector dl1 = grad_lam1(x, y, z);
const Vector dl2 = grad_lam2(x, y, z);
const Vector dl3 = grad_lam3(x, y, z);
const Vector dl4 = grad_lam4(x, y, z);
const Vector dl5 = grad_lam5(x, y, z);
// The basis functions are the terms in the expansion:
// (l1 + l2 + l3 + l4 + l5)^p
// We will compute the derivative by first computing the derivatives
// of these terms w.r.t each of the l1, l2, l3, l4, and l5 and summing
// the results together.
Index idx;
// Derivative w.r.t. l1 times grad(l1)
const int *bp = Poly_1D::Binom(p);
real_t l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcDyBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl1 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl1 * dl1[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
// Derivative w.r.t. l2 times grad(l2)
l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcDxBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl2 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl2*dl2[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
// Derivative w.r.t. l3 times grad(l3)
l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 1; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = i3*ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl3 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl3*dl3[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
// Derivative w.r.t. l4 times grad(l4)
l5i5 = 1.;
for (int i5 = 0; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 1; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = i4*ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl4 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl4*dl4[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
// Derivative w.r.t. l5 times grad(l5)
l5i5 = 1.;
for (int i5 = 1; i5 <= p; i5++)
{
const int *bpi5 = Poly_1D::Binom(p - i5);
const real_t ei5 = i5*bp[i5]*l5i5;
real_t l4i4 = 1.;
for (int i4 = 0; i4 <= p - i5; i4++)
{
const int *bpi45 = Poly_1D::Binom(p - i5 - i4);
const real_t ei45 = ei5*bpi5[i4]*l4i4;
real_t l3i3 = 1.;
for (int i3 = 0; i3 <= p - i5 - i4; i3++)
{
Poly_1D::CalcBinomTerms(p - i5 - i4 - i3, l2, l1, dshape_1d);
real_t ei345 = ei45*bpi45[i3]*l3i3;
for (int i2 = 0; i2 <= p - i5 - i4 - i3; i2++)
{
const int i1 = p - i5 - i4 - i3 - i2;
const int o = idx(i1,i2,i3,i4,i5);
const real_t dshape_dl5 = dshape_1d[i2]*ei345;
for (int d = 0; d < 3; d++)
{
dshape[o + d * nterms] += dshape_dl5*dl5[d];
}
}
l3i3 *= l3;
}
l4i4 *= l4;
}
l5i5 *= l5;
}
}
void L2Pos_PyramidElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
#ifdef MFEM_THREAD_SAFE
Vector m_shape_1d(order + 1);
Vector m_shape(nterms);
#endif
CalcShape(order, ip.x, ip.y, ip.z, m_shape_1d.GetData(), m_shape.GetData());
for (auto const& it : dof_map)
{
if (it.first < m_shape.Size()) { shape[it.second] = m_shape[it.first]; }
}
}
void L2Pos_PyramidElement::CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const
{
#ifdef MFEM_THREAD_SAFE
Vector m_shape_1d(order + 1);
DenseMatrix m_dshape(nterms, 3);
#endif
CalcDShape(order, ip.x, ip.y, ip.z,
m_shape_1d.GetData(), m_dshape.GetData());
for (auto const& it : dof_map)
for (int d=0; d<3; d++)
{
dshape(it.second, d) = m_dshape(it.first, d);
}
}
}
+119
View File
@@ -13,6 +13,7 @@
#define MFEM_FE_POS
#include "fe_base.hpp"
#include "fe_pyramid.hpp"
namespace mfem
{
@@ -256,6 +257,69 @@ public:
};
/// Arbitrary order H1 elements in 3D utilizing the Bernstein basis on a pyramid
///
/// The pyramid affine-related coordinates $\lambda_i$ for $i=1,\ldots,5$ can
/// be used to define a positive H1 basis by noting that $\lambda_i \ge 0$
/// inside the pyramid for all $i$ and that $\sum_{i=1}^5\lambda_i=1$. This
/// leads to $1 = (\sum_{i=1}^5\lambda_i)^p$. The terms of this product,
/// expanded as a polynomial in the $\lambda_i$, can be used as a Bernstein
/// basis of order $p$ on a pyramid.
class H1Pos_PyramidElement : public PositiveFiniteElement, FuentesPyramid
{
protected:
const int nterms;
#ifndef MFEM_THREAD_SAFE
mutable Vector m_shape_1d;
mutable Vector m_shape;
mutable DenseMatrix m_dshape;
#endif
std::map<int,int> dof_map;
struct Index
{
Index() = default;
int operator()(int i1, int i2, int i3, int i4, int i5)
{
const int p = i1 + i2 + i3 + i4 + i5;
const int min24 = std::min(i2,i4);
i1 += min24;
i2 -= min24;
i3 += min24;
i4 -= min24;
return i2 + i3 * (p - i4 - i5) - i4 * i5 * (p + 2)
- ((i3 - 3) * i3) / 2 + i4 * ((p + 1) * (p + 2)) / 2
+ (i4 * i5 * (i4 + i5)) / 2 + ((i4 - 1) * i4 * (i4 +1)) / 6
- (p + 2) * ((i4 - 1) * i4) / 2
+ (i5 * (5 + 2 * p - i5) * (i5 * i5 - i5 * (5 + 2 * p)
+ 2 * (5 + 5 * p + p * p))) / 24;
}
};
public:
/// Construct the H1Pos_PyramidElement of order @a p
H1Pos_PyramidElement(const int p);
// The size of shape is (p+1)(p+2)(p+3)(p+4)/24.
// The size of shape_1d should be at least p+1.
static void CalcShape(const int p, const real_t x, const real_t y,
const real_t z, real_t *shape_1d, real_t *shape);
// The size of dshape is (p+1)(p+2)(p+3)(p+4)/24 by 3.
// The size of dshape_1d should be at least p+1.
static void CalcDShape(const int p, const real_t x, const real_t y,
const real_t z, real_t *dshape_1d, real_t *dshape);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
// Returns (p+1)(p+2)(p+3)(p+4)/24 which is the size of the temporary arrays
// needed above
int GetNumTerms() const { return nterms; }
};
/// Arbitrary order L2 elements in 1D utilizing the Bernstein basis on a segment
class L2Pos_SegmentElement : public PositiveTensorFiniteElement
{
@@ -369,6 +433,61 @@ public:
DenseMatrix &dshape) const override;
};
/// Arbitrary order L2 elements in 3D utilizing the Bernstein basis on a pyramid
class L2Pos_PyramidElement : public PositiveFiniteElement, FuentesPyramid
{
protected:
const int nterms;
#ifndef MFEM_THREAD_SAFE
mutable Vector m_shape_1d;
mutable Vector m_shape;
mutable DenseMatrix m_dshape;
#endif
std::map<int,int> dof_map;
struct Index
{
Index() = default;
int operator()(int i1, int i2, int i3, int i4, int i5)
{
const int p = i1 + i2 + i3 + i4 + i5;
const int min24 = std::min(i2,i4);
i1 += min24;
i2 -= min24;
i3 += min24;
i4 -= min24;
return i2 + i3 * (p - i4 - i5) - i4 * i5 * (p + 2)
- ((i3 - 3) * i3) / 2 + i4 * ((p + 1) * (p + 2)) / 2
+ (i4 * i5 * (i4 + i5)) / 2 + ((i4 - 1) * i4 * (i4 +1)) / 6
- (p + 2) * ((i4 - 1) * i4) / 2
+ (i5 * (5 + 2 * p - i5) * (i5 * i5 - i5 * (5 + 2 * p)
+ 2 * (5 + 5 * p + p * p))) / 24;
}
};
// Returns (p+1)(p+2)(p+3)(p+4)/24 which is the size of the temporary arrays
// needed below
int GetNumTerms() const { return nterms; }
// The size of shape is (p+1)(p+2)(p+3)(p+4)/24.
// The size of shape_1d should be at least p+1.
static void CalcShape(const int p, const real_t x, const real_t y,
const real_t z, real_t *shape_1d, real_t *shape);
// The size of dshape is (p+1)(p+2)(p+3)(p+4)/24 by 3.
// The size of dshape_1d should be at least p+1.
static void CalcDShape(const int p, const real_t x, const real_t y,
const real_t z, real_t *dshape_1d, real_t *dshape);
public:
/// Construct the L2Pos_PyramidElement of order @a p
L2Pos_PyramidElement(const int p);
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
virtual void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const;
};
} // namespace mfem
#endif
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More