Compare commits

...
Author SHA1 Message Date
Chris Vogl 3d3e9919f9 Update examples/sundials/ex16.cpp 2025-11-10 19:24:46 -08:00
Chris Vogl 875430f5d5 found additional instances of 'implicit form' instead of 'mass form' in ARKStepODE, which are now addressed 2025-10-28 10:25:06 -07:00
Chris Vogl 6aba1af158 Fixing comments in ARKStepODE 2025-10-28 09:57:07 -07:00
Chris Vogl ce6b9bd4d8 marked some TDO::SUN methods as deprecated 2025-10-28 09:43:37 -07:00
Chris Vogl cff8552e1a introduced a wrapper to support backward compabilitiy in ARKStepSolver; refactored ARKStepODE to be more specialized 2025-10-28 09:39:57 -07:00
Chris Vogl 5da21c841b reverting changes to TimeDependentOperator (to avoid backwards compability issues) 2025-10-28 07:22:27 -07:00
Chris Vogl de45b67215 extracts ARKStepSolver specific functions from TimeDependentOperator, putting them into a new interface 2025-10-23 23:25:03 -07:00
Tzanio Kolev cd4e583f9f Merge pull request #4659 from mfem/najlkin/parform-impro
Improvements of Par(Mixed)BilinearForm and Par(Block)NonlinearForm
2025-10-18 10:48:44 -07:00
Tzanio Kolev ee94776558 Merge pull request #5066 from mfem/najlkin/fix-nc-blknlform
[BUG] Non-conforming meshes in BlockNonlinearForm
2025-10-18 10:48:25 -07:00
Tzanio Kolev f9be12c539 Merge pull request #5060 from mfem/hypre-cmake
Remove hypre+umpire check in CMake
2025-10-15 16:13:01 -07:00
Tzanio Kolev af478afd00 Merge branch 'master' into najlkin/fix-nc-blknlform 2025-10-15 16:11:05 -07:00
Tzanio Kolev 519e86f134 Merge pull request #5069 from mfem/stale-action-update
Fix duplicated job name in Stale action
2025-10-14 15:47:35 -07:00
Mittal, Ketan f2578fd479 change action name 2025-10-14 09:01:53 -07:00
Tzanio Kolev 563cd25971 Merge pull request #5016 from mfem/stale-action-update
Stale action for PRs in-review
2025-10-12 17:03:19 -07:00
Tzanio Kolev 875c62ca1f Merge pull request #5047 from mfem/fix-magma-inverse
fix magma's Invert
2025-10-12 17:02:42 -07:00
Tzanio Kolev 731b0b7049 Merge pull request #5053 from mfem/mfem-mesh
MFEM mesh
2025-10-12 17:00:40 -07:00
Tzanio Kolev 3c77ad25e9 Merge pull request #4524 from adam-sim-dev/cusparseXcsrsort
Use cusparseXcsrsort instead of the deprecated cusparseXcsru2csr
2025-10-12 16:58:01 -07:00
Jan Nikl e13d1a1d53 Fixed support of non-conforming meshes in BlockNonlinearForm. 2025-10-10 13:32:53 -07:00
Victor A. P. Magri 09e73b5cee Remove check 2025-10-09 17:11:13 -04:00
Victor A. P. Magri 464b441409 Remove check 2025-10-09 17:10:09 -04:00
Andrew Ho 8ae9b217f9 Use CUDA_DIR instead of CUDA_HOME 2025-10-09 13:51:57 -07:00
Victor A. P. Magri 3f0a5ad501 Add check for HYPRE_USING_UMPIRE 2025-10-09 12:49:42 -04:00
Ketan Mittal dfb697b9ae Merge branch 'master' into stale-action-update 2025-10-07 17:15:22 -07:00
Will PaznerandAndrew Ho cf01c6cc8b Add -isystem to NVCC_FLAGS
This will silence compiler warnings that are internal to CUDA headers

Co-authored-by: Andrew Ho <ho37@llnl.gov>
2025-10-07 16:21:27 -07:00
Will Pazner e4dc9a3941 Small change to indentation style 2025-10-07 16:20:06 -07:00
Andrew Ho 6a104e94e1 Merge branch 'master' into cusparseXcsrsort 2025-10-07 15:00:06 -07:00
Tzanio Kolev bf1b25d82e Merge pull request #4567 from mfem/lorentz-pm-dev
Lorentz miniapp [lorentz-pm-dev]
2025-10-07 13:22:38 -07:00
Jan Nikl b7a0b2cf9a Renamed ParallelAssembleInternal(Matrix) and added more documentation. 2025-10-07 12:28:31 -07:00
Will Pazner 9a8f0ad0ef Merge pull request #5048 from farscape-project/checkopen
Add ClosedGL to Quadrature1D::CheckOpen and remove redundant conditions
2025-10-07 11:57:06 -07:00
Will Pazner ee2c069531 Merge pull request #5015 from mfem/bugfix/watts24/int-overflow-reading-large-VTU-mesh
Avoid int overflow for large VTU meshes
2025-10-07 11:32:37 -07:00
nbeams 27a60a4ca3 Change name of output variable in batched inverse unit test 2025-10-06 22:20:10 +00:00
nbeams b1d5104fed Add unit test for batched matrix inverse 2025-10-06 21:50:54 +00:00
Tzanio Kolev 26eecf7575 Merge branch 'master' into cusparseXcsrsort 2025-10-05 13:32:37 -07:00
Tzanio Kolev 9c26ef5401 Merge branch 'master' into lorentz-pm-dev 2025-10-05 13:27:39 -07:00
Tzanio Kolev bce6e2ca76 Merge branch 'master' into najlkin/parform-impro 2025-10-05 13:25:11 -07:00
Tzanio Kolev 26f8f0e955 Merge branch 'master' into fix-magma-inverse 2025-10-05 13:20:43 -07:00
Tzanio Kolev dfc2dfeb52 Merge pull request #4975 from mfem/hypre-3
Add support to hypre-3.0
2025-10-02 11:14:03 -07:00
Tzanio Kolev 7173477670 Merge pull request #5013 from mfem/fix-miniapps-common-clang-cuda
Fix the `miniapps/common` build when using clang + CUDA
2025-10-02 11:13:30 -07:00
Mittal, Ketan 30249a4857 minor 2025-10-01 14:37:32 -07:00
Mittal, Ketan 8a9bdf863a minor 2025-10-01 14:34:29 -07:00
Mittal, Ketan b72368c698 add mesh and modify distance miniapp to use the new mesh 2025-10-01 14:30:22 -07:00
adam-sim-dev e6224e00aa Merge branch 'master' into cusparseXcsrsort 2025-09-30 10:09:49 +08:00
adam-sim-dev 7b82f7b8e0 Merge branch 'master' into hypre-3 2025-09-30 10:03:05 +08:00
Nuno Nobre 582ffe8b66 Add ClosedGL to Quadrature1D::CheckOpen and remove redundant conditions 2025-09-29 17:23:47 +01:00
Tom Stitt aa5b2d4b95 wrong arg 2025-09-29 09:04:33 -07:00
Tzanio Kolev 23616a21f0 Merge pull request #4999 from mfem/feat/blknonlin_esstdof
Add `SetEssentialTrueDofs` to `(Par)BlockNonlinearForm`
2025-09-29 08:07:08 -07:00
Tzanio Kolev df9cc72e58 Merge pull request #5036 from BarrySmith/barry/update-for-petscapi
Update to change in PETSc API (in v3.24)  for MatShellSetOperation()
2025-09-29 08:06:39 -07:00
Tzanio Kolev 15740fcbd3 Merge branch 'master' into hypre-3 2025-09-28 18:26:28 -07:00
Victor A. P. Magri 862c539276 Fix header files inclusion 2025-09-28 19:38:44 -04:00
Tzanio Kolev 7ff759a7ee Merge pull request #4834 from mfem/lor_dg_preconditioner
GPU Assembly of LOR DG Preconditioner
2025-09-27 15:42:50 -07:00
Tzanio Kolev d220a2975c Merge branch 'master' into feat/blknonlin_esstdof 2025-09-27 15:29:32 -07:00
Tzanio Kolev cdde0046ef Merge branch 'master' into fix-miniapps-common-clang-cuda 2025-09-27 15:25:57 -07:00
Sohail Reddy 9f36ae566c fixed style 2025-09-26 17:09:35 -07:00
Victor A. P. Magri 4465fcbd46 Remove debugging call 2025-09-26 12:34:18 -04:00
Victor A. P. Magri 807b13b236 Fix release tag 2025-09-26 12:34:18 -04:00
Victor A. P. Magri 70f4468f0b Remove old header files inclusion 2025-09-26 12:34:18 -04:00
Victor A. P. Magri 5db2e7b347 HYPRE_VERSION fix 2025-09-26 12:34:18 -04:00
Victor A. P. Magri c1df332094 Update hypre's cmake module with Umpire logic 2025-09-26 12:34:18 -04:00
Victor A. P. Magri 75b115cf93 Silence deprecation error involving HYPRE_AssumedPartitionCheck 2025-09-26 12:34:18 -04:00
Victor A. P. Magri 59579f2cdb Fix build with upcoming hypre-3.0 2025-09-26 12:34:18 -04:00
John Camier c0d2821d3e Merge branch 'master' into lor_dg_preconditioner 2025-09-25 15:58:44 -07:00
Tzanio Kolev 082e25ffe8 Merge pull request #4561 from helloworld922/cmake_improvements
CMake improvements
2025-09-25 10:30:26 -07:00
Stowell, Mark L. 7d343e56a5 Switching to +/-infinity() for initial bounds 2025-09-25 10:06:02 -07:00
adam-sim-dev 1eb3d185d5 Merge branch 'master' into cusparseXcsrsort 2025-09-25 09:06:24 +08:00
Dohyun Kim a2fd029daa non-null instead of NULL or nullptr 2025-09-24 15:01:15 -04:00
Dohyun Kim b48b990ac8 "NOT" null! 2025-09-24 14:49:47 -04:00
Dohyun Kim 80c69e9856 style 2025-09-24 14:27:40 -04:00
Anthony dbdee73113 Merge branch 'master' into lor_dg_preconditioner 2025-09-24 18:18:16 +00:00
AnthonyandJohn Camier 7a8a1976a2 Update tests/unit/linalg/test_same_matrices.hpp
Co-authored-by: John Camier <camierjs@gmail.com>
2025-09-24 18:10:44 +00:00
AnthonyandJohn Camier 6911ed0a8a Update tests/unit/fem/test_lor_dg.cpp
Co-authored-by: John Camier <camierjs@gmail.com>
2025-09-24 18:10:31 +00:00
AnthonyandJohn Camier 986e2c04d2 Update tests/unit/fem/test_lor_dg.cpp
Co-authored-by: John Camier <camierjs@gmail.com>
2025-09-24 18:10:21 +00:00
AnthonyandJohn Camier 9db5388362 Update fem/lor/lor_dg_impl.hpp
Co-authored-by: John Camier <camierjs@gmail.com>
2025-09-24 18:10:06 +00:00
Stowell, Mark L. dbf987fb73 Updating doxygen file 2025-09-24 10:57:11 -07:00
Stowell, Mark L. c4a6d855eb Updating CHANGELOG 2025-09-24 10:44:27 -07:00
Dohyun Kim 80c2ee6fed documentation 2025-09-23 22:36:22 -04:00
Tzanio Kolev 68aa9af7c2 Merge pull request #5028 from mfem/indent-off-fix
Added a missing INDENT-ON
2025-09-23 18:47:40 -07:00
Stowell, Mark L. 19fa34eabe Adding data file to gitignore 2025-09-23 16:23:21 -07:00
Tzanio Kolev 359ba5983b Merge branch 'master' into indent-off-fix 2025-09-23 15:48:56 -07:00
Tzanio Kolev 947f2f215a Make style 2025-09-23 14:46:07 -07:00
Veselin Dobrev 52ced84b8c Merge pull request #4931 from mfem/kernel-spec
Kernel Specializations
2025-09-23 14:36:11 -07:00
Veselin Dobrev 6430c45f52 Merge pull request #4609 from mfem/jeremy/ceed-fix
libCEED v1.0 preparation
2025-09-23 14:30:47 -07:00
Tzanio Kolev 6d3c7dfc88 Added a missing INDENT-ON 2025-09-23 14:30:35 -07:00
Stowell, Mark L. 0e2d49799c Updating copyright 2025-09-23 14:18:15 -07:00
Stowell, Mark L. 562b980e7d Merge remote-tracking branch 'origin/master' into lorentz-pm-dev
# Conflicts:
#	.gitignore
2025-09-23 14:14:43 -07:00
Will Pazner 388b7b61b2 Merge pull request #4945 from mfem/grad-eval-device
Add new method: `GridFunction::GetGradients` with support for GPUs
2025-09-23 11:31:34 -07:00
Stowell, Mark L. 2adb4576d3 Sample runs on single lines 2025-09-23 09:15:19 -07:00
Stowell, Mark L. 9f2490cd95 Build trajectory mesh in a function 2025-09-23 09:14:30 -07:00
Barry Smith 4126d32772 Update to change in PETSc API for MatShellSetOperation() 2025-09-22 11:24:29 -04:00
Andrew HoandJohn Camier 080780f047 Update CMakeLists.txt
Co-authored-by: John Camier <camierjs@gmail.com>
2025-09-21 22:37:18 -07:00
camierjs ca2ee9ab05 Merge branch 'master' into lor_dg_preconditioner 2025-09-21 20:15:26 -07:00
John Camier 0d87692863 Merge branch 'master' into cmake_improvements 2025-09-21 20:14:01 -07:00
John Camier 450628554c Merge branch 'master' into kernel-spec 2025-09-21 20:13:38 -07:00
adam-sim-dev 7bc231eb85 Merge branch 'master' into cusparseXcsrsort 2025-09-22 10:31:53 +08:00
Tzanio Kolev 6de39a2637 Merge pull request #3807 from mfem/nurbs-nc
Nonconforming NURBS patches
2025-09-21 15:51:51 -07:00
Tzanio Kolev c4a19c8df0 Merge pull request #4938 from mfem/lininteg-spec
Change more integrators to use kernel dispatch
2025-09-21 15:50:42 -07:00
Tzanio Kolev 280e98b510 Merge pull request #5002 from farscape-project/metis
Fix fetched METIS builds w/ gcc 14+
2025-09-21 15:50:20 -07:00
John Camier 9794243c8b Merge branch 'master' into cmake_improvements 2025-09-21 10:35:54 -07:00
John Camier 333726ce51 Merge branch 'master' into kernel-spec 2025-09-21 10:26:59 -07:00
John Camier d14d286842 Merge branch 'master' into lininteg-spec 2025-09-21 10:26:50 -07:00
John Camier ea3bed0a91 Merge branch 'master' into lor_dg_preconditioner 2025-09-19 07:41:30 -07:00
Toni-ko 877937b8ae resolve conflict 2025-09-18 10:42:35 -07:00
Will Pazner 1e2b33e21c Merge remote-tracking branch 'origin/master' into grad-eval-device
# Conflicts:
#	tests/unit/CMakeLists.txt
2025-09-17 21:35:40 -04:00
Will Pazner f65311b8a0 Merge pull request #5006 from mfem/fix-magma-addmult
Fix transpose op selection in magma addmult
2025-09-17 21:32:11 -04:00
Will Pazner 1254e8782e Merge pull request #4801 from tepperly/improve-mma-doxygen-comments
Format the comments for better doxygen rendering and add more details
2025-09-17 21:30:49 -04:00
Andrew Ho b50d546dac Merge branch 'master' into cmake_improvements 2025-09-17 10:49:22 -07:00
Mittal, Ketan fd01ef188f Merge branch 'stale-action-update' of https://github.com/mfem/mfem into stale-action-update 2025-09-17 10:14:48 -07:00
Mittal, Ketan f2a29326c0 Merge branch 'master' of https://github.com/mfem/mfem into stale-action-update 2025-09-17 10:14:35 -07:00
Mittal, Ketan 1f4a40d9a0 stale action for wip PRs 2025-09-17 10:14:26 -07:00
Dylan Copeland db003bdf86 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-09-17 09:47:43 -07:00
Andrew Ho 8f8e5712ad Merge branch 'master' into lininteg-spec 2025-09-17 07:54:30 -07:00
Tzanio Kolev e671fa5737 Merge branch 'master' into stale-action-update 2025-09-17 03:32:29 -07:00
Tzanio Kolev 40d1550fd6 Merge branch 'master' into najlkin/parform-impro 2025-09-17 03:31:41 -07:00
Tzanio Kolev ae33f831eb Merge branch 'master' into cusparseXcsrsort 2025-09-17 03:28:05 -07:00
Tzanio Kolev 2139999a06 Merge pull request #4958 from mfem/pwconst-coeff-gpu
Add GPU support for PWConstCoefficient
2025-09-17 03:00:04 -07:00
Tzanio Kolev df7f786c7f Merge pull request #4947 from mfem/qfspace-device
Trace assembly optimizations
2025-09-17 02:59:28 -07:00
Veselin Dobrev 79859679fd Merge pull request #5020 from mfem/tmop-ad-mu55-fix
Github CI fix for metric 55
2025-09-16 17:50:16 -07:00
Jan Nikl 193f8a6801 Partially reverted const modifiers in HypreParMatrix::Copy(Bool)CSR(). 2025-09-16 16:19:03 -07:00
Jan Nikl 110720dd04 Fixed documentation of Par(Mixed)BilinearForm::KeepNbrBlock(). 2025-09-16 15:39:35 -07:00
Jan Nikl 3fd335c77b Fixed usage of EliminateVDofsInRHS(). 2025-09-16 15:36:04 -07:00
Tzanio Kolev c0a133fe2c Merge branch 'master' into fix-magma-addmult 2025-09-16 12:30:13 -07:00
Tzanio Kolev 1ffb08db61 Merge branch 'master' into improve-mma-doxygen-comments 2025-09-16 12:30:10 -07:00
Mittal, Ketan 3c0a73479a fix mu55 2025-09-16 09:36:08 -07:00
Ketan Mittal 90e1f08bc7 Merge branch 'master' into stale-action-update 2025-09-15 17:14:09 -07:00
Tzanio Kolev eec906c43d Merge pull request #4836 from mfem/tmop-ad-wcuo
AD for TMOP_WorstCaseUntangleOptimizer_Metric
2025-09-14 20:04:12 -07:00
Tzanio Kolev ea8d19ccf1 Merge pull request #4907 from mfem/najlkin/fix-hyperbolic-bdr
Boundary integration in the hyperbolic framework
2025-09-14 20:03:10 -07:00
Tzanio Kolev def68ccace Merge branch 'master' into najlkin/fix-hyperbolic-bdr 2025-09-14 20:02:54 -07:00
Jan Nikl 3962449ece Updated CHANGELOG. 2025-09-12 22:34:15 -07:00
Mittal, Ketan 37d004206a minor 2025-09-12 11:09:22 -07:00
Mittal, Ketan e1d9b7cfff stale in-review prs 2025-09-12 11:05:00 -07:00
Seth Watts d1c44a7369 Switch my uLongf to size_t since they do not touch zlib 2025-09-12 07:05:04 -07:00
Seth Watts 2c39547bdd Change ints to uLongf (unsigned long) in places where large meshes cause overflow 2025-09-11 17:43:42 -07:00
Veselin Dobrev db66a4423f Export XLINKER as MFEM_XLINKER to config.mk and use that value
instead of reconstructing its value by importing defaults.mk.
2025-09-09 22:47:17 -07:00
Will Pazner 8425377bd1 Rename MFEM_REAL_T to MFEM_CUDA_or_HIP_REAL_T 2025-09-09 16:47:35 -07:00
Veselin Dobrev ea76f8d477 Fix the miniapps/common build when using clang + CUDA 2025-09-09 10:21:55 -07:00
adam-sim-dev 992c5dfc4c Merge branch 'master' into cusparseXcsrsort 2025-09-09 09:28:10 +08:00
Andrew Ho e6826dda5a Merge branch 'master' into qfspace-device 2025-09-08 12:53:41 -07:00
Andrew Ho c4c14822ba Merge remote-tracking branch 'base/qfspace-device' into qfspace-device 2025-09-08 12:53:16 -07:00
Andrew Ho 8f21f70baf added a work-around for std::inclusive/exclusive_scan not present in some c++17 implementations
Also fixed hip builds for scan
2025-09-08 12:51:40 -07:00
Andrew Ho f0027c2ccd Merge branch 'master' into kernel-spec 2025-09-08 12:09:05 -07:00
Andrew Ho 142b1ec60a better fix is to not do abort in else case 2025-09-08 12:08:14 -07:00
Andrew Ho 77f1682547 work-around for compiler warning bug 2025-09-08 12:05:38 -07:00
Tzanio Kolev 0c4c006ef8 Merge pull request #4968 from mfem/najlkin/fix-rt-clone
[BUG] Fixed cloning of RT trace and DG interface FE collections
2025-09-06 12:42:55 -07:00
Tzanio Kolev dd2c68fc72 Merge pull request #4906 from mfem/hex-ref-check
Anisotropic hexahedral refinement without conflicts
2025-09-06 12:42:17 -07:00
Dylan Copeland 6dc6a38ed8 CHANGELOG 2025-09-05 14:50:40 -07:00
Tzanio Kolev 95b3915b52 Merge branch 'master' into tmop-ad-wcuo 2025-09-05 13:35:22 -07:00
Tzanio KolevandTom Epperly bebd0ff8ff Apply suggestion from @tepperly
Co-authored-by: Tom Epperly <epperly2@llnl.gov>
2025-09-05 13:27:23 -07:00
Tzanio Kolev c851e2ec1e Merge branch 'master' into hex-ref-check 2025-09-05 13:01:39 -07:00
Tzanio Kolev 3463dcec04 Merge branch 'master' into qfspace-device 2025-09-05 13:01:35 -07:00
Tzanio Kolev 6ccb7dea8a Merge branch 'master' into nurbs-nc 2025-09-05 13:01:23 -07:00
Tzanio Kolev bf82f4ce39 Merge pull request #4950 from mfem/dfem-lvector-interface
dFEM L-Vector interface
2025-09-05 13:00:15 -07:00
Tzanio Kolev 4fdb3621f5 Merge pull request #4819 from mfem/findpts-interface
Improved FindPointsGSLIB interface
2025-09-05 12:58:35 -07:00
Tzanio Kolev 6e575c4e1f Merge pull request #4980 from mfem/fdpts-improve-dev
Minor improvements to `FindPointsGSLIB`
2025-09-05 12:57:29 -07:00
Tzanio Kolev 79d1f22ebb Merge pull request #4985 from mfem/mem-manager-debug-tweak
Memory manager: debug-mode tweak
2025-09-05 12:56:54 -07:00
Jan Nikl 3207b8b012 Fixed inheritance of AssembleRHSElementVect in BoundaryHyperbolicFlowIntegrator. 2025-09-05 10:18:04 -07:00
Veselin Dobrev cd377f5201 Merge pull request #4937 from mfem/fec-new-fix
bugfix for 4935
2025-09-04 12:19:26 -07:00
Tom Stitt 4f35f73c69 fix tranpose selection 2025-09-03 18:58:39 -07:00
Nuno Nobre 97ac0c3a3e Fix fetched METIS builds w/ gcc 14+ 2025-09-03 13:02:44 +01:00
Andrew Ho 8af7877b68 Merge branch 'qfspace-device' into pwconst-coeff-gpu 2025-09-02 16:15:03 -07:00
John Camier 6cdc6cd026 Merge branch 'master' into lininteg-spec 2025-09-02 15:04:32 -07:00
John Camier 13dc17123d Merge branch 'master' into kernel-spec 2025-09-02 15:00:57 -07:00
Jan Nikl 95327ad4c3 Removed scalar coefficient from BdrHyperbolicDirichletIntegrator. 2025-09-01 14:30:36 -07:00
Jan Nikl a186b57213 Added upwinding to BoundaryHyperbolicLFIntegrator and renamed it to BoundaryHyperbolicFlowIntegrator. 2025-09-01 14:17:08 -07:00
Jan Nikl 0c4d26917b Removed scalar coefficient option from BoundaryHyperbolicLFIntegrator. 2025-09-01 13:20:09 -07:00
Andrew Ho fdc9d7f80e Merge branch 'master' into pwconst-coeff-gpu 2025-08-31 18:06:43 -07:00
adam-sim-dev ec94332c2a Merge branch 'master' into cusparseXcsrsort 2025-09-01 07:35:11 +08:00
Tzanio Kolev 21dc66a447 Merge branch 'master' into najlkin/fix-hyperbolic-bdr 2025-08-31 15:42:09 -07:00
Tzanio Kolev c4c67b141a Merge branch 'master' into qfspace-device 2025-08-31 15:34:48 -07:00
Veselin Dobrev c6329b292e Fix "Specialization<...>::Add()" issue with shared MSVC builds.
Fix some warnings from MSVC.
2025-08-31 09:48:16 -07:00
Tzanio Kolev 5d4bf08ccf Merge branch 'master' into findpts-interface 2025-08-30 18:38:08 -07:00
Tzanio Kolev 0196b7df4a Merge branch 'master' into mem-manager-debug-tweak 2025-08-30 18:31:56 -07:00
Dohyun Kim 5e75bd0837 Merge branch 'master' into feat/blknonlin_esstdof 2025-08-30 07:27:00 +09:00
Dohyun Kim 5f889293c2 style 2025-08-29 18:02:44 -04:00
Dohyun Kim afc5aa96dc GetGradient() returns BlockOperator 2025-08-29 18:00:16 -04:00
Tom Epperly 9b1d29a762 Merge branch 'improve-mma-doxygen-comments' of github.com:tepperly/mfem into improve-mma-doxygen-comments 2025-08-29 14:47:34 -07:00
Tom Epperly b4120d81e4 * Edit comments to avoid lines longer than 80 columns.
* Replace with returns with retains which is what I meant in the first place.
2025-08-29 14:45:36 -07:00
Dohyun Kim 9125bf8291 add SetEssentialTrueDofs 2025-08-29 17:32:48 -04:00
Veselin Dobrev 9d285278f9 In test_col_lag_der.cpp, include mfem.hpp before other headers like
catch.hpp, so that we get the math macros like M_PI under MSVC.
2025-08-29 11:58:49 -07:00
Dylan Copeland b435fbeae6 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-08-29 10:58:34 -07:00
Dylan Copeland b593405fda Merge branch 'master' of github.com:mfem/mfem into hex-ref-check 2025-08-29 10:56:55 -07:00
Veselin Dobrev 5c356a3e2b Merge branch 'master' into grad-eval-device 2025-08-29 08:20:59 -07:00
Veselin Dobrev 2d57401575 Enzyme/LLVM fixes in GitHub CI (#4997)
* Update GitHub CI to handle Enzyme/LLVM changes in Homebrew.

* GitHub CI: try to allow the Enzyme job to fail

* GitHub CI: fix a typo in last commit

* GitHub CI: another try to allow the Enzyme job to fail.

* GitHub CI: another try to allow the Enzyme job to fail.

* GitHub CI: another try to allow the Enzyme job to fail.

* GitHub CI: another try to allow the Enzyme job to fail.

* GitHub CI: try without fail-fast == false.

* GitHub CI: try to fix the LLVM link issue in the Enzyme job.
2025-08-29 08:16:41 -07:00
Veselin Dobrev 9e764dc809 Address reviewer feedback 2025-08-29 03:29:57 -07:00
Veselin Dobrev b7bddf91bc Merge branch 'master' into grad-eval-device 2025-08-28 04:13:05 -07:00
Veselin Dobrev bdbd234c56 Add unit tests for GridFunction::GetGradients.
Update the CMake file for the unit tests.

Update CHANGELOG.
2025-08-28 04:10:32 -07:00
Jan Nikl 513fbe0a28 Added docstring about interior interface usage. 2025-08-27 18:53:20 -07:00
Jan Nikl d4a5f69b52 Minor comment fixes. 2025-08-27 18:47:02 -07:00
Jan Nikl 770aa5bf52 Renamed BdrHyperbolicFormIntegrator to BdrHyperbolicDirichletIntegrator. 2025-08-27 18:35:42 -07:00
Jan Nikl cc2739ef78 make style 2025-08-27 15:41:37 -07:00
Jan NiklandChris Vogl 9351fb1550 Applied suggestions from Chris
Co-authored-by: Chris Vogl <vogl2@llnl.gov>
2025-08-28 11:31:55 -07:00
Vladimir Tomov d6d94117f8 Add null check before freeing finder data
Could segfault with an empty object.
2025-08-27 10:58:12 -07:00
Andrew Ho a7ad5add62 Merge branch 'master' into qfspace-device 2025-08-26 14:41:51 -07:00
Veselin Dobrev a26ef22a49 Merge branch 'master' into jeremy/ceed-fix 2025-08-26 12:21:59 -07:00
Veselin Dobrev 7f788e83b9 Merge pull request #4926 from mfem/dev/docs-add
Add description to GetElementTransformation
2025-08-26 12:16:19 -07:00
Sohail Reddy 1d8952297f Merge branch 'master' into dfem-lvector-interface 2025-08-25 17:24:44 -07:00
Sohail Reddy f5af06ecee combined if-blocks in DifferentiableOperator::Mult() 2025-08-25 16:02:53 -07:00
John Camier c7b9cc6354 Merge branch 'master' into mem-manager-debug-tweak 2025-08-25 08:54:31 -07:00
Joseph Signorelli 68bf2adbe4 int --> unsigned int, and rm std::move 2025-08-21 15:55:23 -07:00
Andrew Ho 1f89bfa040 Merge branch 'master' into cmake_improvements 2025-08-21 14:40:29 -07:00
Dylan Copeland d47695436a Merge branch 'master' of github.com:mfem/mfem into hex-ref-check 2025-08-21 13:11:55 -07:00
Andrew Ho 7284a6c4f9 remove BilinearFormIntegrator::Update
no longer needed now that FaceQuadratureSpace can be efficiently compressed
2025-08-21 13:04:41 -07:00
Andrew Ho 46d05c44a0 review suggestions 2025-08-21 11:16:13 -07:00
Andrew Ho a107678f13 Merge branch 'master' into qfspace-device 2025-08-21 10:31:19 -07:00
Andrew Ho 3dc4463c56 Merge branch 'master' into kernel-spec 2025-08-21 10:26:22 -07:00
Andrew Ho 0b79aa138c Merge branch 'master' into lininteg-spec 2025-08-21 10:25:35 -07:00
Dylan Copeland c76acb2a7b Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-08-20 10:41:06 -07:00
Veselin Dobrev 7b7f77379e Merge branch 'master' into fec-new-fix 2025-08-19 16:54:27 -07:00
Jan Nikl 2b0c1cd199 Merge branch 'master' into najlkin/fix-hyperbolic-bdr 2025-08-19 16:33:34 -07:00
Will Pazner f0cb31088c Merge pull request #4989 from mfem/update-ci-mac
Update Xcode version in macos CI from 15.3 -> 16.4
2025-08-19 16:32:39 -07:00
Jan Nikl b4793a0bd7 Merge branch 'master' into najlkin/fix-hyperbolic-bdr 2025-08-19 16:11:35 -07:00
Andrew Ho 41cccee855 Merge branch 'master' into fec-new-fix 2025-08-19 15:17:23 -07:00
Jeremy L Thompson 8fb8b77b3d Revert "libceed - use /gpu/cuda for tests by default, which is /gpu/cuda/gen, falls back if needed automatically"
This reverts commit c3dcf554df.
2025-08-19 15:47:23 -06:00
Justin Laughlin f407ca7756 Xcode 16.4 2025-08-19 13:58:39 -07:00
Justin Laughlin ab00472c5d Try removing xcode version specification 2025-08-19 13:46:38 -07:00
Justin Laughlin c4a3d31289 Update Xcode version in macos CI from 15.3 -> 16.4 2025-08-19 13:38:07 -07:00
Dylan Copeland 8f6626aede Added MFEMData unit tests for large meshes. 2025-08-19 13:36:02 -07:00
Jan Nikl e3beb0370e Added BdrHyperbolicFormIntegrator. 2025-08-18 23:07:34 -07:00
Andrew Ho fab955250a Merge branch 'master' into qfspace-device 2025-08-18 15:52:07 -07:00
Jeremy L Thompson c3dcf554df libceed - use /gpu/cuda for tests by default, which is /gpu/cuda/gen, falls back if needed automatically 2025-08-18 14:09:36 -06:00
Jeremy L Thompson 8f52ddcf6f upadte INSTALL to note libCEED 0.12 still supported 2025-08-18 10:24:55 -06:00
Dylan Copeland 696ce1e8ed Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-08-17 11:28:40 -07:00
Dylan Copeland 87c6d3a370 Renamed Nonconforming -> NonconformingPatches. Removed unused code. 2025-08-17 11:28:11 -07:00
Tzanio Kolev 20e77be88a Merge pull request #4987 from mfem/gitlab-ci--ruby-to-dane
Move Gitlab CI from Ruby to Dane
2025-08-16 16:01:21 -07:00
Veselin Dobrev 8f2b4bb539 Add a "parallel libCEED example" test to cover more libCEED related code. 2025-08-16 15:41:26 -07:00
Andrew Ho d70b99c4f3 Merge branch 'master' into fec-new-fix 2025-08-16 00:29:08 -07:00
Veselin Dobrev 97a568af13 Move Gitlab CI from Ruby to Dane 2025-08-15 21:27:43 -07:00
Joseph Signorelli 550df43d5e Delete copy ctor + assign, closes #4930 2025-08-15 15:39:55 -07:00
Veselin Dobrev ad993a8b27 In MemoryManager::Insert, when re-registering a pointer, update the check
for the same attributes to allow another valid case that was previously
reported (in debug mode) as an error.
2025-08-15 14:01:48 -07:00
Jeremy L Thompson 6c032cb7cf astyle fixes 2025-08-15 09:09:50 -06:00
Jeremy L Thompson 8104dd3f04 update v0.13 guards - note: will have astyle fixes needed 2025-08-15 09:09:50 -06:00
Jed Brown bdd8696d22 ceed: support 0.12 and 1.0 2025-08-15 09:09:50 -06:00
Jeremy L Thompson 032fb568be libceed - v1.0 updates 2025-08-15 09:09:50 -06:00
Tzanio Kolev cd2715680f Merge pull request #4725 from mfem/qspace-device
Bilinear Operator Assembly optimizations
2025-08-15 07:22:53 -07:00
Tzanio Kolev 62997e9dc7 Merge pull request #4928 from mfem/mpi-dfem-fix
change MPI_INT to MFEM_MPI_SIZE_T
2025-08-15 07:22:37 -07:00
Joseph Signorelli 86405d95a2 Add GetPointsNotFoundIndices 2025-08-13 15:05:11 -07:00
Joseph Signorelli a36151569f Add check to ensure mesh dimension + spatial dimension are equal 2025-08-13 14:59:22 -07:00
Mittal, Ketan e0cb9ebe3b add mu55 2025-08-13 14:29:11 -07:00
Veselin Dobrev 91cdbeee7d Merge pull request #4919 from mfem/revert-hip-memcpy-async-for-d2d
Use `HipMemcpyDtoD` instead of `HipMemcpyDtoDAsync`
2025-08-12 13:58:36 -07:00
dylan-copeland 6f303de40d Minor changes to address review. 2025-08-11 22:07:59 -07:00
dylan-copeland e0c5a8952a Merge branch 'master' of github.com:mfem/mfem into hex-ref-check 2025-08-11 20:44:50 -07:00
Vladimir Z Tomov eb3bd655df Update future::dual. 2025-08-11 14:56:52 -07:00
Vladimir Z Tomov 6a862ca233 Merge branch 'master' into tmop-ad-wcuo 2025-08-11 14:45:24 -07:00
Tzanio Kolev 0466ee74f2 Merge pull request #4622 from mfem/hypre-gpu-tweaks
HYPRE and GPU related tweaks
2025-08-09 10:28:25 -07:00
Tzanio Kolev 50b8873f20 Merge pull request #4923 from mfem/hughcars/cuda-hip-compiler-checks
Check for CUDA or HIP compilers
2025-08-09 10:27:54 -07:00
Andrew Ho 0e7368c055 Merge branch 'master' into qfspace-device 2025-08-08 13:09:10 -07:00
Andrew Ho 0f5898f3e0 Merge branch 'master' into pwconst-coeff-gpu 2025-08-08 13:07:57 -07:00
Tzanio Kolev cdc510145c Merge branch 'master' into findpts-interface 2025-08-08 12:06:12 -07:00
Dylan Copeland 3d6ee379e3 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-08-08 11:35:08 -07:00
Dylan Copeland 2361e45683 Fix for socket glvis output. 2025-08-08 11:34:36 -07:00
Veselin Dobrev cd7dfe2188 Merge pull request #4973 from mfem/macos-llvm-ci
switch to llvm 20 for CI
2025-08-07 17:55:50 -07:00
Mittal, Ketan 25d3ce9704 improve documentation 2025-08-07 17:19:18 -07:00
Mittal, Ketan acea08404c add missing newlines to changelog 2025-08-07 17:04:08 -07:00
Mittal, Ketan e718f2ec58 reviewer comments 2025-08-07 17:02:50 -07:00
Will Pazner e0c1018c9c Adjust cuda versions for CUSPARSE-1897 workaround 2025-08-07 16:32:54 -07:00
Will Pazner 7f263221dd Workaround and unit test for bug CUSPARSE-1897 2025-08-07 15:21:24 -07:00
Andrew Ho 1bf00d3761 switch to llvm20 for CI 2025-08-07 15:18:36 -07:00
Andrew Ho f6247a83dd switch to llvm20 for CI 2025-08-07 15:13:57 -07:00
Andrew Ho f419dc71f8 Merge branch 'qfspace-device' into pwconst-coeff-gpu 2025-08-07 13:38:20 -07:00
Andrew Ho 36c3688968 added AsConst 2025-08-07 13:37:57 -07:00
Andrew Ho 90e79c29fe Merge branch 'qfspace-device' into pwconst-coeff-gpu 2025-08-07 13:14:43 -07:00
Andrew Ho f8c659df1e Merge branch 'qspace-device' into qfspace-device 2025-08-07 12:45:49 -07:00
Andrew Ho b2a0f48001 fixed comment 2025-08-06 09:19:47 -07:00
Veselin Dobrev fb200e4b98 In the 3D version of 'forall', fix (Raja)OmpWrap2D calls to be 3D.
In INSTALL, add version requirement: OpenMP >= 3.1.

Fix a warning in the Vector move constructor about use of uninitialized
values by default initializing the Vector vefore calling its move
assignment operator.
2025-08-06 00:36:29 -07:00
Andrew Ho da852fd0e4 Merge remote-tracking branch 'base/qspace-device' into qspace-device 2025-08-05 18:10:35 -07:00
Andrew Ho c2657d20a8 Check for negative element attributes in debug mode when computing elem_attrs_cache 2025-08-05 18:08:42 -07:00
Veselin Dobrev 47e9b29c0f Restore the MFEM_UNROLL definition -- it is only used in CUDA device code.
Tweak a comment and restore some formatting.
2025-08-05 16:27:15 -07:00
Andrew Ho cbcae09fe8 Merge branch 'master' into qspace-device 2025-08-05 14:30:11 -07:00
Andrew Ho b75c6e96e6 fix doxygen 2025-08-05 14:19:51 -07:00
Andrew Ho a54c5d2105 changed to use MPITypeMap
extend MPITypeMap to all fundamental C++ types except long double
2025-08-05 14:09:11 -07:00
Andrew Ho cd5d098c95 Merge branch 'master' into mpi-dfem-fix 2025-08-05 13:56:30 -07:00
Andrew Ho 30506b52d9 Documentation 2025-08-05 12:29:02 -07:00
Andrew Ho 3f78374d2a ignore attributes <= 0 2025-08-05 12:12:54 -07:00
Veselin Dobrev bd7281bdfa Merge pull request #4960 from mfem/fix-warnings-algoim
Algoim compilation warnings
2025-08-05 12:05:40 -07:00
Andrew Ho 1299d05d21 Merge branch 'master' into mpi-dfem-fix 2025-08-05 11:11:22 -07:00
Veselin Dobrev 39944d8dfb In the INSTALL file, add requirement for ROCm >= 5.6.1 due to the fix
in that version that made HipMemcpyDtoD asynchronous w.r.t. host.
2025-08-05 09:54:53 -07:00
Hugh Carson 6df8ae80cb PR feedback 2025-08-05 11:17:12 -04:00
John Camier 0730fa304a Merge branch 'master' into revert-hip-memcpy-async-for-d2d 2025-08-05 06:06:02 -07:00
Jan Nikl c182459e6a Fixed cloning of RT trace and DG interface FE collections. 2025-08-05 00:39:57 -07:00
Tzanio Kolev 6dfbe25c07 Merge pull request #4955 from mfem/clang-perf-flags
In `miniapps/performance/makefile`, adjust the flags for Clang
2025-08-04 07:44:47 -07:00
adam-sim-dev f82e8c04f9 Merge branch 'master' into cusparseXcsrsort 2025-08-04 11:31:33 +08:00
Andrew Ho 70235124a6 Merge branch 'qspace-device' into qfspace-device 2025-08-02 15:20:35 -07:00
Andrew Ho a8e251c28e 2D and 3D forall for OpenMP 2025-08-02 14:39:24 -07:00
Andrew Ho 9df402b565 suggestions from Veselin 2025-08-02 13:34:13 -07:00
Andrew Ho 5ddbaed1f4 Merge branch 'master' into qspace-device 2025-08-02 12:52:12 -07:00
Tzanio Kolev 02edb95a31 Merge pull request #4957 from farscape-project/conduit
Guarantee data on host when writing conduit files
2025-08-02 09:27:45 -07:00
Veselin DobrevandTom Epperly a328693444 Update fem/coefficient.cpp
Co-authored-by: Tom Epperly <epperly2@llnl.gov>
2025-08-01 09:40:57 -07:00
Andrew Ho 3889095a00 undo accidental change 2025-07-30 11:19:29 -07:00
Andrew Ho 826b089e8f documentation, missing kernel specialization instantiation 2025-07-30 11:15:43 -07:00
Andrew Ho 1bee2fc017 fix documentation 2025-07-30 10:53:42 -07:00
Andrew Ho c0a66cee74 dgdiffusion kernel specialization 2025-07-30 10:41:05 -07:00
Andrew Ho 9b94a6c225 dgtrace kernel specialization 2025-07-30 09:34:30 -07:00
Andrew Ho f0c4c45e02 specializations for vector diffusion 2025-07-30 01:24:35 -07:00
Andrew Ho 8f6912dc2a curlcurl integrator kernel specializations 2025-07-29 23:24:08 -07:00
Andrew Ho ea6053ef9d need kernels in a file so downstream codes can include and add their own specializations 2025-07-29 21:47:17 -07:00
Andrew Ho 7fc1fb501a kernel specializations for convection 2025-07-29 21:27:27 -07:00
Andrew Ho f6afbb8cee Merge branch 'master' into lininteg-spec 2025-07-29 20:39:40 -07:00
Andrew Ho 20d5e01189 added comment 2025-07-29 20:28:15 -07:00
Andrew Ho a979fc6aa6 Merge remote-tracking branch 'base/qfspace-device' into qfspace-device 2025-07-29 17:14:42 -07:00
Andrew Ho 8606afbc40 reset face_indices and inv_face_indices in ResetLazyData 2025-07-29 17:13:51 -07:00
Andrew Ho 28f754844f Merge branch 'qspace-device' into qfspace-device 2025-07-29 17:10:56 -07:00
Andrew Ho 2d6cb3f0e5 Merge remote-tracking branch 'base/qspace-device' into qspace-device 2025-07-29 17:09:37 -07:00
Andrew Ho d06f52461e missing bdr_attrs_cache 2025-07-29 17:09:10 -07:00
Andrew Ho 3853cb6860 fixed typo 2025-07-29 17:07:45 -07:00
Andrew HoandVeselin Dobrev f5d0db2a33 Update mesh/mesh.cpp
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2025-07-29 17:07:04 -07:00
Andrew Ho a102daf621 Merge branch 'master' into qspace-device 2025-07-29 17:04:33 -07:00
Will Pazner ba1805ced8 Simplify FaceQuadratureSpace::GetTransformation 2025-07-29 16:38:29 -07:00
Will Pazner 90863b64e4 Properly set boundary attribute in FaceQuadratureSpace::GetTransformation
Add accessor (and cache the result) for mapping from boundary face indices to
boundary element indices in Mesh::GetBdrFaceToBdrElement.
2025-07-29 15:43:49 -07:00
Dylan Copeland 05d71b6093 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-07-29 12:51:44 -07:00
Will Pazner 597cba8d37 Merge pull request #4954 from mfem/ruby-60
Extend time allocation for testing on ruby from 45 to 60 minutes
2025-07-29 12:49:00 -07:00
Andrew Ho 4c1c8c89ad Merge branch 'master' into qfspace-device 2025-07-29 10:58:53 -07:00
Veselin Dobrev 075a160187 Merge pull request #4827 from mfem/feature/guthrey1/transform_lambda
Allow capturing lambdas for mesh::Transform
2025-07-29 09:34:22 -07:00
Veselin Dobrev 6d8a96a8fb Merge branch 'master' into hypre-gpu-tweaks 2025-07-29 09:08:02 -07:00
Vladimir Z Tomov 8d9579057f Simplified to std:vector. 2025-07-28 15:55:21 -07:00
Vladimir Z Tomov 76d65f5866 Fixed compilation warnings when Algoim is on. 2025-07-28 15:39:50 -07:00
Dylan Copeland 61afd67059 Merge branch 'master' of github.com:mfem/mfem into hex-ref-check 2025-07-28 14:13:17 -07:00
Andrew Ho 3f0b53ac8e fixed make_unique usage 2025-07-28 07:18:01 -07:00
Andrew Ho 0fe75ffdc3 Merge branch 'master' into qfspace-device 2025-07-28 07:14:17 -07:00
Andrew Ho d896e940f7 update to modern C++ style code 2025-07-28 07:10:07 -07:00
Andrew Ho dc0cfb4785 switch to for-each loops 2025-07-28 07:06:34 -07:00
Jan Nikl 15874961af Added BoundaryHyperbolicLFIntegrator. 2025-07-27 23:01:26 -07:00
Jan Nikl c325b92286 Minor reformatting of HyperbolicFormIntegrator. 2025-07-27 23:01:26 -07:00
adam-sim-dev c731dee195 Merge branch 'master' into cusparseXcsrsort 2025-07-28 10:23:43 +08:00
Tzanio Kolev 720fb72372 Merge pull request #4884 from adam-sim-dev/gitignore
Fix gitignore for Windows
2025-07-26 10:45:44 -07:00
Nuno Nobre bbde976378 Guarantee data on host when writing conduit files 2025-07-26 01:31:22 +01:00
Andrew Ho a6e81b4289 Merge remote-tracking branch 'base/qfspace-device-compress' into qfspace-device 2025-07-25 14:29:45 -07:00
Andrew Ho 09165c10e6 Revert "Added lazy offset construction and optional qspace compression"
This reverts commit 1efc5e78e5.
2025-07-25 14:29:04 -07:00
Will Pazner 95ca14247c Support enabling or disabling compression in QuadratureSpaceBase::Offsets 2025-07-25 13:30:39 -07:00
Andrew Ho 1efc5e78e5 Added lazy offset construction and optional qspace compression 2025-07-25 12:10:17 -07:00
Will Pazner fb42b564f2 Fix unused variable warning 2025-07-25 10:46:36 -07:00
Andrew Ho a553c2dba8 update doc since CUB implementation by design requires commutative operators 2025-07-25 10:32:57 -07:00
Will Pazner 9f0216b037 Add GPU support for PWConstCoefficient::Project 2025-07-25 10:11:02 -07:00
Will Pazner 6675385cbe Merge branch 'qfspace-device' into pwconst-coeff-gpu 2025-07-25 09:41:24 -07:00
Will Pazner 8a810f7cf5 Merge branch 'qspace-device' into pwconst-coeff-gpu 2025-07-25 09:41:21 -07:00
Tzanio Kolev 58ad1c79cd Merge pull request #4673 from mfem/cmake-replace-library-files-with-targets
Support fetching of third party libraries using CMake's ExternalProject
2025-07-24 12:23:03 -07:00
Will Pazner b6f755925c Compress offsets in FaceQuadratureSpace 2025-07-23 16:44:47 -07:00
Veselin Dobrev 447cd0f500 In miniapps/performance/makefile, adjust the flags for Clang 2025-07-22 22:14:35 -07:00
adam-sim-dev 2d68b877f2 Merge branch 'master' into gitignore 2025-07-23 10:01:26 +08:00
adam-sim-dev 64c78ff17e Merge branch 'master' into cusparseXcsrsort 2025-07-23 10:01:12 +08:00
Tzanio Kolev cce301f92b Extend time allocation for testing on ruby from 45 to 60 minutes 2025-07-22 12:45:09 -07:00
Andrew Ho 01444aa93c Merge branch 'master' into cmake_improvements 2025-07-22 11:13:35 -07:00
Veselin Dobrev 46ccaee493 Merge branch 'master' into feature/guthrey1/transform_lambda 2025-07-21 19:36:55 -07:00
Andrew Ho 25bd2f9596 Merge remote-tracking branch 'base/qfspace-device' into qfspace-device 2025-07-21 12:08:55 -07:00
Andrew Ho 516f709061 remove old comments 2025-07-21 12:06:08 -07:00
Andrew Ho fa89692e57 Use O(1) way to find number of faces of given type
GetNFbyType is O(n) in number of faces
2025-07-21 11:54:45 -07:00
Andrew Ho 1b6d878189 Added a way to indicate to the bilinear integrators that the mesh/fespace has been updated 2025-07-21 11:31:05 -07:00
Julian Andrej b32f8c8959 remove unused variabel 2025-07-21 11:22:30 -07:00
Julian Andrej e45f5f8595 add unit test 2025-07-21 11:09:09 -07:00
Julian Andrej 03e64ea9b1 add MultLevel 2025-07-21 09:41:14 -07:00
Andrew Ho 4cc9b5c6f6 Merge branch 'master' into qspace-device 2025-07-19 17:07:43 -07:00
Andrew Ho f73f41fc82 Merge branch 'master' into qfspace-device 2025-07-19 17:07:24 -07:00
Andrew Ho 9b1b56a155 avoid overflow in test
found bug for non-commutative scan in cub
2025-07-19 14:20:31 -07:00
Andrew Ho f95b18b457 move face_indices and face_indices_inv into mesh
this allows them to only be re-computed on mesh face info update and
shared between FaceQuadratureSpace objects
2025-07-19 11:24:50 -07:00
Andrew Ho af6d0d7479 Added GPU-accelerated parallel scan 2025-07-18 23:40:16 -07:00
Veselin Dobrev d6cb23ab2f Fix the serial build 2025-07-18 20:06:50 -07:00
Veselin Dobrev 2a65d49db3 Add new method: GridFunction::GetGradients with support for GPU.
Add GPU support in GradientGridFunctionCoefficient and
InnerProductCoefficient by implementing their Project methods.
2025-07-18 19:36:52 -07:00
Dylan Copeland fd6e93c7ad Merge branch 'master' of github.com:mfem/mfem into hex-ref-check 2025-07-18 12:05:17 -07:00
Dylan Copeland 712bee9cce Fixed a bug for repeated refinement in 3D. Added a 3D sample run for ex1. Minor refactoring. 2025-07-17 16:36:30 -07:00
Dylan Copeland 34043e730b New simple 3D example mesh. New unit tests for loading simple 2D and 3D NURBS NC-patch meshes. 2025-07-16 19:36:03 -07:00
Dylan Copeland 850c1813c3 Fixed ex1 for an NC-patch NURBS mesh without IGA. Improved variable naming and documentation. 2025-07-16 13:57:16 -07:00
Dylan Copeland 84c08a69ee Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-07-16 10:46:32 -07:00
Andrew Ho 5496699870 documentation 2025-07-16 08:27:45 -07:00
Andrew Ho 2d3ec4ca67 remove the output name check
sometimes there are equivalent basis with different names created
2025-07-16 08:03:16 -07:00
Andrew Ho 6915a8c6f3 change DomainLFIntegrator to use kernel dispatch 2025-07-15 19:01:30 -07:00
Andrew Ho 0950325080 Merge branch 'master' into kernel-spec 2025-07-15 13:24:17 -07:00
Andrew Ho 03a6f1b190 more missing kernels/organization 2025-07-15 13:10:04 -07:00
Tzanio Kolev 7aa327174a Merge pull request #4811 from mfem/dev-derefine
AMR Matrix-free derefinement operator
2025-07-15 12:22:19 -07:00
Gabriel Esteban Pinochet Soto 769f672ac1 Fix style 2025-07-15 07:22:15 -07:00
Gabriel Pinochet-SotoandChris Vogl dca2a24af2 Update fem/fespace.hpp
Co-authored-by: Chris Vogl <vogl2@llnl.gov>
2025-07-14 21:40:40 -07:00
Gabriel Pinochet-Soto 019194d42d Merge branch 'master' into dev/docs-add 2025-07-14 21:39:43 -07:00
adam-sim-dev 07c0f31e37 Merge branch 'master' into cusparseXcsrsort 2025-07-15 09:21:19 +08:00
adam-sim-dev 8c861b4602 Merge branch 'master' into gitignore 2025-07-15 09:20:33 +08:00
Andrew Ho 4caf208e36 fixed bug in 2D diffusion PA 2025-07-14 17:58:38 -07:00
Andrew Ho b050e307db organize specializations, added important missing ones 2025-07-14 14:45:02 -07:00
Andrew Ho b70589bcac also need to link to rocblas 2025-07-14 12:06:20 -07:00
Andrew Ho 17bbaf500c Merge remote-tracking branch 'base/master' into cmake_improvements 2025-07-14 12:04:05 -07:00
Andrew Ho 267082d6f2 Merge remote-tracking branch 'base/master' into qspace-device 2025-07-12 23:07:56 -07:00
Andrew Ho dd6c207534 formatting 2025-07-11 10:02:11 -07:00
Andrew Ho 71af00ab6d change MPI_INT to MFEM_MPI_SIZE_T
this detects the underlying size of size_t
2025-07-11 09:57:25 -07:00
Andrew Ho 2d5f00635f fixed derefinement for ordering byVDIM 2025-07-10 17:00:49 -07:00
Gabriel Esteban Pinochet Soto 03da0c870c Add description to GetElementTransformation 2025-07-09 08:48:47 -07:00
Dylan Copeland 933e1714c8 Merge branch 'master' of github.com:mfem/mfem into hex-ref-check 2025-07-08 12:37:53 -07:00
Hugh Carson 3f447cb11c Check if a cuda or hip compiler is being used before accessing cuda or hip specific variable 2025-07-07 15:47:32 -04:00
Dylan Copeland a1179d6489 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-07-07 11:15:19 -07:00
Arturo Vargas e629502dca Merge branch 'master' into dev-derefine 2025-07-07 09:55:58 -07:00
Tom Stitt ce434a9c82 HipMemcpyDtoDAsync -> HipMemcpyDtoD since hipMemcpy for d2d is async wip to the host as of 5.6.1 2025-07-03 09:39:58 -07:00
Arturo Vargas 48dd78b154 Merge branch 'master' into dev-derefine 2025-07-03 09:23:21 -07:00
Andrew Ho dc08fc65ce updated changelog 2025-07-01 16:01:38 -07:00
Andrew Ho 3276cb955f Merge branch 'master' into dev-derefine 2025-07-01 15:33:44 -07:00
Tzanio Kolev 60ab10bf58 Merge branch 'master' into najlkin/fix-hyperbolic-bdr 2025-07-01 12:54:29 -07:00
Andrew Ho bcdbda1597 Merge branch 'master' into dev-derefine 2025-07-01 11:24:42 -07:00
adam-sim-dev 0239b86304 Merge branch 'master' into gitignore 2025-06-30 12:15:37 +08:00
Dylan Copeland 5932fcd331 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-06-27 16:22:47 -07:00
Andrew Ho aca8d51f95 Merge branch 'master' into dev-derefine 2025-06-27 09:25:25 -07:00
adam-sim-dev 5cf82dc903 Merge branch 'master' into cusparseXcsrsort 2025-06-27 09:30:04 +08:00
Mittal, Ketan 631f8e4868 merge and resolve CHANGELOG conflict 2025-06-26 09:39:16 -07:00
Mittal, Ketan cb98ed992b update CHANGELOG for this PR and including changes due to bounding PR as well 2025-06-26 09:37:27 -07:00
Andrew Ho 368724d456 fix missing climit header 2025-06-26 09:30:45 -07:00
Mittal, Ketan 95eb39f60f Merge branch 'master' of https://github.com/mfem/mfem into findpts-interface 2025-06-26 09:27:35 -07:00
Tzanio Kolev a99efcdb63 Merge branch 'master' into dev-derefine 2025-06-26 08:25:48 -07:00
Dylan Copeland 7b0f4ad3fd Improved documentation for HashTable. 2025-06-24 16:11:07 -07:00
Dylan Copeland 0f4bdae918 MPI fix for Windows. 2025-06-24 15:42:22 -07:00
Dylan Copeland cf93d97e99 Merge branch 'master' of github.com:mfem/mfem into hex-ref-check 2025-06-24 15:23:02 -07:00
Dylan Copeland 2d84f0cb6e Bug fix. 2025-06-24 15:22:15 -07:00
Dylan Copeland 4b74777aae Remove unused variables. 2025-06-24 15:00:26 -07:00
Dylan Copeland f7bfa3deb0 Refactored to return indices of conflicting refinements. Added documentation. 2025-06-24 13:24:51 -07:00
adam-sim-dev b5a7cf6470 Merge branch 'master' into gitignore 2025-06-24 12:11:35 +08:00
Dylan Copeland 28cfca4dba Merge branch 'master' of github.com:mfem/mfem into hex-ref-check 2025-06-23 21:03:59 -07:00
adam-sim-dev f19ec00b0a Merge branch 'master' into cusparseXcsrsort 2025-06-24 12:03:46 +08:00
Dylan Copeland 89346b597c Enabled parallel anisotropic refinement of hexahedral meshes without conflicting directions on faces. Added a new function to check whether a set of refinements has conflicts, as well as demonstration in miniapp phpref. 2025-06-23 21:02:54 -07:00
Jan Nikl 66ff264731 Added support for boundary integration to HyperbolicFormIntegrator. 2025-06-23 16:40:24 -07:00
Dylan Copeland 1339b6b99a Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-06-20 11:46:01 -07:00
Andrew Ho 9480e5c5bb Merge branch 'master' into cusparseXcsrsort 2025-06-16 12:21:18 -07:00
Andrew Ho 2cfb86aade Merge branch 'master' into cmake_improvements 2025-06-16 12:21:05 -07:00
Andrew Ho 1ac7837dc0 Merge branch 'master' into qspace-device 2025-06-16 12:20:48 -07:00
Andrew Ho e6fc7893be Merge branch 'master' into dev-derefine 2025-06-16 12:20:13 -07:00
Jan Nikl 058fdaae3f Implemented gradient of ParBlockNonlinearForm with shared face contributions. 2025-06-11 16:23:42 -07:00
Jan Nikl 9a92e4875b Implemented Mult of ParBlockNonlinearForm with shared face contributions. 2025-06-11 16:22:16 -07:00
Dylan Copeland 0735280f9d Minor fix. 2025-06-10 23:34:54 -07:00
Dylan Copeland e7c041247f Enabling refinement factor 1 (no-op) in some patch directions. Fixing refinement for NC-patch NURBS meshes not requiring coarsening. 2025-06-10 23:05:12 -07:00
adam-sim-devandJan Nikl 78df8dffb2 Update
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2025-06-10 05:04:44 +08:00
adam-sim-dev d0f5cb73e7 Fix for Windows 2025-06-09 12:17:58 +08:00
Dylan Copeland af00755d68 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-06-06 15:53:33 -07:00
adam-sim-dev cc21011998 Merge pull request #3 from mfem/cusparseXcsrsort-update
cusparseXcsrsort-update by pazner
2025-06-05 14:04:25 +08:00
Will Pazner 09aa9374a9 Use MFEM_REAL_T macro for CUDA/HIP datatype 2025-06-04 20:34:10 -07:00
Will Pazner 78e8cdd7e8 Update SparseMatrix::SortColumnIndices (CUDA or HIP)
Use non-deprecated APIs, and unify the CUDA and HIP implementations.
2025-06-04 14:09:20 -07:00
Andrew Ho 056152aaa6 Merge branch 'master' into qspace-device 2025-06-02 11:38:14 -07:00
Andrew Ho 86e75206b1 Merge branch 'master' into cmake_improvements 2025-06-02 11:38:08 -07:00
Andrew Ho 04a3fd9bb2 Merge branch 'master' into cusparseXcsrsort 2025-06-02 11:38:00 -07:00
Andrew Ho db55be84ad Merge branch 'master' into dev-derefine 2025-06-02 11:37:29 -07:00
Mittal, Ketan 2b962e18a6 Merge branch 'master' of https://github.com/mfem/mfem into tmop-ad-wcuo 2025-05-29 11:50:52 -07:00
Mittal, Ketan 6e5c7fd286 Merge branch 'tmop-ad-wcuo' of https://github.com/mfem/mfem into tmop-ad-wcuo 2025-05-29 11:50:47 -07:00
Mittal, Ketan 6303361f5a minor fix to abort msg 2025-05-29 11:50:35 -07:00
Andrew Ho 02424a41a9 Merge branch 'master' into qspace-device 2025-05-27 12:05:07 -07:00
Andrew Ho 091c6272fc Merge branch 'master' into dev-derefine 2025-05-27 11:57:28 -07:00
Mittal, Ketan e31e0b7c25 minor 2025-05-27 10:52:30 -07:00
Mittal, Ketan 8bf7aaac1f Merge branch 'master' of https://github.com/mfem/mfem into findpts-interface 2025-05-27 10:51:13 -07:00
Mittal, Ketan f83036c4bc minor 2025-05-27 10:51:01 -07:00
Dylan Copeland 72f0b668c8 Bug fix. 2025-05-22 21:48:24 -07:00
Dylan Copeland aefeb46c48 Generalized NURBSPatchMap for master edges on interior boundaries for 2D patch topology. 2025-05-22 20:48:57 -07:00
Stowell, Mark L. 6e111c3ada Adding reference for the Boris algorithm 2025-05-22 14:16:40 -07:00
Andrew Ho 101af72047 Merge branch 'master' into dev-derefine 2025-05-19 12:17:39 -07:00
Dylan Copeland 30a3d7c0d4 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-05-19 10:09:30 -07:00
Will Pazner ea449e1c41 Fix bug in LORBase::AddIntegratorsAndMarkers
Was previously potentially dereferencing null pointer
2025-05-17 22:57:58 -07:00
Will Pazner c9115e74fb Merge remote-tracking branch 'origin/master' into lor_dg_preconditioner 2025-05-16 20:25:22 -07:00
Will Pazner 35040b0336 Remove AMR + DG LOR sample runs
AMR + DG diffusion + PA is not yet implemented
2025-05-16 20:25:12 -07:00
Andrew Ho 01990d4605 don't need _VM 2025-05-13 10:32:01 -07:00
Andrew Ho 4a3cd44695 move tag from VarMessageTag to MessageTag 2025-05-13 04:46:00 -07:00
Andrew Ho 3b059c3995 struct instead of class 2025-05-12 17:21:05 -07:00
Andrew Ho 89dc5ce5c0 parallel version needs to compile to nothing if not building with MPI 2025-05-12 17:19:16 -07:00
Andrew Ho eb205caaa2 fixed collision in ifdef guard 2025-05-12 17:08:39 -07:00
Andrew Ho f50601f1aa fixed using struct vs. class 2025-05-12 16:52:32 -07:00
Andrew Ho 529d6e3bc2 Split deref matrix ops into separate files 2025-05-12 16:34:40 -07:00
Andrew Ho b289def58a Merge branch 'master' into qspace-device 2025-05-12 14:04:22 -07:00
Andrew Ho ef29b1dd30 Merge remote-tracking branch 'base/dev-derefine' into dev-derefine 2025-05-12 11:58:50 -07:00
Andrew Ho 33b3ef6045 Enable GPU testing of fespace/pfespace derefinement 2025-05-12 11:40:26 -07:00
Andrew Ho 657f6ef5fe Merge branch 'master' into dev-derefine 2025-05-12 11:19:22 -07:00
Andrew Ho 96cfef783c Review suggestions
- const on some local variables
- use VarMessageTag instead of hard-coded integers for MPI messages
- comment updates
2025-05-12 10:59:23 -07:00
Andrew Ho 603f43e775 updated fes_kernels member variable documentation 2025-05-12 10:47:13 -07:00
Andrew Ho 932508ad1b fixed bugs 2025-05-07 18:49:36 -07:00
Andrew Ho 0e30ee1e15 Added forall wrappers which flatten 2D and 3D ranges
achieves good performance on CPU and GPU
2025-05-07 18:25:27 -07:00
Andrew Ho dd236b8796 Improved the performance of the 1D forall modulo assembly for CPUs 2025-05-06 22:44:39 -07:00
AnthonyandWill Pazner 4ce11b4a12 Add comment
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2025-05-06 14:16:49 -07:00
dylan-copeland cb580207c8 Fix mac build 2025-05-06 11:27:11 -07:00
Dylan Copeland cd59e68993 Refactored NCNURBSExtension::FindAdditionalFacesSA. 2025-05-06 11:16:24 -07:00
Andrew Ho 9a47f4391d make sure CPU is also fast for mass matrix assembly 2025-05-06 01:15:25 -07:00
dylan-copeland eb61aa4244 Fix mac build 2025-05-05 22:32:17 -07:00
Dylan Copeland 3659acd79d Refactored with a derived class NCNURBSExtension. 2025-05-05 22:04:59 -07:00
Andrew Ho ccc006febf Merge branch 'master' into qspace-device 2025-05-05 13:13:57 -06:00
Dylan Copeland 9d3047b3a7 Documentation. 2025-05-05 11:59:00 -07:00
Tzanio Kolev f2ac9b5653 Merge branch 'master' into nurbs-nc 2025-05-03 13:28:07 -07:00
Andrew Ho a2e33109eb Merge branch 'master' into dev-derefine 2025-05-02 13:04:12 -06:00
Andrew Ho b277a0cb2d Merge branch 'master' into dev-derefine 2025-05-02 10:29:36 -06:00
Andrew Ho f42334cb4d Merge branch 'master' into qspace-device 2025-05-02 10:29:15 -06:00
Mittal, Ketan 8f9e4b27fc minor 2025-05-01 15:43:15 -07:00
Ketan MittalandCopilot 076ad6907f Update fem/tmop.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-30 12:25:37 -07:00
Will Pazner f17b1c4e4f real_t instead of int in DG LOR test 2025-04-30 09:06:32 -07:00
Tzanio Kolev 7cfd3f5c7e Merge branch 'master' into lor_dg_preconditioner 2025-04-30 09:00:41 -07:00
Mittal, Ketan 9faa6f8968 fix compiler error 2025-04-29 10:56:52 -07:00
Mittal, Ketan b5156dcdec Merge branch 'master' of https://github.com/mfem/mfem into tmop-ad-wcuo 2025-04-29 10:14:08 -07:00
Mittal, Ketan cf6c98654a add mu14 and mu66 2025-04-29 10:12:39 -07:00
Will Pazner 63ea83c455 Add make_permuted_mesh.cpp to unit tests CMakeLists.txt 2025-04-29 08:40:07 -07:00
Will Pazner 38ee46c40f Fix shadow warnings 2025-04-28 21:40:10 -07:00
Will Pazner c271283490 Fix lambda capture
Resolve error: lambda capture 'this' is not used
2025-04-28 19:03:19 -07:00
Will Pazner 808f5c94db In LOR solvers, use fast assembly for RHS only for H1 2025-04-28 17:57:22 -07:00
Mittal, Ketan e818d6645b minor 2025-04-28 17:08:28 -07:00
Mittal, Ketan 73313bb44d remove some duplication 2025-04-28 17:07:03 -07:00
Will Pazner 287631bee4 Fix averaging of face penalty factor in LOR DG 2025-04-28 15:14:18 -07:00
Will Pazner 4da6e52698 Fix Doxygen typo 2025-04-28 15:14:18 -07:00
Will Pazner cc12d37693 Doxygen documentation for LOR DG 2025-04-28 15:14:18 -07:00
Will Pazner 35fe98417c Update copyright year 2025-04-28 15:14:18 -07:00
Will Pazner 936f1fc848 Parallel LOR+DG assembly 2025-04-28 15:14:18 -07:00
Will Pazner 2cadeaad4c Add ParFiniteElementSpace::GetFaceNbrGlobalDofMapArray
Returning Array instead of pointer allows use on device
2025-04-28 15:14:18 -07:00
Will Pazner f7fa092013 Batched LOR DG GPU fixes
For integers a and b, converting pow(a,b) to integer truncates, which
can cause indexing issues.

For example, in a CUDA kernel, int(pow(3,1)) evaluates to 2.
2025-04-28 15:14:18 -07:00
Will Pazner 9103db88b6 DG+LOR updates 2025-04-28 15:14:18 -07:00
Will Pazner 0303f12887 Minor LOR+DG modifications 2025-04-28 15:14:18 -07:00
Will Pazner 6650a1dffe Factor out FaceIdxToVolIdx 2025-04-28 15:14:18 -07:00
Will Pazner 9a22d4533f Remove matrix output in LOR DG test 2025-04-28 15:14:18 -07:00
Will Pazner 412715c2e4 Factor out face terms in LOR + DG 2025-04-28 15:14:18 -07:00
Will Pazner 9803cbb671 Simplify LOR+DG implementation 2025-04-28 15:14:18 -07:00
Will Pazner 6805b8c7f6 Simplify LOR+DG unit tests 2025-04-28 15:14:18 -07:00
Will Pazner 7aeba0ff83 Adjust DG kappa in LOR solvers miniapp 2025-04-28 15:14:18 -07:00
Will Pazner dbd55a8fb4 Simplified implementation of BatchedLOR_DG::Assemble2D 2025-04-28 15:14:18 -07:00
Toni-ko 277199c3a5 gpu compatiblility 2025-04-28 15:14:18 -07:00
Toni-ko e7e00e6e39 Got rid of shoelace formula for element area and volume computations 2025-04-28 15:14:18 -07:00
Toni-ko e78c1b8b4c passes orientation tests 2025-04-28 15:14:18 -07:00
Will Pazner dcec51b98a Fix permuted test case
(Test still fails)
2025-04-28 15:14:18 -07:00
Will Pazner 2e9f545a4e DG LOR test case
Add commented-out code for testing 3D face permutations
2025-04-28 15:14:18 -07:00
Toni-ko e49854f3ba Passes tests on ref cube, inline-hex, and any version of inline-hex where nx, ny, nz, sx, sy, and/or sz are changed. 2025-04-28 15:14:18 -07:00
Toni-ko 0bb71aa1fa Passes tests on ref-cube, and inline-hex (including when nx, ny, nz or sx, sy, and sz are changed). 2025-04-28 15:14:18 -07:00
Will Pazner 07dc0f6cfa Change mesh permutation function names 2025-04-28 15:14:18 -07:00
Will Pazner 847183e668 Factor out test code for making permuted meshes 2025-04-28 15:14:18 -07:00
Toni-ko 8a1a264eaa some clean-up 2025-04-28 15:14:18 -07:00
Anthony Kolshorn 606a597303 debugging for gpu 2025-04-28 15:14:18 -07:00
Toni-ko e194835abd quick edit 2025-04-28 15:14:18 -07:00
Toni-ko 208f9b81b3 gpu debugging 2025-04-28 15:14:18 -07:00
Will Pazner e50ebb573e Bugfix 2025-04-28 15:14:18 -07:00
Toni-ko c315298a86 debugging 2025-04-28 15:14:18 -07:00
Will Pazner 12bafa69e8 Debugging 2025-04-28 15:14:18 -07:00
Toni-ko 1729961a89 testing 2025-04-28 15:14:18 -07:00
Will Pazner 6dcc19abab Small LOR DG fixes 2025-04-28 15:14:18 -07:00
Toni-ko a5fccc7514 Debugging 2025-04-28 15:14:18 -07:00
Will Pazner cfe25c432c Template for unifying LOR DG matrix assembly 2025-04-28 15:14:18 -07:00
Will Pazner b8fe4cbf97 Get (p+2) Lobatto vertex coordinates for DG LOR 2025-04-28 15:14:18 -07:00
Will Pazner ea0abf46fe Use eta instead of kappa in LOR Batched DG unit test 2025-04-28 15:14:17 -07:00
Will Pazner 556b43f900 Small fixes in BatchedLOR_DG::Assemble2D 2025-04-28 15:14:17 -07:00
Will Pazner aa567465ac Extract kappa in BatchedLOR_DG 2025-04-28 15:14:17 -07:00
Will Pazner 986cee600f make style 2025-04-28 15:14:17 -07:00
Toni-ko 7634a4b663 Correct sparsity Pattern for LOR DG, wrong values 2025-04-28 15:14:17 -07:00
Will Pazner 1368cfb8cb Framework for LOR DG preconditioner assembly 2025-04-28 15:14:17 -07:00
Will Pazner 53c561cbf0 Update fem/CMakeLists.txt with missing headers 2025-04-28 15:14:17 -07:00
Will Pazner 3c2e847e0a Factor out test same matrix unit test utils 2025-04-28 15:14:17 -07:00
Mittal, Ketan 838398e4e7 AD for WCUO 2025-04-26 17:48:00 -07:00
Tzanio Kolev 6daba6f9fa Merge branch 'master' into nurbs-nc 2025-04-26 12:23:48 -07:00
Tzanio Kolev ac26026ff1 Merge branch 'master' into cmake-replace-library-files-with-targets 2025-04-26 12:19:30 -07:00
Andrew Ho f65f60dbb5 Merge branch 'master' into cmake_improvements 2025-04-25 13:14:09 -07:00
Jan Nikl 9dab032bd0 Merge branch 'master' into najlkin/parform-impro 2025-04-24 15:40:44 -07:00
Pierson Guthrey d439781751 resolve ambiguity, thanks @v-dobrev 2025-04-23 18:08:06 -07:00
Pierson Guthrey 16c9123f98 allow lambdas for mesh Transformation 2025-04-23 17:21:16 -07:00
Andrew Ho cc86e59167 Made getting offsets public, added accessor to internal held offsets 2025-04-23 13:25:28 -07:00
Andrew Ho 52eaf0deb7 Merge branch 'master' into qspace-device 2025-04-23 13:16:59 -07:00
Andrew Ho e73ea1fb77 documentation for parallel version 2025-04-23 12:11:54 -07:00
Andrew Ho ea6c104475 added const and documentation 2025-04-23 12:05:21 -07:00
Mittal, Ketan a26eaed48a fix constructor 2025-04-23 09:26:05 -07:00
Andrew Ho e7762d126e Merge branch 'master' into dev-derefine 2025-04-23 09:02:36 -07:00
Andrew Ho c61d0e07d3 switch to using INT_MAX for rows to skip 2025-04-22 16:51:04 -07:00
Mittal, Ketan 31171c22ce make style 2025-04-22 15:10:07 -07:00
Mittal, Ketan ef47e36e41 minor change to constructor 2025-04-22 15:09:23 -07:00
Mittal, Ketan 3e7280df12 remove unneeded deletes 2025-04-22 12:59:36 -07:00
Mittal, Ketan 10915f67e1 minor 2025-04-22 12:57:37 -07:00
Mittal, Ketan e4b27670c8 re-use constructors 2025-04-22 12:46:41 -07:00
Dylan Copeland 969ba74440 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-04-22 12:32:29 -07:00
Dylan Copeland 68ae30ad6f Remove refinements section from file when not NC-NURBS. 2025-04-22 12:31:58 -07:00
Andrew Ho 720051d641 unused testing var 2025-04-22 08:55:41 -07:00
Andrew Ho 5c25fa49a7 graceful fallback for HOST_PINNED 2025-04-22 08:50:23 -07:00
Andrew Ho d9ef117ee9 Merge branch 'master' into dev-derefine 2025-04-21 23:21:29 -07:00
Andrew Ho b7a8cf6290 CI fixes 2025-04-21 23:20:43 -07:00
Andrew Ho bed1823d72 unused variables 2025-04-21 23:12:54 -07:00
Mittal, Ketan c51895ee22 make style 2025-04-21 21:11:49 -07:00
Mittal, Ketan a19255274d merge and resolve conflicts 2025-04-21 21:11:38 -07:00
Mittal, Ketan 9e5323be86 documentation 2025-04-21 20:20:39 -07:00
Andrew Ho 93a3648712 fixed a few performance bugs 2025-04-21 20:12:35 -07:00
Mittal, Ketan b9932b5cb2 minor 2025-04-21 19:46:53 -07:00
Mittal, Ketan 1e73159e11 fix for serial 2025-04-21 18:50:31 -07:00
Mittal, Ketan 00691298d1 use updated interface 2025-04-21 18:48:52 -07:00
Mittal, Ketan 07ff46c1d6 findpts interface initial commit 2025-04-21 18:28:33 -07:00
Christopher vogl 01eeccee7f updated hypre fetch version; removed unnecessary dependencies on install step; leverage METIS_FETCH_VERSION variable 2025-04-21 15:31:52 -07:00
Christopher vogl 39b6112e69 reverted use of MPI target instead of files 2025-04-21 13:49:18 -07:00
Andrew Ho c70d2b7309 off-diagonals should be implemented now 2025-04-21 00:34:35 -07:00
Andrew Ho c98e8bfe07 Think I have ghost comm data being transferred correctly now 2025-04-20 23:03:10 -07:00
Andrew Ho ef9137bd1f const correctness fix 2025-04-20 22:59:08 -07:00
Andrew Ho e49a62ab1b Merge branch 'master' into cmake_improvements 2025-04-20 13:41:50 -07:00
Andrew Ho 8e0c42a132 fixed a few bugs
still need to finish implementing off-diagonals
2025-04-19 23:04:11 -07:00
Andrew Ho d755037904 Re-arranged DerefineMatrixOpFunctor
Now it's a common implementation with the indexing order separated.

Still need to make it work for off-diagonals.
2025-04-19 20:42:17 -07:00
Andrew Ho b577d2322e diagonals for pfespace derefop working
still need to work out the off-diagonals
2025-04-19 17:46:10 -07:00
Andrew Ho 6f99204d37 code cleanup 2025-04-19 01:32:52 -07:00
Andrew Ho c6e93f5474 Coalesce ParallelDerefineMatrix MPI messages
Not strictly required for correctness, but fewer MPI messages should
always be good
2025-04-18 22:17:24 -07:00
Andrew Ho 21b6ade630 removed derefine multT
I don't think this is ever used or has any meaning
2025-04-17 14:31:44 -07:00
Andrew Ho 2e8685d80a started working on ParDerefineMatrixOp 2025-04-17 11:59:01 -07:00
Andrew Ho 6d8c32db80 only need atomic for mult with DG 2025-04-17 09:01:07 -07:00
Andrew Ho 4adb51df50 fixed documentation and p derefinement oob read 2025-04-16 14:37:47 -07:00
Andrew Ho 6cec49e220 fix compiler warnings 2025-04-16 14:23:35 -07:00
Andrew Ho 9006171327 Merge remote-tracking branch 'base/master' into dev-derefine 2025-04-16 13:18:46 -07:00
Andrew Ho 9e10cd87b1 fixed verify for vdim > 1 2025-04-15 23:15:23 -07:00
Andrew Ho 3f7c551d66 implemented MultTranspose 2025-04-15 22:45:35 -07:00
Andrew Ho a7a5ce5cb1 implemented Mult for VDim ordering 2025-04-15 21:48:53 -07:00
Andrew Ho 4218c11b41 have at least one kernel working 2025-04-15 21:31:55 -07:00
Tzanio Kolev e3b732761f Merge branch 'master' into improve-mma-doxygen-comments 2025-04-15 13:46:52 -07:00
Tzanio Kolev 44f8eb9990 Merge branch 'master' into nurbs-nc 2025-04-15 13:45:42 -07:00
Andrew Ho 44f58a169c Merge branch 'master' into qspace-device 2025-04-15 11:01:58 -07:00
Andrew Ho 3c4a860f3a re-arranged the run operation so functor is responsible
need to change parallelization so vdim can be allocated into shared
memory as well
2025-04-15 10:55:39 -07:00
Andrew Ho 18a256d17b coalesce SHARED_LIBRARY and UNKNOWN_LIBRARY cases
these ended up being the same
2025-04-14 09:43:22 -07:00
Tom Epperly a4d8700473 Minor changes to the documentation. 2025-04-14 08:12:27 -07:00
Andrew Ho 47b73713a6 fixed CMake build with RAJA/CUDA 2025-04-12 09:30:32 -07:00
Andrew Ho 43f4d9d6e3 treat UNKNOWN_LIBRARY as a shared library 2025-04-12 08:53:21 -07:00
Andrew Ho 081bbdd1c2 Merge remote-tracking branch 'base/master' into cmake_improvements 2025-04-12 08:39:26 -07:00
Tom Epperly 80b04009af Resolve more pre-commit checking issues 2025-04-11 16:45:31 -07:00
Tom Epperly 7983d25a14 Fix a mistake 2025-04-11 16:33:32 -07:00
Tom Epperly bf1a63c920 Support mfem preferences about $..$ instead of \f$..\f$ 2025-04-11 16:29:35 -07:00
Tom Epperly b64bb19cf8 Add more space 2025-04-11 16:23:49 -07:00
Tom Epperly 321bcceb1c Format the comments for better doxygen rendering and add more
elaborate comments.
2025-04-11 16:19:48 -07:00
Andrew Ho e64300f84b Re-arranged DerefineMatrixOp to use kernel specialization infrastructure
all that's left is to implement Mult and MultT for specializations
2025-04-10 13:31:26 -07:00
Dylan Copeland c3656a5573 Minor edits. 2025-04-10 12:04:29 -07:00
Dylan Copeland f84d5d1bfa More documentation. Removed allow_bad_orientation option in Mesh. 2025-04-10 11:32:26 -07:00
Dylan Copeland 6ce9d7b3be Updated example nc3-nurbs.mesh. 2025-04-10 10:50:15 -07:00
Dylan Copeland 02dd999886 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-04-09 20:56:36 -07:00
Dylan Copeland 5132b9191c Doc fix. 2025-04-09 16:41:25 -07:00
Andrew Ho 3854184620 have setup for prototype derefinematrixop implemented
still not sure if DerefinementOperator is acceptable/modifiable or not
for this
2025-04-09 16:22:13 -07:00
Dylan Copeland e16cf9a89d Documentation. 2025-04-09 16:02:55 -07:00
Dylan Copeland dd3e76db6c New structs to simplify some arrays. 2025-04-08 22:49:31 -07:00
Dylan Copeland 8578bf4918 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-04-08 12:35:39 -07:00
Dylan Copeland 97e5cf0dc4 Fixed KnotRemove for the case of multiple removals. 2025-04-08 12:34:43 -07:00
Dylan Copeland 40083984c1 Minor fixes. 2025-04-07 22:46:51 -07:00
Dylan Copeland 96cc518acf More refactoring of duplicated code. 2025-04-07 19:00:50 -07:00
Dylan Copeland acb1bb4dc2 Eliminating some code duplication. 2025-04-07 15:25:51 -07:00
Dylan Copeland 8f391e9854 Name correction, from knot to knot-span. 2025-04-07 12:07:14 -07:00
Dylan Copeland dfb73f248f More refactoring. 2025-04-05 23:00:20 -07:00
Dylan Copeland c55f3c13af More simplification and formatting. 2025-04-04 19:27:50 -07:00
Andrew Ho 4a09b7a1fc fix merge compile errors 2025-04-04 16:28:42 -07:00
Andrew Ho 1ea8e59f69 Merge branch 'master' into qspace-device 2025-04-04 16:02:17 -07:00
Dylan Copeland 8d40910fd8 Using efficient search for NC patch edges and faces. 2025-04-04 15:03:36 -07:00
Dylan Copeland b2e61e7e1c Refactoring. 2025-04-03 19:42:24 -07:00
Andrew Ho 7c80866b49 Change TPL library detection so new CMake-style targets will be detected 2025-03-31 14:28:41 -07:00
Andrew Ho 7ec6704a51 Merge remote-tracking branch 'base/master' into cmake_improvements 2025-03-31 14:19:10 -07:00
Dylan Copeland 62dcb4cf1a Generalized for mesh files with uniform spacing and without patch_cp. 2025-03-25 11:43:41 -07:00
Dylan Copeland 0f0d70dad1 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-03-24 17:35:14 -07:00
Andrew Ho 3c1606903c Merge branch 'master' into cmake_improvements 2025-03-24 06:28:59 -07:00
Andrew Ho b6aa248fc9 Merge branch 'master' into qspace-device 2025-03-24 06:27:44 -07:00
Dylan Copeland 80274347ae More refactoring and bug fixes. 2025-03-22 21:47:56 -07:00
Dylan Copeland 622985d8da Interface improvements and refactoring. 2025-03-22 20:39:15 -07:00
Jan Nikl cdfe8102ae Added gradient of ParNonlinearForm with face integrators. 2025-03-18 16:44:51 -07:00
Andrew Ho 754235e932 switched order to if variable == value 2025-03-13 17:07:26 -07:00
Andrew Ho 0cc04c8bd9 Merge branch 'master' into cmake_improvements 2025-03-13 16:37:12 -07:00
Andrew Ho 5f82901f73 revert change to fix #4732
this is in its own PR now
2025-03-12 13:15:47 -07:00
Andrew Ho 41a262563b Merge remote-tracking branch 'origin/cmake_improvements' into cmake_improvements 2025-03-12 13:08:34 -07:00
Andrew Ho b081aa7eea rollback non-cmake related changes from this branch
These will be added in a separate PR
2025-03-12 13:05:56 -07:00
Andrew Ho 3c7a63f742 Merge branch 'master' into cmake_improvements 2025-03-12 10:57:47 -07:00
Andrew Ho ffe14214ae Re-detect HYPRE cmake variables if needed 2025-03-12 10:52:45 -07:00
Dylan Copeland c515b75b53 Setting patch ownership of DOFs. 2025-03-10 10:09:23 -07:00
Jan Nikl 5b82bf0328 Revert "WIP: Added support for trace face integrators in ParMixedBilinearForm."
This reverts commit 323ee572b6.
2025-03-06 06:00:07 -08:00
Dylan Copeland ecab08e1b6 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-03-05 22:30:22 -08:00
Dylan Copeland 5602c66e1a Generalized to allow varying refinement factors on auxiliary and slave edges. Added new partial spacing formula. 2025-03-05 22:28:52 -08:00
Andrew Ho 900085cb9d Add namespace to kernel dispatch macro
This allows external codes to use MFEM_REGISTER_KERNELS to create
their own kernel tables without needing to either have `using
namespace mfem;` or inject symbols into the mfem namespace.
2025-03-04 01:06:07 -08:00
Andrew Ho 0376760aa1 Merge branch 'master' into cmake_improvements 2025-03-04 01:05:38 -08:00
Andrew Ho 2ab9ae818e Merge branch 'master' into cmake_improvements 2025-02-27 09:39:42 -08:00
Andrew Ho 6857e4b277 use set instead of unordered_set to get ordered attributes 2025-02-26 07:14:55 -08:00
Andrew Ho 639a0347fb Merge branch 'master' into qspace-device 2025-02-25 19:43:38 -08:00
Andrew Ho a02f7165d8 Cache bdr_attributes in mesh (used by linearform_ext and bilinearform_ext) 2025-02-25 19:41:36 -08:00
Andrew Ho 4fb48b4e41 Get rid of the ElementAttributesUpdated function
Have users call SetAttributes() instead
2025-02-25 17:16:43 -08:00
Andrew Ho 751dbd0ed9 Merge remote-tracking branch 'base/qspace-device' into qspace-device 2025-02-25 17:05:04 -08:00
Andrew Ho c2c6a94d42 Merge remote-tracking branch 'base/qspace-device' into qspace-device 2025-02-25 17:04:49 -08:00
Andrew HoandWill Pazner 088ec0f461 Update fem/qspace.hpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2025-02-25 17:03:59 -08:00
Andrew Ho 7e1be9da75 Use unordered_set to get unique attributes 2025-02-25 17:00:05 -08:00
Andrew HoandWill Pazner be29d4a3d4 Update mesh/mesh.hpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2025-02-25 16:58:32 -08:00
Andrew HoandWill Pazner be34c5a6bd Update mesh/mesh.cpp
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
2025-02-25 16:57:35 -08:00
Andrew Ho 1035382fad Merge remote-tracking branch 'base/master' into cmake_improvements 2025-02-25 09:12:33 -08:00
Andrew Ho 8bd3569f6d unused variable 2025-02-25 02:31:54 -08:00
Andrew Ho e8908ad646 cache element attributes in mesh 2025-02-24 19:38:29 -08:00
Andrew Ho 6c7673df1c code style 2025-02-24 19:18:40 -08:00
Andrew Ho 1f7f394f4e Merge remote-tracking branch 'base/master' into qspace-device 2025-02-24 18:47:58 -08:00
Christopher vogl bfc6b0708d corrected some unncecessary whitespace added 2025-02-20 16:48:54 -08:00
Christopher vogl 3d5c6d58e8 added options to defaults.cmake and updated INSTALL document 2025-02-20 16:45:40 -08:00
Christopher vogl 6efbd4cc27 applied change suggested by nmnobre to use patched metis to support ARM macs 2025-02-20 16:18:35 -08:00
Christopher vogl 369b9365ad added check for hypre target to top of FindHYPRE 2025-02-20 12:35:19 -08:00
Christopher vogl b35ff2270a applying nmnobre's suggestion to clean up fetched metis directory 2025-02-20 10:24:42 -08:00
Chris VoglandNuno Nobre 7a54a543b0 Apply update_disconnect fix
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2025-02-20 10:06:24 -08:00
Christopher vogl 15420f7049 restored support for FETCH_TPLS 2025-02-20 09:56:32 -08:00
Chris VoglandNuno Nobre dd20722733 Applying suggestions for individual fetching and dynamic hypre versioning
Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2025-02-20 09:42:50 -08:00
Christopher vogl 5577edf446 Added status messages suggested by nmnobre 2025-02-19 09:08:40 -08:00
Chris VoglandNuno Nobre 230a345ef3 Apply suggestions from nmnobre
1. use git tag instead of commit
2. explicitly specify hypre library install directory

Co-authored-by: Nuno Nobre <nuno.nobre@stfc.ac.uk>
2025-02-19 08:42:45 -08:00
adam-sim-dev 90f33b1a86 Merge branch 'master' into cusparseXcsrsort 2025-02-19 08:36:21 +08:00
dylan-copeland c354e4cd27 Fix mac build. 2025-02-13 13:43:28 -08:00
Dylan Copeland 01d92c7133 Fixed the 2D case for knotvector-dependent refinement factors. 2025-02-13 12:59:45 -08:00
adam-sim-dev 136ae2d98f Merge branch 'master' into cusparseXcsrsort 2025-02-13 09:53:40 +08:00
Dylan Copeland 12896cd9ed Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2025-02-12 12:29:48 -08:00
Dylan Copeland 15ecbb5e6e Refactoring with a new struct. 2025-02-12 12:27:53 -08:00
Dylan Copeland b5ed99e1cd Added the capability to specify a refinement factor for each knotvector. Piecewise knotvectors can have multiple refinement factors. 2025-02-11 21:24:07 -08:00
adam-sim-dev 449a57d9ad Merge branch 'master' into cusparseXcsrsort 2025-02-05 09:41:21 +08:00
Tzanio Kolev 41b65d6333 Merge branch 'master' into najlkin/parform-impro 2025-02-04 14:55:19 -08:00
Tzanio Kolev 17e48c4d46 Merge branch 'master' into cmake_improvements 2025-02-04 14:53:31 -08:00
adam-sim-dev 7ac5b61955 Merge branch 'master' into cusparseXcsrsort 2025-01-31 18:28:18 +08:00
adam-sim-dev c98f117689 Merge branch 'master' into cusparseXcsrsort 2025-01-27 21:48:43 +08:00
Christopher vogl 89f1dce705 added support for fetching hypre with CUDA, HIP, and floats 2025-01-23 10:26:20 -08:00
Christopher vogl 7f17c1f049 see prior message (clearly I need more coffee) 2025-01-22 17:48:30 -08:00
Christopher vogl 7e6edcddec changes that should have been part of prior commit (more commenting) 2025-01-22 17:47:38 -08:00
Christopher vogl d89b01e24c updated commenting of new code 2025-01-22 17:46:04 -08:00
Christopher vogl 33f1150c34 updated FindMETIS to also use ExternalProject 2025-01-22 16:14:09 -08:00
Christopher vogl c6a05d371b fixed capitalization and made fetch directory consistent 2025-01-22 16:13:41 -08:00
Christopher vogl f97a29f6e8 refactored FindHYPRE to use ExternalProject instead of FetchContent 2025-01-22 15:00:06 -08:00
Christopher vogl 85ae72fada changed lib to Lib to be consistent with METIS capitalization 2025-01-21 16:16:30 -08:00
Christopher vogl 27a5bd71ee whitespace 2025-01-21 15:27:14 -08:00
Christopher vogl 643db22bef minor tweaks, commenting, and cleanup 2025-01-21 15:25:18 -08:00
Christopher vogl 97fb6be029 Merge remote-tracking branch 'origin/master' into cmake-replace-library-files-with-targets 2025-01-21 13:41:24 -08:00
Christopher vogl 9587ef212d added fetching of HYPRE and METIS with FETCH_TPLS flag 2025-01-21 13:41:08 -08:00
Tzanio Kolev 337a0298bf Merge branch 'master' into cusparseXcsrsort 2025-01-19 13:08:07 -08:00
Christopher vogl 35462b8645 refactored CMakeLists to support targets for TPLs 2025-01-15 13:13:18 -08:00
adam-sim-dev 7930b9b3ca Merge branch 'master' into cusparseXcsrsort 2025-01-13 12:09:24 +08:00
Jan Nikl 2534d2207d Fixed name of ParallelEliminateTrialEssentialBC(). 2025-01-09 10:49:10 -08:00
Jan Nikl 260b817b3c Merge branch 'master' into najlkin/parform-impro 2025-01-09 10:01:52 -08:00
Jan Nikl 613d5dd826 Fixed constness in some HyperParMatrix constructors. 2025-01-08 17:56:42 -08:00
Jan Nikl 323ee572b6 WIP: Added support for trace face integrators in ParMixedBilinearForm. 2025-01-08 17:56:05 -08:00
Jan Nikl 56ff5ac5bb Added support for interior face integrators to ParMixedBilinearForm. 2025-01-08 17:55:42 -08:00
Jan Nikl e1a06bd6c8 Added methods to Par(Mixed)BilinearForm for elimination of essential BCs. 2025-01-08 17:55:08 -08:00
Jan Nikl 9acae54669 Extended ParMixedBilinearForm methods for parallel assembly. 2025-01-08 17:54:28 -08:00
Jan Nikl 7d92e22a45 Added ParallelAssembleInternal() method to ParBilinearForm. 2025-01-08 17:53:21 -08:00
adam-sim-dev 7c0bc9c338 Merge branch 'master' into lorentz-pm-dev 2025-01-09 06:11:27 +08:00
Dylan Copeland b62aa1491f Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2024-12-30 17:54:54 -08:00
Dylan Copeland 7bff34ba6c Fixed multiple refinements. Implemented another case for auxiliary faces. 2024-12-30 13:55:01 -08:00
adam-sim-dev c0d8ba243d Merge branch 'master' into cusparseXcsrsort 2024-12-30 08:30:06 +08:00
adam-sim-dev c946067b9b Merge branch 'master' into cusparseXcsrsort 2024-12-19 04:49:25 +08:00
Andrew Ho db803eb74a hypre could require rocsolver as well when built with hip 2024-12-11 21:17:59 -08:00
Veselin Dobrev 4f0f353720 Print error code (in addition to the error string) on CUDA/HIP errors 2024-12-09 18:20:32 -08:00
Veselin Dobrev a3156023d0 Avoid HYPRE initialization via calls to HypreUsingGPU() and
GetHypreMemoryLocation() when running serial codes.
2024-12-09 18:03:01 -08:00
adam-sim-dev c35e5ad7fe Merge branch 'master' into cusparseXcsrsort 2024-12-08 18:57:22 +08:00
adam-sim-dev 059f0acee6 Merge branch 'master' into cusparseXcsrsort 2024-12-06 02:39:06 +08:00
Dylan Copeland a1ea837c1d Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2024-12-02 20:05:42 -08:00
Dylan Copeland 186ab1409e Documentation 2024-12-02 19:36:26 -08:00
Dylan Copeland 1c6d968ed7 Refinement by formulas in 2D. 2024-12-02 19:07:51 -08:00
adam-sim-dev e18d795334 Merge branch 'master' into cusparseXcsrsort 2024-11-27 09:13:48 +08:00
Andrew Ho 377c5d16f5 Merge branch 'master' into cmake_improvements 2024-11-26 11:53:50 -08:00
Andrew Ho 674379e6c9 macro should expand to include namespace
This allows user codes to not require `using namespace mfem;` in their
code to use MFEM_DEVICE_SYNC or MFEM_STREAM_SYNC
2024-11-26 11:42:28 -08:00
Dylan Copeland d0f0e2c392 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2024-11-25 14:58:54 -08:00
Dylan Copeland bf6d19e152 Refinement by formulas in 3D, starting from fully coarsened NC patches. 2024-11-25 14:40:07 -08:00
Andrew Ho 7794c291be Expose more parallelism in mass integrator assemblePA 2024-11-22 13:01:58 -08:00
Andrew Ho 7ca49cb200 FaceQuadratureSpace also needs to save ne 2024-11-22 12:01:20 -08:00
Andrew Ho e48d41c9dc return correct NE for compressed qspace 2024-11-22 11:51:20 -08:00
Andrew Ho 0ead1d9c77 Implemented offset compression in qspace 2024-11-22 11:40:33 -08:00
adam-sim-dev 243b234033 Merge branch 'master' into cusparseXcsrsort 2024-11-21 11:22:17 +08:00
Andrew Ho e2168f9348 code style 2024-11-20 15:56:17 -08:00
Andrew Ho 65516eca23 offsets need to be accessible to the host 2024-11-20 15:47:43 -08:00
Andrew Ho 79d9314560 Fix issue with using CUDA lambda functions in private/protected member functions 2024-11-19 17:06:07 -08:00
Will Pazner d91d39bc00 Construct quadrature space offsets on device (when possible)
This can be done easily when there is only one geometry type in the mesh
2024-11-19 12:52:22 -08:00
Andrew Ho 56c5f17e01 Enhanced the parsing of CUDA_ARCH
Compatible with the existing syntax:
CUDA_ARCH=sm_70

Expanded capabilities:
CUDA_ARCH=all
CUDA_ARCH=all-major
CUDA_ARCH=native

List separated format and CMAKE_CUDA_ARCHITECTURES format:
CUDA_ARCH=sm_70,sm_86
CUDA_ARCH=sm_70;sm_86
CUDA_ARCH=70;86

supports CMake versions before 3.18 still.
CMake will complain about missing CUDA_ARCHITECTURES for targets if
you use "all", "all-major", or "native" for CMake versions 3.18-3.24,
however it will compile correctly. This is due to a limitation of
CMake being able to handle these cases.
2024-11-19 09:19:00 -08:00
adam-sim-dev 5afe2a09a3 Merge branch 'master' into cusparseXcsrsort 2024-11-18 11:06:52 +08:00
adam-sim-dev 64f8ab42c1 Merge branch 'master' into cusparseXcsrsort 2024-11-13 10:55:58 +08:00
adam-sim-dev 5fb9fc8ec5 Merge branch 'master' into cusparseXcsrsort 2024-11-13 08:41:35 +08:00
Mark L. Stowell 5a5dcd44df Fixing time step calculation 2024-11-07 15:51:27 -08:00
Mark L. Stowell d4ff68d2bd Selecting sample runs 2024-11-07 15:51:00 -08:00
Mark L. Stowell ac3417555c Adding to .gitignore 2024-11-07 13:36:33 -08:00
Mark L. Stowell e8bd89a672 Fixing mistakes in test command lines 2024-11-07 10:50:52 -08:00
Mark L. Stowell fc3c897fa6 Adding two simple tests of the lorentz miniapp 2024-11-07 09:30:04 -08:00
Mark L. Stowell 58bc2b070e make style 2024-11-07 08:48:49 -08:00
Mark L. Stowell 991284d3b6 Merge branch 'master' into lorentz-pm-dev 2024-11-07 08:44:35 -08:00
adam-sim-dev 587d437f32 Merge branch 'master' into cusparseXcsrsort 2024-11-05 08:43:47 +08:00
adam-sim-dev c0ae0f0a4b Merge branch 'master' into cusparseXcsrsort 2024-11-04 08:28:10 +08:00
Mark L. Stowell 615448bbc3 Cleanup 2024-11-01 17:34:16 -07:00
Mark L. Stowell 68cfee09e0 Make fields optional 2024-11-01 11:59:08 -07:00
Mark L. Stowell a0656da6ef Fixing banner 2024-11-01 10:37:36 -07:00
Mark L. Stowell 1395d44724 Changing miniapp name in secondary locations 2024-11-01 10:18:30 -07:00
Mark L. Stowell a42a394111 Changing the name of the new miniapp 2024-11-01 10:12:11 -07:00
Mark L. Stowell 0fa8b85391 Adding a new miniapp for particle trajectory due to Lorentz forces 2024-10-31 17:38:31 -07:00
Mark L. Stowell d4db7ef8cd Improving VisItDataCollection output from two miniapps to make them more usable 2024-10-31 17:36:08 -07:00
Andrew Ho 3d9af90191 need to link to cudart so projects depending on CUDA+MFEM don't need
to know about cuda directly
2024-10-30 18:17:47 -07:00
Andrew Ho 1ab9f62208 Fixed CMake install module file with CUDA or HIP 2024-10-30 17:11:43 -07:00
adam-sim-dev 179e6ec141 Merge branch 'master' into cusparseXcsrsort 2024-10-29 09:42:22 +08:00
adam-sim-dev 2434d4ac71 Merge branch 'master' into cusparseXcsrsort 2024-10-24 16:48:24 +08:00
adam-sim-devandAndrew Ho a9e5c58897 Correct descrA to matA_descr
Co-authored-by: Andrew Ho <ho37@llnl.gov>
2024-10-16 08:21:37 +08:00
adam-sim-dev 35d9fa1f6c Merge branch 'master' into cusparseXcsrsort 2024-10-15 12:15:04 +08:00
adam-sim-dev fb9117e9fb Merge branch 'master' into cusparseXcsrsort 2024-10-10 22:51:24 +08:00
Dylan Copeland 4af5e6a758 Added a flag to Mesh loader, allowing for bad orientation. Debugged the case of a patch only 1 element wide. 2024-10-03 16:05:44 -07:00
adam-sim-dev d4d149a5ff Use cusparseXcsrsort instead of the deprecated cusparseXcsru2csr 2024-09-29 14:27:26 +08:00
dylan-copeland b0dd0109bb More pedantic warning fixes. 2024-09-04 21:59:44 -07:00
Dylan Copeland ac9f49a137 Fix shadowed variable. 2024-09-04 21:43:27 -07:00
Dylan Copeland 178b9b8170 Fix last commit. 2024-09-04 21:32:05 -07:00
dylan-copeland 886579fb48 Moved new code for NC-NURBS to a new cpp file. 2024-09-04 21:13:08 -07:00
dylan-copeland 7367c5a42e Fix mac warnings. 2024-09-04 20:35:43 -07:00
Dylan Copeland b47ec8d14d Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2024-09-04 20:03:51 -07:00
Dylan Copeland a31f758d55 Generalized for auxiliary edges and faces in 3D. 2024-09-04 17:19:40 -07:00
Dylan Copeland 181247ffcf More rearranging. 2024-06-03 21:12:42 -07:00
Dylan Copeland cf5e341f49 Rearranged new code to simplify git diffs. 2024-06-03 20:58:42 -07:00
dylan-copeland 15b20e62ac Fixed comparison of different signedness. 2024-06-03 19:04:23 -07:00
dylan-copeland b8ad8fb003 Fixed build on mac. 2024-06-03 18:18:41 -07:00
Dylan Copeland 7fe11de76a Fixed some shadowed variables. 2024-06-03 17:08:00 -07:00
Dylan Copeland d12164148a Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2024-06-03 16:16:28 -07:00
Dylan Copeland f480dd23a4 Extension to 3D. 2024-06-03 13:16:55 -07:00
Dylan Copeland fd57eb3076 Merge branch 'master' of github.com:mfem/mfem into nurbs-nc 2023-12-13 15:25:29 -08:00
Dylan Copeland 4e6ac3490e Added data structures for auxiliary NC edges defined for patch intersections on subsets of patch edges. 2023-12-04 13:59:02 -08:00
Dylan Copeland 177e16ca9d Added option to specify "vertex_to_knot" in mesh file, for the case that refinement heirarchy does not exist and the mesh may have NURBS patches neighboring arbitrary elements. 2023-09-08 14:07:09 -07:00
Dylan Copeland 29e3f9b7a6 Initial 2D implementation of NC-NURBS meshes, with an example in ex1.cpp. 2023-08-02 14:53:54 -07:00
216 changed files with 20301 additions and 5677 deletions
+13 -6
View File
@@ -132,12 +132,14 @@ jobs:
hypre-target: int32
precision: fp64
enzyme: true
config-opts: MFEM_USE_ENZYME=YES ENZYME_DIR=$(brew --prefix enzyme)
config-opts: MFEM_USE_ENZYME=YES ENZYME_DIR=$(brew --prefix enzyme) LDFLAGS=-L$LLVM_PREFIX/lib/c++
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}-${{ matrix.precision }}${{ matrix.enzyme && '-enzyme' || '' }}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.enzyme && true || false }}
steps:
# Fix 'No space left on device' errors for Ubuntu builds.
- name: Run Actions Cleaner
@@ -168,10 +170,13 @@ jobs:
env
shell: bash
# For info on Xcode see:
# - https://github.com/actions/runner-images/issues/12541
# - https://github.com/actions/runner-images/blob/releases/macos-15-arm64/20250811/images/macos/macos-15-arm64-Readme.md#xcode
- name: Xcode version setup (MacOS)
if: matrix.os == 'macos-latest'
run: |
XCODE_PATH="/Applications/Xcode_15.3.app"
XCODE_PATH="/Applications/Xcode_16.4.app"
echo "> sudo xcode-select -s ${XCODE_PATH}"
sudo xcode-select -s ${XCODE_PATH}
echo "> g++ -v"
@@ -289,10 +294,12 @@ jobs:
run: |
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew update
brew install llvm@19 enzyme
echo "LLVM_PREFIX=$(brew --prefix llvm@19)" >> $GITHUB_ENV
echo "OMPI_CC=$(brew --prefix llvm@19)/bin/clang" >> $GITHUB_ENV
echo "OMPI_CXX=$(brew --prefix llvm@19)/bin/clang++" >> $GITHUB_ENV
brew install enzyme
ENZYME_LLVM=$(brew info enzyme | sed -n 's/^Required:.*\(llvm[^ ]*\).*/\1/p')
LLVM_PREFIX=$(brew --prefix $ENZYME_LLVM)
echo "LLVM_PREFIX=$LLVM_PREFIX" >> $GITHUB_ENV
echo "OMPI_CC=$LLVM_PREFIX/bin/clang" >> $GITHUB_ENV
echo "OMPI_CXX=$LLVM_PREFIX/bin/clang++" >> $GITHUB_ENV
# MFEM build and test
- name: build
+44
View File
@@ -29,3 +29,47 @@ jobs:
operations-per-run: 500
exempt-issue-labels: "bug,WIP,ready-for-review,in-review,in-next"
exempt-pr-labels: "bug,WIP,ready-for-review,in-review,in-next"
# Stale action for PRs with "in-review" label.
stale-in-review-pr:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
actions: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: ':warning: This PR has been automatically marked as stale because it has not had any activity in the last 150 days. *If no activity occurs in the next 30 days, it will be automatically closed.* Thank you for your contributions.'
only-pr-labels: "in-review"
days-before-pr-stale: 150
days-before-pr-close: 30
days-before-issue-stale: -1
days-before-issue-close: -1
stale-pr-label: 'stale'
operations-per-run: 500
# Stale action for PRs with "WIP" label.
stale-wip-pr:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
actions: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: ':warning: This PR has been automatically marked as stale because it has not had any activity in the last 300 days. *If no activity occurs in the next 30 days, it will be automatically closed.* Thank you for your contributions.'
only-pr-labels: "WIP"
days-before-pr-stale: 300
days-before-pr-close: 30
days-before-issue-stale: -1
days-before-issue-close: -1
stale-pr-label: 'stale'
operations-per-run: 500
+7 -4
View File
@@ -208,10 +208,13 @@ miniapps/electromagnetics/volta
miniapps/electromagnetics/tesla
miniapps/electromagnetics/maxwell
miniapps/electromagnetics/joule
miniapps/electromagnetics/lorentz
miniapps/electromagnetics/Volta-AMR*
miniapps/electromagnetics/Tesla-AMR*
miniapps/electromagnetics/Maxwell-Parallel*
miniapps/electromagnetics/Joule_*
miniapps/electromagnetics/Joule_[0-9]*
miniapps/electromagnetics/Lorentz_[0-9]*
miniapps/electromagnetics/Lorentz.dat
miniapps/gslib/field-diff
miniapps/gslib/field-interp
@@ -267,9 +270,9 @@ miniapps/meshing/bounding-box*
miniapps/meshing/jacobian-determinant*
miniapps/mtop/parheat
miniapps/mtop/ParHeat*
miniapps/mtop/ParHeat/*
miniapps/mtop/seqheat
miniapps/mtop/SeqHeat*
miniapps/mtop/SeqHeat/*
miniapps/autodiff/paradiff
miniapps/autodiff/seqadiff
@@ -277,7 +280,7 @@ miniapps/autodiff/seqtest
miniapps/autodiff/par_example
miniapps/autodiff/seq_example
miniapps/autodiff/seq_test
miniapps/autodiff/Exampl*
miniapps/autodiff/Example/*
miniapps/navier/navier_mms
miniapps/navier/navier_kovasznay
+5 -5
View File
@@ -22,7 +22,7 @@ include:
# the "needs" keyword and express the DAG of jobs for more efficiency.
# - We use setup and setup_baseline phases to download content outside of mfem
# directory.
# - Allocate/Release is where ruby resource are allocated/released once for all.
# - Allocate/Release is where Dane resource are allocated/released once for all.
# - Build and Test is where we build and MFEM for multiple toolchains.
# - Baseline_checks gathers baseline-type test suites execution
# - Baseline_publish, only available on master, allows to update baseline
@@ -53,7 +53,7 @@ variables:
AUTOTEST_COMMIT: "YES"
# Trigger subpipelines:
ruby-build-and-test:
dane-build-and-test:
stage: sub-pipelines
variables:
# Explicitly pass down values that we want to be able to set when triggering
@@ -61,10 +61,10 @@ ruby-build-and-test:
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
trigger:
include: .gitlab/ruby-build-and-test.yml
include: .gitlab/dane-build-and-test.yml
strategy: depend
ruby-baseline:
dane-baseline:
stage: sub-pipelines
variables:
# Explicitly pass down values that we want to be able to set when triggering
@@ -73,7 +73,7 @@ ruby-baseline:
AUTOTEST: "${AUTOTEST}"
AUTOTEST_COMMIT: "${AUTOTEST_COMMIT}"
trigger:
include: .gitlab/ruby-baseline.yml
include: .gitlab/dane-baseline.yml
strategy: depend
lassen-build-and-test:
+3 -3
View File
@@ -24,7 +24,7 @@ and `test type`.
Machines typically include:
* Ruby: 2nd Gen Intel Xeon (Cascade Lake)
* Dane: Intel Sapphire Rapids
* Lassen: Power9 + Nvidia GPU
* Corona: AMD GPU
@@ -76,13 +76,13 @@ with a spack spec of MFEM, within the limits permitted by the MFEM spack
package.
In any build-and-test sub-pipeline a job basically consists in defining the
spack spec to use. Adding a job on ruby for example resumes to:
spack spec to use. Adding a job on Dane for example resumes to:
```yaml
<job_name>:
variables:
SPEC: "<spack_spec>"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_dane
```
The remaining and non trivial work is to make sure this spec is working. To
+1 -1
View File
@@ -24,7 +24,7 @@ variables:
# TODO: add a clean-up mechanism
BUILD_ROOT: ${USER_CI_TOP_DIR}/${CI_PROJECT_NAME}-${MACHINE_NAME}-pipeline-${CI_PIPELINE_ID}
# On LLNL's ruby, there is only one allocation shared among jobs in order to
# On LLNL's Dane, there is only one allocation shared among jobs in order to
# save time and resource. This allocation has to be uniquely named so that we
# are sure to retrieve it.
ALLOC_NAME: ${CI_PROJECT_NAME}_ci_${CI_PIPELINE_ID}
@@ -9,17 +9,17 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# GitLab pipelines configurations for the Ruby machine at LLNL
# GitLab pipelines configurations for the Dane machine at LLNL
variables:
MACHINE_NAME: ruby
MACHINE_NAME: dane
.on_ruby:
.on_dane:
tags:
- shell
- ruby
- dane
rules:
# Don't run ruby jobs if...
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_RUBY == "OFF"'
# Don't run dane jobs if...
- if: '$CI_COMMIT_BRANCH =~ /_qnone/ || $ON_DANE == "OFF"'
when: never
# Don't run autotest update if...
- if: '$CI_JOB_NAME =~ /report/ && $AUTOTEST != "YES"'
@@ -40,16 +40,17 @@ variables:
- when: on_success
# Spack helped builds
# Generic ruby build job, extending build script
.build_and_test_on_ruby:
extends: [.on_ruby]
# Generic dane build job, extending build script
.build_and_test_on_dane:
extends: [.on_dane]
stage: build_and_test
script:
# THREADS is used by 'tests/gitlab/build_and_test', run below
- export THREADS=16
# Dane has 224 threads/node and we run 7 separate jobs: 224=7*32
- export THREADS=28
- echo ${ALLOC_NAME}
- export JOBID=$(squeue -h --name=${ALLOC_NAME} --format=%A)
- echo ${JOBID}
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) --reservation=ci -t 45 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- srun $( [[ -n "${JOBID}" ]] && echo "--jobid=${JOBID}" ) --reservation=ci -t 60 -N 1 tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
+1 -1
View File
@@ -18,7 +18,7 @@
setup_baseline:
tags:
- shell
- ruby
- dane
stage: setup
variables:
GIT_STRATEGY: none
+1 -1
View File
@@ -16,7 +16,7 @@
setup:
tags:
- shell
- ruby
- dane
stage: setup
variables:
GIT_STRATEGY: none
@@ -19,8 +19,8 @@ stages:
- cleanup
- baseline_publish
baselinecheck_mfem_intel_ruby:
extends: [.on_ruby]
baselinecheck_mfem_intel_dane:
extends: [.on_dane]
stage: baseline_check
variables:
# TPLS_DIR is used in .gitlab/scripts/baseline to provide the tpls location
@@ -31,8 +31,8 @@ baselinecheck_mfem_intel_ruby:
script:
- echo ${BUILD_ROOT}
- echo ${TPLS_DIR}
# Used by the tests in MFEM/tests:
- export MFEM_TEST_NP=48
# Used by the tests in MFEM/tests, dane has 224 threads/node:
- export MFEM_TEST_NP=192
# The next script uses the following environment variables:
# * BASELINE_TEST, SYS_TYPE, CI_PROJECT_DIR, ARTIFACTS_DIR,
# * BUILD_ROOT, TPLS_DIR, MACHINE_NAME
@@ -44,7 +44,7 @@ baselinecheck_mfem_intel_ruby:
allow_failure: true
cleanup:
extends: .on_ruby
extends: .on_dane
stage: cleanup
variables:
GIT_STRATEGY: none
@@ -53,7 +53,7 @@ cleanup:
- rm -rf "${BUILD_ROOT}" || true
report_baseline:
extends: [.on_ruby]
extends: [.on_dane]
stage: baseline_report
script:
- echo ${MACHINE_NAME}
@@ -113,8 +113,8 @@ report_baseline:
exit $err
) 9> autotest.lock
baselinepublish_mfem_ruby:
extends: [.on_ruby]
baselinepublish_mfem_dane:
extends: [.on_dane]
stage: baseline_publish
rules:
# - if: '$CI_COMMIT_BRANCH == "master" || $REBASELINE == "YES"'
@@ -129,5 +129,5 @@ baselinepublish_mfem_ruby:
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/ruby-config.yml
- local: .gitlab/configs/dane-config.yml
- local: .gitlab/configs/setup-baseline.yml
@@ -19,54 +19,54 @@ stages:
allocate_resource:
variables:
GIT_STRATEGY: none
extends: .on_ruby
extends: .on_dane
stage: allocate_resource
script:
- echo ${ALLOC_NAME}
- salloc --exclusive --nodes=1 --reservation=ci --time=60 --no-shell --job-name=${ALLOC_NAME}
timeout: 6h
# GitLab jobs for the Ruby machine at LLNL
# GitLab jobs for the Dane machine at LLNL
debug_ser_gcc_10:
variables:
SPEC: "%gcc@10.3.1 +debug~mpi"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_dane
debug_par_gcc_10:
variables:
SPEC: "%gcc@10.3.1 +debug+mpi"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_dane
opt_ser_gcc_10:
variables:
SPEC: "%gcc@10.3.1 ~mpi"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_dane
opt_par_gcc_10:
variables:
SPEC: "%gcc@10.3.1"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_dane
opt_par_gcc_10_sundials:
variables:
SPEC: "%gcc@10.3.1 +sundials"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_dane
opt_par_gcc_10_petsc:
variables:
SPEC: "%gcc@10.3.1 +petsc ^petsc+mumps~superlu-dist"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_dane
opt_par_gcc_10_pumi:
variables:
SPEC: "%gcc@10.3.1 +pumi"
extends: .build_and_test_on_ruby
extends: .build_and_test_on_dane
# Release
release_resource:
variables:
GIT_STRATEGY: none
extends: .on_ruby
extends: .on_dane
stage: release_resource_and_report
script:
- echo ${ALLOC_NAME}
@@ -78,17 +78,17 @@ release_resource:
report_job_success:
stage: release_resource_and_report
extends:
- .on_ruby
- .on_dane
- .report_job_success
report_job_failure:
stage: release_resource_and_report
extends:
- .on_ruby
- .on_dane
- .report_job_failure
include:
- local: .gitlab/configs/common.yml
- local: .gitlab/configs/ruby-config.yml
- local: .gitlab/configs/dane-config.yml
- local: .gitlab/configs/setup-build-and-test.yml
- local: .gitlab/configs/report-build-and-test.yml
+2 -2
View File
@@ -14,7 +14,7 @@
# locals
glob_err=${BASELINE_TEST}.err
base=${BASELINE_TEST}-${SYS_TYPE}
if [[ "${MACHINE_NAME}" == "ruby" ]]; then
if [[ "${MACHINE_NAME}" == "dane" ]]; then
base="${BASELINE_TEST}-${MACHINE_NAME}"
fi
base_diff=${base}.diff
@@ -31,7 +31,7 @@ cd tests
mkdir _${BASELINE_TEST} && cd _${BASELINE_TEST}
# run
if [[ "${MACHINE_NAME}" == "ruby" ]]; then
if [[ "${MACHINE_NAME}" == "dane" ]]; then
salloc --nodes=1 --exclusive --reservation=ci ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
elif [[ ${MACHINE_NAME} == "corona" ]]; then
salloc --nodes=1 -t 60 -p pbatch ../runtest ../../mfem "${BASELINE_TEST} ${TPLS_DIR}"
+2 -2
View File
@@ -11,7 +11,7 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# There will be collision between corona and ruby baselines.
# There will be collision between corona and dane baselines.
# Once the corresponding files have been generated, we can switch to machine
# specific ref.
ARTIFACT_PATH=${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/baseline-${SYS_TYPE}
@@ -21,7 +21,7 @@ PATCH_FILE=${ARTIFACT_PATH}.patch
FULL_FILE=${ARTIFACT_PATH}.out
DIFF_FILE=${ARTIFACT_PATH}.diff
# There will be collision between corona and ruby baselines.
# There will be collision between corona and dane baselines.
# Once the corresponding files have been generated, we can switch to machine
# specific ref.
SAVED_NAME=baseline-${SYS_TYPE}.saved
+51 -1
View File
@@ -27,9 +27,27 @@ Discretization improvements
- In the ParMoonolith integration, added support for variational resampling of
H1 vector fields.
- Added support for boundary integration to the hyperbolic framework. In this
regard, new classes `BdrHyperbolicDirichletIntegrator` and
`BoundaryHyperbolicFlowIntegrator` have been introduced for implementation
of weak Dirichlet boundary conditions with a general flux or for the linear
case respectively.
- Added method to compute piecewise linear bounds on high-order functions on
tensor-product elements.
- Parallel anisotropic refinement of hexahedral meshes is now supported,
provided that neighboring hexahedra are not refined in conflicting directions.
A new ParMesh method is added to check for such conflicts, before refinement.
Meshing improvements
--------------------
- Introduced NC-patch NURBS meshes, which are conforming element-wise but allow
for nonconforming patch topology. This new mesh format supports element
spacing formulas for refinement, as well as local refinement factors for a
subset of knot vectors.
- Added support for higher order meshes in Mesh::MakeSimplicial and
ParMesh::MakeSimplicial.
@@ -44,9 +62,20 @@ GPU computing
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).
- Introduced MFEM_FOREACH_THREAD_DIRECT, which directly maps loop tasks to GPU
threads, assigning one task per thread.
- Implemented a GPU-accelerated matrix-free AMR derefinement `GridFunction`
update operator. This supports mixed geometry meshes and variable order
spaces, and is the default derefinement operator constructed by
`FiniteElementSpace::Update` and `ParFiniteElementSpace::Update`.
The operator requires `FiniteElementSpace::Nonconforming() == true`.
- Added new method: GridFunction::GetGradients, with GPU support, for computing
the gradients of a GridFunction on all elements.
- Added GPU support in GradientGridFunctionCoefficient and
InnerProductCoefficient by implementing their Project methods.
New and updated examples and miniapps
-------------------------------------
- Added miniapps to demonstrate an implementation of the absolute-value
@@ -55,10 +84,22 @@ New and updated examples and miniapps
operators as smoothers.
These miniapps can be found in `miniapps/diag-smoothers`.
API changes
- Added a new miniapp (meshing/mesh-bounding-boxes) that computes the bounding
boxes for each element of a given mesh, and the bounds on the determinant of
the Jacobian of the transformation.
- Added a new miniapp (tools/gridfunction-bounds) to compute piecewise linear
bounds on a given high-order grid function.
- Added a new miniapp (electromagnetics/lorentz) which computes the trajectory
of a charged particle, subject to Lorentz forces, in electrostatic and/or
magnetostatic fields as computed by the volta or tesla miniapps.
API changes:
-----------
- mfem::internal::tensor and mfem::internal::dual have been moved to
mfem::future::tensor and mfem::future::dual.
- API addition: in class `Operator`, added virtual functions: `AbsMult`, and
`AbsMultTranspose`; in class `Vector`, added `Abs` and `Pow`.
@@ -66,16 +107,25 @@ Miscellaneous
-------------
- Added the "gpu", "raja-gpu", and "ceed-gpu" backend aliases/shortcuts which
automatically select between CUDA or HIP.
- The CUDA-specific names used by some of the unit tests like 'cunit_tests' and
'pcunit_tests' were replaced by names using 'gpu' instead of 'c' (short for
CUDA) or 'cuda'. These tests automatically run the CUDA/HIP tests based on the
MFEM build configuration.
- Added the option to enable GPU-aware MPI in MFEM using the environment
variable 'MFEM_GPU_AWARE_MPI' set to any value. Setting this environment
variable is an alternative to calling 'Device::SetGPUAwareMPI(true)'.
- Added parallel Address Sanitizer, serial and parallel Undefined Behavior
Sanitizer and serial Memory Sanitizer GitHub actions tests on Ubuntu.
- FindPointsGSLIB has a new constructor that accepts the mesh object and
internally calls the Setup() method so that the user does not have to.
The FreeData() method has also been moved to the destructor so the user does
not need to manually free-up the memory if the destructor is called before
MPI_Finalize().
Version 4.8, released on Apr 9, 2025
====================================
+25 -11
View File
@@ -278,6 +278,11 @@ if (MFEM_USE_OPENMP OR MFEM_USE_LEGACY_OPENMP)
endif()
endif()
# Umpire (must be included before hypre, so hypre can use it if needed)
if (MFEM_USE_UMPIRE)
find_package(UMPIRE REQUIRED)
endif()
# MPI -> hypre; PETSc (optional)
if (MFEM_USE_MPI)
find_package(MPI REQUIRED)
@@ -495,14 +500,13 @@ endif()
# RAJA
if (MFEM_USE_RAJA)
# RAJA uses FindCUDA, which needs CMP0146=OLD in CMake >= 3.27
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.27.0)
cmake_policy(SET CMP0146 OLD)
endif()
find_package(RAJA REQUIRED)
endif()
# UMPIRE
if (MFEM_USE_UMPIRE)
find_package(UMPIRE REQUIRED)
endif()
# GOOGLE-BENCHMARK
if (MFEM_USE_BENCHMARK)
find_package(Benchmark REQUIRED)
@@ -596,18 +600,25 @@ set(MFEM_TPLS OPENMP HYPRE LAPACK BLAS SuperLUDist STRUMPACK METIS SuiteSparse
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
ALGOIM ENZYME)
ALGOIM ENZYME CUDA::cudart)
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
# Add all created targets and *_FOUND libraries in the variables TPL_TARGETS and
# TPL_LIBRARIES, respectively.
set(TPL_TARGETS)
set(TPL_LIBRARIES "")
set(TPL_INCLUDE_DIRS "")
foreach(TPL IN LISTS MFEM_TPLS)
if (${TPL}_FOUND)
if (${TPL}_FOUND OR TARGET ${TPL})
message(STATUS "MFEM: using package ${TPL}")
list(APPEND TPL_LIBRARIES ${${TPL}_LIBRARIES})
list(APPEND TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS})
if (TARGET ${TPL})
list(APPEND TPL_TARGETS ${TPL})
else()
list(APPEND TPL_LIBRARIES ${${TPL}_LIBRARIES})
list(APPEND TPL_INCLUDE_DIRS ${${TPL}_INCLUDE_DIRS})
endif()
endif()
endforeach(TPL)
list(REVERSE TPL_LIBRARIES)
list(REMOVE_DUPLICATES TPL_LIBRARIES)
list(REVERSE TPL_LIBRARIES)
@@ -680,7 +691,10 @@ set(MFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
# Declaring the library
mfem_add_library(mfem ${SOURCES} ${HEADERS} ${MASTER_HEADERS})
# message(STATUS "TPL_LIBRARIES = ${TPL_LIBRARIES}")
target_link_libraries(mfem PUBLIC ${TPL_LIBRARIES})
target_link_libraries(mfem PUBLIC ${TPL_LIBRARIES} ${TPL_TARGETS})
if (TPL_TARGETS)
add_dependencies(mfem ${TPL_TARGETS})
endif()
if (MINGW)
target_link_libraries(mfem PRIVATE ws2_32)
endif()
+17 -1
View File
@@ -121,6 +121,11 @@ Parallel build:
make -j 4
(For METIS 5, see https://mfem.org/building/#parallel-build-using-metis-5)
Parallel build with fetching of hypre and METIS:
mkdir <mfem-buil-dir> ; cd <mfem-build-dir>
cmake <mfem-source-dir> -DMFEM_USE_MPI=YES -DFETCH_TPLS=YES
make -j 4
CUDA build:
(this build requires CMake 3.17 or newer)
mkdir <mfem-build-dir> ; cd <mfem-build-dir>
@@ -663,6 +668,7 @@ The specific libraries and their options are:
- OpenMP (optional), usually part of compiler, used when either MFEM_USE_OPENMP
or MFEM_USE_LEGACY_OPENMP is set to YES.
Options: OPENMP_OPT, OPENMP_LIB.
Versions: OpenMP >= 3.1 when MFEM_USE_OPENMP=YES.
- High-resolution POSIX clocks: when using MFEM_TIMER_TYPE = 2, it may be
necessary to link with a system library (e.g. librt.so).
@@ -842,6 +848,7 @@ The specific libraries and their options are:
- HIP (optional), used when MFEM_USE_HIP = YES.
URL: https://rocmdocs.amd.com
Options: HIP_CXX, HIP_ARCH, HIP_OPT, HIP_LIB.
Versions: ROCm >= 5.6.1.
- OCCA (optional), used when MFEM_USE_OCCA = YES.
URL: https://libocca.org
@@ -852,7 +859,7 @@ The specific libraries and their options are:
URL: https://github.com/CEED/libCEED
https://ceed.exascaleproject.org/libceed
Options: CEED_DIR, CEED_OPT, CEED_LIB.
Versions: libCEED >= 0.12.
Versions: libCEED >= 0.12.0.
- RAJA (optional), used when MFEM_USE_RAJA = YES.
Beginning with MFEM v4.5.1, only RAJA v2022.10.3+ is supported.
@@ -1074,6 +1081,9 @@ The following options are CMake specific:
MFEM_ENABLE_TESTING - Enable the ctest framework for testing.
MFEM_ENABLE_EXAMPLES - Build all of the examples by default.
MFEM_ENABLE_MINIAPPS - Build all of the miniapps by default.
FETCH_TPLS - Enable fetching of all supported third-party libraries.
HYPRE_FETCH - Enable fetching of hypre.
METIS_FETCH - Enable fetching of metis.
External libraries (CMake):
---------------------------
@@ -1135,6 +1145,12 @@ The following built-in CMake packages are also used:
set the <LIBNAME>_LIBRARIES option directly; the configuration option
<LIBNAME>_DIR is not supported.
The MFEM CMake build system also provides fetching (automated building) for the
packages/libraries listed below. Note that when fetching is enabled, any related
auto-detection functionality is disabled.
- HYPRE
- METIS
Building without GNU make or CMake
==================================
+25
View File
@@ -84,6 +84,31 @@ set_and_check(MFEM_LIBRARY_DIR "@PACKAGE_LIB_INSTALL_DIR@")
check_required_components(MFEM)
include(CMakeFindDependencyMacro)
if (MFEM_USE_CUDA)
# required for projects linking to MFEM+CUDA, even if they don't use CUDA directly
find_dependency(CUDAToolkit)
endif (MFEM_USE_CUDA)
if (MFEM_USE_HIP)
# hip/rocm uses the modern MFEM way of linking to targets, need to find dependencies
find_dependency(HIP)
find_dependency(HIPBLAS)
find_dependency(HIPSPARSE)
if (MFEM_USE_MPI)
# assume HYPRE uses HIP
# alternatively could check HYPRE_USING_HIP
find_dependency(rocsparse)
find_dependency(rocrand)
find_dependency(rocsolver)
endif (MFEM_USE_MPI)
endif (MFEM_USE_HIP)
if (MFEM_USE_RAJA)
find_dependency(RAJA)
endif()
if (NOT TARGET mfem)
include(${CMAKE_CURRENT_LIST_DIR}/MFEMTargets.cmake)
endif (NOT TARGET mfem)
+97 -3
View File
@@ -9,21 +9,25 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Defines the following variables:
# Defines the following variables if fetching of TPLs is disabled (default):
# - HYPRE_FOUND
# - HYPRE_LIBRARIES
# - HYPRE_INCLUDE_DIRS
# - HYPRE_VERSION
# - HYPRE_USING_CUDA (internal)
# - HYPRE_USING_HIP (internal)
# otherwise, the following are defined:
# - HYPRE (imported library target)
# - HYPRE_VERSION (cache variable)
if (HYPRE_FOUND)
if (HYPRE_FOUND OR TARGET HYPRE)
if (HYPRE_USING_CUDA)
find_package(CUDAToolkit REQUIRED)
endif()
if (HYPRE_USING_HIP)
find_package(rocsparse REQUIRED)
find_package(rocrand REQUIRED)
find_package(rocsolver REQUIRED)
endif()
if (HYPRE_LIBRARIES AND HYPRE_INCLUDE_DIRS AND HYPRE_VERSION)
find_package_handle_standard_args(HYPRE
@@ -33,6 +37,95 @@ if (HYPRE_FOUND)
endif()
endif()
if (HYPRE_FETCH OR FETCH_TPLS)
# Collect all HYPRE_ENABLE variables and pass them to hypre, assuming they are BOOL.
set(HYPRE_CMAKE_OPTIONS "")
get_cmake_property(all_vars VARIABLES)
foreach(var ${all_vars})
if(var MATCHES "^HYPRE_ENABLE")
list(APPEND HYPRE_CMAKE_OPTIONS "-D${var}:BOOL=${${var}}")
endif()
endforeach()
set(HYPRE_FETCH_VERSION 2.33.0)
set(HYPRE_FETCH_TAG "v${HYPRE_FETCH_VERSION}" CACHE STRING "Tag, branch, or commit for HYPRE")
add_library(HYPRE STATIC IMPORTED)
# set options and associated dependencies
list(APPEND HYPRE_CMAKE_OPTIONS -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE})
if (MFEM_USE_CUDA)
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_CUDA:BOOL=ON -DCMAKE_CUDA_ARCHITECTURES:STRING=${CMAKE_CUDA_ARCHITECTURES})
find_package(CUDAToolkit REQUIRED)
target_link_libraries(HYPRE INTERFACE CUDA::cusparse CUDA::curand CUDA::cublas)
elseif (MFEM_USE_HIP)
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_HIP:BOOL=ON)
find_package(rocsparse REQUIRED)
find_package(rocrand REQUIRED)
target_link_libraries(HYPRE INTERFACE rocsparse rocrand)
endif()
if (MFEM_USE_CUDA OR MFEM_USE_HIP)
if (MFEM_USE_UMPIRE)
if (EXISTS ${umpire_DIR})
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_UMPIRE:BOOL=ON -Dumpire_DIR:PATH=${umpire_DIR})
else()
message(FATAL_ERROR "MFEM_USE_UMPIRE=ON, however umpire_DIR isn't visible to HYPRE")
endif()
else()
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_UMPIRE:BOOL=OFF)
message(WARNING
"================================================================================
Umpire is disabled while building HYPRE with GPU support.
This is not recommended for performance reasons!
Consider enabling Umpire with -DMFEM_USE_UMPIRE=ON and providing -DUMPIRE_DIR.
================================================================================")
endif()
endif()
if (MFEM_USE_SINGLE)
list(APPEND HYPRE_CMAKE_OPTIONS -DHYPRE_ENABLE_SINGLE:BOOL=ON)
endif()
# define external project and create future include directory so it is present
# to pass CMake checks at end of MFEM configuration step
message(STATUS "Will fetch HYPRE ${HYPRE_FETCH_TAG} to be built with ${HYPRE_CMAKE_OPTIONS}")
set(HYPRE_INSTALL ${CMAKE_BINARY_DIR}/fetch/hypre)
include(ExternalProject)
ExternalProject_Add(hypre
GIT_REPOSITORY https://github.com/hypre-space/hypre.git
GIT_TAG ${HYPRE_FETCH_TAG}
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
UPDATE_DISCONNECTED TRUE
SOURCE_SUBDIR src
PREFIX ${HYPRE_INSTALL}
BUILD_COMMAND ${CMAKE_COMMAND} --build . -- -j${CMAKE_BUILD_PARALLEL_LEVEL}
CMAKE_CACHE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${HYPRE_INSTALL} -DCMAKE_INSTALL_LIBDIR:PATH=lib ${HYPRE_CMAKE_OPTIONS})
file(MAKE_DIRECTORY ${HYPRE_INSTALL}/include)
# set imported library target properties
add_dependencies(HYPRE hypre)
set_target_properties(HYPRE PROPERTIES
IMPORTED_LOCATION ${HYPRE_INSTALL}/lib/libHYPRE.a
INTERFACE_INCLUDE_DIRECTORIES ${HYPRE_INSTALL}/include)
# convert HYPRE version to integer
if (HYPRE_FETCH_TAG MATCHES "^v?([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
# Exact release tag X.Y.Z
string(REGEX MATCHALL "[0-9]+" HYPRE_SPLIT_VERSION "${HYPRE_FETCH_TAG}")
elseif (HYPRE_FETCH_VERSION MATCHES "([0-9]+)\\.([0-9]+)(\\.([0-9]+))?")
string(REGEX MATCHALL "[0-9]+" HYPRE_SPLIT_VERSION "${HYPRE_FETCH_VERSION}")
else (NOT DEFINED HYPRE_VERSION)
message(FATAL_ERROR "Unable to find HYPRE release version. Please provide it via -DHYPRE_VERSION")
endif()
if (HYPRE_SPLIT_VERSION AND NOT DEFINED HYPRE_VERSION)
list(GET HYPRE_SPLIT_VERSION 0 HYPRE_MAJOR_VERSION)
list(GET HYPRE_SPLIT_VERSION 1 HYPRE_MINOR_VERSION)
if (HYPRE_SPLIT_VERSION GREATER 2)
list(GET HYPRE_SPLIT_VERSION 2 HYPRE_PATCH_VERSION)
else()
set(HYPRE_PATCH_VERSION 0)
endif()
math(EXPR HYPRE_VERSION "10000*${HYPRE_MAJOR_VERSION} + 100*${HYPRE_MINOR_VERSION} + ${HYPRE_PATCH_VERSION}")
set(HYPRE_VERSION ${HYPRE_VERSION} CACHE STRING "HYPRE version." FORCE)
endif()
return()
endif()
include(MfemCmakeUtilities)
mfem_find_package(HYPRE HYPRE HYPRE_DIR "include" "HYPRE.h" "lib" "HYPRE"
"Paths to headers required by HYPRE." "Libraries required by HYPRE."
@@ -97,7 +190,8 @@ endif()
if (HYPRE_FOUND AND HYPRE_USING_HIP)
find_package(rocsparse REQUIRED)
find_package(rocrand REQUIRED)
list(APPEND HYPRE_LIBRARIES ${rocsparse_LIBRARIES} ${rocrand_LIBRARIES})
find_package(rocsolver REQUIRED)
list(APPEND HYPRE_LIBRARIES ${rocsparse_LIBRARIES} ${rocrand_LIBRARIES} roc::rocsolver roc::rocblas)
set(HYPRE_LIBRARIES ${HYPRE_LIBRARIES} CACHE STRING
"HYPRE libraries + dependencies." FORCE)
message(STATUS "Updated HYPRE_LIBRARIES: ${HYPRE_LIBRARIES}")
+30 -1
View File
@@ -9,10 +9,39 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
# Defines the following variables:
# Defines the following variables if fetching of TPLs is disabled (default):
# - METIS_FOUND
# - METIS_LIBRARIES
# - METIS_INCLUDE_DIRS
# - METIS_VERSION_5
# otherwise, the following are defined:
# - METIS (imported library target)
# - METIS_VERSION_5 (cache variable)
if (METIS_FETCH OR FETCH_TPLS)
set(METIS_FETCH_VERSION 4.0.3)
add_library(METIS STATIC IMPORTED)
# define external project
message(STATUS "Will fetch METIS ${METIS_FETCH_VERSION} to be built with default options")
set(PREFIX ${CMAKE_BINARY_DIR}/fetch/metis)
include(ExternalProject)
ExternalProject_Add(metis
GIT_REPOSITORY https://github.com/mfem/tpls
GIT_TAG b60352fbe9675d374b00828055e55be4584c7995 # tag from 1/16/25
GIT_SHALLOW TRUE
UPDATE_DISCONNECTED TRUE
PREFIX ${PREFIX}
CONFIGURE_COMMAND tar -xzf ../metis/metis-${METIS_FETCH_VERSION}-mac.tgz --strip=1
BUILD_COMMAND $(MAKE) COPTIONS=-Wno-incompatible-pointer-types
INSTALL_COMMAND mkdir -p ${PREFIX}/lib && cp libmetis.a ${PREFIX}/lib/)
# set imported library target properties
add_dependencies(METIS metis)
set_target_properties(METIS PROPERTIES
IMPORTED_LOCATION ${PREFIX}/lib/libmetis.a)
# set cache variables that would otherwise be set after mfem_find_package call
set(METIS_VERSION_5 FALSE CACHE BOOL "Is METIS version 5?")
return()
endif()
include(MfemCmakeUtilities)
mfem_find_package(METIS METIS METIS_DIR "include;Lib" "metis.h"
@@ -718,7 +718,7 @@ function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
get_target_property(IsImported ${tgt} IMPORTED)
# message(STATUS "${tgt}[IMPORTED]: ${IsImported}")
# Generally, the possible target types are: STATIC_LIBRARY, MODULE_LIBRARY,
# SHARED_LIBRARY, INTERFACE_LIBRARY, EXECUTABLE.
# SHARED_LIBRARY, INTERFACE_LIBRARY, UNKNOWN_LIBRARY, EXECUTABLE.
get_target_property(type ${tgt} TYPE)
# message(STATUS "${tgt}[TYPE]: ${type}")
unset(ImportConfig)
@@ -766,7 +766,7 @@ function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
else()
message(STATUS " *** Warning: [${tgt}] LOCATION not defined!")
endif()
elseif ("${type}" STREQUAL "SHARED_LIBRARY")
elseif ("${type}" STREQUAL "SHARED_LIBRARY" OR "${type}" STREQUAL "UNKNOWN_LIBRARY")
get_target_property(Location ${tgt} LOCATION)
if (Location)
get_filename_component(Dir ${Location} DIRECTORY)
@@ -932,12 +932,14 @@ function(mfem_export_mk_files)
endif()
set(MFEM_BUILD_TAG "${CMAKE_SYSTEM}")
set(MFEM_PREFIX "${CMAKE_INSTALL_PREFIX}")
# For the next 4 variable, these are the values for the build-tree version of
# For the next 4 variables, these are the values for the build-tree version of
# 'config.mk'
set(MFEM_INC_DIR "${PROJECT_BINARY_DIR}")
set(MFEM_LIB_DIR "${PROJECT_BINARY_DIR}")
set(MFEM_TEST_MK "${PROJECT_SOURCE_DIR}/config/test.mk")
set(MFEM_CONFIG_EXTRA "MFEM_BUILD_DIR ?= ${PROJECT_BINARY_DIR}")
# TODO: CUDA/HIP support:
set(MFEM_XLINKER "${CMAKE_CXX_LINKER_WRAPPER_FLAG}")
set(MFEM_MPIEXEC ${MPIEXEC})
if (NOT MFEM_MPIEXEC)
set(MFEM_MPIEXEC "mpirun")
+4 -1
View File
@@ -23,11 +23,14 @@
#include "_config.hpp"
#endif
#include <cstdint>
#include <climits>
namespace mfem
{
#if (defined(MFEM_USE_CUDA) && defined(__CUDACC__)) || \
(defined(MFEM_USE_HIP) && defined(__HIPCC__))
(defined(MFEM_USE_HIP) && defined(__HIP__))
#define MFEM_HOST_DEVICE __host__ __device__
#else
#define MFEM_HOST_DEVICE
+1
View File
@@ -88,6 +88,7 @@ MFEM_BUILD_TAG = @MFEM_BUILD_TAG@
MFEM_PREFIX = @MFEM_PREFIX@
MFEM_INC_DIR = @MFEM_INC_DIR@
MFEM_LIB_DIR = @MFEM_LIB_DIR@
MFEM_XLINKER = @MFEM_XLINKER@
# Location of test.mk
MFEM_TEST_MK = @MFEM_TEST_MK@
+6
View File
@@ -89,6 +89,12 @@ option(MFEM_ENABLE_EXAMPLES "Build all of the examples" OFF)
option(MFEM_ENABLE_MINIAPPS "Build all of the miniapps" OFF)
option(MFEM_ENABLE_BENCHMARKS "Build all of the benchmarks" OFF)
# Allow a user to specify fetching of certain third-party libraries instead of
# searching for existing installations.
option(FETCH_TPLS "Enable fetching of all supported third-party libraries" OFF)
option(HYPRE_FETCH "Enable fetching of hypre" OFF)
option(METIS_FETCH "Enable fetching of METIS" OFF)
# Setting CXX/MPICXX on the command line or in user.cmake will overwrite the
# autodetected C++ compiler.
# set(CXX g++)
+1 -1
View File
@@ -57,7 +57,7 @@ CUDA_DIR = $(or $(CUDA_HOME),$(patsubst %/,%,$(dir \
CLANG_CUDA_FLAGS = -xcuda --cuda-path=$(CUDA_DIR) --cuda-gpu-arch=$(CUDA_ARCH)
# flags for nvcc
NVCC_FLAGS = -x=cu --expt-extended-lambda --expt-relaxed-constexpr \
-arch=$(CUDA_ARCH)
-arch=$(CUDA_ARCH) -isystem "$(CUDA_DIR)/include"
# Prefixes for passing flags to the host compiler and linker when using
# CUDA_CXX=nvcc
CUDA_XCOMPILER = -Xcompiler=
+593
View File
@@ -0,0 +1,593 @@
MFEM mesh v1.0
# Created by: Pointwise
# MFEM Geometry Types:
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
dimension
2
elements
160
1 3 1 164 163 0
1 3 164 165 162 163
1 3 2 166 164 1
1 3 166 132 165 164
1 3 3 167 166 2
1 3 167 131 132 166
1 3 4 168 167 3
1 3 168 130 131 167
1 3 5 169 168 4
1 3 169 129 130 168
1 3 6 170 169 5
1 3 170 128 129 169
1 3 171 172 170 6
1 3 172 127 128 170
1 3 124 125 172 171
1 3 125 126 127 172
1 3 162 165 173 161
1 3 165 132 133 173
1 3 161 173 174 160
1 3 173 133 134 174
1 3 160 174 175 159
1 3 174 134 135 175
1 3 6 7 176 171
1 3 7 8 177 176
1 3 171 176 123 124
1 3 176 177 122 123
1 3 159 175 178 158
1 3 175 135 136 178
1 3 158 178 179 157
1 3 178 136 137 179
1 3 157 179 180 156
1 3 179 137 138 180
1 3 122 177 181 121
1 3 177 8 182 181
1 3 8 9 183 182
1 3 9 10 184 183
1 3 10 11 185 184
1 3 11 12 186 185
1 3 12 13 187 186
1 3 13 14 15 187
1 3 121 181 119 120
1 3 181 182 118 119
1 3 182 183 117 118
1 3 183 184 188 117
1 3 184 185 109 188
1 3 185 186 108 109
1 3 186 187 189 108
1 3 187 15 16 189
1 3 109 110 190 188
1 3 110 111 191 190
1 3 111 112 113 191
1 3 188 190 116 117
1 3 190 191 115 116
1 3 191 113 114 115
1 3 189 192 107 108
1 3 192 193 106 107
1 3 193 194 105 106
1 3 194 195 104 105
1 3 195 196 103 104
1 3 16 17 192 189
1 3 17 18 193 192
1 3 18 19 194 193
1 3 19 20 195 194
1 3 20 21 196 195
1 3 97 98 197 96
1 3 98 99 198 197
1 3 99 100 199 198
1 3 100 101 200 199
1 3 101 102 201 200
1 3 102 103 202 201
1 3 103 196 203 202
1 3 196 21 22 203
1 3 96 197 204 95
1 3 197 198 39 204
1 3 198 199 38 39
1 3 199 200 205 38
1 3 200 201 32 205
1 3 201 202 31 32
1 3 202 203 206 31
1 3 203 22 23 206
1 3 32 33 207 205
1 3 33 34 35 207
1 3 205 207 37 38
1 3 207 35 36 37
1 3 39 40 208 204
1 3 40 41 209 208
1 3 41 42 210 209
1 3 42 43 211 210
1 3 43 44 212 211
1 3 204 208 94 95
1 3 208 209 93 94
1 3 209 210 92 93
1 3 210 211 91 92
1 3 211 212 90 91
1 3 90 212 213 89
1 3 212 44 214 213
1 3 44 45 215 214
1 3 45 46 216 215
1 3 46 47 217 216
1 3 47 48 218 217
1 3 48 49 219 218
1 3 49 50 51 219
1 3 89 213 87 88
1 3 213 214 86 87
1 3 214 215 85 86
1 3 215 216 84 85
1 3 216 217 83 84
1 3 217 218 82 83
1 3 218 219 220 82
1 3 219 51 52 220
1 3 53 221 220 52
1 3 221 81 82 220
1 3 54 222 221 53
1 3 222 80 81 221
1 3 55 223 222 54
1 3 223 79 80 222
1 3 26 27 224 25
1 3 27 28 29 224
1 3 25 224 225 24
1 3 224 29 30 225
1 3 24 225 206 23
1 3 225 30 31 206
1 3 154 155 226 153
1 3 155 156 180 226
1 3 153 226 227 152
1 3 226 180 138 227
1 3 152 227 228 151
1 3 227 138 139 228
1 3 151 228 229 150
1 3 228 139 140 229
1 3 150 229 230 149
1 3 229 140 141 230
1 3 149 230 231 148
1 3 230 141 142 231
1 3 148 231 232 147
1 3 231 142 143 232
1 3 147 232 145 146
1 3 232 143 144 145
1 3 56 233 223 55
1 3 233 78 79 223
1 3 57 234 233 56
1 3 234 77 78 233
1 3 58 235 234 57
1 3 235 76 77 234
1 3 61 236 59 60
1 3 236 235 58 59
1 3 62 237 236 61
1 3 237 76 235 236
1 3 63 238 237 62
1 3 238 75 76 237
1 3 64 239 238 63
1 3 239 74 75 238
1 3 65 240 239 64
1 3 240 73 74 239
1 3 66 241 240 65
1 3 241 72 73 240
1 3 67 242 241 66
1 3 242 71 72 241
1 3 68 69 242 67
1 3 69 70 71 242
boundary
164
3 1 0 1
3 1 1 2
3 1 2 3
3 1 3 4
3 1 4 5
3 1 5 6
3 1 6 7
3 1 7 8
3 1 8 9
3 1 9 10
3 1 10 11
3 1 11 12
3 1 12 13
3 1 13 14
3 1 16 17
3 1 17 18
3 1 18 19
3 1 19 20
3 1 20 21
3 1 21 22
3 1 22 23
3 1 23 24
3 1 24 25
3 1 25 26
3 1 26 27
3 1 27 28
3 1 28 29
3 1 29 30
3 1 30 31
3 1 31 32
3 1 32 33
3 1 33 34
3 1 34 35
3 1 35 36
3 1 36 37
3 1 37 38
3 1 38 39
3 1 39 40
3 1 40 41
3 1 41 42
3 1 42 43
3 1 43 44
3 1 49 50
3 1 48 49
3 1 47 48
3 1 46 47
3 1 45 46
3 1 44 45
3 1 52 53
3 1 53 54
3 1 54 55
3 1 57 58
3 1 56 57
3 1 55 56
3 1 60 61
3 1 61 62
3 1 62 63
3 1 63 64
3 1 64 65
3 1 65 66
3 1 66 67
3 1 67 68
3 1 75 76
3 1 74 75
3 1 73 74
3 1 72 73
3 1 71 72
3 1 70 71
3 1 76 77
3 1 77 78
3 1 78 79
3 1 81 82
3 1 80 81
3 1 79 80
3 1 82 83
3 1 83 84
3 1 84 85
3 1 85 86
3 1 86 87
3 1 87 88
3 1 94 95
3 1 93 94
3 1 92 93
3 1 91 92
3 1 90 91
3 1 96 97
3 1 95 96
3 1 97 98
3 1 98 99
3 1 99 100
3 1 100 101
3 1 101 102
3 1 102 103
3 1 107 108
3 1 106 107
3 1 105 106
3 1 104 105
3 1 103 104
3 1 108 109
3 1 109 110
3 1 110 111
3 1 111 112
3 1 112 113
3 1 113 114
3 1 114 115
3 1 115 116
3 1 116 117
3 1 119 120
3 1 118 119
3 1 117 118
3 1 131 132
3 1 130 131
3 1 129 130
3 1 128 129
3 1 127 128
3 1 126 127
3 1 132 133
3 1 133 134
3 1 134 135
3 1 137 138
3 1 136 137
3 1 135 136
3 1 138 139
3 1 139 140
3 1 140 141
3 1 141 142
3 1 142 143
3 1 143 144
3 1 147 148
3 1 146 147
3 1 153 154
3 1 152 153
3 1 151 152
3 1 150 151
3 1 149 150
3 1 148 149
3 1 156 157
3 1 157 158
3 1 158 159
3 1 161 162
3 1 160 161
3 1 159 160
2 1 69 70
2 1 68 69
3 1 88 89
3 1 89 90
3 1 121 122
3 1 120 121
3 1 123 124
3 1 122 123
3 1 125 126
3 1 124 125
1 1 144 145
1 1 145 146
3 1 15 16
3 1 14 15
3 1 50 51
3 1 51 52
3 1 59 60
3 1 58 59
3 1 154 155
3 1 155 156
3 1 163 0
3 1 162 163
vertices
243
2
4 4
4 3.5
4 3
4 2.5
4 2
4 1.5
4 1
4.5 1
5 1
5 1.5
5 2
5 2.5
5 3
5 3.5
5 4
5.500 4
6 4
6.500 4
7 4
7.5 4
8 4
8.5 4
9 4
9.5 4
10 4
10.5 4
11 4
11 3.5
11 3
10.5 3
10 3
9.5 3
9.5 2.5
10 2.5
10.5 2.5
10.5 2
10.5 1.5
10 1.5
9.5 1.5
9.5 1
10 1
10.5 1
11 1
11.5 1
12 1
12 1.5
12 2
12 2.5
12 3
12 3.5
12 4
12.5 4
13 4
13.333 3.75
13.666 3.5
14.000 3.25
14.333 3.5
14.666 3.75
15.000 4
15.500 4
16.000 4
16.000 3.5
16.000 3
16.000 2.5
16.000 2
16.000 1.5
16.000 1
16.000 0.5
16.000 0
15.500 0
15.000 0
15.000 0.5000000000000002
15.000 1
15.000 1.5
15.000 2
15.000 2.5
15.000 3
14.666 2.75
14.333 2.5
14.000 2.25
13.666 2.5
13.333 2.75
13 3
13 2.5
13 2
13 1.5
13 1
13 0.500
13 0
12.5 0
12 0
11.5 0
11 0
10.5 0
10 0
9.5 0
9 0
8.5 0
8.5 0.5
8.5 1
8.5 1.5
8.5 2
8.5 2.5
8.5 3
8 3
7.5 3
7 3
6.500 3
6 3
6 2.5
6.5 2.5
7 2.5
7.5 2.5
7.5 2
7.5 1.5
7.000 1.5
6.5 1.5
6 1.5
6 1
6 0.5
6 0
5.5 0
5 0
4.5 0
4 0
3.5 0
3 0
3 0.500
3 1
3 1.5
3 2
3 2.5
3 3
2.666 2.75
2.333 2.5
2.000 2.25
1.666 2.5
1.333 2.75
1.000 3
1.000 2.5
1.000 2
1.000 1.5
1.000 1
1.000 0.5000
1.000 0
0.5000 0
0.0000 0
0.0000 0.5
0.0000 1
0.0000 1.5
0.0000 2
0.0000 2.5
0.0000 3
0.0000 3.5
0.0000 4
0.5000 4
1.000 4
1.333 3.75
1.666 3.5
2.000 3.25
2.333 3.5
2.666 3.75
3 4
3.5 4
3.5 3.5
3 3.5
3.5 3
3.5 2.5
3.5 2
3.5 1.5
3.5 1
4 0.5
3.5 0.5
2.666 3.25
2.333 3
2.000 2.75
4.5 0.5
5 0.5
1.666 3
1.333 3.25
1.000 3.5
5.5 0.5
5.500 1
5.500 1.5
5.500 2
5.500 2.5
5.500 3
5.500 3.5
6 2
6 3.5
6.5 2
7 2
6.5 3.5
7 3.5
7.5 3.5
8 3.5
8.5 3.5
9 0.5
9 1
9 1.5
9 2
9 2.5
9 3
9 3.5
9.5 0.5
9.5 2
9.5 3.5
10 2
10 0.5
10.5 0.5
11 0.5
11.5 0.5
12 0.5
12.5 0.500
12.5 1
12.5 1.5
12.5 2
12.5 2.5
12.5 3
12.5 3.5
13 3.5
13.333 3.250
13.666 3
14.000 2.75
10.5 3.5
10 3.5
0.500 3.5
0.500 3
0.500 2.5
0.500 2
0.500 1.5
0.500 1
0.500 0.5
14.333 3
14.666 3.25
15.000 3.5
15.500 3.5
15.500 3
15.500 2.5
15.500 2
15.500 1.5
15.500 1
15.500 0.5
+342
View File
@@ -0,0 +1,342 @@
MFEM NURBS NC-patch mesh v1.0
dimension
3
elements
13
0 1 5 0 8 10 11 9 4 6 7 5
0 1 5 0 18 8 24 32 30 23 36 38
0 1 5 0 0 18 32 14 12 30 38 29
0 1 5 0 32 24 10 20 38 36 26 35
0 1 5 0 14 32 20 2 29 38 35 16
0 1 5 0 30 23 36 38 31 22 37 39
0 1 5 0 12 30 38 29 13 31 39 28
0 1 5 0 38 36 26 35 39 37 27 34
0 1 5 0 29 38 35 16 28 39 34 17
0 1 5 0 31 22 37 39 19 9 25 33
0 1 5 0 13 31 39 28 1 19 33 15
0 1 5 0 39 37 27 34 33 25 11 21
0 1 5 0 28 39 34 17 15 33 21 3
boundary
31
9999 3 8 10 6 4
9999 3 10 11 7 6
9999 3 11 9 5 7
9999 3 9 8 4 5
9999 3 4 6 7 5
9999 3 32 24 8 18
9999 3 18 8 23 30
9999 3 14 32 18 0
9999 3 0 18 30 12
9999 3 14 0 12 29
9999 3 20 10 24 32
9999 3 10 20 35 26
9999 3 2 20 32 14
9999 3 20 2 16 35
9999 3 2 14 29 16
9999 3 30 23 22 31
9999 3 12 30 31 13
9999 3 29 12 13 28
9999 3 26 35 34 27
9999 3 35 16 17 34
9999 3 16 29 28 17
9999 3 31 22 9 19
9999 3 19 9 25 33
9999 3 13 31 19 1
9999 3 28 13 1 15
9999 3 1 19 33 15
9999 3 27 34 21 11
9999 3 33 25 11 21
9999 3 34 17 3 21
9999 3 17 28 15 3
9999 3 15 33 21 3
vertex_to_knotspan
8
23 0 1 8 10 11 9
22 0 2 8 10 11 9
24 1 0 8 10 11 9
36 1 1 8 10 11 9
37 1 2 8 10 11 9
25 1 3 8 10 11 9
26 2 1 8 10 11 9
27 2 2 8 10 11 9
coordinates
40
3
0 0 0
0 1 0
4 0 0
4 1 0
0 0 4
0 1 4
4 0 4
4 1 4
0 0 2
0 1 2
4 0 2
4 1 2
0 0.333333333333333 0
0 0.666666666666667 0
2 0 0
2 1 0
4 0.333333333333334 0
4 0.666666666666667 0
0 0 1
0 1 1
4 0 1
4 1 1
0 0.666666666666667 2
0 0.333333333333333 2
2 0 2
2 1 2
4 0.333333333333333 2
4 0.666666666666667 2
2 0.666666666666667 0
2 0.333333333333333 0
0 0.333333333333333 1
0 0.666666666666667 1
1.81325211007895 0 1
1.81325211007895 1 1
4 0.666666666666667 1
4 0.333333333333333 1
2 0.333333333333333 2
2 0.666666666666667 2
1.81325211007895 0.333333333333333 1
1.81325211007895 0.666666666666667 1
edges
87
0 8 10
1 10 11
0 9 11
1 8 9
0 4 6
1 6 7
0 5 7
1 4 5
2 4 8
2 6 10
2 7 11
2 5 9
9 18 8
7 8 24
9 32 24
7 18 32
9 30 23
7 23 36
9 38 36
7 30 38
3 18 30
3 8 23
3 24 36
3 32 38
8 0 18
8 14 32
7 0 14
8 12 30
8 29 38
7 12 29
3 0 12
3 14 29
6 24 10
9 20 10
6 32 20
6 36 26
9 35 26
6 38 35
3 10 26
3 20 35
8 2 20
6 14 2
8 16 35
6 29 16
3 2 16
9 31 22
7 22 37
9 39 37
7 31 39
4 30 31
4 23 22
4 36 37
4 38 39
8 13 31
8 28 39
7 13 28
4 12 13
4 29 28
6 37 27
9 34 27
6 39 34
4 26 27
4 35 34
8 17 34
6 28 17
4 16 17
9 19 9
7 9 25
9 33 25
7 19 33
5 31 19
5 22 9
5 37 25
5 39 33
8 1 19
8 15 33
7 1 15
5 13 1
5 28 15
6 25 11
9 21 11
6 33 21
5 27 11
5 34 21
8 3 21
6 15 3
5 17 3
knotvectors
10
1 3 0 0 0.5 1 1
1 4 0 0 0.333333333333333 0.666666666666667 1 1
1 3 0 0 0.5 1 1
1 2 0 0 1 1
1 2 0 0 1 1
1 2 0 0 1 1
1 2 0 0 1 1
1 2 0 0 1 1
1 2 0 0 1 1
1 2 0 0 1 1
spacing
0
weights
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
FiniteElementSpace
FiniteElementCollection: NURBS1
VDim: 3
Ordering: 1
0 0 0
0 1 0
4 0 0
4 1 0
0 0 4
0 1 4
4 0 4
4 1 4
0 0 2
0 1 2
4 0 2
4 1 2
0 0.333333333333333 0
0 0.666666666666667 0
2 0 0
2 1 0
4 0.333333333333334 0
4 0.666666666666667 0
0 0 1
0 1 1
4 0 1
4 1 1
0 0.666666666666667 2
0 0.333333333333333 2
2 0 2
2 1 2
4 0.333333333333333 2
4 0.666666666666667 2
2 0.666666666666667 0
2 0.333333333333333 0
0 0.333333333333333 1
0 0.666666666666667 1
1.81325211007895 0 1
1.81325211007895 1 1
4 0.666666666666667 1
4 0.333333333333333 1
2 0.333333333333333 2
2 0.666666666666667 2
1.81325211007895 0.333333333333333 1
1.81325211007895 0.666666666666667 1
2 0 4
4 0.333333333333333 4
4 0.666666666666667 4
2 1 4
0 0.333333333333333 4
0 0.666666666666667 4
0 0 3
4 0 3
4 1 3
0 1 3
2 0 3
4 0.333333333333333 3
4 0.666666666666667 3
2 1 3
0 0.666666666666667 3
0 0.333333333333333 3
2 0.333333333333333 4
2 0.666666666666667 4
2 0.333333333333333 3
2 0.666666666666667 3
+96
View File
@@ -0,0 +1,96 @@
MFEM NURBS NC-patch mesh v1.0
dimension
2
# rank attr geom ref_type nodes/children
elements
3
0 1 3 0 0 4 5 1
0 1 3 0 6 7 4 2
0 1 3 0 6 3 5 7
# attr geom nodes
boundary
7
1 1 0 4
1 1 5 1
1 1 1 0
1 1 2 6
1 1 6 3
1 1 4 2
1 1 5 3
vertex_to_knotspan
1
7 1 4 5
# top-level node coordinates
coordinates
8
2
0 0
0 1
2 0
2 1
1 0
1 1
2 0.5
1 0.5
edges
11
0 0 4
1 4 5
0 1 5
1 0 1
2 6 7
4 7 4
2 2 4
4 6 2
3 6 3
2 3 5
3 7 5
knotvectors
5
1 3 0 0 0.5 1 1
1 3 0 0 0.5 1 1
1 2 0 0 1 1
1 2 0 0 1 1
1 2 0 0 1 1
spacing
0
weights
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
FiniteElementSpace
FiniteElementCollection: NURBS1
VDim: 2
Ordering: 1
0 0
0 1
2 0
2 1
1 0
1 1
2 0.5
1 0.5
0.5 0
0.5 1
0 0.5
0.5 0.5
mfem_mesh_end
+1
View File
@@ -202,6 +202,7 @@ namespace mfem {
* - <a class="el" href="tesla_8cpp_source.html">Tesla</a>: simple magnetostatics simulation code
* - <a class="el" href="maxwell_8cpp_source.html">Maxwell</a>: simple transient full-wave electromagnetics simulation code
* - <a class="el" href="joule_8cpp_source.html">Joule</a>: transient magnetics and Joule heating miniapp
* - <a class="el" href="lorentz_8cpp_source.html">Lorentz</a>: simple particle tracking code based on the Lorentz force
* - <a class="el" href="classmfem_1_1navier_1_1NavierSolver.html">Navier</a>: solve the transient incompressible Navier-Stokes equations
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
* - <a class="el" href="klein-bottle_8cpp_source.html">Klein Bottle</a>: generate three types of Klein bottle surfaces
+9
View File
@@ -205,6 +205,15 @@ if (MFEM_ENABLE_TESTING)
$<TARGET_FILE:ex25p> "-no-vis" "--mumps-solver"
${MPIEXEC_POSTFLAGS})
endif()
# Parallel libCEED example
if (MFEM_USE_CEED AND MFEM_USE_MPI)
add_test(NAME ex1p_ceed_np=${MFEM_MPI_NP}
COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${MFEM_MPI_NP}
${MPIEXEC_PREFLAGS}
$<TARGET_FILE:ex1p> "-no-vis" "-d ceed-cpu" "-pa" "-a"
${MPIEXEC_POSTFLAGS})
endif()
endif()
# Include the examples/amgx directory if AmgX is enabled
+1
View File
@@ -27,6 +27,7 @@
// ex1 -m ../data/fichera-amr.mesh
// ex1 -m ../data/mobius-strip.mesh
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
// ex1 -m ../data/nc3-nurbs.mesh -o -1
//
// Device sample runs:
// ex1 -pa -d cuda
+6
View File
@@ -173,6 +173,12 @@ ex11p-test-cpardiso: ex11p
@$(call mfem-test,$<, $(RUN_MPI), MKL_CPARDISO example,--cpardiso)
test-par-YES: ex11p-test-cpardiso
endif
ifeq ($(MFEM_USE_CEED),YES)
ex1p-test-ceed: ex1p
@$(call mfem-test,$<, $(RUN_MPI),\
Parallel libCEED example,-d ceed-cpu -pa -a)
test-par-YES: ex1p-test-ceed
endif
# Testing: "test" target and mfem-test* variables are defined in config/test.mk
+119 -66
View File
@@ -28,10 +28,8 @@
//
// The example demonstrates the use of nonlinear operators (the
// class ConductionOperator defining C(u)), as well as their
// implicit time integration. Note that implementing the method
// ConductionOperator::ImplicitSolve is the only requirement for
// high-order implicit (SDIRK) time integration. By default, this
// example uses the SUNDIALS ODE solvers from CVODE and ARKODE.
// implicit time integration. By default, this example uses the
// SUNDIALS ODE solvers from CVODE and ARKODE.
//
// We recommend viewing examples 2, 9 and 10 before viewing this
// example.
@@ -51,15 +49,16 @@ using namespace mfem;
* and K(u) is the diffusion operator with diffusivity depending on u:
* (\kappa + \alpha u).
*
* Class ConductionOperatorOperator represents the above ODE operator in the
* general form F(u, k, t) = G(u, t) where
* Class ConductionOperator represents the above ODE operator as a
* TimeDependentOperator for use with native MFEM integrators and CVODE
* integrators, i.e., F(u, k, t) = G(u, t) with F(u, du/dt, t) = du/dt and
* G(u, t) = -K(u) u
*
* 1. F(u, du/dt, t) = du/dt (ODE is expressed in EXPLICIT form)
* G(u, t) = - inv(M) K(u) u
* 2. F(u, du/dt, t) = M du/dt (ODE is expressed in IMPLICIT form)
* G(u, t) = - K(u) u
* Class ConductionOperator represents the above ODE operator as an
* ARKStepODE for use with ARKODE integrators, i.e., either M du/dt = -K(u) u
* (mass form) or du/dt = -inv(M) K(u) u (MFEM form)
*/
class ConductionOperator : public TimeDependentOperator
class ConductionOperator : public TimeDependentOperator, public ARKStepODE
{
FiniteElementSpace &fespace;
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
@@ -81,50 +80,90 @@ class ConductionOperator : public TimeDependentOperator
mutable Vector z; // auxiliary vector
const bool use_mass_form;
public:
ConductionOperator(FiniteElementSpace &f, const real_t alpha,
const real_t kappa, const Vector &u,
const Type &ode_expression_type);
const bool use_mass_form);
// Compute K(u_n) for use as an approximation in - K(u) u
void SetConductionTensor(const Vector &u);
/** Compute G(u, t) as defined in the IMPLICIT expression form of the ODE
operator, i.e., @a v = - K(u_n) @a u. Note that K(u_n) is an
approximation to K(u). */
void ExplicitMult(const Vector &u, Vector &v) const override;
// ********* methods for MFEM native time integrators *********
/** Solve for k in F(u, k, t) = G(u, t) for either EXPLICIT or IMPLICIT
expression forms of the ODE operator, i.e., @a k = - inv(M) K(u_n) @a u.
/** Solve for k in F(u, k, t) = G(u, t), i.e., @a k = - inv(M) K(u_n) @a u.
Note that K(u_n) is an approximation to K(u). */
void Mult(const Vector &u, Vector &k) const override;
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t) for either EXPLICIT
or IMPLICIT expression forms of the ODE operator, i.e.,
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u . Note that K(u_n) is an
approximation to K(u). */
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t), i.e.,
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u .
Note that K(u_n) is an approximation to K(u). */
void ImplicitSolve(const real_t gam, const Vector &u, Vector &k) override;
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F for
either EXPLICIT or IMPLICIT expression forms of the ODE operator, i.e.,
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
real_t gam) override;
// ********* methods for ARKODE time integrators *********
// TODO: add comments
int ARKSize() const override;
// TODO: add comments
bool ARKInMassForm() const override;
// TODO: add comments
void ARKEvaluateRHS(const Vector &u, const real_t t, Vector &result) const override;
// TODO: add comments
int ARKImplicitSetup(const Vector &u, const real_t t, const Vector &fu,
int jok, int *jcur, real_t gam) override;
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
with the residual @a r providing either
1. @a r = G - F = inv(M) f(u) - k (EXPLICIT expression form)
1. @a r = G - F = f(u) - M k (IMPLICIT expression form)
1. @a r = G - F = inv(M) f(u) - k (MFEM form)
1. @a r = G - F = f(u) - M k (mass form)
*/
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
int ARKImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
int SUNMassSetup() override;
int ARKMassSetup(const real_t t) override;
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override;
int ARKMassSolve(const Vector &b, Vector &x, real_t tol) override;
int SUNMassMult(const Vector &x, Vector &v) override;
int ARKMassMult(const Vector &x, Vector &v) override;
// ********* methods for CVODE time integrators *********
// note these methods merely call the corresponding ARKStepODE methods until
// the CVODESolver is refactored to use specialized interface like ARKStepODE
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F, i.e.,
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
real_t gam) override
{
return ARKImplicitSetup(u, 0.0, fu, jok, jcur, gam); // the ODE is autonomous
}
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
with the residual @a r providing @a r = G - F = inv(M) f(u) - k. */
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override
{
return ARKImplicitSolve(r, dk, tol);
}
int SUNMassSetup() override
{
return ARKMassSetup(0.0); // the ODE is autonomous
}
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override
{
return ARKMassSolve(b, x, tol);
}
int SUNMassMult(const Vector &x, Vector &v) override
{
return ARKMassMult(x, v);
}
};
real_t InitialTemperature(const Vector &x)
@@ -245,16 +284,7 @@ int main(int argc, char *argv[])
u_gf.GetTrueDofs(u);
// 6. Initialize the conduction ODE operator and the visualization.
ConductionOperator::Type ode_expression_type;
if (use_mass_solver)
{
ode_expression_type = ConductionOperator::Type::IMPLICIT;
}
else
{
ode_expression_type = ConductionOperator::Type::EXPLICIT;
}
ConductionOperator oper(fespace, alpha, kappa, u, ode_expression_type);
ConductionOperator oper(fespace, alpha, kappa, u, use_mass_solver);
u_gf.SetFromTrueDofs(u);
{
@@ -352,7 +382,7 @@ int main(int argc, char *argv[])
}
std::unique_ptr<ARKStepSolver> arkode(
new ARKStepSolver(arkode_solver_type));
arkode->Init(oper);
arkode->Init(&oper);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
if (ode_solver_type == 11 || ode_solver_type == 14)
@@ -445,9 +475,10 @@ int main(int argc, char *argv[])
ConductionOperator::ConductionOperator(FiniteElementSpace &fes,
const real_t alpha, const real_t kappa,
const Vector &u,
const Type &ode_expression_type)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa), z(height)
const bool use_mass_form)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0),
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa), z(height),
use_mass_form(use_mass_form)
{
// specify a relative tolerance for all solves with MFEM integrators
const real_t rel_tol = 1e-8;
@@ -474,6 +505,16 @@ ConductionOperator::ConductionOperator(FiniteElementSpace &fes,
SetConductionTensor(u);
}
int ConductionOperator::ARKSize() const
{
return z.Size();
}
bool ConductionOperator::ARKInMassForm() const
{
return use_mass_form;
}
void ConductionOperator::SetConductionTensor(const Vector &u)
{
// Compute K(u_n).
@@ -491,17 +532,27 @@ void ConductionOperator::SetConductionTensor(const Vector &u)
K->FormSystemMatrix(ess_tdof_list, Kmat);
}
void ConductionOperator::ExplicitMult(const Vector &u, Vector &v) const
void ConductionOperator::ARKEvaluateRHS(const Vector &u, const real_t t,
Vector &result) const
{
// Compute - K(u_n) u.
Kmat.Mult(u, v);
v.Neg();
if (use_mass_form) // compute -K(u_n) u.
{
Kmat.Mult(u, result);
result.Neg();
}
else // compute -inv(M) K(u_n) u
{
Kmat.Mult(u, z);
z.Neg();
M_solver.Mult(z, result);
}
}
void ConductionOperator::Mult(const Vector &u, Vector &k) const
{
// Compute - inv(M) K(u_n) u.
ExplicitMult(u, z);
Kmat.Mult(u, z);
z.Neg();
M_solver.Mult(z, k);
}
@@ -509,14 +560,16 @@ void ConductionOperator::ImplicitSolve(const real_t gam, const Vector &u,
Vector &k)
{
// Solve for k in M k = - K(u_n) [u + gam*k].
ExplicitMult(u, z);
Kmat.Mult(u, z);
z.Neg();
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
T_solver.Mult(z, k);
}
int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
int jok, int *jcur, real_t gam)
int ConductionOperator::ARKImplicitSetup(const Vector &u, const real_t t,
const Vector &fu, int jok, int *jcur,
real_t gam)
{
// Compute T = M + gamma K(u_n).
T = std::unique_ptr<SparseMatrix>(Add(1.0, Mmat, gam, Kmat));
@@ -525,22 +578,22 @@ int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
return SUN_SUCCESS;
}
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
int ConductionOperator::ARKImplicitSolve(const Vector &r, Vector &dk,
real_t tol)
{
// Solve the system [M + gamma K(u_n)] dk = - K(u_n) u - M k.
// What value r is providing depends on the ODE expression form:
// EXPLICIT form: r = -inv(M) K(u_n) u - k
// IMPLICIT form: r = -K(u_n) u - M k
// MFEM form: r = -inv(M) K(u_n) u - k
// mass form: r = -K(u_n) u - M k
T_solver.SetRelTol(tol);
if (isExplicit())
if (use_mass_form)
{
Mmat.Mult(r, z);
T_solver.Mult(z, dk);
T_solver.Mult(r, dk);
}
else
{
T_solver.Mult(r, dk);
Mmat.Mult(r, z);
T_solver.Mult(z, dk);
}
if (T_solver.GetConverged())
{
@@ -552,13 +605,13 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
}
}
int ConductionOperator::SUNMassSetup()
int ConductionOperator::ARKMassSetup(const real_t t)
{
// Do nothing b/c mass solver was setup in constructor.
return SUN_SUCCESS;
}
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
int ConductionOperator::ARKMassSolve(const Vector &b, Vector &x, real_t tol)
{
// Solve the system M x = b.
M_solver.SetRelTol(tol);
@@ -573,7 +626,7 @@ int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
}
}
int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
int ConductionOperator::ARKMassMult(const Vector &x, Vector &v)
{
// Compute M x.
Mmat.Mult(x, v);
+119 -66
View File
@@ -29,10 +29,8 @@
//
// The example demonstrates the use of nonlinear operators (the
// class ConductionOperator defining C(u)), as well as their
// implicit time integration. Note that implementing the method
// ConductionOperator::ImplicitSolve is the only requirement for
// high-order implicit (SDIRK) time integration. By default, this
// example uses the SUNDIALS ODE solvers from CVODE and ARKODE.
// implicit time integration. By default, this example uses the
// SUNDIALS ODE solvers from CVODE and ARKODE.
//
// We recommend viewing examples 2, 9 and 10 before viewing this
// example.
@@ -52,15 +50,16 @@ using namespace mfem;
* and K(u) is the diffusion operator with diffusivity depending on u:
* (\kappa + \alpha u).
*
* Class ConductionOperatorOperator represents the above ODE operator in the
* general form F(u, k, t) = G(u, t) where either
* Class ConductionOperator represents the above ODE operator as a
* TimeDependentOperator for use with native MFEM integrators and CVODE
* integrators, i.e., F(u, k, t) = G(u, t) with F(u, du/dt, t) = du/dt and
* G(u, t) = -K(u) u
*
* 1. F(u, du/dt, t) = du/dt (ODE is expressed in EXPLICIT form)
* G(u, t) = - inv(M) K(u) u
* 2. F(u, du/dt, t) = M du/dt (ODE is expressed in IMPLICIT form)
* G(u, t) = - K(u) u
* Class ConductionOperator represents the above ODE operator as an
* ARKStepODE for use with ARKODE integrators, i.e., either M du/dt = -K(u) u
* (mass form) or du/dt = -inv(M) K(u) u (MFEM form)
*/
class ConductionOperator : public TimeDependentOperator
class ConductionOperator : public TimeDependentOperator, public ARKStepODE
{
ParFiniteElementSpace &fespace;
Array<int> ess_tdof_list; // this list remains empty for pure Neumann b.c.
@@ -82,50 +81,90 @@ class ConductionOperator : public TimeDependentOperator
mutable Vector z; // auxiliary vector
const bool use_mass_form;
public:
ConductionOperator(ParFiniteElementSpace &f, const real_t alpha,
const real_t kappa, const Vector &u,
const Type &ode_expression_type);
const bool use_mass_form);
// Compute K(u_n) for use as an approximation in - K(u) u
void SetConductionTensor(const Vector &u);
/** Compute G(u, t) as defined in the IMPLICIT expression form of the ODE
operator, i.e., @a v = - K(u_n) @a u. Note that K(u_n) is an
approximation to K(u). */
void ExplicitMult(const Vector &u, Vector &v) const override;
// ********* methods for MFEM native time integrators *********
/** Solve for k in F(u, k, t) = G(u, t) for either EXPLICIT or IMPLICIT
expression forms of the ODE operator, i.e., @a k = - inv(M) K(u_n) @a u.
/** Solve for k in F(u, k, t) = G(u, t), i.e., @a k = - inv(M) K(u_n) @a u.
Note that K(u_n) is an approximation to K(u). */
void Mult(const Vector &u, Vector &k) const override;
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t) for either EXPLICIT
or IMPLICIT expression forms of the ODE operator, i.e.,
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u . Note that K(u_n) is an
approximation to K(u). */
/** Solve for k in F(u + gam*k, k, t) = G(u + gam*k, t), i.e.,
[ M + @a gam K(u_n) ] @a k = - K(u_n) @a u .
Note that K(u_n) is an approximation to K(u). */
void ImplicitSolve(const real_t gam, const Vector &u, Vector &k) override;
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F for
either EXPLICIT or IMPLICIT expression forms of the ODE operator, i.e.,
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
real_t gam) override;
// ********* methods for ARKODE time integrators *********
// TODO: add comments
int ARKSize() const override;
// TODO: add comments
bool ARKInMassForm() const override;
// TODO: add comments
void ARKEvaluateRHS(const Vector &u, const real_t t, Vector &result) const override;
// TODO: add comments
int ARKImplicitSetup(const Vector &u, const real_t t, const Vector &fu,
int jok, int *jcur, real_t gam) override;
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
with the residual @a r providing either
1. @a r = G - F = inv(M) f(u) - k (EXPLICIT expression form)
1. @a r = G - F = f(u) - M k (IMPLICIT expression form)
1. @a r = G - F = inv(M) f(u) - k (MFEM form)
1. @a r = G - F = f(u) - M k (mass form)
*/
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
int ARKImplicitSolve(const Vector &r, Vector &dk, real_t tol) override;
int SUNMassSetup() override;
int ARKMassSetup(const real_t t) override;
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override;
int ARKMassSolve(const Vector &b, Vector &x, real_t tol) override;
int SUNMassMult(const Vector &x, Vector &v) override;
int ARKMassMult(const Vector &x, Vector &v) override;
// ********* methods for CVODE time integrators *********
// note these methods merely call the corresponding ARKStepODE methods until
// the CVODESolver is refactored to use specialized interface like ARKStepODE
/** Setup to solve for dk in [dF/dk + gam*dF/du - gam*dG/du] dk = G - F, i.e.,
[M - @a gam Jf(u)] dk = G - F, where Jf(u) is an approximation of the
Jacobian of -K(u) u. The approximation chosen here is Jf(u) = -K(u_n). */
int SUNImplicitSetup(const Vector &u, const Vector &fu, int jok, int *jcur,
real_t gam) override
{
return ARKImplicitSetup(u, 0.0, fu, jok, jcur, gam); // the ODE is autonomous
}
/** Solve for @a dk in the system in SUNImplicitSetup to the given tolerance,
with the residual @a r providing @a r = G - F = inv(M) f(u) - k. */
int SUNImplicitSolve(const Vector &r, Vector &dk, real_t tol) override
{
return ARKImplicitSolve(r, dk, tol);
}
int SUNMassSetup() override
{
return ARKMassSetup(0.0); // the ODE is autonomous
}
int SUNMassSolve(const Vector &b, Vector &x, real_t tol) override
{
return ARKMassSolve(b, x, tol);
}
int SUNMassMult(const Vector &x, Vector &v) override
{
return ARKMassMult(x, v);
}
};
real_t InitialTemperature(const Vector &x)
@@ -273,16 +312,7 @@ int main(int argc, char *argv[])
u_gf.GetTrueDofs(u);
// 8. Initialize the conduction ODE operator and the visualization.
ConductionOperator::Type ode_expression_type;
if (use_mass_solver)
{
ode_expression_type = ConductionOperator::Type::IMPLICIT;
}
else
{
ode_expression_type = ConductionOperator::Type::EXPLICIT;
}
ConductionOperator oper(fespace, alpha, kappa, u, ode_expression_type);
ConductionOperator oper(fespace, alpha, kappa, u, use_mass_solver);
u_gf.SetFromTrueDofs(u);
{
@@ -394,7 +424,7 @@ int main(int argc, char *argv[])
}
std::unique_ptr<ARKStepSolver> arkode(
new ARKStepSolver(MPI_COMM_WORLD, arkode_solver_type));
arkode->Init(oper);
arkode->Init(&oper);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
if (ode_solver_type == 11 || ode_solver_type == 14)
@@ -497,10 +527,11 @@ int main(int argc, char *argv[])
ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
const real_t alpha, const real_t kappa,
const Vector &u,
const Type &ode_expression_type)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0, ode_expression_type),
const bool use_mass_form)
: TimeDependentOperator(fes.GetTrueVSize(), 0.0),
fespace(fes), M(&fespace), alpha(alpha), kappa(kappa),
M_solver(fes.GetComm()), T_solver(fes.GetComm()), z(height)
M_solver(fes.GetComm()), T_solver(fes.GetComm()), z(height),
use_mass_form(use_mass_form)
{
// specify a relative tolerance for all solves with MFEM integrators
const real_t rel_tol = 1e-8;
@@ -528,6 +559,16 @@ ConductionOperator::ConductionOperator(ParFiniteElementSpace &fes,
SetConductionTensor(u);
}
int ConductionOperator::ARKSize() const
{
return z.Size();
}
bool ConductionOperator::ARKInMassForm() const
{
return use_mass_form;
}
void ConductionOperator::SetConductionTensor(const Vector &u)
{
// Compute K(u_n).
@@ -545,17 +586,27 @@ void ConductionOperator::SetConductionTensor(const Vector &u)
K->FormSystemMatrix(ess_tdof_list, Kmat);
}
void ConductionOperator::ExplicitMult(const Vector &u, Vector &v) const
void ConductionOperator::ARKEvaluateRHS(const Vector &u, const real_t t,
Vector &result) const
{
// Compute - K(u_n) u.
Kmat.Mult(u, v);
v.Neg();
if (use_mass_form) // compute -K(u_n) u.
{
Kmat.Mult(u, result);
result.Neg();
}
else // compute -inv(M) K(u_n) u
{
Kmat.Mult(u, z);
z.Neg();
M_solver.Mult(z, result);
}
}
void ConductionOperator::Mult(const Vector &u, Vector &k) const
{
// Compute - inv(M) K(u_n) u.
ExplicitMult(u, z);
Kmat.Mult(u, z);
z.Neg();
M_solver.Mult(z, k);
}
@@ -563,14 +614,16 @@ void ConductionOperator::ImplicitSolve(const real_t gam, const Vector &u,
Vector &k)
{
// Solve for k in M k = - K(u_n) [u + gam*k].
ExplicitMult(u, z);
Kmat.Mult(u, z);
z.Neg();
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
T_solver.SetOperator(*T);
T_solver.Mult(z, k);
}
int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
int jok, int *jcur, real_t gam)
int ConductionOperator::ARKImplicitSetup(const Vector &u, const real_t t,
const Vector &fu, int jok, int *jcur,
real_t gam)
{
// Compute T = M + gamma K(u_n).
T = std::unique_ptr<HypreParMatrix>(Add(1.0, Mmat, gam, Kmat));
@@ -579,22 +632,22 @@ int ConductionOperator::SUNImplicitSetup(const Vector &u, const Vector &fu,
return SUN_SUCCESS;
}
int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
int ConductionOperator::ARKImplicitSolve(const Vector &r, Vector &dk,
real_t tol)
{
// Solve the system [M + gamma K(u_n)] dk = - K(u_n) u - M k.
// What value r is providing depends on the ODE expression form:
// EXPLICIT form: r = -inv(M) K(u_n) u - k
// IMPLICIT form: r = -K(u_n) u - M k
// MFEM form: r = -inv(M) K(u_n) u - k
// mass form: r = -K(u_n) u - M k
T_solver.SetRelTol(tol);
if (isExplicit())
if (use_mass_form)
{
Mmat.Mult(r, z);
T_solver.Mult(z, dk);
T_solver.Mult(r, dk);
}
else
{
T_solver.Mult(r, dk);
Mmat.Mult(r, z);
T_solver.Mult(z, dk);
}
if (T_solver.GetConverged())
{
@@ -606,13 +659,13 @@ int ConductionOperator::SUNImplicitSolve(const Vector &r, Vector &dk,
}
}
int ConductionOperator::SUNMassSetup()
int ConductionOperator::ARKMassSetup(const real_t t)
{
// Do nothing b/c mass solver was setup in constructor.
return SUN_SUCCESS;
}
int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
int ConductionOperator::ARKMassSolve(const Vector &b, Vector &x, real_t tol)
{
// Solve the system M x = b.
M_solver.SetRelTol(tol);
@@ -627,7 +680,7 @@ int ConductionOperator::SUNMassSolve(const Vector &b, Vector &x, real_t tol)
}
}
int ConductionOperator::SUNMassMult(const Vector &x, Vector &v)
int ConductionOperator::ARKMassMult(const Vector &x, Vector &v)
{
// Compute M x.
Mmat.Mult(x, v);
+21 -3
View File
@@ -119,7 +119,7 @@ public:
and advection matrices, and b describes the flow on the boundary. This can
be written as a general ODE, du/dt = M^{-1} (K u + b), and this class is
used to evaluate the right-hand side. */
class FE_Evolution : public TimeDependentOperator
class FE_Evolution : public TimeDependentOperator, public ARKStepODE
{
private:
BilinearForm &M, &K;
@@ -133,9 +133,14 @@ private:
public:
FE_Evolution(BilinearForm &M_, BilinearForm &K_, const Vector &b_);
// TimeDependentOperator methods for MFEM native and CVODE time integrators
virtual void Mult(const Vector &x, Vector &y) const;
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
// ARKStepODE methods for ARKODE time integrators
int ARKSize() const override;
void ARKEvaluateRHS(const Vector &u, const real_t t, Vector& result) const override;
virtual ~FE_Evolution();
};
@@ -404,14 +409,14 @@ int main(int argc, char *argv[])
ode_solver = cvode; break;
case 8:
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
arkode->Init(adv);
arkode->Init(&adv);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
arkode->SetOrder(4);
ode_solver = arkode; break;
case 9:
arkode = new ARKStepSolver(ARKStepSolver::EXPLICIT);
arkode->Init(adv);
arkode->Init(&adv);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
arkode->SetERKTableNum(ARKODE_FEHLBERG_13_7_8);
@@ -520,6 +525,19 @@ void FE_Evolution::ImplicitSolve(const double dt, const Vector &x, Vector &k)
dg_solver->Mult(z, k);
}
int FE_Evolution::ARKSize() const
{
return z.Size();
}
void FE_Evolution::ARKEvaluateRHS(const Vector &u, const real_t t, Vector &result) const
{
// y = M^{-1} (K x + b)
K.Mult(u, z);
z += b;
M_solver.Mult(z, result);
}
FE_Evolution::~FE_Evolution()
{
delete M_prec;
+20 -2
View File
@@ -206,7 +206,7 @@ public:
and advection matrices, and b describes the flow on the boundary. This can
be written as a general ODE, du/dt = M^{-1} (K u + b), and this class is
used to evaluate the right-hand side. */
class FE_Evolution : public TimeDependentOperator
class FE_Evolution : public TimeDependentOperator, public ARKStepODE
{
private:
OperatorHandle M, K;
@@ -221,9 +221,14 @@ public:
FE_Evolution(ParBilinearForm &M_, ParBilinearForm &K_, const Vector &b_,
PrecType prec_type);
// TimeDependentOperator methods for MFEM native and CVODE time integrators
virtual void Mult(const Vector &x, Vector &y) const;
virtual void ImplicitSolve(const double dt, const Vector &x, Vector &k);
// ARKStepODE methods for ARKODE time integrators
int ARKSize() const override;
void ARKEvaluateRHS(const Vector &u, const real_t t, Vector& result) const override;
virtual ~FE_Evolution();
};
@@ -575,7 +580,7 @@ int main(int argc, char *argv[])
case 8:
case 9:
arkode = new ARKStepSolver(MPI_COMM_WORLD, ARKStepSolver::EXPLICIT);
arkode->Init(adv);
arkode->Init(&adv);
arkode->SetSStolerances(reltol, abstol);
arkode->SetMaxStep(dt);
if (ode_solver_type == 9)
@@ -743,6 +748,19 @@ void FE_Evolution::Mult(const Vector &x, Vector &y) const
M_solver.Mult(z, y);
}
int FE_Evolution::ARKSize() const
{
return z.Size();
}
void FE_Evolution::ARKEvaluateRHS(const Vector &u, const real_t t, Vector &result) const
{
// y = M^{-1} (K x + b)
K->Mult(u, z);
z += b;
M_solver.Mult(z, result);
}
FE_Evolution::~FE_Evolution()
{
delete M_prec;
+12
View File
@@ -82,6 +82,8 @@ set(SRCS
fe/fe_ser.cpp
fe_coll.cpp
fespace.cpp
derefmat_op.cpp
pderefmat_op.cpp
geom.cpp
gridfunc.cpp
hybridization.cpp
@@ -169,6 +171,11 @@ set(HDRS
bilinearform.hpp
bilinearform_ext.hpp
bilininteg.hpp
integ/lininteg_domain_kernels.hpp
integ/bilininteg_dgdiffusion_kernels.hpp
integ/bilininteg_dgtrace_kernels.hpp
integ/bilininteg_vecdiffusion_kernels.hpp
integ/bilininteg_convection_kernels.hpp
integ/bilininteg_diffusion_kernels.hpp
integ/bilininteg_elasticity_kernels.hpp
integ/bilininteg_hcurl_kernels.hpp
@@ -239,8 +246,13 @@ set(HDRS
lor/lor_ams.hpp
lor/lor_batched.hpp
lor/lor_h1.hpp
lor/lor_dg.hpp
lor/lor_nd.hpp
lor/lor_rt.hpp
lor/lor_h1_impl.hpp
lor/lor_dg_impl.hpp
lor/lor_nd_impl.hpp
lor/lor_rt_impl.hpp
lor/lor_util.hpp
multigrid.hpp
nonlinearform.hpp
+26 -64
View File
@@ -266,11 +266,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
// Gather the attributes on the host from all the elements
const Mesh &mesh = *trial_fes->GetMesh();
elem_attributes.SetSize(mesh.GetNE());
for (int i = 0; i < mesh.GetNE(); ++i)
{
elem_attributes[i] = mesh.GetAttribute(i);
}
elem_attributes = &mesh.GetElementAttributes();
}
// Construct face restriction operators only if the bilinear form has
@@ -329,45 +325,7 @@ void PABilinearFormExtension::SetupRestrictionOperators(const L2FaceValues m)
bdr_face_dYdn.SetSize(bdr_face_restrict_lex->Height());
}
const Mesh &mesh = *trial_fes->GetMesh();
// See LinearFormExtension::Update for explanation of f_to_be logic.
std::unordered_map<int,int> f_to_be;
for (int i = 0; i < mesh.GetNBE(); ++i)
{
const int f = mesh.GetBdrElementFaceIndex(i);
f_to_be[f] = i;
}
const int nf_bdr = trial_fes->GetNFbyType(FaceType::Boundary);
bdr_attributes.SetSize(nf_bdr);
int f_ind = 0;
int missing_bdr_elems = 0;
for (int f = 0; f < mesh.GetNumFaces(); ++f)
{
if (!mesh.GetFaceInformation(f).IsOfFaceType(FaceType::Boundary))
{
continue;
}
int attribute = 1; // default value
if (f_to_be.find(f) != f_to_be.end())
{
const int be = f_to_be[f];
attribute = mesh.GetBdrAttribute(be);
}
else
{
// If a boundary face does not correspond to the a boundary element,
// we assign it the default attribute of 1. We also generate a
// warning at runtime with the number of such missing elements.
++missing_bdr_elems;
}
bdr_attributes[f_ind] = attribute;
++f_ind;
}
if (missing_bdr_elems)
{
MFEM_WARNING("Missing " << missing_bdr_elems << " boundary elements "
"for boundary faces.");
}
bdr_face_attributes = &trial_fes->GetMesh()->GetBdrFaceAttributes();
}
}
@@ -429,7 +387,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
{
const int attr = d_attr[e];
if (d_m[attr - 1] == 0)
if (attr <= 0 || d_m[attr - 1] == 0)
{
for (int i = 0; i < nd; ++i)
{
@@ -450,7 +408,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
for (int i = 0; i < iSz; ++i)
{
assemble_diagonal_with_markers(*integrators[i], elem_markers[i],
elem_attributes, localY);
*elem_attributes, localY);
}
const ElementRestriction* H1elem_restrict =
dynamic_cast<const ElementRestriction*>(elem_restrict);
@@ -476,7 +434,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
for (int i = 0; i < iSz; ++i)
{
assemble_diagonal_with_markers(*integrators[i], elem_markers[i],
elem_attributes, y);
*elem_attributes, y);
}
}
@@ -489,7 +447,7 @@ void PABilinearFormExtension::AssembleDiagonal(Vector &y) const
for (int i = 0; i < n_bdr_integs; ++i)
{
assemble_diagonal_with_markers(*bdr_integs[i], bdr_markers[i],
bdr_attributes, bdr_face_Y);
*bdr_face_attributes, bdr_face_Y);
}
bdr_face_restrict_lex->AddAbsMultTranspose(bdr_face_Y, y);
}
@@ -588,7 +546,7 @@ void PABilinearFormExtension::MultInternal(const Vector &x, Vector &y,
for (int i = 0; i < iSz; ++i)
{
AddMultWithMarkers(*integrators[i], localX, elem_markers[i],
elem_attributes, false, localY, useAbs);
*elem_attributes, false, localY, useAbs);
}
if (H1elem_restrict && useAbs)
{
@@ -690,8 +648,8 @@ void PABilinearFormExtension::MultInternal(const Vector &x, Vector &y,
}
for (int i = 0; i < n_bdr_integs; ++i)
{
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
false, bdr_face_Y);
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i],
*bdr_face_attributes, false, bdr_face_Y);
}
for (int i = 0; i < n_bdr_face_integs; ++i)
{
@@ -699,12 +657,14 @@ void PABilinearFormExtension::MultInternal(const Vector &x, Vector &y,
{
AddMultNormalDerivativesWithMarkers(
*bdr_face_integs[i], bdr_face_X, bdr_face_dXdn,
bdr_face_markers[i], bdr_attributes, bdr_face_Y, bdr_face_dYdn);
bdr_face_markers[i], *bdr_face_attributes, bdr_face_Y,
bdr_face_dYdn);
}
else
{
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
bdr_attributes, false, bdr_face_Y);
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X,
bdr_face_markers[i], *bdr_face_attributes, false,
bdr_face_Y);
}
}
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
@@ -727,7 +687,7 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
localY = 0.0;
for (int i = 0; i < iSz; ++i)
{
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], elem_attributes,
AddMultWithMarkers(*integrators[i], localX, elem_markers[i], *elem_attributes,
true, localY);
}
elem_restrict->MultTranspose(localY, y);
@@ -774,13 +734,14 @@ void PABilinearFormExtension::MultTranspose(const Vector &x, Vector &y) const
bdr_face_Y = 0.0;
for (int i = 0; i < n_bdr_integs; ++i)
{
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i], bdr_attributes,
true, bdr_face_Y);
AddMultWithMarkers(*bdr_integs[i], bdr_face_X, bdr_markers[i],
*bdr_face_attributes, true, bdr_face_Y);
}
for (int i = 0; i < n_bdr_face_integs; ++i)
{
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X, bdr_face_markers[i],
bdr_attributes, true, bdr_face_Y);
AddMultWithMarkers(*bdr_face_integs[i], bdr_face_X,
bdr_face_markers[i], *bdr_face_attributes, true,
bdr_face_Y);
}
bdr_face_restrict_lex->AddMultTransposeInPlace(bdr_face_Y, y);
}
@@ -804,7 +765,7 @@ static void AddWithMarkers_(
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
{
const int attr = d_attr[e];
if (d_m[attr - 1] == 0) { return; }
if (attr <= 0 || d_m[attr - 1] == 0) { return; }
for (int i = 0; i < nd; ++i)
{
d_y(i, e) += d_x(i, e);
@@ -920,7 +881,8 @@ void EABilinearFormExtension::Assemble()
{
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;
const real_t val =
d_a[e] > 0 ? (d_m[d_a[e] - 1] ? d_ea_1(i, e) : 0) : 0;
if (add)
{
d_ea_2(i, e) += val;
@@ -953,7 +915,7 @@ void EABilinearFormExtension::Assemble()
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);
*elem_attributes, add);
}
}
}
@@ -982,7 +944,7 @@ void EABilinearFormExtension::Assemble()
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);
*bdr_face_attributes, add);
}
}
}
@@ -1031,7 +993,7 @@ void EABilinearFormExtension::Assemble()
ea_data_tmp,
add);
add_with_markers(ea_data_tmp, ea_data_bdr, nf_bdr, *markers,
bdr_attributes, add);
*bdr_face_attributes, add);
}
}
}
+2 -1
View File
@@ -69,7 +69,8 @@ class PABilinearFormExtension : public BilinearFormExtension
protected:
const FiniteElementSpace *trial_fes, *test_fes; // Not owned
/// Attributes of all mesh elements.
Array<int> elem_attributes, bdr_attributes;
const Array<int> *elem_attributes; // Not owned
const Array<int> *bdr_face_attributes; // Not owned
mutable Vector tmp_evec; // Work array
mutable Vector localX, localY;
mutable Vector int_face_X, int_face_Y;
+152 -50
View File
@@ -23,6 +23,8 @@
namespace mfem
{
class QuadratureSpace;
class FaceQuadratureSpace;
/// Abstract base class BilinearFormIntegrator
class BilinearFormIntegrator : public NonlinearFormIntegrator
@@ -812,7 +814,7 @@ protected:
const FiniteElement & test_fe) const
{
return (trial_fe.GetDim() == 1 && test_fe.GetDim() == 1 &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
}
@@ -884,7 +886,7 @@ protected:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
}
@@ -919,7 +921,7 @@ protected:
const FiniteElement & trial_fe,
const FiniteElement & test_fe) const
{
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
return (trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
}
@@ -1600,7 +1602,7 @@ public:
{
return (trial_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
}
@@ -1635,7 +1637,7 @@ public:
{
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
}
@@ -1669,7 +1671,7 @@ public:
{
return (trial_fe.GetDim() == 2 && test_fe.GetDim() == 2 &&
trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
}
@@ -1760,7 +1762,7 @@ public:
const FiniteElement & test_fe) const
{
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR );
}
@@ -1793,7 +1795,7 @@ public:
const FiniteElement & test_fe) const
{
return (trial_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
trial_fe.GetDerivType() == mfem::FiniteElement::GRAD &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
test_fe.GetDerivType() == mfem::FiniteElement::DIV );
}
@@ -1832,7 +1834,7 @@ public:
const FiniteElement & test_fe) const
{
return (trial_fe.GetRangeType() == mfem::FiniteElement::VECTOR &&
trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
trial_fe.GetDerivType() == mfem::FiniteElement::DIV &&
test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
test_fe.GetDerivType() == mfem::FiniteElement::GRAD
);
@@ -1973,7 +1975,7 @@ protected:
const FiniteElement & test_fe) const override
{
return (trial_fe.GetCurlDim() == 3 && test_fe.GetRangeDim() == 3 &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
trial_fe.GetDerivType() == mfem::FiniteElement::CURL &&
test_fe.GetRangeType() == mfem::FiniteElement::VECTOR );
}
@@ -2494,8 +2496,7 @@ private:
#endif
public:
ConvectionIntegrator(VectorCoefficient &q, real_t a = 1.0)
: Q(&q) { alpha = a; }
ConvectionIntegrator(VectorCoefficient &q, real_t a = 1.0);
void AssembleElementMatrix(const FiniteElement &,
ElementTransformation &,
@@ -2528,6 +2529,28 @@ public:
bool SupportsCeed() const override { return DeviceCanUseCeed(); }
/// arguments: NE, B, G, Bt, Gt, pa_data, x, y, D1D, Q1D
using ApplyKernelType = void (*)(const int, const Array<real_t> &,
const Array<real_t> &,
const Array<real_t> &,
const Array<real_t> &, const Vector &,
const Vector &, Vector &, const int,
const int);
/// arguments: DIMS, D1D, Q1D
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
/// arguments: DIMS, D1D, Q1D
MFEM_REGISTER_KERNELS(ApplyPATKernels, ApplyKernelType, (int, int, int));
template <int DIM, int D1D, int Q1D>
static void AddSpecialization()
{
ApplyPAKernels::Specialization<DIM, D1D, Q1D>::Add();
ApplyPATKernels::Specialization<DIM, D1D, Q1D>::Add();
}
struct Kernels { Kernels(); };
protected:
const IntegrationRule* GetDefaultIntegrationRule(
const FiniteElement& trial_fe,
@@ -2798,15 +2821,13 @@ protected:
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
public:
CurlCurlIntegrator() { Q = NULL; DQ = NULL; MQ = NULL; }
CurlCurlIntegrator();
/// Construct a bilinear form integrator for Nedelec elements
CurlCurlIntegrator(Coefficient &q, const IntegrationRule *ir = NULL) :
BilinearFormIntegrator(ir), Q(&q), DQ(NULL), MQ(NULL) { }
CurlCurlIntegrator(Coefficient &q, const IntegrationRule *ir = nullptr);
CurlCurlIntegrator(DiagonalMatrixCoefficient &dq,
const IntegrationRule *ir = NULL) :
BilinearFormIntegrator(ir), Q(NULL), DQ(&dq), MQ(NULL) { }
CurlCurlIntegrator(MatrixCoefficient &mq, const IntegrationRule *ir = NULL) :
BilinearFormIntegrator(ir), Q(NULL), DQ(NULL), MQ(&mq) { }
const IntegrationRule *ir = nullptr);
CurlCurlIntegrator(MatrixCoefficient &mq,
const IntegrationRule *ir = nullptr);
/* Given a particular Finite Element, compute the
element curl-curl matrix elmat */
@@ -2836,6 +2857,34 @@ public:
void AssembleDiagonalPA(Vector& diag) override;
const Coefficient *GetCoefficient() const { return Q; }
/// arguments: d1d, q1d, symmetric, NE, bo, bc, bot, bct, gc, gct, pa_data,
/// x, y, useAbs
using ApplyKernelType = void (*)(
const int, const int, const bool, const int, const Array<real_t> &,
const Array<real_t> &, const Array<real_t> &, const Array<real_t> &,
const Array<real_t> &, const Array<real_t> &, const Vector &,
const Vector &, Vector &, const bool);
/// arguments: d1d, q1d, symmetric, ne, Bo, Bc, Go, Gc, pa_data, diag
using DiagonalKernelType = void (*)(const int, const int, const bool,
const int, const Array<real_t> &,
const Array<real_t> &,
const Array<real_t> &,
const Array<real_t> &, const Vector &,
Vector &);
/// parameters: dim, d1d, q1d
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
/// parameters: dim, d1d, q1d
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
struct Kernels { Kernels(); };
template <int DIM, int D1D, int Q1D> static void AddSpecialization()
{
ApplyPAKernels::Specialization<DIM, D1D, Q1D>::Add();
DiagonalPAKernels::Specialization<DIM, D1D, Q1D>::Add();
}
};
/** Integrator for $(\mathrm{curl}(u), \mathrm{curl}(v))$ for FE spaces defined by 'dim' copies of a
@@ -3089,21 +3138,18 @@ private:
Vector vcoeff;
public:
VectorDiffusionIntegrator() { }
VectorDiffusionIntegrator(const IntegrationRule *ir = nullptr);
/** \brief Integrator with unit coefficient for caller-specified vector
dimension.
If the vector dimension does not match the true dimension of the space,
the resulting element matrix will be mathematically invalid. */
VectorDiffusionIntegrator(int vector_dimension)
: vdim(vector_dimension) { }
VectorDiffusionIntegrator(int vector_dimension);
VectorDiffusionIntegrator(Coefficient &q)
: Q(&q) { }
VectorDiffusionIntegrator(Coefficient &q);
VectorDiffusionIntegrator(Coefficient &q, const IntegrationRule *ir)
: BilinearFormIntegrator(ir), Q(&q) { }
VectorDiffusionIntegrator(Coefficient &q, const IntegrationRule *ir);
/** \brief Integrator with scalar coefficient for caller-specified vector
dimension.
@@ -3113,8 +3159,7 @@ public:
If the vector dimension does not match the true dimension of the space,
the resulting element matrix will be mathematically invalid. */
VectorDiffusionIntegrator(Coefficient &q, int vector_dimension)
: Q(&q), vdim(vector_dimension) { }
VectorDiffusionIntegrator(Coefficient &q, int vector_dimension);
/** \brief Integrator with \c VectorCoefficient. The vector dimension of the
\c FiniteElementSpace is assumed to be the same as the dimension of the
@@ -3125,8 +3170,7 @@ public:
If the vector dimension does not match the true dimension of the space,
the resulting element matrix will be mathematically invalid. */
VectorDiffusionIntegrator(VectorCoefficient &vq)
: VQ(&vq), vdim(vq.GetVDim()) { }
VectorDiffusionIntegrator(VectorCoefficient &vq);
/** \brief Integrator with \c MatrixCoefficient. The vector dimension of the
\c FiniteElementSpace is assumed to be the same as the dimension of the
@@ -3137,8 +3181,7 @@ public:
If the vector dimension does not match the true dimension of the space,
the resulting element matrix will be mathematically invalid. */
VectorDiffusionIntegrator(MatrixCoefficient& mq)
: MQ(&mq), vdim(mq.GetVDim()) { }
VectorDiffusionIntegrator(MatrixCoefficient& mq);
void AssembleElementMatrix(const FiniteElement &el,
ElementTransformation &Trans,
@@ -3154,6 +3197,28 @@ public:
void AddMultPA(const Vector &x, Vector &y) const override;
void AddMultMF(const Vector &x, Vector &y) const override;
bool SupportsCeed() const override { return DeviceCanUseCeed(); }
/// arguments: ne, B, G, Bt, Gt, pa_data, x, y, d1d, q1d, vdim
using ApplyKernelType = void (*)(const int, const Array<real_t> &,
const Array<real_t> &,
const Array<real_t> &,
const Array<real_t> &, const Vector &,
const Vector &, Vector &, const int,
const int, const int);
/// arguments: dim, vdim, d1d, q1d
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int, int));
template <int DIM, int VDIM, int D1D, int Q1D>
static void AddSpecialization()
{
ApplyPAKernels::Specialization<DIM, VDIM, D1D, Q1D>::Add();
}
struct Kernels
{
Kernels();
};
};
/** Integrator for the linear elasticity form:
@@ -3307,8 +3372,8 @@ public:
class DGTraceIntegrator : public BilinearFormIntegrator
{
protected:
Coefficient *rho;
VectorCoefficient *u;
Coefficient *rho = nullptr;
VectorCoefficient *u = nullptr;
real_t alpha, beta;
// PA extension
Vector pa_data;
@@ -3321,17 +3386,16 @@ private:
Vector tr_shape1, te_shape1, tr_shape2, te_shape2;
public:
DGTraceIntegrator(real_t a, real_t b);
/// Construct integrator with $\rho = 1$, $\beta = \alpha/2$.
DGTraceIntegrator(VectorCoefficient &u_, real_t a)
{ rho = NULL; u = &u_; alpha = a; beta = 0.5*a; }
DGTraceIntegrator(VectorCoefficient &u_, real_t a);
/// Construct integrator with $\rho = 1$.
DGTraceIntegrator(VectorCoefficient &u_, real_t a, real_t b)
{ rho = NULL; u = &u_; alpha = a; beta = b; }
DGTraceIntegrator(VectorCoefficient &u_, real_t a, real_t b);
DGTraceIntegrator(Coefficient &rho_, VectorCoefficient &u_,
real_t a, real_t b)
{ rho = &rho_; u = &u_; alpha = a; beta = b; }
real_t a, real_t b);
using BilinearFormIntegrator::AssembleFaceMatrix;
void AssembleFaceMatrix(const FiniteElement &el1,
@@ -3370,6 +3434,26 @@ public:
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
const ElementTransformation &T);
/// arguments: nf, B, Bt, pa_data, x, y, dofs1D, quad1D
using ApplyKernelType = void (*)(const int, const Array<real_t> &,
const Array<real_t> &, const Vector &,
const Vector &, Vector &, const int,
const int);
/// arguments: DIM, d1d, q1d
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
/// arguments: DIM, d1d, q1d
MFEM_REGISTER_KERNELS(ApplyPATKernels, ApplyKernelType, (int, int, int));
template <int DIM, int D1D, int Q1D> static void AddSpecialization()
{
ApplyPAKernels::Specialization<DIM, D1D, Q1D>::Add();
ApplyPATKernels::Specialization<DIM, D1D, Q1D>::Add();
}
struct Kernels { Kernels(); };
private:
void SetupPA(const FiniteElementSpace &fes, FaceType type);
};
@@ -3416,8 +3500,8 @@ public:
class DGDiffusionIntegrator : public BilinearFormIntegrator
{
protected:
Coefficient *Q;
MatrixCoefficient *MQ;
Coefficient *Q = nullptr;
MatrixCoefficient *MQ = nullptr;
real_t sigma, kappa;
// these are not thread-safe!
@@ -3432,15 +3516,11 @@ protected:
IntegrationRules irs{0, Quadrature1D::GaussLobatto};
public:
DGDiffusionIntegrator(const real_t s, const real_t k)
: Q(NULL), MQ(NULL), sigma(s), kappa(k) { }
DGDiffusionIntegrator(Coefficient &q, const real_t s, const real_t k)
: Q(&q), MQ(NULL), sigma(s), kappa(k) { }
DGDiffusionIntegrator(MatrixCoefficient &q, const real_t s, const real_t k)
: Q(NULL), MQ(&q), sigma(s), kappa(k) { }
DGDiffusionIntegrator(const real_t s, const real_t k);
DGDiffusionIntegrator(Coefficient &q, const real_t s, const real_t k);
DGDiffusionIntegrator(MatrixCoefficient &q, const real_t s, const real_t k);
using BilinearFormIntegrator::AssembleFaceMatrix;
void AssembleFaceMatrix(const FiniteElement &el1,
const FiniteElement &el2,
void AssembleFaceMatrix(const FiniteElement &el1, const FiniteElement &el2,
FaceElementTransformations &Trans,
DenseMatrix &elmat) override;
@@ -3459,6 +3539,28 @@ public:
const IntegrationRule &GetRule(int order, Geometry::Type geom);
real_t GetPenaltyParameter() const { return kappa; }
/// arguments: nf, B, Bt, G, Gt, sigma, pa_data, x, dxdn, y, dydn, dofs1D,
/// quad1D
using ApplyKernelType = void (*)(const int, const Array<real_t> &,
const Array<real_t> &,
const Array<real_t> &,
const Array<real_t> &, const real_t,
const Vector &, const Vector &_,
const Vector &, Vector &, Vector &,
const int, const int);
/// arguments: DIM, d1d, q1d
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
template <int DIM, int D1D, int Q1D> static void AddSpecialization()
{
ApplyPAKernels::Specialization<DIM, D1D, Q1D>::Add();
}
struct Kernels { Kernels(); };
private:
void SetupPA(const FiniteElementSpace &fes, FaceType type);
};
@@ -8,6 +8,7 @@
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include <ceed/types.h>
/// A structure used to pass additional data to f_build_conv and f_apply_conv
struct ConvectionContext {
@@ -91,7 +92,7 @@ CEED_QFUNCTION(f_build_conv_const)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for building quadrature data for a convection operator
@@ -167,7 +168,7 @@ CEED_QFUNCTION(f_build_conv_quad)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for applying a conv operator
@@ -233,7 +234,7 @@ CEED_QFUNCTION(f_apply_conv)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for applying a conv operator
@@ -381,7 +382,7 @@ CEED_QFUNCTION(f_apply_conv_mf_const)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
@@ -525,5 +526,5 @@ CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
@@ -8,7 +8,7 @@
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include <ceed/types.h>
/// A structure used to pass additional data to f_build_diff and f_apply_diff
struct DiffusionContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
@@ -85,7 +85,7 @@ CEED_QFUNCTION(f_build_diff_const)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for building quadrature data for a diffusion operator
@@ -161,7 +161,7 @@ CEED_QFUNCTION(f_build_diff_quad)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for applying a diff operator
@@ -241,7 +241,7 @@ CEED_QFUNCTION(f_apply_diff)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for applying a diff operator
@@ -394,7 +394,7 @@ CEED_QFUNCTION(f_apply_diff_mf_const)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
CEED_QFUNCTION(f_apply_diff_mf_quad)(void *ctx, CeedInt Q,
@@ -549,5 +549,5 @@ CEED_QFUNCTION(f_apply_diff_mf_quad)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
+6 -6
View File
@@ -8,7 +8,7 @@
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include <ceed/types.h>
/// A structure used to pass additional data to f_build_diff and f_apply_diff
struct MassContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
@@ -53,7 +53,7 @@ CEED_QFUNCTION(f_build_mass_const)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for building quadrature data for a mass operator with a
@@ -95,7 +95,7 @@ CEED_QFUNCTION(f_build_mass_quad)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for applying a mass operator
@@ -135,7 +135,7 @@ CEED_QFUNCTION(f_apply_mass)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for applying a diff operator
@@ -199,7 +199,7 @@ CEED_QFUNCTION(f_apply_mass_mf_const)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
CEED_QFUNCTION(f_apply_mass_mf_quad)(void *ctx, CeedInt Q,
@@ -266,5 +266,5 @@ CEED_QFUNCTION(f_apply_mass_mf_quad)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
@@ -8,6 +8,7 @@
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include <ceed/types.h>
/// A structure used to pass additional data to f_build_conv and f_apply_conv
struct NLConvectionContext { CeedInt dim, space_dim, vdim; CeedScalar coeff; };
@@ -87,7 +88,7 @@ CEED_QFUNCTION(f_build_conv_const)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for building quadrature data for a convection operator
@@ -167,7 +168,7 @@ CEED_QFUNCTION(f_build_conv_quad)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for applying a conv operator
@@ -247,7 +248,7 @@ CEED_QFUNCTION(f_apply_conv)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
/// libCEED Q-function for applying a conv operator
@@ -362,7 +363,7 @@ CEED_QFUNCTION(f_apply_conv_mf_const)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
@@ -475,5 +476,5 @@ CEED_QFUNCTION(f_apply_conv_mf_quad)(void *ctx, CeedInt Q,
}
break;
}
return 0;
return CEED_ERROR_SUCCESS;
}
+12 -1
View File
@@ -18,10 +18,21 @@
#include <ceed.h>
#if !CEED_VERSION_GE(0,12,0)
#if !CEED_VERSION_GE(0, 12, 0)
#error MFEM requires a libCEED version >= 0.12.0
#endif
#if !CEED_VERSION_GE(0, 13, 0)
#define CeedOperatorCreateComposite(ceed, op) \
CeedCompositeOperatorCreate((ceed), (op))
#define CeedOperatorCompositeAddSub(op, sub) \
CeedCompositeOperatorAddSub((op), (sub))
#define CeedOperatorCompositeGetNumSub(op, num) \
CeedCompositeOperatorGetNumSub((op), (num))
#define CeedOperatorCompositeGetSubList(op, list) \
CeedCompositeOperatorGetSubList((op), (list))
#endif
namespace mfem
{
+2 -2
View File
@@ -83,7 +83,7 @@ public:
}
// Create composite CeedOperator
CeedCompositeOperatorCreate(internal::ceed, &oper);
CeedOperatorCreateComposite(internal::ceed, &oper);
// Create each sub-CeedOperator
sub_ops.reserve(element_indices.size());
@@ -101,7 +101,7 @@ public:
int nelem = *count[value.first];
sub_op->Assemble(info, fes, ir, nelem, indices, Q);
sub_ops.push_back(sub_op);
CeedCompositeOperatorAddSub(oper, sub_op->GetCeedOperator());
CeedOperatorCompositeAddSub(oper, sub_op->GetCeedOperator());
}
const int ndofs = fes.GetVDim() * fes.GetNDofs();
+6 -6
View File
@@ -140,11 +140,7 @@ int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field)
CeedOperator *subops;
if (isComposite)
{
#if CEED_VERSION_GE(0, 10, 2)
ierr = CeedCompositeOperatorGetSubList(oper, &subops); PCeedChk(ierr);
#else
ierr = CeedOperatorGetSubList(oper, &subops); PCeedChk(ierr);
#endif
ierr = CeedOperatorCompositeGetSubList(oper, &subops); PCeedChk(ierr);
ierr = CeedOperatorGetQFunction(subops[0], &qf); PCeedChk(ierr);
}
else
@@ -171,7 +167,11 @@ int CeedOperatorGetActiveField(CeedOperator oper, CeedOperatorField *field)
for (int i = 0; i < numinputfields; ++i)
{
ierr = CeedOperatorFieldGetVector(inputfields[i], &if_vector); PCeedChk(ierr);
if (if_vector == CEED_VECTOR_ACTIVE)
bool is_active = if_vector == CEED_VECTOR_ACTIVE;
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedVectorDestroy(&if_vector); PCeedChk(ierr);
#endif
if (is_active)
{
if (found)
{
+6 -11
View File
@@ -228,7 +228,7 @@ void AddToCompositeOperator(BilinearFormIntegrator *integ, CeedOperator op)
{
if (integ->SupportsCeed())
{
CeedCompositeOperatorAddSub(op, integ->GetCeedOp().GetCeedOperator());
CeedOperatorCompositeAddSub(op, integ->GetCeedOp().GetCeedOperator());
}
else
{
@@ -240,7 +240,7 @@ CeedOperator CreateCeedCompositeOperatorFromBilinearForm(BilinearForm &form)
{
int ierr;
CeedOperator op;
ierr = CeedCompositeOperatorCreate(internal::ceed, &op); PCeedChk(ierr);
ierr = CeedOperatorCreateComposite(internal::ceed, &op); PCeedChk(ierr);
MFEM_VERIFY(form.GetBBFI()->Size() == 0,
"Not implemented for this integrator!");
@@ -271,18 +271,13 @@ CeedOperator CoarsenCeedCompositeOperator(
MFEM_ASSERT(isComposite, "");
CeedOperator op_coarse;
ierr = CeedCompositeOperatorCreate(internal::ceed,
ierr = CeedOperatorCreateComposite(internal::ceed,
&op_coarse); PCeedChk(ierr);
int nsub;
CeedOperator *subops;
#if CEED_VERSION_GE(0, 10, 2)
ierr = CeedCompositeOperatorGetNumSub(op, &nsub); PCeedChk(ierr);
ierr = CeedCompositeOperatorGetSubList(op, &subops); PCeedChk(ierr);
#else
ierr = CeedOperatorGetNumSub(op, &nsub); PCeedChk(ierr);
ierr = CeedOperatorGetSubList(op, &subops); PCeedChk(ierr);
#endif
ierr = CeedOperatorCompositeGetNumSub(op, &nsub); PCeedChk(ierr);
ierr = CeedOperatorCompositeGetSubList(op, &subops); PCeedChk(ierr);
for (int isub=0; isub<nsub; ++isub)
{
CeedOperator subop = subops[isub];
@@ -294,7 +289,7 @@ CeedOperator CoarsenCeedCompositeOperator(
// refcounted by existing objects
ierr = CeedBasisDestroy(&basis_coarse); PCeedChk(ierr);
ierr = CeedBasisDestroy(&basis_c2f); PCeedChk(ierr);
ierr = CeedCompositeOperatorAddSub(op_coarse, subop_coarse);
ierr = CeedOperatorCompositeAddSub(op_coarse, subop_coarse);
PCeedChk(ierr);
ierr = CeedOperatorDestroy(&subop_coarse); PCeedChk(ierr);
}
+52 -14
View File
@@ -81,12 +81,27 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
ierr = CeedOperatorFieldGetVector(input_fields[i], &vec); PCeedChk(ierr);
if (vec == CEED_VECTOR_ACTIVE)
{
ierr = CeedOperatorFieldGetBasis(input_fields[i], &basisin);
PCeedChk(ierr);
CeedBasis basis;
ierr = CeedOperatorFieldGetBasis(input_fields[i], &basis); PCeedChk(ierr);
if (!basisin)
{
ierr = CeedBasisReferenceCopy(basis, &basisin); PCeedChk(ierr);
}
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedBasisDestroy(&basis); PCeedChk(ierr);
#endif
ierr = CeedBasisGetNumComponents(basisin, &ncomp); PCeedChk(ierr);
ierr = CeedBasisGetDimension(basisin, &dim); PCeedChk(ierr);
ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstrin);
CeedElemRestriction rstr;
ierr = CeedOperatorFieldGetElemRestriction(input_fields[i], &rstr);
PCeedChk(ierr);
if (!rstrin)
{
ierr = CeedElemRestrictionReferenceCopy(rstr, &rstrin); PCeedChk(ierr);
}
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedElemRestrictionDestroy(&rstr); PCeedChk(ierr);
#endif
CeedEvalMode emode;
ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
PCeedChk(ierr);
@@ -112,6 +127,9 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
break; // Caught by QF Assembly
}
}
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedVectorDestroy(&vec); PCeedChk(ierr);
#endif
}
// Determine active output basis
@@ -127,11 +145,25 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
ierr = CeedOperatorFieldGetVector(output_fields[i], &vec); PCeedChk(ierr);
if (vec == CEED_VECTOR_ACTIVE)
{
ierr = CeedOperatorFieldGetBasis(output_fields[i], &basisout);
PCeedChk(ierr);
ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstrout);
PCeedChk(ierr);
CeedBasis basis;
ierr = CeedOperatorFieldGetBasis(output_fields[i], &basis); PCeedChk(ierr);
if (!basisout)
{
ierr = CeedBasisReferenceCopy(basis, &basisout); PCeedChk(ierr);
}
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedBasisDestroy(&basis); PCeedChk(ierr);
#endif
CeedElemRestriction rstr;
ierr = CeedOperatorFieldGetElemRestriction(output_fields[i], &rstr);
PCeedChk(ierr);
if (!rstrout)
{
ierr = CeedElemRestrictionReferenceCopy(rstr, &rstrout); PCeedChk(ierr);
}
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedElemRestrictionDestroy(&rstr); PCeedChk(ierr);
#endif
CeedEvalMode emode;
ierr = CeedQFunctionFieldGetEvalMode(qffields[i], &emode);
PCeedChk(ierr);
@@ -157,6 +189,9 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
break; // Caught by QF Assembly
}
}
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedVectorDestroy(&vec); PCeedChk(ierr);
#endif
}
CeedInt nelem, elemsize, nqpts;
@@ -200,7 +235,11 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
PCeedChk(ierr);
CeedInt layout[3];
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedElemRestrictionGetELayout(rstr_q, layout); PCeedChk(ierr);
#else
ierr = CeedElemRestrictionGetELayout(rstr_q, &layout); PCeedChk(ierr);
#endif
ierr = CeedElemRestrictionDestroy(&rstr_q); PCeedChk(ierr);
// enforce structurally symmetric for later elimination
@@ -285,6 +324,10 @@ int CeedSingleOperatorFullAssemble(CeedOperator op, SparseMatrix *out)
ierr = CeedVectorRestoreArrayRead(assembledqf, &assembledqfarray);
PCeedChk(ierr);
ierr = CeedVectorDestroy(&assembledqf); PCeedChk(ierr);
ierr = CeedElemRestrictionDestroy(&rstrin); PCeedChk(ierr);
ierr = CeedElemRestrictionDestroy(&rstrout); PCeedChk(ierr);
ierr = CeedBasisDestroy(&basisin); PCeedChk(ierr);
ierr = CeedBasisDestroy(&basisout); PCeedChk(ierr);
ierr = CeedHackFree(&emodein); PCeedChk(ierr);
ierr = CeedHackFree(&emodeout); PCeedChk(ierr);
@@ -310,13 +353,8 @@ int CeedOperatorFullAssemble(CeedOperator op, SparseMatrix **mat)
{
CeedInt numsub;
CeedOperator *subops;
#if CEED_VERSION_GE(0, 10, 2)
CeedCompositeOperatorGetNumSub(op, &numsub);
ierr = CeedCompositeOperatorGetSubList(op, &subops); PCeedChk(ierr);
#else
CeedOperatorGetNumSub(op, &numsub);
ierr = CeedOperatorGetSubList(op, &subops); PCeedChk(ierr);
#endif
ierr = CeedOperatorCompositeGetNumSub(op, &numsub); PCeedChk(ierr);
ierr = CeedOperatorCompositeGetSubList(op, &subops); PCeedChk(ierr);
for (int i = 0; i < numsub; ++i)
{
ierr = CeedSingleOperatorFullAssemble(subops[i], out); PCeedChk(ierr);
+25 -1
View File
@@ -120,7 +120,11 @@ int CeedATPMGElemRestriction(int order,
}
ierr = CeedVectorRestoreArray(in_lvec, &lvec_data); PCeedChk(ierr);
CeedInt in_layout[3];
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedElemRestrictionGetELayout(er_in, in_layout); PCeedChk(ierr);
#else
ierr = CeedElemRestrictionGetELayout(er_in, &in_layout); PCeedChk(ierr);
#endif
if (in_layout[0] == 0 && in_layout[1] == 0 && in_layout[2] == 0)
{
return CeedError(ceed, 1, "Cannot interpret e-vector ordering of given"
@@ -664,7 +668,11 @@ int CeedATPMGOperator(CeedOperator oper, int order_reduction,
for (int i = 0; i < numinputfields; ++i)
{
#if CEED_VERSION_GE(0, 13, 0)
const char * fieldname;
#else
char * fieldname;
#endif
ierr = CeedQFunctionFieldGetName(inputqfields[i], &fieldname); PCeedChk(ierr);
if (if_vector[i] == CEED_VECTOR_ACTIVE)
{
@@ -676,10 +684,19 @@ int CeedATPMGOperator(CeedOperator oper, int order_reduction,
ierr = CeedOperatorSetField(coper, fieldname, er_input[i], basis_input[i],
if_vector[i]); PCeedChk(ierr);
}
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedVectorDestroy(&if_vector[i]); PCeedChk(ierr);
ierr = CeedElemRestrictionDestroy(&er_input[i]); PCeedChk(ierr);
ierr = CeedBasisDestroy(&basis_input[i]); PCeedChk(ierr);
#endif
}
for (int i = 0; i < numoutputfields; ++i)
{
#if CEED_VERSION_GE(0, 13, 0)
const char * fieldname;
#else
char * fieldname;
#endif
ierr = CeedQFunctionFieldGetName(outputqfields[i], &fieldname); PCeedChk(ierr);
if (of_vector[i] == CEED_VECTOR_ACTIVE)
{
@@ -691,6 +708,11 @@ int CeedATPMGOperator(CeedOperator oper, int order_reduction,
ierr = CeedOperatorSetField(coper, fieldname, er_output[i], basis_output[i],
of_vector[i]); PCeedChk(ierr);
}
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedVectorDestroy(&of_vector[i]); PCeedChk(ierr);
ierr = CeedElemRestrictionDestroy(&er_output[i]); PCeedChk(ierr);
ierr = CeedBasisDestroy(&basis_output[i]); PCeedChk(ierr);
#endif
}
delete [] er_input;
delete [] er_output;
@@ -741,7 +763,9 @@ int CeedOperatorGetOrder(CeedOperator oper, CeedInt * order)
int P1d;
ierr = CeedBasisGetNumNodes1D(basis, &P1d); PCeedChk(ierr);
*order = P1d - 1;
#if CEED_VERSION_GE(0, 13, 0)
ierr = CeedBasisDestroy(&basis); PCeedChk(ierr);
#endif
return 0;
}
+99
View File
@@ -12,6 +12,7 @@
// Implementation of Coefficient class
#include "fem.hpp"
#include "../general/forall.hpp"
#include <cmath>
#include <limits>
@@ -80,6 +81,49 @@ real_t PWConstCoefficient::Eval(ElementTransformation & T,
return (constants(att-1));
}
void PWConstCoefficient::Project(QuadratureFunction &qf)
{
auto &qs = *qf.GetSpace();
const bool compressed =
qs.Offsets(QSpaceOffsetStorage::COMPRESSED).Size() == 1;
const int *offsets = qs.Offsets(QSpaceOffsetStorage::COMPRESSED).Read();
const int ne = qs.GetNE();
const int *attributes = [&]()
{
if (dynamic_cast<QuadratureSpace*>(&qs) != nullptr)
{
return qs.GetMesh()->GetElementAttributes().Read();
}
else if (auto *qs_f = dynamic_cast<FaceQuadratureSpace*>(&qs))
{
MFEM_VERIFY(qs_f->GetFaceType() == FaceType::Boundary,
"Interior faces do not have attributes.");
return qs.GetMesh()->GetBdrFaceAttributes().Read();
}
else
{
MFEM_ABORT("Unsupported case.");
}
}();
const real_t *d_c = constants.Read();
real_t *d_qf = qf.Write();
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
{
const int a = attributes[e];
const real_t elementConstant = d_c[a - 1];
const int begin = compressed ? e*offsets[0] : offsets[e];
const int end = compressed ? (e+1)*offsets[0] : offsets[e+1];
for (int i = begin; i < end; ++i)
{
d_qf[i] = elementConstant;
}
});
}
void PWCoefficient::InitMap(const Array<int> & attr,
const Array<Coefficient*> & coefs)
{
@@ -519,6 +563,26 @@ void GradientGridFunctionCoefficient::Eval(
}
}
void GradientGridFunctionCoefficient::Project(QuadratureFunction &qf)
{
const FiniteElementSpace &fes = *GridFunc->FESpace();
const Mesh &mesh = *fes.GetMesh();
const int sdim = mesh.SpaceDimension();
const int gf_vdim = fes.GetVDim(); // assumed to be 1 in this class
qf.SetVDim(sdim*gf_vdim);
if (mesh.GetNE() == 0) { return; }
// All mesh element must be the same type:
MFEM_VERIFY(mesh.GetNumGeometries(mesh.Dimension()) == 1,
"All mesh elements must be the same type!");
const IntegrationRule &ir = qf.GetIntRule(0);
// All elements must use the same quadrature rule:
MFEM_VERIFY(qf.Size() == sdim*gf_vdim*ir.GetNPoints()*mesh.GetNE(),
"All mesh elements must use the same quadrature rule!");
// QuadratureFunction uses the layout qf_vdim x nq x ne, i.e.
// gf_vdim x sdim x nq x nq, so we need to request QVectorLayout::byVDIM:
GridFunc->GetGradients(ir, qf, QVectorLayout::byVDIM);
}
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient(
const GridFunction *gf)
: VectorCoefficient(0)
@@ -1065,6 +1129,41 @@ real_t InnerProductCoefficient::Eval(ElementTransformation &T,
return va * vb;
}
void InnerProductCoefficient::Project(QuadratureFunction &qf)
{
MFEM_VERIFY(a->GetVDim() == b->GetVDim(),
"Incompatible vector coefficients: a->GetVDim(): "
<< a->GetVDim() << ", b->GetVDim(): " << b->GetVDim());
const int vdim = a->GetVDim();
MFEM_VERIFY(vdim >= 1, "invalid vdim: " << vdim);
// When running on device, make sure the output data is allocated before any
// local temporary data to reduce potential heap fragmentation:
auto dot_d = qf.Write();
QuadratureFunction qf_a(qf.GetSpace(), vdim);
QuadratureFunction qf_b(qf.GetSpace(), vdim);
a->Project(qf_a);
b->Project(qf_b);
auto a_d = qf_a.Read();
auto b_d = qf_b.Read();
mfem::forall(qf.GetSpace()->GetSize(), [=] MFEM_HOST_DEVICE (int i)
{
const real_t *ai = a_d + i*vdim;
const real_t *bi = b_d + i*vdim;
real_t dot = ai[0]*bi[0];
for (int d = 1; d < vdim; d++)
{
dot += ai[d]*bi[d];
}
dot_d[i] = dot;
});
}
VectorRotProductCoefficient::VectorRotProductCoefficient(VectorCoefficient &A,
VectorCoefficient &B)
: a(&A), b(&B), va(A.GetVDim()), vb(B.GetVDim())
+9
View File
@@ -132,6 +132,9 @@ public:
/// Evaluate the coefficient.
real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip) override;
/// Fill the QuadratureFunction @a qf with the piecewise constant values.
void Project(QuadratureFunction &qf) override;
};
/** @brief A piecewise coefficient with the pieces keyed off the element
@@ -894,6 +897,9 @@ public:
void Eval(DenseMatrix &M, ElementTransformation &T,
const IntegrationRule &ir) override;
/// @copydoc VectorCoefficient::Project(QuadratureFunction &)
void Project(QuadratureFunction &qf) override;
virtual ~GradientGridFunctionCoefficient() { }
};
@@ -1771,6 +1777,9 @@ public:
/// Evaluate the coefficient at @a ip.
real_t Eval(ElementTransformation &T,
const IntegrationPoint &ip) override;
/// @copydoc Coefficient::Project(QuadratureFunction &)
void Project(QuadratureFunction &qf) override;
};
/// Scalar coefficient defined as a cross product of two vectors in the xy-plane.
+4 -4
View File
@@ -912,7 +912,7 @@ ConduitDataCollection::GridFunctionToBlueprintField(mfem::GridFunction *gf,
if (vdim == 1) // scalar case
{
n_field["values"].set_external(gf->GetData(),
n_field["values"].set_external(const_cast<real_t *>(gf->HostRead()),
ndofs);
}
else // vector case
@@ -925,18 +925,18 @@ ConduitDataCollection::GridFunctionToBlueprintField(mfem::GridFunction *gf,
int vdim_stride = (ordering == Ordering::byNODES ? ndofs : 1);
index_t offset = 0;
index_t stride = sizeof(double) * entry_stride;
index_t stride = sizeof(real_t) * entry_stride;
for (int d = 0; d < vdim; d++)
{
std::ostringstream oss;
oss << "v" << d;
std::string comp_name = oss.str();
n_field["values"][comp_name].set_external(gf->GetData(),
n_field["values"][comp_name].set_external(const_cast<real_t *>(gf->HostRead()),
ndofs,
offset,
stride);
offset += sizeof(double) * vdim_stride;
offset += sizeof(real_t) * vdim_stride;
}
}
+266
View File
@@ -0,0 +1,266 @@
// 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.
#include "derefmat_op.hpp"
#include "fes_kernels.hpp"
/// \cond DO_NOT_DOCUMENT
namespace mfem
{
namespace internal
{
template <Ordering::Type Order, bool Atomic>
static void DerefMultKernelImpl(const DerefineMatrixOp &op, const Vector &x,
Vector &y)
{
DerefineMatrixOpMultFunctor<Order, Atomic> func;
func.xptr = x.Read();
y.UseDevice();
y = 0.;
func.yptr = y.ReadWrite();
func.bsptr = op.block_storage.Read();
func.boptr = op.block_offsets.Read();
func.brptr = op.block_row_idcs_offsets.Read();
func.bcptr = op.block_col_idcs_offsets.Read();
func.rptr = op.row_idcs.Read();
func.cptr = op.col_idcs.Read();
func.vdims = op.fespace->GetVDim();
func.nblocks = op.block_offsets.Size();
func.width = op.Width() / func.vdims;
func.height = op.Height() / func.vdims;
func.Run(op.max_rows);
}
} // namespace internal
DerefineMatrixOp::DerefineMatrixOp(FiniteElementSpace &fespace_, int old_ndofs,
const Table *old_elem_dof,
const Table *old_elem_fos)
: Operator(fespace_.GetVSize(), old_ndofs * fespace_.GetVDim()),
fespace(&fespace_)
{
static Kernels kernels;
constexpr int max_team_size = 256;
/// TODO: Implement DofTransformation support
MFEM_VERIFY(fespace->Nonconforming(),
"Not implemented for conforming meshes.");
MFEM_VERIFY(old_ndofs, "Missing previous (finer) space.");
MFEM_VERIFY(fespace->GetNDofs() <= old_ndofs,
"Previous space is not finer.");
const CoarseFineTransformations &dtrans =
fespace->GetMesh()->ncmesh->GetDerefinementTransforms();
MFEM_ASSERT(dtrans.embeddings.Size() == old_elem_dof->Size(), "");
const bool is_dg = fespace->FEColl()->GetContType()
== FiniteElementCollection::DISCONTINUOUS;
DenseMatrix localRVO; // for variable-order only
DenseTensor localR[Geometry::NumGeom];
int total_rows = 0;
int total_cols = 0;
block_offsets.SetSize(dtrans.embeddings.Size());
block_offsets.HostWrite();
if (fespace->IsVariableOrder())
{
// TODO: any potential for some compression here?
// determine storage size and offsets
block_offsets[0] = 0;
int total_size = 0;
for (int k = 0; k < dtrans.embeddings.Size(); ++k)
{
const Embedding &emb = dtrans.embeddings[k];
const FiniteElement *fe = fespace->GetFE(emb.parent);
const int ldof = fe->GetDof();
if (k + 1 < dtrans.embeddings.Size())
{
block_offsets[k + 1] = block_offsets[k] + ldof * ldof;
}
total_rows += ldof;
total_cols += ldof;
total_size += ldof * ldof;
}
block_storage.SetSize(total_size);
}
else
{
// compression scheme:
// block_offsets is the start of each block, potentially repeated
// only need to store localR for used shapes
Mesh::GeometryList elem_geoms(*fespace->GetMesh());
int geom_offsets[Geometry::NumGeom];
{
int size = 0;
for (int i = 0; i < elem_geoms.Size(); ++i)
{
fespace->GetLocalDerefinementMatrices(elem_geoms[i],
localR[elem_geoms[i]]);
geom_offsets[elem_geoms[i]] = size;
size += localR[elem_geoms[i]].TotalSize();
}
block_storage.SetSize(size);
// copy blocks into block_storage
auto bs_ptr = block_storage.HostWrite();
for (int i = 0; i < elem_geoms.Size(); ++i)
{
std::copy(localR[elem_geoms[i]].Data(),
localR[elem_geoms[i]].Data()
+ localR[elem_geoms[i]].TotalSize(),
bs_ptr);
bs_ptr += localR[elem_geoms[i]].TotalSize();
}
}
for (int k = 0; k < dtrans.embeddings.Size(); ++k)
{
const Embedding &emb = dtrans.embeddings[k];
Geometry::Type geom =
fespace->GetMesh()->GetElementBaseGeometry(emb.parent);
auto size = localR[geom].SizeI() * localR[geom].SizeJ();
total_rows += localR[geom].SizeI();
total_cols += localR[geom].SizeJ();
// set block offsets and sizes
block_offsets[k] = geom_offsets[geom] + size * emb.matrix;
}
}
row_idcs.SetSize(total_rows);
row_idcs.HostWrite();
col_idcs.SetSize(total_cols);
col_idcs.HostWrite();
block_row_idcs_offsets.SetSize(dtrans.embeddings.Size() + 1);
block_row_idcs_offsets.HostWrite();
block_col_idcs_offsets.SetSize(dtrans.embeddings.Size() + 1);
block_col_idcs_offsets.HostWrite();
block_row_idcs_offsets[0] = 0;
block_col_idcs_offsets[0] = 0;
// compute index information
Array<int> dofs, old_dofs;
max_rows = 1;
{
Array<int> mark(fespace->GetNDofs());
mark = 0;
auto bs_ptr = block_storage.HostWrite();
int ridx = 0;
int cidx = 0;
int num_marked = 0;
for (int k = 0; k < dtrans.embeddings.Size(); k++)
{
const Embedding &emb = dtrans.embeddings[k];
Geometry::Type geom =
fespace->GetMesh()->GetElementBaseGeometry(emb.parent);
if (fespace->IsVariableOrder())
{
const FiniteElement *fe = fespace->GetFE(emb.parent);
const DenseTensor &pmats = dtrans.point_matrices[geom];
const int ldof = fe->GetDof();
IsoparametricTransformation isotr;
isotr.SetIdentityTransformation(geom);
localRVO.SetSize(ldof, ldof);
isotr.SetPointMat(pmats(emb.matrix));
// Local restriction is size ldofxldof assuming that the parent
// and child are of same polynomial order.
fe->GetLocalRestriction(isotr, localRVO);
// copy block
auto size = localRVO.Height() * localRVO.Width();
std::copy(localRVO.Data(), localRVO.Data() + size, bs_ptr);
bs_ptr += size;
}
DenseMatrix &lR =
fespace->IsVariableOrder() ? localRVO : localR[geom](emb.matrix);
block_row_idcs_offsets[k + 1] =
block_row_idcs_offsets[k] + lR.Height();
block_col_idcs_offsets[k + 1] = block_col_idcs_offsets[k] + lR.Width();
max_rows = std::max(lR.Height(), max_rows);
// index information
fespace->elem_dof->GetRow(emb.parent, dofs);
old_elem_dof->GetRow(k, old_dofs);
MFEM_VERIFY(old_dofs.Size() == dofs.Size(),
"Parent and child must have same #dofs.");
for (int i = 0; i < lR.Height(); ++i, ++ridx)
{
if (!std::isfinite(lR(i, 0)))
{
row_idcs[ridx] = INT_MAX;
continue;
}
int r = dofs[i];
int m = (r >= 0) ? r : (-1 - r);
if (is_dg || !mark[m])
{
row_idcs[ridx] = r;
mark[m] = 1;
++num_marked;
}
else
{
row_idcs[ridx] = INT_MAX;
}
}
for (int i = 0; i < lR.Width(); ++i, ++cidx)
{
col_idcs[cidx] = old_dofs[i];
}
}
if (!is_dg && !fespace->IsVariableOrder())
{
MFEM_VERIFY(num_marked * fespace->GetVDim() == Height(),
"internal error: not all rows were set.");
}
}
// if not using GPU, set max_rows/max_cols to zero
if (Device::Allows(Backend::DEVICE_MASK))
{
max_rows = std::min(max_rows, max_team_size);
}
else
{
max_rows = 1;
}
}
void DerefineMatrixOp::Mult(const Vector &x, Vector &y) const
{
const bool is_dg = fespace->FEColl()->GetContType()
== FiniteElementCollection::DISCONTINUOUS;
// DG needs atomic summation
MultKernel::Run(fespace->GetOrdering(), is_dg, *this, x, y);
}
DerefineMatrixOp::Kernels::Kernels()
{
MultKernel::Specialization<Ordering::byNODES, false>::Add();
MultKernel::Specialization<Ordering::byVDIM, false>::Add();
MultKernel::Specialization<Ordering::byNODES, true>::Add();
MultKernel::Specialization<Ordering::byVDIM, true>::Add();
}
template <Ordering::Type Order, bool Atomic>
DerefineMatrixOp::MultKernelType DerefineMatrixOp::MultKernel::Kernel()
{
return internal::DerefMultKernelImpl<Order, Atomic>;
}
DerefineMatrixOp::MultKernelType
DerefineMatrixOp::MultKernel::Fallback(Ordering::Type, bool)
{
MFEM_ABORT("invalid MultKernel parameters");
}
} // namespace mfem
/// \endcond DO_NOT_DOCUMENT
+65
View File
@@ -0,0 +1,65 @@
// 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_DEREFMAT_OP
#define MFEM_DEREFMAT_OP
#include "fespace.hpp"
#include "kernel_dispatch.hpp"
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
struct DerefineMatrixOp : public Operator
{
FiniteElementSpace *fespace;
/// offsets into block_storage
Array<int> block_offsets;
/// offsets into row_idcs
Array<int> block_row_idcs_offsets;
/// offsets into col_idcs
Array<int> block_col_idcs_offsets;
/// mapping for row dofs, INT_MAX indicates the block row should be ignored.
/// negative means the row data should be negated.
Array<int> row_idcs;
/// mapping for col dofs, negative means the col data should be negated.
Array<int> col_idcs;
/// dense block matrices which can be reused to construct the full matrix
/// operation. These are stored contiguously and blocks have no restrictions
/// on shape (can be rectangle and differ from block to block).
Vector block_storage;
/// maximum height of any block in block_storage for GPU
/// parallelization, or 1 for CPU runs.
int max_rows;
using MultKernelType = void (*)(const DerefineMatrixOp &, const Vector &,
Vector &);
/// template args: ordering, atomic
MFEM_REGISTER_KERNELS(MultKernel, MultKernelType, (Ordering::Type, bool));
struct Kernels
{
Kernels();
};
void Mult(const Vector &x, Vector &y) const;
DerefineMatrixOp(FiniteElementSpace &fespace_, int old_ndofs,
const Table *old_elem_dof, const Table *old_elem_fos);
};
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
#endif
+43 -11
View File
@@ -231,22 +231,53 @@ public:
const std::vector<FieldDescriptor> &parameters,
const ParMesh &mesh);
/// MultLevel enum to indicate if the T->L Operators are used in the
/// Mult method.
enum MultLevel
{
TVECTOR,
LVECTOR
};
/// @brief Set the MultLevel mode for the DifferentiableOperator.
/// The default is TVECTOR, which means that the Operator will use
/// T->L before Mult and L->T Operators after.
void SetMultLevel(MultLevel level)
{
mult_level = level;
}
/// @brief Compute the action of the operator on a given vector.
///
/// @param solutions_t The solution vector in which to compute the action.
/// This has to be a T-dof vector.
/// @param result_t Result vector of the action of the operator on
/// solutions_t. The result is a T-dof vector.
void Mult(const Vector &solutions_t, Vector &result_t) const override
/// @param solutions_in The solution vector in which to compute the action.
/// This has to be a T-dof vector if MultLevel is set to TVECTOR, or L-dof
/// Vector if MultLevel is set to LVECTOR.
/// @param result_in Result vector of the action of the operator on
/// solutions. The result is a T-dof vector or L-dof vector depending on
/// the MultLevel.
void Mult(const Vector &solutions_in, Vector &result_in) const override
{
MFEM_ASSERT(!action_callbacks.empty(), "no integrators have been set");
prolongation(solutions, solutions_t, solutions_l);
residual_l = 0.0;
for (auto &action : action_callbacks)
if (mult_level == MultLevel::LVECTOR)
{
action(solutions_l, parameters_l, residual_l);
get_lvectors(solutions, solutions_in, solutions_l);
result_in = 0.0;
for (auto &action : action_callbacks)
{
action(solutions_l, parameters_l, result_in);
}
}
else
{
prolongation(solutions, solutions_in, solutions_l);
residual_l = 0.0;
for (auto &action : action_callbacks)
{
action(solutions_l, parameters_l, residual_l);
}
prolongation_transpose(residual_l, result_in);
}
prolongation_transpose(residual_l, result_t);
}
/// @brief Add a domain integrator to the operator.
@@ -345,6 +376,8 @@ public:
private:
const ParMesh &mesh;
MultLevel mult_level = TVECTOR;
std::vector<action_t> action_callbacks;
std::map<size_t,
std::vector<derivative_action_t>> derivative_action_callbacks;
@@ -354,7 +387,6 @@ private:
std::vector<assemble_derivative_hypreparmatrix_callback_t>>
assemble_derivative_hypreparmatrix_callbacks;
std::vector<FieldDescriptor> solutions;
std::vector<FieldDescriptor> parameters;
// solutions and parameters
+22 -4
View File
@@ -327,8 +327,8 @@ void print_mpi_sync(const std::string& msg)
// First gather string lengths
size_t msg_len = msg.length();
std::vector<size_t> lengths(nranks);
MPI_Gather(&msg_len, 1, MPI_INT,
lengths.data(), 1, MPI_INT,
MPI_Gather(&msg_len, 1, MPITypeMap<size_t>::mpi_type,
lengths.data(), 1, MPITypeMap<size_t>::mpi_type,
0, MPI_COMM_WORLD);
if (myrank == 0)
@@ -568,7 +568,7 @@ struct ThreadBlocks
int z = 1;
};
#if (defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP))
#if defined(MFEM_USE_CUDA_OR_HIP)
template <typename func_t>
__global__ void forall_kernel_shmem(func_t f, int n)
{
@@ -591,7 +591,7 @@ void forall(func_t f,
if (Device::Allows(Backend::CUDA_MASK) ||
Device::Allows(Backend::HIP_MASK))
{
#if (defined(MFEM_USE_CUDA) || defined(MFEM_USE_HIP))
#if defined(MFEM_USE_CUDA_OR_HIP)
// int gridsize = (N + Z - 1) / Z;
int num_bytes = num_shmem * sizeof(decltype(shmem));
dim3 block_size(blocks.x, blocks.y, blocks.z);
@@ -1076,6 +1076,24 @@ void prolongation(const std::vector<FieldDescriptor> fields,
}
}
inline
void get_lvectors(const std::vector<FieldDescriptor> fields,
const Vector &x,
std::vector<Vector> &fields_l)
{
int data_offset = 0;
for (std::size_t i = 0; i < fields.size(); i++)
{
const int sz = GetVSize(fields[i]);
fields_l[i].SetSize(sz);
const Vector x_i(const_cast<Vector&>(x), data_offset, sz);
fields_l[i] = x_i;
data_offset += sz;
}
}
/// @brief Get a transpose prolongation callback for a field descriptor.
///
/// In the special case of a one field operator, the transpose prolongation
+24
View File
@@ -259,6 +259,30 @@ inline void FaceIdxToVolIdx3D(const int index, const int size1d,
i = yz_plane ? level : _i;
}
MFEM_HOST_DEVICE
inline int FaceIdxToVolIdx(int dim, int i, int size1d, int face0, int face1,
int side, int orientation)
{
if (dim == 2)
{
int ix, iy;
internal::FaceIdxToVolIdx2D(i, size1d, face0, face1, side, ix, iy);
return ix + iy*size1d;
}
else if (dim == 3)
{
int ix, iy, iz;
internal::FaceIdxToVolIdx3D(i, size1d, face0, face1, side, orientation,
ix, iy, iz);
return ix + size1d*iy + size1d*size1d*iz;
}
else
{
MFEM_ABORT_KERNEL("Invalid dimension");
return -1;
}
};
} // namespace internal
} // namespace mfem
+3 -7
View File
@@ -401,9 +401,6 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
{
MFEM_ABORT("unknown FiniteElementCollection: " << name);
}
MFEM_VERIFY(!strcmp(fec->Name(), name), "input name: \"" << name
<< "\" does not match the created collection name: \""
<< fec->Name() << '"');
return fec;
}
@@ -2459,8 +2456,7 @@ RT_FECollection::RT_FECollection(const int order, const int dim,
const char *cb_name = BasisType::Name(cb_type); // this may abort
MFEM_ABORT("unknown closed BasisType: " << cb_name);
}
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid &&
ob_type != BasisType::IntegratedGLL)
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid)
{
const char *ob_name = BasisType::Name(ob_type); // this may abort
MFEM_ABORT("unknown open BasisType: " << ob_name);
@@ -2518,6 +2514,7 @@ RT_FECollection::RT_FECollection(const int p, const int dim,
const int map_type, const bool signs,
const int ob_type)
: FiniteElementCollection(p + 1)
, dim(dim)
, ob_type(ob_type)
{
if (Quadrature1D::CheckOpen(BasisType::GetQuadrature1D(ob_type)) ==
@@ -2786,8 +2783,7 @@ ND_FECollection::ND_FECollection(const int p, const int dim,
int cp_type = BasisType::GetQuadrature1D(cb_type);
// Error checking
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid &&
ob_type != BasisType::IntegratedGLL)
if (Quadrature1D::CheckOpen(op_type) == Quadrature1D::Invalid)
{
const char *ob_name = BasisType::Name(ob_type);
MFEM_ABORT("Invalid open basis point type: " << ob_name);
+14
View File
@@ -464,6 +464,13 @@ public:
RT_Trace_FECollection(const int p, const int dim,
const int map_type = FiniteElement::INTEGRAL,
const int ob_type = BasisType::GaussLegendre);
FiniteElementCollection *Clone(int p) const override
{
const int map_type = (strncmp(rt_name, "RT_Trace", 8) == 0)?
(FiniteElement::INTEGRAL):(FiniteElement::VALUE);
return new RT_Trace_FECollection(p, dim, map_type, ob_type);
}
};
/** Arbitrary order discontinuous finite elements defined on the interface
@@ -475,6 +482,13 @@ public:
DG_Interface_FECollection(const int p, const int dim,
const int map_type = FiniteElement::VALUE,
const int ob_type = BasisType::GaussLegendre);
FiniteElementCollection *Clone(int p) const override
{
const int map_type = (strncmp(rt_name, "DG_Iface", 8) == 0)?
(FiniteElement::VALUE):(FiniteElement::INTEGRAL);
return new DG_Interface_FECollection(p, dim, map_type, ob_type);
}
};
/// Arbitrary order H(curl)-conforming Nedelec finite elements.
+249
View File
@@ -0,0 +1,249 @@
// 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_FES_KERNELS_HPP
#define MFEM_FES_KERNELS_HPP
#include "../general/forall.hpp"
#include <climits>
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
namespace internal
{
///
/// Implements matrix-vector multiply $y = A x$ for a sparse matrix composed of
/// a sum of smaller dense blocks. There is additional permutation/sign
/// information associated with each block. The base class only implements
/// helper routines such as computing block widths, index into x, index into y,
/// and column in A given sub-block information.
/// @sa DerefineMatrixOpMultFunctor
///
/// @tparam Order vdim ordering for x and y. Note that for Diag = false this is
/// ignored for x as x has a special interleaved order.
/// @tparam Base used for the curious recurring template pattern (CRTP) so the
/// base class can access child class fields without virtual functions
/// @tparam Diag true if this corresponds to the diagonal block (coarse element
/// and fine element are on our rank), false otherwise (coarse element is on our
/// rank, fine element is on a different rank).
///
template <Ordering::Type Order, class Base, bool Diag = true>
struct DerefineMatrixOpFunctorBase;
template <class Base>
struct DerefineMatrixOpFunctorBase<Ordering::byNODES, Base, true>
{
/// block column indices offsets
const int *bcptr;
/// column indices
const int *cptr;
int MFEM_HOST_DEVICE BlockWidth(int k) const
{
return bcptr[k + 1] - bcptr[k];
}
void MFEM_HOST_DEVICE Col(int j, int k, int &col, int &sign) const
{
col = cptr[bcptr[k] + j];
if (col < 0)
{
col = -1 - col;
sign = -sign;
}
}
int MFEM_HOST_DEVICE IndexX(int col, int vdim, int) const
{
return col + vdim * static_cast<const Base *>(this)->width;
}
int MFEM_HOST_DEVICE IndexY(int row, int vdim) const
{
return row + vdim * static_cast<const Base *>(this)->height;
}
};
template <class Base>
struct DerefineMatrixOpFunctorBase<Ordering::byVDIM, Base, true>
{
/// block column indices offsets
const int *bcptr;
/// column indices
const int *cptr;
int MFEM_HOST_DEVICE BlockWidth(int k) const
{
return bcptr[k + 1] - bcptr[k];
}
void MFEM_HOST_DEVICE Col(int j, int k, int &col, int &sign) const
{
col = cptr[bcptr[k] + j];
if (col < 0)
{
col = -1 - col;
sign = -sign;
}
}
int MFEM_HOST_DEVICE IndexX(int col, int vdim, int) const
{
return vdim + col * static_cast<const Base *>(this)->vdims;
}
int MFEM_HOST_DEVICE IndexY(int row, int vdim) const
{
return vdim + row * static_cast<const Base *>(this)->vdims;
}
};
template <class Base>
struct DerefineMatrixOpFunctorBase<Ordering::byNODES, Base, false>
{
/// receive segment offsets
const int *segptr;
/// receive segment index
const int *rsptr;
/// off-diagonal block column offsets
const int *coptr;
/// off-diagonal block widths
const int *bwptr;
int MFEM_HOST_DEVICE BlockWidth(int k) const { return bwptr[k]; }
void MFEM_HOST_DEVICE Col(int j, int k, int &col, int &sign) const
{
col = coptr[k] + j;
}
int MFEM_HOST_DEVICE IndexX(int col, int vdim, int k) const
{
int tmp = rsptr[k];
int segwidth = segptr[tmp + 1] - segptr[tmp];
return segptr[tmp] * static_cast<const Base *>(this)->vdims + col +
vdim * segwidth;
}
int MFEM_HOST_DEVICE IndexY(int row, int vdim) const
{
return row + vdim * static_cast<const Base *>(this)->height;
}
};
template <class Base>
struct DerefineMatrixOpFunctorBase<Ordering::byVDIM, Base, false>
{
/// receive segment offsets
const int *segptr;
/// receive segment index
const int *rsptr;
/// off-diagonal block column offsets
const int *coptr;
/// off-diagonal block widths
const int *bwptr;
int MFEM_HOST_DEVICE BlockWidth(int k) const { return bwptr[k]; }
void MFEM_HOST_DEVICE Col(int j, int k, int &col, int &sign) const
{
col = coptr[k] + j;
}
int MFEM_HOST_DEVICE IndexX(int col, int vdim, int k) const
{
int tmp = rsptr[k];
int segwidth = segptr[tmp + 1] - segptr[tmp];
return segptr[tmp] * static_cast<const Base *>(this)->vdims + col +
vdim * segwidth;
}
int MFEM_HOST_DEVICE IndexY(int row, int vdim) const
{
return vdim + row * static_cast<const Base *>(this)->vdims;
}
};
/// internally used to implement the derefinement operator Mult diagonal
/// block
template <Ordering::Type Order, bool Atomic, bool Diag = true>
struct DerefineMatrixOpMultFunctor
: public DerefineMatrixOpFunctorBase<
Order, DerefineMatrixOpMultFunctor<Order, Atomic, Diag>, Diag>
{
const real_t *xptr;
real_t *yptr;
/// block storage
const real_t *bsptr;
/// block offsets
const int *boptr;
/// block row index offsets
const int *brptr;
/// row indices
const int *rptr;
// number of blocks
int nblocks;
// number of components
int vdims;
/// overall operator height (for vdim = 1)
int height;
/// overall operator width (for vdim = 1)
int width;
void MFEM_HOST_DEVICE operator()(int kidx) const
{
int k = kidx % nblocks;
int vdim = kidx / nblocks;
int block_height = brptr[k + 1] - brptr[k];
int block_width = this->BlockWidth(k);
MFEM_FOREACH_THREAD(i, x, block_height)
{
int row = rptr[brptr[k] + i];
int rsign = 1;
if (row < 0)
{
row = -1 - row;
rsign = -1;
}
if (row < INT_MAX)
{
// row not marked as unused
real_t sum = 0;
for (int j = 0; j < block_width; ++j)
{
int col, sign = rsign;
this->Col(j, k, col, sign);
sum += sign * bsptr[boptr[k] + i + j * block_height] *
xptr[this->IndexX(col, vdim, k)];
}
#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)
if (Atomic)
{
atomicAdd(yptr + this->IndexY(row, vdim), sum);
}
else
#endif
{
yptr[this->IndexY(row, vdim)] += sum;
}
}
}
}
/// N is the max block row size (doesn't have to be a power of 2)
void Run(int N) const { forall_2D(nblocks * vdims, N, 1, *this); }
};
} // namespace internal
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
#endif
+13 -6
View File
@@ -17,6 +17,9 @@
#include "fem.hpp"
#include "ceed/interface/util.hpp"
#include "derefmat_op.hpp"
#include <algorithm>
#include <cmath>
#include <cstdarg>
@@ -24,9 +27,9 @@ using namespace std;
namespace mfem
{
template <> void Ordering::
DofsToVDofs<Ordering::byNODES>(int ndofs, int vdim, Array<int> &dofs)
template <>
void Ordering::DofsToVDofs<Ordering::byNODES>(int ndofs, int vdim,
Array<int> &dofs)
{
// static method
int size = dofs.Size();
@@ -40,8 +43,9 @@ DofsToVDofs<Ordering::byNODES>(int ndofs, int vdim, Array<int> &dofs)
}
}
template <> void Ordering::
DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
template <>
void Ordering::DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim,
Array<int> &dofs)
{
// static method
int size = dofs.Size();
@@ -55,7 +59,6 @@ DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
}
}
FiniteElementSpace::FiniteElementSpace()
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
@@ -4244,7 +4247,11 @@ void FiniteElementSpace::Update(bool want_transform)
case Mesh::DEREFINE:
{
BuildConformingInterpolation();
#if 0
Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
#else
Th.Reset(new DerefineMatrixOp(*this, old_ndofs, old_elem_dof, old_elem_fos));
#endif
if (IsVariableOrder())
{
if (cP && cR_hp)
+11 -3
View File
@@ -113,7 +113,7 @@ class QuadratureSpace;
class QuadratureInterpolator;
class FaceQuadratureInterpolator;
class PRefinementTransferOperator;
struct DerefineMatrixOp;
/** @brief Class FiniteElementSpace - responsible for providing FEM view of the
mesh, mainly managing the set of degrees of freedom.
@@ -246,6 +246,7 @@ class FiniteElementSpace
friend class PRefinementTransferOperator;
friend void Mesh::Swap(Mesh &, bool);
friend class LORBase;
friend struct DerefineMatrixOp;
protected:
/// The mesh that FE space lives on (not owned).
@@ -682,8 +683,12 @@ public:
NURBSExtension *GetNURBSext() { return NURBSext; }
NURBSExtension *StealNURBSext();
bool Conforming() const { return mesh->Conforming() && cP == NULL; }
bool Nonconforming() const { return mesh->Nonconforming() || cP != NULL; }
bool Conforming() const
{
return NURBSext != NULL ||
(mesh->Conforming() && cP == NULL);
}
bool Nonconforming() const { return !Conforming(); }
/** Set the prolongation operator of the space to an arbitrary sparse matrix,
creating a copy of the argument. */
@@ -921,6 +926,9 @@ public:
{ return mesh->GetBdrElementType(i); }
/// Returns ElementTransformation for the @a i-th element.
/// @note The returned pointer references an object owned by the associated
/// @a Mesh that will be modified by other calls to `GetElementTransformation`.
/// As such, this pointer should @b not be deleted by the caller.
ElementTransformation *GetElementTransformation(int i) const
{ return mesh->GetElementTransformation(i); }
+46 -2
View File
@@ -68,7 +68,7 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
Vector::Load(input, fes->GetVSize());
// if the mesh is a legacy (v1.1) NC mesh, it has old vertex ordering
if (fes->Nonconforming() &&
if (fes->Nonconforming() && fes->GetMesh()->ncmesh &&
fes->GetMesh()->ncmesh->IsLegacyLoaded())
{
LegacyNCReorder();
@@ -1374,6 +1374,50 @@ void GridFunction::GetVectorGradientHat(
MultAtB(loc_data_mat, dshape, gh);
}
void GridFunction::GetGradients(const IntegrationRule &ir, Vector &grad,
QVectorLayout ql, MemoryType d_mt) const
{
const FiniteElement &fe = *fes->GetTypicalFE();
const int dim = fe.GetDim();
const int vdim = fes->GetVDim();
const int NE = fes->GetNE();
const int ND = fe.GetDof();
const int NQ = ir.GetNPoints();
MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
Device::GetDeviceMemoryType();
// ql == QVectorLayout::byNODES : NQ x VDIM x DIM x NE
// ql == QVectorLayout::byVDIM : VDIM x DIM x NQPT x NE
grad.SetSize(dim*vdim*NQ*NE, my_d_mt);
const QuadratureInterpolator &qi = *fes->GetQuadratureInterpolator(ir);
qi.SetOutputLayout(ql);
const bool use_tensor_products = UsesTensorBasis(*fes);
qi.DisableTensorProducts(!use_tensor_products);
const ElementDofOrdering e_ordering = use_tensor_products ?
ElementDofOrdering::LEXICOGRAPHIC :
ElementDofOrdering::NATIVE;
const Operator *elem_restr = fes->GetElementRestriction(e_ordering);
// Pre-compute the geometric factors in order to set the desired MemoryType
// they use:
fes->GetMesh()->GetGeometricFactors(
ir, GeometricFactors::JACOBIANS, my_d_mt);
if (elem_restr) // currently, always true
{
Vector f_e(vdim*ND*NE, my_d_mt);
elem_restr->Mult(*this, f_e);
qi.PhysDerivatives(f_e, grad);
}
else
{
qi.PhysDerivatives(*this, grad);
}
}
real_t GridFunction::GetDivergence(ElementTransformation &T) const
{
DofTransformation doftrans;
@@ -2624,7 +2668,7 @@ void GridFunction::ProjectBdrCoefficient(Coefficient *coeff[],
}
for (int i = 0; i < values_counter.Size(); i++)
{
MFEM_ASSERT(bool(values_counter[i]) == ess_vdofs_marker[i],
MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
"internal error");
}
#endif
+31 -2
View File
@@ -153,7 +153,8 @@ public:
/// Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
void SetFromTrueVector() { SetFromTrueDofs(GetTrueVector()); }
/// Returns the values in the vertices of i'th element for dimension vdim.
/** @brief Returns the values at the vertices of element @a i for the 1-based
dimension vdim. */
void GetNodalValues(int i, Array<real_t> &nval, int vdim = 1) const;
/** @name Element index Get Value Methods
@@ -308,7 +309,8 @@ public:
/// For a vector grid function, makes sure that the ordering is byNODES.
void ReorderByNodes();
/// Return the values as a vector on mesh vertices for dimension vdim.
/** @brief Returns the values as a vector at mesh vertices, for the 1-based
dimension vdim. */
void GetNodalValues(Vector &nval, int vdim = 1) const;
void GetVectorFieldNodalValues(Vector &val, int comp) const;
@@ -359,6 +361,33 @@ public:
variable. */
void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const;
/** @brief Evaluate the gradients of the GridFunction at the given quadrature
points, @a ir, in all mesh elements. */
/** This method assumes that all mesh elements are the same type and that the
IntegrationRule @a ir is consistent with that type of element.
@param[in] ir Quadrature points at which the gradients are to be
evaluated.
@param[out] grad Output vector of size `SDIM*VDIM*NQ*NE` where `SDIM` is
the spatial dimention of the mesh, `VDIM` is the vector
dimension of the GridFunction, `NQ` is the number of
quadrature points in @a ir, and `NE` is the number of
elements in the mesh. The layout of @a grad is
determined by the parameter @a ql: when @a ql is
QVectorLayout::byNODES, the layout is
`NQ x VDIM x SDIM x NE`; when @a ql is
QVectorLayout::byVDIM, the layout is
`VDIM x SDIM x NQ x NE`.
@param[in] ql Determines the layout of the output vector @a grad; see
the description of @a grad for details.
@param[in] d_mt MemoryType to use for allocating the output vector
@a grad, as well the GeometricFactors and temporary
vector used by the method. By default, the current
device memory type is used. */
void GetGradients(const IntegrationRule &ir, Vector &grad,
QVectorLayout ql = QVectorLayout::byNODES,
MemoryType d_mt = MemoryType::DEFAULT) const;
/** Compute $ (\int_{\Omega} (*this) \psi_i)/(\int_{\Omega} \psi_i) $,
where $ \psi_i $ are the basis functions for the FE space of avgs.
Both FE spaces should be scalar and on the same mesh. */
+154 -128
View File
@@ -85,9 +85,9 @@ namespace mfem
{
FindPointsGSLIB::FindPointsGSLIB()
: mesh(NULL),
fec_map_lin(NULL),
fdataD(NULL), cr(NULL), gsl_comm(NULL),
: mesh(nullptr),
fec_map_lin(nullptr),
fdataD(nullptr), cr(nullptr), gsl_comm(nullptr),
dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
{
@@ -97,10 +97,10 @@ FindPointsGSLIB::FindPointsGSLIB()
gf_rst_map.SetSize(4);
for (int i = 0; i < mesh_split.Size(); i++)
{
mesh_split[i] = NULL;
ir_split[i] = NULL;
fes_rst_map[i] = NULL;
gf_rst_map[i] = NULL;
mesh_split[i] = nullptr;
ir_split[i] = nullptr;
fes_rst_map[i] = nullptr;
gf_rst_map[i] = nullptr;
}
gsl_comm = new gslib::comm;
@@ -117,27 +117,40 @@ FindPointsGSLIB::FindPointsGSLIB()
crystal_init(cr, gsl_comm);
}
FindPointsGSLIB::FindPointsGSLIB(Mesh &mesh_in, const double bb_t,
const double newt_tol, const int npt_max)
: FindPointsGSLIB()
{
Setup(mesh_in, bb_t, newt_tol, npt_max);
}
FindPointsGSLIB::~FindPointsGSLIB()
{
crystal_free(cr);
comm_free(gsl_comm);
delete gsl_comm;
delete cr;
for (int i = 0; i < 4; i++)
FreeData();
#ifdef MFEM_USE_MPI
if (!Mpi::IsFinalized()) // currently segfaults inside gslib otherwise
#endif
{
if (mesh_split[i]) { delete mesh_split[i]; mesh_split[i] = NULL; }
if (ir_split[i]) { delete ir_split[i]; ir_split[i] = NULL; }
if (fes_rst_map[i]) { delete fes_rst_map[i]; fes_rst_map[i] = NULL; }
if (gf_rst_map[i]) { delete gf_rst_map[i]; gf_rst_map[i] = NULL; }
crystal_free(cr);
comm_free(gsl_comm);
delete gsl_comm;
delete cr;
}
if (fec_map_lin) { delete fec_map_lin; fec_map_lin = NULL; }
for (int i = 0; i < mesh_split.Size(); i++)
{
if (mesh_split[i]) { delete mesh_split[i]; mesh_split[i] = nullptr; }
if (ir_split[i]) { delete ir_split[i]; ir_split[i] = nullptr; }
if (fes_rst_map[i]) { delete fes_rst_map[i]; fes_rst_map[i] = nullptr; }
if (gf_rst_map[i]) { delete gf_rst_map[i]; gf_rst_map[i] = nullptr; }
}
if (fec_map_lin) { delete fec_map_lin; fec_map_lin = nullptr; }
}
#ifdef MFEM_USE_MPI
FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
: mesh(NULL),
fec_map_lin(NULL),
fdataD(NULL), cr(NULL), gsl_comm(NULL),
: mesh(nullptr),
fec_map_lin(nullptr),
fdataD(nullptr), cr(nullptr), gsl_comm(nullptr),
dim(-1), points_cnt(-1), setupflag(false), default_interp_value(0),
avgtype(AvgType::ARITHMETIC), bdr_tol(1e-8)
{
@@ -147,10 +160,10 @@ FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
gf_rst_map.SetSize(4);
for (int i = 0; i < mesh_split.Size(); i++)
{
mesh_split[i] = NULL;
ir_split[i] = NULL;
fes_rst_map[i] = NULL;
gf_rst_map[i] = NULL;
mesh_split[i] = nullptr;
ir_split[i] = nullptr;
fes_rst_map[i] = nullptr;
gf_rst_map[i] = nullptr;
}
gsl_comm = new gslib::comm;
@@ -158,12 +171,21 @@ FindPointsGSLIB::FindPointsGSLIB(MPI_Comm comm_)
comm_init(gsl_comm, comm_);
crystal_init(cr, gsl_comm);
}
FindPointsGSLIB::FindPointsGSLIB(ParMesh &mesh_in, const double bb_t,
const double newt_tol, const int npt_max)
: FindPointsGSLIB(mesh_in.GetComm())
{
Setup(mesh_in, bb_t, newt_tol, npt_max);
}
#endif
void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
const int npt_max)
{
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
MFEM_VERIFY(m.SpaceDimension() == m.Dimension(),
"Mesh spatial dimension and reference element dimension must be the same");
const int meshOrder = m.GetNodes()->FESpace()->GetMaxElementOrder();
// call FreeData if FindPointsGSLIB::Setup has been called already
@@ -171,37 +193,9 @@ void FindPointsGSLIB::Setup(Mesh &m, const double bb_t, const double newt_tol,
mesh = &m;
dim = mesh->Dimension();
unsigned dof1D = meshOrder + 1;
const unsigned int dof1D = meshOrder+1;
SetupSplitMeshes();
if (dim == 2)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
}
else if (dim == 3)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], meshOrder);
if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], meshOrder);
}
SetupSplitMeshesAndIntegrationRules(meshOrder);
GetNodalValues(mesh->GetNodes(), gsl_mesh);
@@ -1128,13 +1122,18 @@ void FindPointsGSLIB::Interpolate(Mesh &m, const Vector &point_pos,
void FindPointsGSLIB::FreeData()
{
if (!setupflag) { return; }
if (dim == 2)
#ifdef MFEM_USE_MPI
if (!Mpi::IsFinalized()) // currently segfaults inside gslib otherwise
#endif
{
findpts_free_2((gslib::findpts_data_2 *)this->fdataD);
}
else
{
findpts_free_3((gslib::findpts_data_3 *)this->fdataD);
if (dim == 2)
{
findpts_free_2((gslib::findpts_data_2 *)this->fdataD);
}
else
{
findpts_free_3((gslib::findpts_data_3 *)this->fdataD);
}
}
gsl_code.DeleteAll();
gsl_proc.DeleteAll();
@@ -1158,8 +1157,8 @@ void FindPointsGSLIB::FreeData()
void FindPointsGSLIB::SetupSplitMeshes()
{
fec_map_lin = new H1_FECollection(1, dim);
if (mesh->Dimension() == 2)
if (fec_map_lin == nullptr) { fec_map_lin = new H1_FECollection(1, dim); }
if (dim == 2)
{
int Nvert = 7;
int NEsplit = 3;
@@ -1201,7 +1200,7 @@ void FindPointsGSLIB::SetupSplitMeshes()
mesh_split[1] = new Mesh(Mesh::MakeCartesian2D(1, 1,
Element::QUADRILATERAL));
}
else if (mesh->Dimension() == 3)
else if (dim == 3)
{
mesh_split[0] = new Mesh(Mesh::MakeCartesian3D(1, 1, 1,
Element::HEXAHEDRON));
@@ -1346,41 +1345,6 @@ void FindPointsGSLIB::SetupSplitMeshes()
}
}
}
NE_split_total = 0;
split_element_map.SetSize(0);
split_element_index.SetSize(0);
int NEsplit = 0;
for (int e = 0; e < mesh->GetNE(); e++)
{
const Geometry::Type gt = mesh->GetElement(e)->GetGeometryType();
if (gt == Geometry::TRIANGLE || gt == Geometry::PRISM)
{
NEsplit = 3;
}
else if (gt == Geometry::TETRAHEDRON)
{
NEsplit = 4;
}
else if (gt == Geometry::PYRAMID)
{
NEsplit = 8;
}
else if (gt == Geometry::SQUARE || gt == Geometry::CUBE)
{
NEsplit = 1;
}
else
{
MFEM_ABORT("Unsupported geometry type.");
}
NE_split_total += NEsplit;
for (int i = 0; i < NEsplit; i++)
{
split_element_map.Append(e);
split_element_index.Append(i);
}
}
}
void FindPointsGSLIB::SetupIntegrationRuleForSplitMesh(Mesh *meshin,
@@ -1431,6 +1395,79 @@ void FindPointsGSLIB::SetupIntegrationRuleForSplitMesh(Mesh *meshin,
}
}
void FindPointsGSLIB::SetupSplitMeshesAndIntegrationRules(const int order)
{
MFEM_VERIFY(mesh, "Setup FindPointsGSLIB with mesh first.");
const int dof1D = order+1;
const int dim = mesh->Dimension();
SetupSplitMeshes();
if (dim == 2)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], order);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], order);
}
else if (dim == 3)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], order);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], order);
if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], order);
if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], order);
}
// Setup map for non tensor-product elements
NE_split_total = 0;
split_element_map.SetSize(0);
split_element_index.SetSize(0);
int NEsplit = 0;
for (int e = 0; e < mesh->GetNE(); e++)
{
const Geometry::Type gt = mesh->GetElement(e)->GetGeometryType();
if (gt == Geometry::TRIANGLE || gt == Geometry::PRISM)
{
NEsplit = 3;
}
else if (gt == Geometry::TETRAHEDRON)
{
NEsplit = 4;
}
else if (gt == Geometry::PYRAMID)
{
NEsplit = 8;
}
else if (gt == Geometry::SQUARE || gt == Geometry::CUBE)
{
NEsplit = 1;
}
else
{
MFEM_ABORT("Unsupported geometry type.");
}
NE_split_total += NEsplit;
for (int i = 0; i < NEsplit; i++)
{
split_element_map.Append(e);
split_element_index.Append(i);
}
}
}
void FindPointsGSLIB::GetNodalValues(const GridFunction *gf_in,
Vector &node_vals)
{
@@ -2081,6 +2118,19 @@ void FindPointsGSLIB::InterpolateGeneral(const GridFunction &field_in,
} // parallel
}
Array<unsigned int> FindPointsGSLIB::GetPointsNotFoundIndices() const
{
Array<unsigned int> nf_idxs;
for (int i = 0; i < gsl_code.Size(); i++)
{
if (gsl_code[i] == 2)
{
nf_idxs.Append(i);
}
}
return nf_idxs;
}
void FindPointsGSLIB::DistributePointInfoToOwningMPIRanks(
Array<unsigned int> &recv_elem, Vector &recv_ref,
Array<unsigned int> &recv_code)
@@ -2386,6 +2436,10 @@ void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
{
MFEM_VERIFY(m.GetNodes() != NULL, "Mesh nodes are required.");
const int meshOrder = m.GetNodes()->FESpace()->GetMaxElementOrder();
const int gfOrder = gfmax ? gfmax->FESpace()->GetMaxElementOrder() :
meshOrder;
MFEM_VERIFY(meshOrder == gfOrder,
"Mesh order must match gfmax order in OversetFindPointsGSLIB.");
// FreeData if OversetFindPointsGSLIB::Setup has been called already
if (setupflag) { FreeData(); }
@@ -2395,35 +2449,7 @@ void OversetFindPointsGSLIB::Setup(Mesh &m, const int meshid,
const FiniteElement *fe = mesh->GetNodalFESpace()->GetTypicalFE();
unsigned dof1D = fe->GetOrder() + 1;
SetupSplitMeshes();
if (dim == 2)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
}
else if (dim == 3)
{
if (ir_split[0]) { delete ir_split[0]; ir_split[0] = NULL; }
ir_split[0] = new IntegrationRule(pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[0], ir_split[0], meshOrder);
if (ir_split[1]) { delete ir_split[1]; ir_split[1] = NULL; }
ir_split[1] = new IntegrationRule(4*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[1], ir_split[1], meshOrder);
if (ir_split[2]) { delete ir_split[2]; ir_split[2] = NULL; }
ir_split[2] = new IntegrationRule(3*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[2], ir_split[2], meshOrder);
if (ir_split[3]) { delete ir_split[3]; ir_split[3] = NULL; }
ir_split[3] = new IntegrationRule(8*pow(dof1D, dim));
SetupIntegrationRuleForSplitMesh(mesh_split[3], ir_split[3], meshOrder);
}
SetupSplitMeshesAndIntegrationRules(meshOrder);
GetNodalValues(mesh->GetNodes(), gsl_mesh);
@@ -2480,7 +2506,7 @@ void OversetFindPointsGSLIB::FindPoints(const Vector &point_pos,
{
MFEM_VERIFY(setupflag, "Use OversetFindPointsGSLIB::Setup before "
"finding points.");
MFEM_VERIFY(overset, "Please setup FindPoints for overlapping grids.");
MFEM_VERIFY(overset, "Please use OversetFindPoints for overlapping grids.");
points_cnt = point_pos.Size() / dim;
unsigned int match = 0; // Don't find points in the mesh if point_id=mesh_id
+28 -3
View File
@@ -13,7 +13,11 @@
#define MFEM_GSLIB
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#include "pgridfunc.hpp"
#else
#include "gridfunc.hpp"
#endif
#ifdef MFEM_USE_GSLIB
@@ -131,6 +135,10 @@ protected:
IntegrationRule *irule,
int order);
/// Helper function that calls \ref SetupSplitMeshes and
/// \ref SetupIntegrationRuleForSplitMesh.
virtual void SetupSplitMeshesAndIntegrationRules(const int order);
/// Get GridFunction value at the points expected by GSLIB.
virtual void GetNodalValues(const GridFunction *gf_in, Vector &node_vals);
@@ -190,14 +198,23 @@ protected:
void InterpolateOnDevice(const Vector &field_in_evec, Vector &field_out,
const int nel, const int ncomp,
const int dof1dsol, const int ordering);
public:
FindPointsGSLIB();
FindPointsGSLIB(Mesh &mesh_in, const double bb_t = 0.1,
const double newt_tol = 1.0e-12,
const int npt_max = 256);
#ifdef MFEM_USE_MPI
FindPointsGSLIB(MPI_Comm comm_);
FindPointsGSLIB(ParMesh &mesh_in, const double bb_t = 0.1,
const double newt_tol = 1.0e-12,
const int npt_max = 256);
#endif
virtual ~FindPointsGSLIB();
FindPointsGSLIB(const FindPointsGSLIB&) = delete;
FindPointsGSLIB& operator=(const FindPointsGSLIB&) = delete;
/** Initializes the internal mesh in gslib, by sending the positions of the
Gauss-Lobatto nodes of the input Mesh object \p m.
@@ -212,8 +229,8 @@ public:
@param[in] npt_max (Optional) Number of points for simultaneous
iteration. This alters performance and
memory footprint.*/
void Setup(Mesh &m, const double bb_t = 0.1,
const double newt_tol = 1.0e-12,
void Setup(Mesh &m, const double bb_t = 0.1, const double newt_tol = 1.0e-12,
const int npt_max = 256);
/** Searches positions given in physical space by \p point_pos.
These positions can be ordered byNodes: (XXX...,YYY...,ZZZ) or
@@ -289,7 +306,12 @@ public:
/** Cleans up memory allocated internally by gslib.
Note that in parallel, this must be called before MPI_Finalize(), as it
calls MPI_Comm_free() for internal gslib communicators. */
calls MPI_Comm_free() for internal gslib communicators. FreeData is
also called by the class destructor and there are no memory leaks if the
destructor is called before MPI_Finalize(). If the destructor is called
after MPI_Finalize(), there will be an error because gslib will try to
invoke some MPI functions.
*/
virtual void FreeData();
/// Return code for each point searched by FindPoints: inside element (0), on
@@ -312,6 +334,9 @@ public:
/// point found by FindPoints.
virtual const Vector &GetGSLIBReferencePosition() const { return gsl_ref; }
/// Get array of indices of not-found points.
Array<unsigned int> GetPointsNotFoundIndices() const;
/** @name Methods to support a custom interpolation procedure.
\brief The physical-space point that the user seeks to interpolate at
could be located inside an element on another mpi rank.
+348 -35
View File
@@ -181,7 +181,7 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
// current elements' the number of degrees of freedom
// does not consider the number of equations
const int dof1 = el1.GetDof();
const int dof2 = el2.GetDof();
const int dof2 = (Tr.Elem2No >= 0)?(el2.GetDof()):(0);
#ifdef MFEM_THREAD_SAFE
// Local storage for element integration
@@ -219,7 +219,9 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
const IntegrationRule *ir = IntRule;
if (!ir)
{
const int order = 2*std::max(el1.GetOrder(), el2.GetOrder()) + IntOrderOffset;
const int max_el_order = dof2 ? std::max(el1.GetOrder(),
el2.GetOrder()) : el1.GetOrder();
const int order = 2*max_el_order + IntOrderOffset;
ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
// loop over integration points
@@ -231,18 +233,22 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
// Calculate basis functions on both elements at the face
el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
// Interpolate elfun at the point
elfun1_mat.MultTranspose(shape1, state1);
elfun2_mat.MultTranspose(shape2, state2);
if (dof2)
{
// Calculate basis functions on both elements at the face
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
// Interpolate elfun at the point
elfun2_mat.MultTranspose(shape2, state2);
}
// Get the normal vector and the flux on the face
if (nor.Size() == 1) // if 1D, use 1 or -1.
{
// This assume the 1D integration point is in (0,1). This may not work
// if this changes.
nor(0) = (Tr.GetElement1IntPoint().x - 0.5) * 2.0;
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
}
else
{
@@ -250,14 +256,18 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
}
// Compute F(u+, x) and F(u-, x) with maximum characteristic speed
// Compute hat(F) using evaluated quantities
const real_t speed = numFlux.Eval(state1, state2, nor, Tr, fluxN);
const real_t speed = (dof2) ? numFlux.Eval(state1, state2, nor, Tr, fluxN):
fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN);
// Update the global max char speed
max_char_speed = std::max(speed, max_char_speed);
// pre-multiply integration weight to flux
AddMult_a_VWt(-ip.weight*sign, shape1, fluxN, elvect1_mat);
AddMult_a_VWt(+ip.weight*sign, shape2, fluxN, elvect2_mat);
if (dof2)
{
AddMult_a_VWt(+ip.weight*sign, shape2, fluxN, elvect2_mat);
}
}
}
@@ -268,7 +278,7 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
// current elements' the number of degrees of freedom
// does not consider the number of equations
const int dof1 = el1.GetDof();
const int dof2 = el2.GetDof();
const int dof2 = (Tr.Elem2No >= 0)?(el2.GetDof()):(0);
#ifdef MFEM_THREAD_SAFE
// Local storage for element integration
@@ -302,7 +312,9 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
const IntegrationRule *ir = IntRule;
if (!ir)
{
const int order = 2*std::max(el1.GetOrder(), el2.GetOrder()) + IntOrderOffset;
const int max_el_order = dof2 ? std::max(el1.GetOrder(),
el2.GetOrder()) : el1.GetOrder();
const int order = 2*max_el_order + IntOrderOffset;
ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
// loop over integration points
@@ -312,20 +324,25 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
Tr.SetAllIntPoints(&ip); // set face and element int. points
// Calculate basis functions on both elements at the face
// Calculate basis functions of the first element at the face
el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
// Interpolate elfun at the point
elfun1_mat.MultTranspose(shape1, state1);
elfun2_mat.MultTranspose(shape2, state2);
if (dof2)
{
// Calculate basis function of the second element at the face
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
// Interpolate elfun at the point
elfun2_mat.MultTranspose(shape2, state2);
}
// Get the normal vector and the flux on the face
if (nor.Size() == 1) // if 1D, use 1 or -1.
{
// This assume the 1D integration point is in (0,1). This may not work
// if this changes.
nor(0) = (Tr.GetElement1IntPoint().x - 0.5) * 2.0;
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
}
else
{
@@ -335,7 +352,14 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
// Trial side 1
// Compute hat(J) using evaluated quantities
numFlux.Grad(1, state1, state2, nor, Tr, JDotN);
if (dof2)
{
numFlux.Grad(1, state1, state2, nor, Tr, JDotN);
}
else
{
fluxFunction.ComputeFluxJacobianDotN(state1, nor, Tr, JDotN);
}
const int ioff = fluxFunction.num_equations * dof1;
@@ -360,36 +384,325 @@ void HyperbolicFormIntegrator::AssembleFaceGrad(
}
}
// Trial side 2
if (dof2)
{
// Trial side 2
// Compute hat(J) using evaluated quantities
numFlux.Grad(2, state1, state2, nor, Tr, JDotN);
const int joff = ioff;
for (int di = 0; di < fluxFunction.num_equations; di++)
for (int dj = 0; dj < fluxFunction.num_equations; dj++)
{
// pre-multiply integration weight to Jacobian
const real_t w = +ip.weight * sign * JDotN(di,dj);
for (int j = 0; j < dof2; j++)
{
// Test side 1
for (int i = 0; i < dof1; i++)
{
elmat(i+dof1*di, joff+j+dof2*dj) += w * shape1(i) * shape2(j);
}
// Test side 2
for (int i = 0; i < dof2; i++)
{
elmat(ioff+i+dof2*di, joff+j+dof2*dj) -= w * shape2(i) * shape2(j);
}
}
}
}
}
}
BdrHyperbolicDirichletIntegrator::BdrHyperbolicDirichletIntegrator(
const NumericalFlux &numFlux,
VectorCoefficient &bdrState,
const int IntOrderOffset,
real_t sign)
: NonlinearFormIntegrator(),
numFlux(numFlux),
fluxFunction(numFlux.GetFluxFunction()),
u_vcoeff(bdrState),
IntOrderOffset(IntOrderOffset),
sign(sign),
num_equations(fluxFunction.num_equations)
{
MFEM_VERIFY(fluxFunction.num_equations == bdrState.GetVDim(),
"Flux function does not match the vector dimension of the coefficient!");
#ifndef MFEM_THREAD_SAFE
state_in.SetSize(num_equations);
state_out.SetSize(num_equations);
fluxN.SetSize(num_equations);
JDotN.SetSize(num_equations);
nor.SetSize(fluxFunction.dim);
#endif
ResetMaxCharSpeed();
}
void BdrHyperbolicDirichletIntegrator::AssembleFaceVector(
const FiniteElement &el, const FiniteElement &,
FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect)
{
MFEM_ASSERT(Tr.Elem2No < 0, "Not a boundary face!");
// current elements' the number of degrees of freedom
// does not consider the number of equations
const int dof = el.GetDof();
#ifdef MFEM_THREAD_SAFE
// Local storage for element integration
// shape function value at an integration point
Vector shape(dof);
// normal vector (usually not a unit vector)
Vector nor(Tr.GetSpaceDim());
// state value at an integration point - interior
Vector state_in(num_equations);
// state value at an integration point - boundary
Vector state_out(num_equations);
// hat(F)(u,x)
Vector fluxN(num_equations);
#else
shape.SetSize(dof);
#endif
elvect.SetSize(dof * num_equations);
elvect = 0.0;
const DenseMatrix elfun_mat(elfun.GetData(), dof, num_equations);
DenseMatrix elvect_mat(elvect.GetData(), dof, num_equations);
// Obtain integration rule. If integration is rule is given, then use it.
// Otherwise, get (2*p + IntOrderOffset) order integration rule
const IntegrationRule *ir = IntRule;
if (!ir)
{
const int order = 2*el.GetOrder() + IntOrderOffset;
ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
// loop over integration points
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Tr.SetAllIntPoints(&ip); // set face and element int. points
// Calculate basis functions at the face
el.CalcShape(Tr.GetElement1IntPoint(), shape);
// Interpolate elfun at the point
elfun_mat.MultTranspose(shape, state_in);
// Evaluate boundary state at the point
u_vcoeff.Eval(state_out, Tr, ip);
// Get the normal vector and the flux on the face
if (nor.Size() == 1) // if 1D, use 1 or -1.
{
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
}
else
{
CalcOrtho(Tr.Jacobian(), nor);
}
// Compute F(u+, x) and F(u_b, x) with maximum characteristic speed
// Compute hat(F) using evaluated quantities
const real_t speed = numFlux.Eval(state_in, state_out, nor, Tr, fluxN);
// Update the global max char speed
max_char_speed = std::max(speed, max_char_speed);
// pre-multiply integration weight to flux
AddMult_a_VWt(-ip.weight*sign, shape, fluxN, elvect_mat);
}
}
void BdrHyperbolicDirichletIntegrator::AssembleFaceGrad(
const FiniteElement &el, const FiniteElement &,
FaceElementTransformations &Tr, const Vector &elfun, DenseMatrix &elmat)
{
// current elements' the number of degrees of freedom
// does not consider the number of equations
const int dof = el.GetDof();
#ifdef MFEM_THREAD_SAFE
// Local storage for element integration
// shape function value at an integration point
Vector shape(dof);
// normal vector (usually not a unit vector)
Vector nor(Tr.GetSpaceDim());
// state value at an integration point - interior
Vector state_in(num_equations);
// state value at an integration point - boundary
Vector state_out(num_equations);
// hat(J)(u,x)
DenseMatrix JDotN(num_equations);
#else
shape.SetSize(dof);
#endif
elmat.SetSize(dof * num_equations);
elmat = 0.0;
const DenseMatrix elfun_mat(elfun.GetData(), dof, num_equations);
// Obtain integration rule. If integration is rule is given, then use it.
// Otherwise, get (2*p + IntOrderOffset) order integration rule
const IntegrationRule *ir = IntRule;
if (!ir)
{
const int order = 2*el.GetOrder() + IntOrderOffset;
ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
// loop over integration points
for (int q = 0; q < ir->GetNPoints(); q++)
{
const IntegrationPoint &ip = ir->IntPoint(q);
Tr.SetAllIntPoints(&ip); // set face and element int. points
// Calculate basis functions at the face
el.CalcShape(Tr.GetElement1IntPoint(), shape);
// Interpolate elfun at the point
elfun_mat.MultTranspose(shape, state_in);
// Evaluate boundary state at the point
u_vcoeff.Eval(state_out, Tr, ip);
// Get the normal vector and the flux on the face
if (nor.Size() == 1) // if 1D, use 1 or -1.
{
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
}
else
{
CalcOrtho(Tr.Jacobian(), nor);
}
// Compute hat(J) using evaluated quantities
numFlux.Grad(2, state1, state2, nor, Tr, JDotN);
const int joff = ioff;
numFlux.Grad(1, state_in, state_out, nor, Tr, JDotN);
for (int di = 0; di < fluxFunction.num_equations; di++)
for (int dj = 0; dj < fluxFunction.num_equations; dj++)
{
// pre-multiply integration weight to Jacobian
const real_t w = +ip.weight * sign * JDotN(di,dj);
for (int j = 0; j < dof2; j++)
{
// Test side 1
for (int i = 0; i < dof1; i++)
const real_t w = -ip.weight * sign * JDotN(di,dj);
for (int j = 0; j < dof; j++)
for (int i = 0; i < dof; i++)
{
elmat(i+dof1*di, joff+j+dof2*dj) += w * shape1(i) * shape2(j);
elmat(i+dof*di, j+dof*dj) += w * shape(i) * shape(j);
}
// Test side 2
for (int i = 0; i < dof2; i++)
{
elmat(ioff+i+dof2*di, joff+j+dof2*dj) -= w * shape2(i) * shape2(j);
}
}
}
}
}
BoundaryHyperbolicFlowIntegrator::BoundaryHyperbolicFlowIntegrator(
const FluxFunction &flux, VectorCoefficient &u, real_t alpha_, real_t beta_,
const int IntOrderOffset_)
: fluxFunction(flux), u_vcoeff(u), alpha(alpha_), beta(beta_),
IntOrderOffset(IntOrderOffset_)
{
MFEM_VERIFY(fluxFunction.num_equations == u_vcoeff.GetVDim(),
"Flux function does not match the vector dimension of the coefficient!");
#ifndef MFEM_THREAD_SAFE
state.SetSize(fluxFunction.num_equations);
nor.SetSize(fluxFunction.dim);
fluxN.SetSize(fluxFunction.num_equations);
#endif
ResetMaxCharSpeed();
}
void BoundaryHyperbolicFlowIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
mfem_error("BoundaryHyperbolicFlowIntegrator::AssembleRHSElementVect\n"
" is not implemented as boundary integrator!\n"
" Use LinearForm::AddBdrFaceIntegrator instead of\n"
" LinearForm::AddBoundaryIntegrator.");
}
void BoundaryHyperbolicFlowIntegrator::AssembleRHSElementVect(
const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect)
{
// current elements' the number of degrees of freedom
// does not consider the number of equations
const int dof = el.GetDof();
#ifdef MFEM_THREAD_SAFE
// Local storage for element integration
// shape function value at an integration point
Vector shape(dof);
// state value at an integration point
Vector state(fluxFunction.num_equations);
// normal vector (usually not a unit vector)
Vector nor(Tr.GetSpaceDim());
// hat(F)(u,x)
Vector fluxN(fluxFunction.num_equations);
#else
shape.SetSize(dof);
#endif
elvect.SetSize(dof * fluxFunction.num_equations);
elvect = 0.0;
DenseMatrix elvect_mat(elvect.GetData(), dof, fluxFunction.num_equations);
// Obtain integration rule. If integration is rule is given, then use it.
// Otherwise, get (2*p + IntOrderOffset) order integration rule
const IntegrationRule *ir = IntRule;
if (!ir)
{
const int order = 2*el.GetOrder() + IntOrderOffset;
ir = &IntRules.Get(Tr.GetGeometryType(), order);
}
// loop over integration points
for (int i = 0; i < ir->GetNPoints(); i++)
{
const IntegrationPoint &ip = ir->IntPoint(i);
Tr.SetAllIntPoints(&ip); // set face and element int. points
// Calculate basis functions on both elements at the face
el.CalcShape(Tr.GetElement1IntPoint(), shape);
// Evaluate the coefficient at the point
u_vcoeff.Eval(state, Tr, ip);
// Get the normal vector and the flux on the face
if (nor.Size() == 1) // if 1D, use 1 or -1.
{
nor(0) = 2*Tr.GetElement1IntPoint().x - 1.;
}
else
{
CalcOrtho(Tr.Jacobian(), nor);
}
// Compute F(u, x) with maximum characteristic speed
const real_t speed = fluxFunction.ComputeFluxDotN(state, nor, Tr, fluxN);
// Update the global max char speed
max_char_speed = std::max(speed, max_char_speed);
// pre-multiply integration weight to flux
const real_t a = 0.5 * alpha * ip.weight;
const real_t b = beta * ip.weight;
for (int n = 0; n < fluxFunction.num_equations; n++)
{
fluxN(n) = a * fluxN(n) - b * fabs(fluxN(n));
}
AddMultVWt(shape, fluxN, elvect_mat);
}
}
real_t FluxFunction::ComputeFluxDotN(const Vector &U,
const Vector &normal,
FaceElementTransformations &Tr,
+188 -16
View File
@@ -306,12 +306,14 @@ MFEM_DEPRECATED typedef NumericalFlux RiemannSolver;
class HyperbolicFormIntegrator : public NonlinearFormIntegrator
{
private:
// The maximum characteristic speed, updated during element/face vector assembly
real_t max_char_speed;
const NumericalFlux &numFlux; // Numerical flux that maps F(u±,x) to F̂
const FluxFunction &fluxFunction;
const int IntOrderOffset; // integration order offset, 2*p + IntOrderOffset.
const real_t sign;
// The maximum characteristic speed, updated during element/face vector assembly
real_t max_char_speed;
#ifndef MFEM_THREAD_SAFE
// Local storage for element integration
Vector shape; // shape function value at an integration point
@@ -331,8 +333,9 @@ private:
public:
const int num_equations; // the number of equations
/**
* @brief Construct a new Hyperbolic Form Integrator object
* @brief Construct a new HyperbolicFormIntegrator object
*
* @param[in] numFlux numerical flux
* @param[in] IntOrderOffset integration order offset
@@ -343,21 +346,14 @@ public:
const int IntOrderOffset = 0,
const real_t sign = 1.);
/**
* @brief Reset the Max Char Speed 0
*
*/
void ResetMaxCharSpeed()
{
max_char_speed = 0.0;
}
/// Reset the maximum characteristic speed to zero
void ResetMaxCharSpeed() { max_char_speed = 0.0; }
real_t GetMaxCharSpeed()
{
return max_char_speed;
}
/// Get the maximum characteristic speed
real_t GetMaxCharSpeed() const { return max_char_speed; }
const FluxFunction &GetFluxFunction() { return fluxFunction; }
/// Get the associated flux function
const FluxFunction &GetFluxFunction() const { return fluxFunction; }
/**
* @brief Implements (F(u), v) with abstract F computed by
@@ -416,6 +412,182 @@ public:
const Vector &elfun, DenseMatrix &elmat) override;
};
/**
* @brief Abstract boundary hyperbolic form integrator, assembling
* <(u,u_b,x) n, [v]> term for scalar finite elements at the boundary.
*
* This form integrator is coupled with a NumericalFlux that implements the
* numerical flux at the boundary faces. The flux F is obtained from the
* FluxFunction assigned to the aforementioned NumericalFlux with the given
* boundary coefficient for the state u_b.
*
* Note the class can be used for imposing conditions on interior interfaces.
*/
class BdrHyperbolicDirichletIntegrator : public NonlinearFormIntegrator
{
private:
const NumericalFlux &numFlux; // Numerical flux that maps F to F̂
const FluxFunction &fluxFunction;
VectorCoefficient &u_vcoeff; // Boundary state vector coefficient
const int IntOrderOffset; // integration order offset, 2*p + IntOrderOffset.
const real_t sign;
// The maximum characteristic speed, updated during element/face vector assembly
real_t max_char_speed;
#ifndef MFEM_THREAD_SAFE
// Local storage for element integration
Vector shape; // shape function value at an integration point
Vector state_in; // state value at an integration point - interior
Vector state_out; // state value at an integration point - boundary
Vector nor; // normal vector, see mfem::CalcOrtho()
Vector fluxN; // F̂(u⁻,u_b,x) n
DenseMatrix JDotN; // Ĵ(u⁻,u_b,x) n
#endif
public:
const int num_equations; // the number of equations
/**
* @brief Construct a new BdrHyperbolicDirichletIntegrator object
*
* @param[in] numFlux numerical flux
* @param[in] bdrState boundary state coefficient
* @param[in] IntOrderOffset integration order offset
* @param[in] sign sign of the convection term
*/
BdrHyperbolicDirichletIntegrator(
const NumericalFlux &numFlux,
VectorCoefficient &bdrState,
const int IntOrderOffset = 0,
const real_t sign = 1.);
/// Reset the maximum characteristic speed to zero
void ResetMaxCharSpeed() { max_char_speed = 0.0; }
/// Get the maximum characteristic speed
real_t GetMaxCharSpeed() const { return max_char_speed; }
/// Get the associated flux function
const FluxFunction &GetFluxFunction() const { return fluxFunction; }
/**
* @brief Implements <-(u,u_b,x) n, [v]> with abstract computed by
* NumericalFlux::Eval() of the numerical flux object
*
* @param[in] el1 finite element of the interior element
* @param[in] el2 not used
* @param[in] Tr face element transformations
* @param[in] elfun local coefficient of basis for the interior element
* @param[out] elvect evaluated dual vector <-(u,u_b,x) n, [v]>
*/
void AssembleFaceVector(const FiniteElement &el1,
const FiniteElement &el2,
FaceElementTransformations &Tr,
const Vector &elfun, Vector &elvect) override;
/**
* @brief Implements <-(u,u_b,x) n, [v]> with abstract computed by
* NumericalFlux::Grad() of the numerical flux object
*
* @param[in] el1 finite element of the interior element
* @param[in] el2 not used
* @param[in] Tr face element transformations
* @param[in] elfun local coefficient of basis for the interior element
* @param[out] elmat evaluated Jacobian matrix <-(u,u_b,x) n, [v]>
*/
void AssembleFaceGrad(const FiniteElement &el1,
const FiniteElement &el2,
FaceElementTransformations &Tr,
const Vector &elfun, DenseMatrix &elmat) override;
};
/**
* @brief Abstract boundary hyperbolic linear form integrator, assembling
* <ɑ/2 F(u,x) n - β |F(u,x) n|, v> terms for scalar finite elements.
*
* This form integrator is coupled with a FluxFunction that evaluates the
* flux F at the boundary.
*
* Note the upwinding is performed component-wise. For general boundary
* integration with a numerical flux, see BdrHyperbolicDirichletIntegrator.
*/
class BoundaryHyperbolicFlowIntegrator : public LinearFormIntegrator
{
const FluxFunction &fluxFunction;
VectorCoefficient &u_vcoeff;
const real_t alpha, beta;
const int IntOrderOffset; // integration order offset, 2*p + IntOrderOffset.
// The maximum characteristic speed, updated during face vector assembly
real_t max_char_speed;
#ifndef MFEM_THREAD_SAFE
// Local storage for element integration
Vector shape; // shape function value at an integration point
Vector state; // state value at an integration point
Vector nor; // normal vector, see mfem::CalcOrtho()
Vector fluxN; // F(u,x) n
#endif
public:
/**
* @brief Construct a new BoundaryHyperbolicFlowIntegrator object
*
* @param[in] flux flux function
* @param[in] u vector state coefficient
* @param[in] alpha ɑ coefficient (β = ɑ/2)
* @param[in] IntOrderOffset integration order offset
*/
BoundaryHyperbolicFlowIntegrator(const FluxFunction &flux, VectorCoefficient &u,
real_t alpha = -1., int IntOrderOffset = 0)
: BoundaryHyperbolicFlowIntegrator(flux, u, alpha, alpha/2., IntOrderOffset) { }
/**
* @brief Construct a new BoundaryHyperbolicFlowIntegrator object
*
* @param[in] flux flux function
* @param[in] u vector state coefficient
* @param[in] alpha ɑ coefficient
* @param[in] beta β coefficient
* @param[in] IntOrderOffset integration order offset
*/
BoundaryHyperbolicFlowIntegrator(const FluxFunction &flux, VectorCoefficient &u,
real_t alpha, real_t beta, int IntOrderOffset = 0);
/// Reset the maximum characteristic speed to zero
void ResetMaxCharSpeed() { max_char_speed = 0.0; }
/// Get the maximum characteristic speed
real_t GetMaxCharSpeed() const { return max_char_speed; }
/// Get the associated flux function
const FluxFunction &GetFluxFunction() const { return fluxFunction; }
using LinearFormIntegrator::AssembleRHSElementVect;
/**
* @warning Boundary element integration not implemented, use
* AssembleRHSElementVect(const FiniteElement&,
* FaceElementTransformations &, Vector &) instead
*/
void AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect) override;
/**
* @brief Implements <-F(u,x) n, v> with abstract F computed by
* FluxFunction::ComputeFluxDotN() of the flux function object
*
* @param[in] el finite element
* @param[in] Tr face element transformations
* @param[out] elvect evaluated dual vector <F(u,x) n, v>
*/
void AssembleRHSElementVect(const FiniteElement &el,
FaceElementTransformations &Tr,
Vector &elvect) override;
};
/**
* @brief Rusanov flux, also known as local Lax-Friedrichs,
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+89 -174
View File
@@ -15,6 +15,86 @@
namespace mfem
{
CurlCurlIntegrator::CurlCurlIntegrator() : Q(nullptr), DQ(nullptr), MQ(nullptr)
{
static Kernels kernels;
}
CurlCurlIntegrator::CurlCurlIntegrator(Coefficient &q,
const IntegrationRule *ir)
: BilinearFormIntegrator(ir), Q(&q), DQ(nullptr), MQ(nullptr)
{
static Kernels kernels;
}
CurlCurlIntegrator::CurlCurlIntegrator(DiagonalMatrixCoefficient &dq,
const IntegrationRule *ir)
: BilinearFormIntegrator(ir), Q(nullptr), DQ(&dq), MQ(nullptr)
{
static Kernels kernels;
}
CurlCurlIntegrator::CurlCurlIntegrator(MatrixCoefficient &mq,
const IntegrationRule *ir)
: BilinearFormIntegrator(ir), Q(nullptr), DQ(nullptr), MQ(&mq)
{
static Kernels kernels;
}
/// \cond DO_NOT_DOCUMENT
CurlCurlIntegrator::Kernels::Kernels()
{
CurlCurlIntegrator::AddSpecialization<3, 2, 3>();
CurlCurlIntegrator::AddSpecialization<3, 3, 4>();
CurlCurlIntegrator::AddSpecialization<3, 4, 5>();
CurlCurlIntegrator::AddSpecialization<3, 5, 6>();
}
CurlCurlIntegrator::ApplyKernelType
CurlCurlIntegrator::ApplyPAKernels::Fallback(int DIM, int, int)
{
if (DIM == 2) { return internal::PACurlCurlApply2D; }
else if (DIM == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
return internal::SmemPACurlCurlApply3D;
}
else
{
return internal::PACurlCurlApply3D;
}
}
else { MFEM_ABORT(""); }
}
CurlCurlIntegrator::DiagonalKernelType
CurlCurlIntegrator::DiagonalPAKernels::Fallback(int DIM, int, int)
{
if (DIM == 2)
{
return internal::PACurlCurlAssembleDiagonal2D;
}
else if (DIM == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
return internal::SmemPACurlCurlAssembleDiagonal3D;
}
else
{
return internal::PACurlCurlAssembleDiagonal3D;
}
}
else
{
MFEM_ABORT("");
}
}
/// \endcond DO_NOT_DOCUMENT
void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
// Assumes tensor-product elements
@@ -77,129 +157,16 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
void CurlCurlIntegrator::AssembleDiagonalPA(Vector& diag)
{
if (dim == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPACurlCurlAssembleDiagonal3D<2,3>(
dofs1D,
quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
case 0x34:
return internal::SmemPACurlCurlAssembleDiagonal3D<3,4>(
dofs1D,
quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
case 0x45:
return internal::SmemPACurlCurlAssembleDiagonal3D<4,5>(
dofs1D,
quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
case 0x56:
return internal::SmemPACurlCurlAssembleDiagonal3D<5,6>(
dofs1D,
quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
default:
return internal::SmemPACurlCurlAssembleDiagonal3D(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
}
}
else
{
internal::PACurlCurlAssembleDiagonal3D(dofs1D, quad1D, symmetric, ne,
mapsO->B, mapsC->B,
mapsO->G, mapsC->G,
pa_data, diag);
}
}
else if (dim == 2)
{
internal::PACurlCurlAssembleDiagonal2D(dofs1D, quad1D, ne,
mapsO->B, mapsC->G, pa_data, diag);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
DiagonalPAKernels::Run(dim, dofs1D, quad1D, dofs1D, quad1D, symmetric, ne,
mapsO->B, mapsC->B, mapsO->G, mapsC->G, pa_data,
diag);
}
void CurlCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
if (dim == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPACurlCurlApply3D<2,3>(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
case 0x34:
return internal::SmemPACurlCurlApply3D<3,4>(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
case 0x45:
return internal::SmemPACurlCurlApply3D<4,5>(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
case 0x56:
return internal::SmemPACurlCurlApply3D<5,6>(
dofs1D, quad1D,
symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
default:
return internal::SmemPACurlCurlApply3D(
dofs1D, quad1D, symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
}
}
else
{
internal::PACurlCurlApply3D(dofs1D, quad1D, symmetric, ne, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, mapsC->G, mapsC->Gt,
pa_data, x, y);
}
}
else if (dim == 2)
{
internal::PACurlCurlApply2D(dofs1D, quad1D, ne, mapsO->B, mapsO->Bt,
mapsC->G, mapsC->Gt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
ApplyPAKernels::Run(dim, dofs1D, quad1D, dofs1D, quad1D, symmetric, ne,
mapsO->B, mapsC->B, mapsO->Bt, mapsC->Bt, mapsC->G,
mapsC->Gt, pa_data, x, y, false);
}
void CurlCurlIntegrator::AddAbsMultPA(const Vector &x, Vector &y) const
@@ -209,61 +176,9 @@ void CurlCurlIntegrator::AddAbsMultPA(const Vector &x, Vector &y) const
auto absO = mapsO->Abs();
auto absC = mapsC->Abs();
if (dim == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPACurlCurlApply3D<2,3>(
dofs1D, quad1D,
symmetric, ne,
absO.B, absC.B, absO.Bt, absC.Bt,
absC.G, absC.Gt, abs_pa_data, x, y, true);
case 0x34:
return internal::SmemPACurlCurlApply3D<3,4>(
dofs1D, quad1D,
symmetric, ne,
absO.B, absC.B, absO.Bt, absC.Bt,
absC.G, absC.Gt, abs_pa_data, x, y, true);
case 0x45:
return internal::SmemPACurlCurlApply3D<4,5>(
dofs1D, quad1D,
symmetric, ne,
absO.B, absC.B, absO.Bt, absC.Bt,
absC.G, absC.Gt, abs_pa_data, x, y, true);
case 0x56:
return internal::SmemPACurlCurlApply3D<5,6>(
dofs1D, quad1D,
symmetric, ne,
absO.B, absC.B, absO.Bt, absC.Bt,
absC.G, absC.Gt, abs_pa_data, x, y, true);
default:
return internal::SmemPACurlCurlApply3D<0,0>(
dofs1D, quad1D, symmetric, ne,
absO.B, absC.B, absO.Bt, absC.Bt,
absC.G, absC.Gt, abs_pa_data, x, y, true);
}
}
else
{
internal::PACurlCurlApply3D<0,0>(
dofs1D, quad1D, symmetric, ne,
absO.B, absC.B, absO.Bt, absC.Bt, absC.G, absC.Gt,
abs_pa_data, x, y, true);
}
}
else if (dim == 2)
{
internal::PACurlCurlApply2D(dofs1D, quad1D, ne, absO.B, absO.Bt,
absC.G, absC.Gt, abs_pa_data, x, y, true);
}
else
{
MFEM_ABORT("Unsupported dimension!");
}
ApplyPAKernels::Run(dim, dofs1D, quad1D, dofs1D, quad1D, symmetric, ne,
absO.B, absC.B, absO.Bt, absC.Bt, absC.G, absC.Gt,
abs_pa_data, x, y, true);
}
} // namespace mfem
@@ -0,0 +1,500 @@
// 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_BILININTEG_DGDIFFUSION_KERNELS_HPP
#define MFEM_BILININTEG_DGDIFFUSION_KERNELS_HPP
#include "../../general/forall.hpp"
#include "../../mesh/face_nbr_geom.hpp"
#include "../fe/face_map_utils.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
/// \cond DO_NOT_DOCUMENT
namespace mfem
{
namespace internal
{
template <int T_D1D = 0, int T_Q1D = 0>
static void PADGDiffusionApply2D(const int NF, const Array<real_t> &b,
const Array<real_t> &bt,
const Array<real_t> &g,
const Array<real_t> &gt, const real_t sigma,
const Vector &pa_data, const Vector &x_,
const Vector &dxdn_, Vector &y_, Vector &dydn_,
const int d1d = 0, const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B_ = Reshape(b.Read(), Q1D, D1D);
auto G_ = Reshape(g.Read(), Q1D, D1D);
auto pa =
Reshape(pa_data.Read(), 6, Q1D, NF); // (q, 1/h, J00, J01, J10, J11)
auto x = Reshape(x_.Read(), D1D, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, 2, NF);
auto dxdn = Reshape(dxdn_.Read(), D1D, 2, NF);
auto dydn = Reshape(dydn_.ReadWrite(), D1D, 2, NF);
const int NBX = std::max(D1D, Q1D);
mfem::forall_2D(NF, NBX, 2, [=] MFEM_HOST_DEVICE(int f) -> void
{
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t u0[max_D1D];
MFEM_SHARED real_t u1[max_D1D];
MFEM_SHARED real_t du0[max_D1D];
MFEM_SHARED real_t du1[max_D1D];
MFEM_SHARED real_t Bu0[max_Q1D];
MFEM_SHARED real_t Bu1[max_Q1D];
MFEM_SHARED real_t Bdu0[max_Q1D];
MFEM_SHARED real_t Bdu1[max_Q1D];
MFEM_SHARED real_t r[max_Q1D];
MFEM_SHARED real_t BG[2 * max_D1D * max_Q1D];
DeviceMatrix B(BG, Q1D, D1D);
DeviceMatrix G(BG + D1D * Q1D, Q1D, D1D);
if (MFEM_THREAD_ID(y) == 0)
{
MFEM_FOREACH_THREAD(p, x, Q1D)
{
for (int d = 0; d < D1D; ++d)
{
B(p, d) = B_(p, d);
G(p, d) = G_(p, d);
}
}
}
MFEM_SYNC_THREAD;
// copy edge values to u0, u1 and copy edge normals to du0, du1
MFEM_FOREACH_THREAD(side, y, 2)
{
real_t *u = (side == 0) ? u0 : u1;
real_t *du = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d, x, D1D)
{
u[d] = x(d, side, f);
du[d] = dxdn(d, side, f);
}
}
MFEM_SYNC_THREAD;
// eval @ quad points
MFEM_FOREACH_THREAD(side, y, 2)
{
real_t *u = (side == 0) ? u0 : u1;
real_t *du = (side == 0) ? du0 : du1;
real_t *Bu = (side == 0) ? Bu0 : Bu1;
real_t *Bdu = (side == 0) ? Bdu0 : Bdu1;
MFEM_FOREACH_THREAD(p, x, Q1D)
{
const real_t Je_side[] = {pa(2 + 2 * side, p, f),
pa(2 + 2 * side + 1, p, f)
};
Bu[p] = 0.0;
Bdu[p] = 0.0;
for (int d = 0; d < D1D; ++d)
{
const real_t b = B(p, d);
const real_t g = G(p, d);
Bu[p] += b * u[d];
Bdu[p] += Je_side[0] * b * du[d] + Je_side[1] * g * u[d];
}
}
}
MFEM_SYNC_THREAD;
// term - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >:
if (MFEM_THREAD_ID(y) == 0)
{
MFEM_FOREACH_THREAD(p, x, Q1D)
{
const real_t q = pa(0, p, f);
const real_t hi = pa(1, p, f);
const real_t jump = Bu0[p] - Bu1[p];
const real_t avg = Bdu0[p] + Bdu1[p]; // = {Q du/dn} * w * det(J)
r[p] = -avg + hi * q * jump;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(d, x, D1D)
{
real_t Br = 0.0;
for (int p = 0; p < Q1D; ++p)
{
Br += B(p, d) * r[p];
}
u0[d] = Br; // overwrite u0, u1
u1[d] = -Br;
} // for d
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side, y, 2)
{
real_t *du = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d, x, D1D) { du[d] = 0.0; }
}
MFEM_SYNC_THREAD;
// term sigma * < [u], {Q dv/dn} >
MFEM_FOREACH_THREAD(side, y, 2)
{
real_t *const du = (side == 0) ? du0 : du1;
real_t *const u = (side == 0) ? u0 : u1;
MFEM_FOREACH_THREAD(d, x, D1D)
{
for (int p = 0; p < Q1D; ++p)
{
const real_t Je[] = {pa(2 + 2 * side, p, f),
pa(2 + 2 * side + 1, p, f)
};
const real_t jump = Bu0[p] - Bu1[p];
const real_t r_p = Je[0] * jump; // normal
const real_t w_p = Je[1] * jump; // tangential
du[d] += sigma * B(p, d) * r_p;
u[d] += sigma * G(p, d) * w_p;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side, y, 2)
{
real_t *u = (side == 0) ? u0 : u1;
real_t *du = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d, x, D1D)
{
y(d, side, f) += u[d];
dydn(d, side, f) += du[d];
}
}
}); // mfem::forall
}
template <int T_D1D = 0, int T_Q1D = 0>
static void PADGDiffusionApply3D(const int NF, const Array<real_t> &b,
const Array<real_t> &bt,
const Array<real_t> &g,
const Array<real_t> &gt, const real_t sigma,
const Vector &pa_data, const Vector &x_,
const Vector &dxdn_, Vector &y_, Vector &dydn_,
const int d1d = 0, const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B_ = Reshape(b.Read(), Q1D, D1D);
auto G_ = Reshape(g.Read(), Q1D, D1D);
// (J0[0], J0[1], J0[2], J1[0], J1[1], J1[2], q/h)
auto pa = Reshape(pa_data.Read(), 7, Q1D, Q1D, NF);
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
auto dxdn = Reshape(dxdn_.Read(), D1D, D1D, 2, NF);
auto dydn = Reshape(dydn_.ReadWrite(), D1D, D1D, 2, NF);
const int NBX = std::max(D1D, Q1D);
mfem::forall_3D(NF, NBX, NBX, 2, [=] MFEM_HOST_DEVICE(int f) -> void
{
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t u0[max_Q1D][max_Q1D];
MFEM_SHARED real_t u1[max_Q1D][max_Q1D];
MFEM_SHARED real_t du0[max_Q1D][max_Q1D];
MFEM_SHARED real_t du1[max_Q1D][max_Q1D];
MFEM_SHARED real_t Gu0[max_Q1D][max_Q1D];
MFEM_SHARED real_t Gu1[max_Q1D][max_Q1D];
MFEM_SHARED real_t Bu0[max_Q1D][max_Q1D];
MFEM_SHARED real_t Bu1[max_Q1D][max_Q1D];
MFEM_SHARED real_t Bdu0[max_Q1D][max_Q1D];
MFEM_SHARED real_t Bdu1[max_Q1D][max_Q1D];
MFEM_SHARED real_t kappa_Qh[max_Q1D][max_Q1D];
MFEM_SHARED real_t nJe[2][max_Q1D][max_Q1D][3];
MFEM_SHARED real_t BG[2 * max_D1D * max_Q1D];
// some buffers are reused multiple times, but for clarity have new names:
real_t(*Bj0)[max_Q1D] = Bu0;
real_t(*Bj1)[max_Q1D] = Bu1;
real_t(*Bjn0)[max_Q1D] = Bdu0;
real_t(*Bjn1)[max_Q1D] = Bdu1;
real_t(*Gj0)[max_Q1D] = Gu0;
real_t(*Gj1)[max_Q1D] = Gu1;
DeviceMatrix B(BG, Q1D, D1D);
DeviceMatrix G(BG + D1D * Q1D, Q1D, D1D);
// copy face values to u0, u1 and copy normals to du0, du1
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d2, x, D1D)
{
MFEM_FOREACH_THREAD(d1, y, D1D)
{
u[d2][d1] = x(d1, d2, side,
f); // copy transposed for better memory access
du[d2][d1] = dxdn(d1, d2, side, f);
}
}
MFEM_FOREACH_THREAD(p1, x, Q1D)
{
MFEM_FOREACH_THREAD(p2, y, Q1D)
{
for (int l = 0; l < 3; ++l)
{
nJe[side][p2][p1][l] = pa(3 * side + l, p1, p2, f);
}
if (side == 0)
{
kappa_Qh[p2][p1] = pa(6, p1, p2, f);
}
}
}
if (side == 0)
{
MFEM_FOREACH_THREAD(p, x, Q1D)
{
MFEM_FOREACH_THREAD(d, y, D1D)
{
B(p, d) = B_(p, d);
G(p, d) = G_(p, d);
}
}
}
}
MFEM_SYNC_THREAD;
// eval u and normal derivative @ quad points
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
real_t(*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
real_t(*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
real_t(*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
MFEM_FOREACH_THREAD(p1, x, Q1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
real_t bu = 0.0;
real_t bdu = 0.0;
real_t gu = 0.0;
for (int d1 = 0; d1 < D1D; ++d1)
{
const real_t b = B(p1, d1);
const real_t g = G(p1, d1);
bu += b * u[d2][d1];
bdu += b * du[d2][d1];
gu += g * u[d2][d1];
}
Bu[p1][d2] = bu;
Bdu[p1][d2] = bdu;
Gu[p1][d2] = gu;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
real_t(*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
real_t(*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
real_t(*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
MFEM_FOREACH_THREAD(p2, x, Q1D)
{
MFEM_FOREACH_THREAD(p1, y, Q1D)
{
const real_t *Je = nJe[side][p2][p1];
real_t bbu = 0.0;
real_t bgu = 0.0;
real_t gbu = 0.0;
real_t bbdu = 0.0;
for (int d2 = 0; d2 < D1D; ++d2)
{
const real_t b = B(p2, d2);
const real_t g = G(p2, d2);
bbu += b * Bu[p1][d2];
gbu += g * Bu[p1][d2];
bgu += b * Gu[p1][d2];
bbdu += b * Bdu[p1][d2];
}
u[p2][p1] = bbu;
// du <- Q du/dn * w * det(J)
du[p2][p1] = Je[0] * bbdu + Je[1] * bgu + Je[2] * gbu;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t(*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
real_t(*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
real_t(*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
MFEM_FOREACH_THREAD(d1, x, D1D)
{
MFEM_FOREACH_THREAD(p2, y, Q1D)
{
real_t bj = 0.0;
real_t bjn = 0.0;
real_t gj = 0.0;
real_t br = 0.0;
for (int p1 = 0; p1 < Q1D; ++p1)
{
const real_t b = B(p1, d1);
const real_t g = G(p1, d1);
const real_t *Je = nJe[side][p2][p1];
const real_t jump = u0[p2][p1] - u1[p2][p1];
const real_t avg = du0[p2][p1] + du1[p2][p1];
// r = - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >
const real_t r = -avg + kappa_Qh[p2][p1] * jump;
// bj, gj, bjn contribute to sigma term
bj += b * Je[0] * jump;
gj += g * Je[1] * jump;
bjn += b * Je[2] * jump;
br += b * r;
}
Bj[d1][p2] = sigma * bj;
Bjn[d1][p2] = sigma * bjn;
// group br and gj together since we will multiply them both by B
// and then sum
const real_t sgn = (side == 0) ? 1.0 : -1.0;
Gj[d1][p2] = sgn * br + sigma * gj;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
real_t(*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
real_t(*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
real_t(*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
MFEM_FOREACH_THREAD(d2, x, D1D)
{
MFEM_FOREACH_THREAD(d1, y, D1D)
{
real_t bbj = 0.0;
real_t gbj = 0.0;
real_t bgj = 0.0;
for (int p2 = 0; p2 < Q1D; ++p2)
{
const real_t b = B(p2, d2);
const real_t g = G(p2, d2);
bbj += b * Bj[d1][p2];
bgj += b * Gj[d1][p2];
gbj += g * Bjn[d1][p2];
}
du[d2][d1] = bbj;
u[d2][d1] = bgj + gbj;
}
}
}
MFEM_SYNC_THREAD;
// map back to y and dydn
MFEM_FOREACH_THREAD(side, z, 2)
{
const real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
const real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d2, x, D1D)
{
MFEM_FOREACH_THREAD(d1, y, D1D)
{
y(d1, d2, side, f) += u[d2][d1];
dydn(d1, d2, side, f) += du[d2][d1];
}
}
}
});
}
} // namespace internal
template <int DIM, int D1D, int Q1D>
DGDiffusionIntegrator::ApplyKernelType
DGDiffusionIntegrator::ApplyPAKernels::Kernel()
{
if constexpr (DIM == 2)
{
return internal::PADGDiffusionApply2D<D1D, Q1D>;
}
else if constexpr (DIM == 3)
{
return internal::PADGDiffusionApply3D<D1D, Q1D>;
}
MFEM_ABORT("");
}
} // namespace mfem
/// \endcond DO_NOT_DOCUMENT
#endif
+163 -591
View File
@@ -11,42 +11,39 @@
#include "../../general/forall.hpp"
#include "../../mesh/face_nbr_geom.hpp"
#include "../fe/face_map_utils.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "../fe/face_map_utils.hpp"
using namespace std;
#include "bilininteg_dgdiffusion_kernels.hpp"
namespace mfem
{
static void PADGDiffusionSetup2D(const int Q1D,
const int NE,
const int NF,
static void PADGDiffusionSetup2D(const int Q1D, const int NE, const int NF,
const Array<real_t> &w,
const GeometricFactors &el_geom,
const FaceGeometricFactors &face_geom,
const FaceNeighborGeometricFactors *nbr_geom,
const Vector &q,
const real_t sigma,
const real_t kappa,
Vector &pa_data,
const Vector &q, const real_t sigma,
const real_t kappa, Vector &pa_data,
const Array<int> &face_info_)
{
const auto J_loc = Reshape(el_geom.J.Read(), Q1D, Q1D, 2, 2, NE);
const auto detJe_loc = Reshape(el_geom.detJ.Read(), Q1D, Q1D, NE);
const int n_nbr = nbr_geom ? nbr_geom->num_neighbor_elems : 0;
const auto J_shared = Reshape(nbr_geom ? nbr_geom->J.Read() : nullptr,
Q1D, Q1D, 2, 2, n_nbr);
const auto detJ_shared = Reshape(nbr_geom ? nbr_geom->detJ.Read() : nullptr,
Q1D, Q1D, n_nbr);
const auto J_shared =
Reshape(nbr_geom ? nbr_geom->J.Read() : nullptr, Q1D, Q1D, 2, 2, n_nbr);
const auto detJ_shared =
Reshape(nbr_geom ? nbr_geom->detJ.Read() : nullptr, Q1D, Q1D, n_nbr);
const auto detJf = Reshape(face_geom.detJ.Read(), Q1D, NF);
const auto n = Reshape(face_geom.normal.Read(), Q1D, 2, NF);
const bool const_q = (q.Size() == 1);
const auto Q = const_q ? Reshape(q.Read(), 1,1) : Reshape(q.Read(), Q1D,NF);
const auto Q =
const_q ? Reshape(q.Read(), 1, 1) : Reshape(q.Read(), Q1D, NF);
const auto W = w.Read();
@@ -56,7 +53,7 @@ static void PADGDiffusionSetup2D(const int Q1D,
// (q, 1/h, J0_0, J0_1, J1_0, J1_1)
auto pa = Reshape(pa_data.Write(), 6, Q1D, NF);
mfem::forall(NF, [=] MFEM_HOST_DEVICE (int f) -> void
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f) -> void
{
const int normal_dir[] = {face_info(0, f), face_info(1, f)};
const int fid[] = {face_info(4, f), face_info(5, f)};
@@ -74,7 +71,7 @@ static void PADGDiffusionSetup2D(const int Q1D,
for (int p = 0; p < Q1D; ++p)
{
const real_t Qp = const_q ? Q(0,0) : Q(p, f);
const real_t Qp = const_q ? Q(0, 0) : Q(p, f);
pa(0, p, f) = kappa * Qp * W[p] * detJf(p, f);
real_t hi = 0.0;
@@ -85,17 +82,19 @@ static void PADGDiffusionSetup2D(const int Q1D,
// Always opposite direction in "native" ordering
// Need to multiply the native=>lex0 with native=>lex1 and negate
const int sgn = (side == 1) ? -1*sgn0*sgn1 : 1;
const int sgn = (side == 1) ? -1 * sgn0 * sgn1 : 1;
const int e = el[side];
const auto &J = (side == 1 && shared) ? J_shared : J_loc;
const auto &detJ = (side == 1 && shared) ? detJ_shared : detJe_loc;
real_t nJi[2];
nJi[0] = n(p,0,f)*J(i,j, 1,1, e) - n(p,1,f)*J(i,j,0,1,e);
nJi[1] = -n(p,0,f)*J(i,j,1,0, e) + n(p,1,f)*J(i,j,0,0,e);
nJi[0] =
n(p, 0, f) * J(i, j, 1, 1, e) - n(p, 1, f) * J(i, j, 0, 1, e);
nJi[1] =
-n(p, 0, f) * J(i, j, 1, 0, e) + n(p, 1, f) * J(i, j, 0, 0, e);
const real_t dJe = detJ(i,j,e);
const real_t dJe = detJ(i, j, e);
const real_t dJf = detJf(p, f);
const real_t w = factor * Qp * W[p] * dJf / dJe;
@@ -104,9 +103,9 @@ static void PADGDiffusionSetup2D(const int Q1D,
const int ti = 1 - ni;
// Normal
pa(2 + 2*side + 0, p, f) = w * nJi[ni];
pa(2 + 2 * side + 0, p, f) = w * nJi[ni];
// Tangential
pa(2 + 2*side + 1, p, f) = sgn * w * nJi[ti];
pa(2 + 2 * side + 1, p, f) = sgn * w * nJi[ti];
hi += factor * dJf / dJe;
}
@@ -122,47 +121,43 @@ static void PADGDiffusionSetup2D(const int Q1D,
});
}
static void PADGDiffusionSetup3D(const int Q1D,
const int NE,
const int NF,
static void PADGDiffusionSetup3D(const int Q1D, const int NE, const int NF,
const Array<real_t> &w,
const GeometricFactors &el_geom,
const FaceGeometricFactors &face_geom,
const FaceNeighborGeometricFactors *nbr_geom,
const Vector &q,
const real_t sigma,
const real_t kappa,
Vector &pa_data,
const Vector &q, const real_t sigma,
const real_t kappa, Vector &pa_data,
const Array<int> &face_info_)
{
const auto J_loc = Reshape(el_geom.J.Read(), Q1D, Q1D, Q1D, 3, 3, NE);
const auto detJe_loc = Reshape(el_geom.detJ.Read(), Q1D, Q1D, Q1D, NE);
const int n_nbr = nbr_geom ? nbr_geom->num_neighbor_elems : 0;
const auto J_shared = Reshape(nbr_geom ? nbr_geom->J.Read() : nullptr,
Q1D, Q1D, Q1D, 3, 3, n_nbr);
const auto detJ_shared = Reshape(nbr_geom ? nbr_geom->detJ.Read() : nullptr,
Q1D, Q1D, Q1D, n_nbr);
const auto J_shared = Reshape(nbr_geom ? nbr_geom->J.Read() : nullptr, Q1D,
Q1D, Q1D, 3, 3, n_nbr);
const auto detJ_shared =
Reshape(nbr_geom ? nbr_geom->detJ.Read() : nullptr, Q1D, Q1D, Q1D, n_nbr);
const auto detJf = Reshape(face_geom.detJ.Read(), Q1D, Q1D, NF);
const auto n = Reshape(face_geom.normal.Read(), Q1D, Q1D, 3, NF);
const bool const_q = (q.Size() == 1);
const auto Q = const_q ? Reshape(q.Read(), 1, 1, 1)
: Reshape(q.Read(), Q1D, Q1D, NF);
const auto Q =
const_q ? Reshape(q.Read(), 1, 1, 1) : Reshape(q.Read(), Q1D, Q1D, NF);
const auto W = Reshape(w.Read(), Q1D, Q1D);
// (perm[0], perm[1], perm[2], element_index, local_face_id, orientation)
const auto face_info = Reshape(face_info_.Read(), 6, 2, NF);
constexpr int _el_ = 3; // offset in face_info for element index
constexpr int _el_ = 3; // offset in face_info for element index
constexpr int _fid_ = 4; // offset in face_info for local face id
constexpr int _or_ = 5; // offset in face_info for orientation
constexpr int _or_ = 5; // offset in face_info for orientation
// (J00, J01, J02, J10, J11, J12, q/h)
const auto pa = Reshape(pa_data.Write(), 7, Q1D, Q1D, NF);
mfem::forall_2D(NF, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int f) -> void
mfem::forall_2D(NF, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int f) -> void
{
MFEM_SHARED int perm[2][3];
MFEM_SHARED int el[2];
@@ -172,10 +167,7 @@ static void PADGDiffusionSetup3D(const int Q1D,
MFEM_FOREACH_THREAD(side, x, 2)
{
MFEM_FOREACH_THREAD(i, y, 3)
{
perm[side][i] = face_info(i, side, f);
}
MFEM_FOREACH_THREAD(i, y, 3) { perm[side][i] = face_info(i, side, f); }
if (MFEM_THREAD_ID(y) == 0)
{
@@ -200,16 +192,16 @@ static void PADGDiffusionSetup3D(const int Q1D,
{
MFEM_FOREACH_THREAD(p2, y, Q1D)
{
const real_t Qp = const_q ? Q(0,0,0) : Q(p1, p2, f);
const real_t dJf = detJf(p1,p2,f);
const real_t Qp = const_q ? Q(0, 0, 0) : Q(p1, p2, f);
const real_t dJf = detJf(p1, p2, f);
real_t hi = 0.0;
for (int side = 0; side < nsides; ++side)
{
int i, j, k;
internal::FaceIdxToVolIdx3D(
p1 + Q1D*p2, Q1D, fid[0], fid[1], side, ortn[1], i, j, k);
internal::FaceIdxToVolIdx3D(p1 + Q1D * p2, Q1D, fid[0], fid[1],
side, ortn[1], i, j, k);
const int e = el[side];
const auto &J = shared[side] ? J_shared : J_loc;
@@ -217,27 +209,45 @@ static void PADGDiffusionSetup3D(const int Q1D,
// *INDENT-OFF*
real_t nJi[3];
nJi[0] = ( -J(i,j,k, 1,2, e)*J(i,j,k, 2,1, e) + J(i,j,k, 1,1, e)*J(i,j,k, 2,2, e)) * n(p1,p2, 0, f)
+ ( J(i,j,k, 0,2, e)*J(i,j,k, 2,1, e) - J(i,j,k, 0,1, e)*J(i,j,k, 2,2, e)) * n(p1,p2, 1, f)
+ (-J(i,j,k, 0,2, e)*J(i,j,k, 1,1, e) + J(i,j,k, 0,1, e)*J(i,j,k, 1,2, e)) * n(p1,p2, 2, f);
nJi[0] = (-J(i, j, k, 1, 2, e) * J(i, j, k, 2, 1, e) +
J(i, j, k, 1, 1, e) * J(i, j, k, 2, 2, e)) *
n(p1, p2, 0, f) +
(J(i, j, k, 0, 2, e) * J(i, j, k, 2, 1, e) -
J(i, j, k, 0, 1, e) * J(i, j, k, 2, 2, e)) *
n(p1, p2, 1, f) +
(-J(i, j, k, 0, 2, e) * J(i, j, k, 1, 1, e) +
J(i, j, k, 0, 1, e) * J(i, j, k, 1, 2, e)) *
n(p1, p2, 2, f);
nJi[1] = ( J(i,j,k, 1,2, e)*J(i,j,k, 2,0, e) - J(i,j,k, 1,0, e)*J(i,j,k, 2,2, e)) * n(p1,p2, 0, f)
+ (-J(i,j,k, 0,2, e)*J(i,j,k, 2,0, e) + J(i,j,k, 0,0, e)*J(i,j,k, 2,2, e)) * n(p1,p2, 1, f)
+ ( J(i,j,k, 0,2, e)*J(i,j,k, 1,0, e) - J(i,j,k, 0,0, e)*J(i,j,k, 1,2, e)) * n(p1,p2, 2, f);
nJi[1] = (J(i, j, k, 1, 2, e) * J(i, j, k, 2, 0, e) -
J(i, j, k, 1, 0, e) * J(i, j, k, 2, 2, e)) *
n(p1, p2, 0, f) +
(-J(i, j, k, 0, 2, e) * J(i, j, k, 2, 0, e) +
J(i, j, k, 0, 0, e) * J(i, j, k, 2, 2, e)) *
n(p1, p2, 1, f) +
(J(i, j, k, 0, 2, e) * J(i, j, k, 1, 0, e) -
J(i, j, k, 0, 0, e) * J(i, j, k, 1, 2, e)) *
n(p1, p2, 2, f);
nJi[2] = ( -J(i,j,k, 1,1, e)*J(i,j,k, 2,0, e) + J(i,j,k, 1,0, e)*J(i,j,k, 2,1, e)) * n(p1,p2, 0, f)
+ ( J(i,j,k, 0,1, e)*J(i,j,k, 2,0, e) - J(i,j,k, 0,0, e)*J(i,j,k, 2,1, e)) * n(p1,p2, 1, f)
+ (-J(i,j,k, 0,1, e)*J(i,j,k, 1,0, e) + J(i,j,k, 0,0, e)*J(i,j,k, 1,1, e)) * n(p1,p2, 2, f);
nJi[2] = (-J(i, j, k, 1, 1, e) * J(i, j, k, 2, 0, e) +
J(i, j, k, 1, 0, e) * J(i, j, k, 2, 1, e)) *
n(p1, p2, 0, f) +
(J(i, j, k, 0, 1, e) * J(i, j, k, 2, 0, e) -
J(i, j, k, 0, 0, e) * J(i, j, k, 2, 1, e)) *
n(p1, p2, 1, f) +
(-J(i, j, k, 0, 1, e) * J(i, j, k, 1, 0, e) +
J(i, j, k, 0, 0, e) * J(i, j, k, 1, 1, e)) *
n(p1, p2, 2, f);
// *INDENT-ON*
const real_t dJe = detJe(i,j,k,e);
const real_t dJe = detJe(i, j, k, e);
const real_t val = factor * Qp * W(p1, p2) * dJf / dJe;
for (int d = 0; d < 3; ++d)
{
const int idx = std::abs(perm[side][d]) - 1;
const int sgn = (perm[side][d] < 0) ? -1 : 1;
pa(3*side + d, p1, p2, f) = sgn * val * nJi[idx];
pa(3 * side + d, p1, p2, f) = sgn * val * nJi[idx];
}
hi += factor * dJf / dJe;
@@ -257,7 +267,8 @@ static void PADGDiffusionSetup3D(const int Q1D,
}
static void PADGDiffusionSetupFaceInfo2D(const int nf, const Mesh &mesh,
const FaceType type, Array<int> &face_info_)
const FaceType type,
Array<int> &face_info_)
{
const int ne = mesh.GetNE();
@@ -326,8 +337,7 @@ inline void FaceNormalPermutation(int perm[3], const int face_id)
// Assigns to perm the permutation as in FaceNormalPermutation for the second
// element on the face but signed to indicate the sign of the normal derivative.
inline void SignedFaceNormalPermutation(int perm[3],
const int face_id1,
inline void SignedFaceNormalPermutation(int perm[3], const int face_id1,
const int face_id2,
const int orientation)
{
@@ -386,17 +396,19 @@ inline void SignedFaceNormalPermutation(int perm[3],
}
static void PADGDiffusionSetupFaceInfo3D(const int nf, const Mesh &mesh,
const FaceType type, Array<int> &face_info_)
const FaceType type,
Array<int> &face_info_)
{
const int ne = mesh.GetNE();
int fidx = 0;
// face_info array has 12 entries per face, 6 for each of the adjacent elements:
// (perm[0], perm[1], perm[2], element_index, local_face_id, orientation)
// face_info array has 12 entries per face, 6 for each of the adjacent
// elements: (perm[0], perm[1], perm[2], element_index, local_face_id,
// orientation)
face_info_.SetSize(nf * 12);
constexpr int _e_ = 3; // offset for element index
constexpr int _e_ = 3; // offset for element index
constexpr int _fid_ = 4; // offset for local face id
constexpr int _or_ = 5; // offset for orientation
constexpr int _or_ = 5; // offset for orientation
auto face_info = Reshape(face_info_.HostWrite(), 6, 2, nf);
for (int f = 0; f < mesh.GetNumFaces(); ++f)
@@ -408,9 +420,9 @@ static void PADGDiffusionSetupFaceInfo3D(const int nf, const Mesh &mesh,
const int fid0 = f_info.element[0].local_face_id;
const int or0 = f_info.element[0].orientation;
face_info( _e_, 0, fidx) = f_info.element[0].index;
face_info(_e_, 0, fidx) = f_info.element[0].index;
face_info(_fid_, 0, fidx) = fid0;
face_info( _or_, 0, fidx) = or0;
face_info(_or_, 0, fidx) = or0;
FaceNormalPermutation(&face_info(0, 0, fidx), fid0);
@@ -421,16 +433,17 @@ static void PADGDiffusionSetupFaceInfo3D(const int nf, const Mesh &mesh,
if (f_info.IsShared())
{
face_info( _e_, 1, fidx) = ne + f_info.element[1].index;
face_info(_e_, 1, fidx) = ne + f_info.element[1].index;
}
else
{
face_info( _e_, 1, fidx) = f_info.element[1].index;
face_info(_e_, 1, fidx) = f_info.element[1].index;
}
face_info(_fid_, 1, fidx) = fid1;
face_info( _or_, 1, fidx) = or1;
face_info(_or_, 1, fidx) = or1;
SignedFaceNormalPermutation(&face_info(0, 1, fidx), fid0, fid1, or1);
SignedFaceNormalPermutation(&face_info(0, 1, fidx), fid0, fid1,
or1);
}
else
{
@@ -448,8 +461,8 @@ static void PADGDiffusionSetupFaceInfo3D(const int nf, const Mesh &mesh,
void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
FaceType type)
{
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
const MemoryType mt =
(pa_mt == MemoryType::DEFAULT) ? Device::GetDeviceMemoryType() : pa_mt;
const int ne = fes.GetNE();
nf = fes.GetNFbyType(type);
@@ -458,16 +471,17 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
Mesh &mesh = *fes.GetMesh();
const Geometry::Type face_geom_type = mesh.GetTypicalFaceGeometry();
const FiniteElement &el = *fes.GetTypicalTraceElement();
const int ir_order = IntRule ? IntRule->GetOrder()
const int ir_order = IntRule
? IntRule->GetOrder()
: GetRule(el.GetOrder(), face_geom_type).GetOrder();
const IntegrationRule &ir = irs.Get(face_geom_type, ir_order);
dim = mesh.Dimension();
const int q1d = (ir.GetOrder() + 3)/2;
MFEM_ASSERT(q1d == pow(real_t(ir.Size()), 1.0/(dim - 1)), "");
const int q1d = (ir.GetOrder() + 3) / 2;
MFEM_ASSERT(q1d == pow(real_t(ir.Size()), 1.0 / (dim - 1)), "");
const auto vol_ir = irs.Get(mesh.GetTypicalElementGeometry(), ir_order);
const auto geom_flags = GeometricFactors::JACOBIANS |
GeometricFactors::DETERMINANTS;
const auto geom_flags =
GeometricFactors::JACOBIANS | GeometricFactors::DETERMINANTS;
const auto el_geom = mesh.GetGeometricFactors(vol_ir, geom_flags, mt);
std::unique_ptr<FaceNeighborGeometricFactors> nbr_geom;
@@ -476,8 +490,8 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
nbr_geom.reset(new FaceNeighborGeometricFactors(*el_geom));
}
const auto face_geom_flags = FaceGeometricFactors::DETERMINANTS |
FaceGeometricFactors::NORMALS;
const auto face_geom_flags =
FaceGeometricFactors::DETERMINANTS | FaceGeometricFactors::NORMALS;
auto face_geom = mesh.GetFaceGeometricFactors(ir, face_geom_flags, type, mt);
maps = &el.GetDofToQuad(ir, DofToQuad::TENSOR);
dofs1D = maps->ndof;
@@ -489,9 +503,18 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
// Evaluate the coefficient at the face quadrature points.
FaceQuadratureSpace fqs(mesh, ir, type);
CoefficientVector q(fqs, CoefficientStorage::COMPRESSED);
if (Q) { q.Project(*Q); }
else if (MQ) { MFEM_ABORT("Not yet implemented"); /* q.Project(*MQ); */ }
else { q.SetConstant(1.0); }
if (Q)
{
q.Project(*Q);
}
else if (MQ)
{
MFEM_ABORT("Not yet implemented"); /* q.Project(*MQ); */
}
else
{
q.SetConstant(1.0);
}
Array<int> face_info;
if (dim == 1)
@@ -501,14 +524,16 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
else if (dim == 2)
{
PADGDiffusionSetupFaceInfo2D(nf, mesh, type, face_info);
PADGDiffusionSetup2D(quad1D, ne, nf, ir.GetWeights(), *el_geom, *face_geom,
nbr_geom.get(), q, sigma, kappa, pa_data, face_info);
PADGDiffusionSetup2D(quad1D, ne, nf, ir.GetWeights(), *el_geom,
*face_geom, nbr_geom.get(), q, sigma, kappa, pa_data,
face_info);
}
else if (dim == 3)
{
PADGDiffusionSetupFaceInfo3D(nf, mesh, type, face_info);
PADGDiffusionSetup3D(quad1D, ne, nf, ir.GetWeights(), *el_geom, *face_geom,
nbr_geom.get(), q, sigma, kappa, pa_data, face_info);
PADGDiffusionSetup3D(quad1D, ne, nf, ir.GetWeights(), *el_geom,
*face_geom, nbr_geom.get(), q, sigma, kappa, pa_data,
face_info);
}
}
@@ -524,529 +549,76 @@ void DGDiffusionIntegrator::AssemblePABoundaryFaces(
SetupPA(fes, FaceType::Boundary);
}
template<int T_D1D = 0, int T_Q1D = 0> static
void PADGDiffusionApply2D(const int NF,
const Array<real_t> &b,
const Array<real_t> &bt,
const Array<real_t>& g,
const Array<real_t>& gt,
const real_t sigma,
const Vector &pa_data,
const Vector &x_,
const Vector &dxdn_,
Vector &y_,
Vector &dydn_,
const int d1d = 0,
const int q1d = 0)
void DGDiffusionIntegrator::AddMultPAFaceNormalDerivatives(const Vector &x,
const Vector &dxdn,
Vector &y,
Vector &dydn) const
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B_ = Reshape(b.Read(), Q1D, D1D);
auto G_ = Reshape(g.Read(), Q1D, D1D);
auto pa = Reshape(pa_data.Read(), 6, Q1D, NF); // (q, 1/h, J00, J01, J10, J11)
auto x = Reshape(x_.Read(), D1D, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, 2, NF);
auto dxdn = Reshape(dxdn_.Read(), D1D, 2, NF);
auto dydn = Reshape(dydn_.ReadWrite(), D1D, 2, NF);
const int NBX = std::max(D1D, Q1D);
mfem::forall_2D(NF, NBX, 2, [=] MFEM_HOST_DEVICE (int f) -> void
{
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t u0[max_D1D];
MFEM_SHARED real_t u1[max_D1D];
MFEM_SHARED real_t du0[max_D1D];
MFEM_SHARED real_t du1[max_D1D];
MFEM_SHARED real_t Bu0[max_Q1D];
MFEM_SHARED real_t Bu1[max_Q1D];
MFEM_SHARED real_t Bdu0[max_Q1D];
MFEM_SHARED real_t Bdu1[max_Q1D];
MFEM_SHARED real_t r[max_Q1D];
MFEM_SHARED real_t BG[2*max_D1D*max_Q1D];
DeviceMatrix B(BG, Q1D, D1D);
DeviceMatrix G(BG + D1D*Q1D, Q1D, D1D);
if (MFEM_THREAD_ID(y) == 0)
{
MFEM_FOREACH_THREAD(p,x,Q1D)
{
for (int d = 0; d < D1D; ++d)
{
B(p,d) = B_(p,d);
G(p,d) = G_(p,d);
}
}
}
MFEM_SYNC_THREAD;
// copy edge values to u0, u1 and copy edge normals to du0, du1
MFEM_FOREACH_THREAD(side,y,2)
{
real_t *u = (side == 0) ? u0 : u1;
real_t *du = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d,x,D1D)
{
u[d] = x(d, side, f);
du[d] = dxdn(d, side, f);
}
}
MFEM_SYNC_THREAD;
// eval @ quad points
MFEM_FOREACH_THREAD(side,y,2)
{
real_t *u = (side == 0) ? u0 : u1;
real_t *du = (side == 0) ? du0 : du1;
real_t *Bu = (side == 0) ? Bu0 : Bu1;
real_t *Bdu = (side == 0) ? Bdu0 : Bdu1;
MFEM_FOREACH_THREAD(p,x,Q1D)
{
const real_t Je_side[] = {pa(2 + 2*side, p, f), pa(2 + 2*side + 1, p, f)};
Bu[p] = 0.0;
Bdu[p] = 0.0;
for (int d = 0; d < D1D; ++d)
{
const real_t b = B(p,d);
const real_t g = G(p,d);
Bu[p] += b*u[d];
Bdu[p] += Je_side[0] * b * du[d] + Je_side[1] * g * u[d];
}
}
}
MFEM_SYNC_THREAD;
// term - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >:
if (MFEM_THREAD_ID(y) == 0)
{
MFEM_FOREACH_THREAD(p,x,Q1D)
{
const real_t q = pa(0, p, f);
const real_t hi = pa(1, p, f);
const real_t jump = Bu0[p] - Bu1[p];
const real_t avg = Bdu0[p] + Bdu1[p]; // = {Q du/dn} * w * det(J)
r[p] = -avg + hi * q * jump;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(d,x,D1D)
{
real_t Br = 0.0;
for (int p = 0; p < Q1D; ++p)
{
Br += B(p, d) * r[p];
}
u0[d] = Br; // overwrite u0, u1
u1[d] = -Br;
} // for d
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side,y,2)
{
real_t *du = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d,x,D1D)
{
du[d] = 0.0;
}
}
MFEM_SYNC_THREAD;
// term sigma * < [u], {Q dv/dn} >
MFEM_FOREACH_THREAD(side,y,2)
{
real_t * const du = (side == 0) ? du0 : du1;
real_t * const u = (side == 0) ? u0 : u1;
MFEM_FOREACH_THREAD(d,x,D1D)
{
for (int p = 0; p < Q1D; ++p)
{
const real_t Je[] = {pa(2 + 2*side, p, f), pa(2 + 2*side + 1, p, f)};
const real_t jump = Bu0[p] - Bu1[p];
const real_t r_p = Je[0] * jump; // normal
const real_t w_p = Je[1] * jump; // tangential
du[d] += sigma * B(p, d) * r_p;
u[d] += sigma * G(p, d) * w_p;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side,y,2)
{
real_t *u = (side == 0) ? u0 : u1;
real_t *du = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d,x,D1D)
{
y(d, side, f) += u[d];
dydn(d, side, f) += du[d];
}
}
}); // mfem::forall
ApplyPAKernels::Run(dim, dofs1D, quad1D, nf, maps->B, maps->Bt, maps->G,
maps->Gt, sigma, pa_data, x, dxdn, y, dydn, dofs1D,
quad1D);
}
template <int T_D1D = 0, int T_Q1D = 0>
static void PADGDiffusionApply3D(const int NF,
const Array<real_t>& b,
const Array<real_t>& bt,
const Array<real_t>& g,
const Array<real_t>& gt,
const real_t sigma,
const Vector& pa_data,
const Vector& x_,
const Vector& dxdn_,
Vector& y_,
Vector& dydn_,
const int d1d = 0,
const int q1d = 0)
DGDiffusionIntegrator::DGDiffusionIntegrator(const real_t s, const real_t k)
: sigma(s), kappa(k)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B_ = Reshape(b.Read(), Q1D, D1D);
auto G_ = Reshape(g.Read(), Q1D, D1D);
// (J0[0], J0[1], J0[2], J1[0], J1[1], J1[2], q/h)
auto pa = Reshape(pa_data.Read(), 7, Q1D, Q1D, NF);
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
auto dxdn = Reshape(dxdn_.Read(), D1D, D1D, 2, NF);
auto dydn = Reshape(dydn_.ReadWrite(), D1D, D1D, 2, NF);
const int NBX = std::max(D1D, Q1D);
mfem::forall_3D(NF, NBX, NBX, 2, [=] MFEM_HOST_DEVICE (int f) -> void
{
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t u0[max_Q1D][max_Q1D];
MFEM_SHARED real_t u1[max_Q1D][max_Q1D];
MFEM_SHARED real_t du0[max_Q1D][max_Q1D];
MFEM_SHARED real_t du1[max_Q1D][max_Q1D];
MFEM_SHARED real_t Gu0[max_Q1D][max_Q1D];
MFEM_SHARED real_t Gu1[max_Q1D][max_Q1D];
MFEM_SHARED real_t Bu0[max_Q1D][max_Q1D];
MFEM_SHARED real_t Bu1[max_Q1D][max_Q1D];
MFEM_SHARED real_t Bdu0[max_Q1D][max_Q1D];
MFEM_SHARED real_t Bdu1[max_Q1D][max_Q1D];
MFEM_SHARED real_t kappa_Qh[max_Q1D][max_Q1D];
MFEM_SHARED real_t nJe[2][max_Q1D][max_Q1D][3];
MFEM_SHARED real_t BG[2*max_D1D*max_Q1D];
// some buffers are reused multiple times, but for clarity have new names:
real_t (*Bj0)[max_Q1D] = Bu0;
real_t (*Bj1)[max_Q1D] = Bu1;
real_t (*Bjn0)[max_Q1D] = Bdu0;
real_t (*Bjn1)[max_Q1D] = Bdu1;
real_t (*Gj0)[max_Q1D] = Gu0;
real_t (*Gj1)[max_Q1D] = Gu1;
DeviceMatrix B(BG, Q1D, D1D);
DeviceMatrix G(BG + D1D*Q1D, Q1D, D1D);
// copy face values to u0, u1 and copy normals to du0, du1
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d2, x, D1D)
{
MFEM_FOREACH_THREAD(d1, y, D1D)
{
u[d2][d1] = x(d1, d2, side, f); // copy transposed for better memory access
du[d2][d1] = dxdn(d1, d2, side, f);
}
}
MFEM_FOREACH_THREAD(p1, x, Q1D)
{
MFEM_FOREACH_THREAD(p2, y, Q1D)
{
for (int l=0; l < 3; ++l)
{
nJe[side][p2][p1][l] = pa(3*side + l, p1, p2, f);
}
if (side == 0)
{
kappa_Qh[p2][p1] = pa(6, p1, p2, f);
}
}
}
if (side == 0)
{
MFEM_FOREACH_THREAD(p, x, Q1D)
{
MFEM_FOREACH_THREAD(d, y, D1D)
{
B(p, d) = B_(p, d);
G(p, d) = G_(p, d);
}
}
}
}
MFEM_SYNC_THREAD;
// eval u and normal derivative @ quad points
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
real_t (*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
real_t (*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
real_t (*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
MFEM_FOREACH_THREAD(p1, x, Q1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
real_t bu = 0.0;
real_t bdu = 0.0;
real_t gu = 0.0;
for (int d1=0; d1 < D1D; ++d1)
{
const real_t b = B(p1, d1);
const real_t g = G(p1, d1);
bu += b * u[d2][d1];
bdu += b * du[d2][d1];
gu += g * u[d2][d1];
}
Bu[p1][d2] = bu;
Bdu[p1][d2] = bdu;
Gu[p1][d2] = gu;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
real_t (*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
real_t (*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
real_t (*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
MFEM_FOREACH_THREAD(p2, x, Q1D)
{
MFEM_FOREACH_THREAD(p1, y, Q1D)
{
const real_t * Je = nJe[side][p2][p1];
real_t bbu = 0.0;
real_t bgu = 0.0;
real_t gbu = 0.0;
real_t bbdu = 0.0;
for (int d2 = 0; d2 < D1D; ++d2)
{
const real_t b = B(p2, d2);
const real_t g = G(p2, d2);
bbu += b * Bu[p1][d2];
gbu += g * Bu[p1][d2];
bgu += b * Gu[p1][d2];
bbdu += b * Bdu[p1][d2];
}
u[p2][p1] = bbu;
// du <- Q du/dn * w * det(J)
du[p2][p1] = Je[0] * bbdu + Je[1] * bgu + Je[2] * gbu;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t (*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
real_t (*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
real_t (*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
MFEM_FOREACH_THREAD(d1, x, D1D)
{
MFEM_FOREACH_THREAD(p2, y, Q1D)
{
real_t bj = 0.0;
real_t bjn = 0.0;
real_t gj = 0.0;
real_t br = 0.0;
for (int p1 = 0; p1 < Q1D; ++p1)
{
const real_t b = B(p1, d1);
const real_t g = G(p1, d1);
const real_t * Je = nJe[side][p2][p1];
const real_t jump = u0[p2][p1] - u1[p2][p1];
const real_t avg = du0[p2][p1] + du1[p2][p1];
// r = - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >
const real_t r = -avg + kappa_Qh[p2][p1] * jump;
// bj, gj, bjn contribute to sigma term
bj += b * Je[0] * jump;
gj += g * Je[1] * jump;
bjn += b * Je[2] * jump;
br += b * r;
}
Bj[d1][p2] = sigma * bj;
Bjn[d1][p2] = sigma * bjn;
// group br and gj together since we will multiply them both by B
// and then sum
const real_t sgn = (side == 0) ? 1.0 : -1.0;
Gj[d1][p2] = sgn * br + sigma * gj;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(side, z, 2)
{
real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
real_t (*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
real_t (*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
real_t (*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
MFEM_FOREACH_THREAD(d2, x, D1D)
{
MFEM_FOREACH_THREAD(d1, y, D1D)
{
real_t bbj = 0.0;
real_t gbj = 0.0;
real_t bgj = 0.0;
for (int p2 = 0; p2 < Q1D; ++p2)
{
const real_t b = B(p2, d2);
const real_t g = G(p2, d2);
bbj += b * Bj[d1][p2];
bgj += b * Gj[d1][p2];
gbj += g * Bjn[d1][p2];
}
du[d2][d1] = bbj;
u[d2][d1] = bgj + gbj;
}
}
}
MFEM_SYNC_THREAD;
// map back to y and dydn
MFEM_FOREACH_THREAD(side, z, 2)
{
const real_t (*u)[max_Q1D] = (side == 0) ? u0 : u1;
const real_t (*du)[max_Q1D] = (side == 0) ? du0 : du1;
MFEM_FOREACH_THREAD(d2, x, D1D)
{
MFEM_FOREACH_THREAD(d1, y, D1D)
{
y(d1, d2, side, f) += u[d2][d1];
dydn(d1, d2, side, f) += du[d2][d1];
}
}
}
});
static Kernels kernels;
}
static void PADGDiffusionApply(const int dim,
const int D1D,
const int Q1D,
const int NF,
const Array<real_t> &B,
const Array<real_t> &Bt,
const Array<real_t> &G,
const Array<real_t> &Gt,
const real_t sigma,
const Vector &pa_data,
const Vector &x,
const Vector &dxdn,
Vector &y,
Vector &dydn)
DGDiffusionIntegrator::DGDiffusionIntegrator(Coefficient &q, const real_t s,
const real_t k)
: DGDiffusionIntegrator(s, k)
{
Q = &q;
}
DGDiffusionIntegrator::DGDiffusionIntegrator(MatrixCoefficient &q,
const real_t s, const real_t k)
: DGDiffusionIntegrator(s, k)
{
MQ = &q;
}
/// \cond DO_NOT_DOCUMENT
DGDiffusionIntegrator::ApplyKernelType
DGDiffusionIntegrator::ApplyPAKernels::Fallback(int dim, int, int)
{
if (dim == 2)
{
auto kernel = PADGDiffusionApply2D<0,0>;
switch ((D1D << 4 ) | Q1D)
{
case 0x23: kernel = PADGDiffusionApply2D<2,3>; break;
case 0x34: kernel = PADGDiffusionApply2D<3,4>; break;
case 0x45: kernel = PADGDiffusionApply2D<4,5>; break;
case 0x56: kernel = PADGDiffusionApply2D<5,6>; break;
case 0x67: kernel = PADGDiffusionApply2D<6,7>; break;
case 0x78: kernel = PADGDiffusionApply2D<7,8>; break;
case 0x89: kernel = PADGDiffusionApply2D<8,9>; break;
case 0x9A: kernel = PADGDiffusionApply2D<9,10>; break;
}
kernel(NF, B, Bt, G, Gt, sigma, pa_data, x, dxdn, y, dydn, D1D, Q1D);
return internal::PADGDiffusionApply2D;
}
else if (dim == 3)
{
auto kernel = PADGDiffusionApply3D<0,0>;
switch ((D1D << 4) | Q1D)
{
case 0x24: kernel = PADGDiffusionApply3D<2,4>; break;
case 0x35: kernel = PADGDiffusionApply3D<3,5>; break;
case 0x46: kernel = PADGDiffusionApply3D<4,6>; break;
case 0x57: kernel = PADGDiffusionApply3D<5,7>; break;
case 0x68: kernel = PADGDiffusionApply3D<6,8>; break;
case 0x79: kernel = PADGDiffusionApply3D<7,9>; break;
case 0x8A: kernel = PADGDiffusionApply3D<8,10>; break;
case 0x9B: kernel = PADGDiffusionApply3D<9,11>; break;
}
kernel(NF, B, Bt, G, Gt, sigma, pa_data, x, dxdn, y, dydn, D1D, Q1D);
return internal::PADGDiffusionApply3D;
}
else
{
MFEM_ABORT("Unsupported dimension");
MFEM_ABORT("");
}
}
void DGDiffusionIntegrator::AddMultPAFaceNormalDerivatives(
const Vector &x, const Vector &dxdn, Vector &y, Vector &dydn) const
DGDiffusionIntegrator::Kernels::Kernels()
{
PADGDiffusionApply(dim, dofs1D, quad1D, nf,
maps->B, maps->Bt, maps->G, maps->Gt,
sigma, pa_data, x, dxdn, y, dydn);
DGDiffusionIntegrator::AddSpecialization<2, 2, 3>();
DGDiffusionIntegrator::AddSpecialization<2, 3, 4>();
DGDiffusionIntegrator::AddSpecialization<2, 4, 5>();
DGDiffusionIntegrator::AddSpecialization<2, 5, 6>();
DGDiffusionIntegrator::AddSpecialization<2, 6, 7>();
DGDiffusionIntegrator::AddSpecialization<2, 7, 8>();
DGDiffusionIntegrator::AddSpecialization<2, 8, 9>();
DGDiffusionIntegrator::AddSpecialization<2, 9, 10>();
DGDiffusionIntegrator::AddSpecialization<3, 2, 4>();
DGDiffusionIntegrator::AddSpecialization<3, 3, 5>();
DGDiffusionIntegrator::AddSpecialization<3, 4, 6>();
DGDiffusionIntegrator::AddSpecialization<3, 5, 7>();
DGDiffusionIntegrator::AddSpecialization<3, 6, 8>();
DGDiffusionIntegrator::AddSpecialization<3, 7, 9>();
DGDiffusionIntegrator::AddSpecialization<3, 8, 10>();
DGDiffusionIntegrator::AddSpecialization<3, 9, 11>();
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
+793
View File
@@ -0,0 +1,793 @@
// 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 BILININTEG_DGTRACE_KERNELS_HPP
#define BILININTEG_DGTRACE_KERNELS_HPP
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "../restriction.hpp"
/// \cond DO_NOT_DOCUMENT
namespace mfem
{
namespace internal
{
// PA DGTrace Apply 2D kernel for Gauss-Lobatto/Bernstein
template <int T_D1D = 0, int T_Q1D = 0>
static void PADGTraceApply2D(const int NF, const Array<real_t> &b,
const Array<real_t> &bt, const Vector &op_,
const Vector &x_, Vector &y_, const int d1d = 0,
const int q1d = 0)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, 2, 2, NF);
auto x = Reshape(x_.Read(), D1D, VDIM, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, VDIM, 2, NF);
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
real_t u0[max_D1D][VDIM];
real_t u1[max_D1D][VDIM];
for (int d = 0; d < D1D; d++)
{
for (int c = 0; c < VDIM; c++)
{
u0[d][c] = x(d, c, 0, f);
u1[d][c] = x(d, c, 1, f);
}
}
real_t Bu0[max_Q1D][VDIM];
real_t Bu1[max_Q1D][VDIM];
for (int q = 0; q < Q1D; ++q)
{
for (int c = 0; c < VDIM; c++)
{
Bu0[q][c] = 0.0;
Bu1[q][c] = 0.0;
}
for (int d = 0; d < D1D; ++d)
{
const real_t b = B(q, d);
for (int c = 0; c < VDIM; c++)
{
Bu0[q][c] += b * u0[d][c];
Bu1[q][c] += b * u1[d][c];
}
}
}
real_t DBu[max_Q1D][VDIM];
for (int q = 0; q < Q1D; ++q)
{
for (int c = 0; c < VDIM; c++)
{
DBu[q][c] = op(q, 0, 0, f) * Bu0[q][c] + op(q, 1, 0, f) * Bu1[q][c];
}
}
real_t BDBu[max_D1D][VDIM];
for (int d = 0; d < D1D; ++d)
{
for (int c = 0; c < VDIM; c++)
{
BDBu[d][c] = 0.0;
}
for (int q = 0; q < Q1D; ++q)
{
const real_t b = Bt(d, q);
for (int c = 0; c < VDIM; c++)
{
BDBu[d][c] += b * DBu[q][c];
}
}
for (int c = 0; c < VDIM; c++)
{
y(d, c, 0, f) += BDBu[d][c];
y(d, c, 1, f) += -BDBu[d][c];
}
}
});
}
// PA DGTrace Apply 3D kernel for Gauss-Lobatto/Bernstein
template <int T_D1D = 0, int T_Q1D = 0>
static void PADGTraceApply3D(const int NF, const Array<real_t> &b,
const Array<real_t> &bt, const Vector &op_,
const Vector &x_, Vector &y_, const int d1d = 0,
const int q1d = 0)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, 2, NF);
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
real_t u0[max_D1D][max_D1D][VDIM];
real_t u1[max_D1D][max_D1D][VDIM];
for (int d1 = 0; d1 < D1D; d1++)
{
for (int d2 = 0; d2 < D1D; d2++)
{
for (int c = 0; c < VDIM; c++)
{
u0[d1][d2][c] = x(d1, d2, c, 0, f);
u1[d1][d2][c] = x(d1, d2, c, 1, f);
}
}
}
real_t Bu0[max_Q1D][max_D1D][VDIM];
real_t Bu1[max_Q1D][max_D1D][VDIM];
for (int q = 0; q < Q1D; ++q)
{
for (int d2 = 0; d2 < D1D; d2++)
{
for (int c = 0; c < VDIM; c++)
{
Bu0[q][d2][c] = 0.0;
Bu1[q][d2][c] = 0.0;
}
for (int d1 = 0; d1 < D1D; ++d1)
{
const real_t b = B(q, d1);
for (int c = 0; c < VDIM; c++)
{
Bu0[q][d2][c] += b * u0[d1][d2][c];
Bu1[q][d2][c] += b * u1[d1][d2][c];
}
}
}
}
real_t BBu0[max_Q1D][max_Q1D][VDIM];
real_t BBu1[max_Q1D][max_Q1D][VDIM];
for (int q1 = 0; q1 < Q1D; ++q1)
{
for (int q2 = 0; q2 < Q1D; q2++)
{
for (int c = 0; c < VDIM; c++)
{
BBu0[q1][q2][c] = 0.0;
BBu1[q1][q2][c] = 0.0;
}
for (int d2 = 0; d2 < D1D; ++d2)
{
const real_t b = B(q2, d2);
for (int c = 0; c < VDIM; c++)
{
BBu0[q1][q2][c] += b * Bu0[q1][d2][c];
BBu1[q1][q2][c] += b * Bu1[q1][d2][c];
}
}
}
}
real_t DBBu[max_Q1D][max_Q1D][VDIM];
for (int q1 = 0; q1 < Q1D; ++q1)
{
for (int q2 = 0; q2 < Q1D; q2++)
{
for (int c = 0; c < VDIM; c++)
{
DBBu[q1][q2][c] = op(q1, q2, 0, 0, f) * BBu0[q1][q2][c] +
op(q1, q2, 1, 0, f) * BBu1[q1][q2][c];
}
}
}
real_t BDBBu[max_Q1D][max_D1D][VDIM];
for (int q1 = 0; q1 < Q1D; ++q1)
{
for (int d2 = 0; d2 < D1D; d2++)
{
for (int c = 0; c < VDIM; c++)
{
BDBBu[q1][d2][c] = 0.0;
}
for (int q2 = 0; q2 < Q1D; ++q2)
{
const real_t b = Bt(d2, q2);
for (int c = 0; c < VDIM; c++)
{
BDBBu[q1][d2][c] += b * DBBu[q1][q2][c];
}
}
}
}
real_t BBDBBu[max_D1D][max_D1D][VDIM];
for (int d1 = 0; d1 < D1D; ++d1)
{
for (int d2 = 0; d2 < D1D; d2++)
{
for (int c = 0; c < VDIM; c++)
{
BBDBBu[d1][d2][c] = 0.0;
}
for (int q1 = 0; q1 < Q1D; ++q1)
{
const real_t b = Bt(d1, q1);
for (int c = 0; c < VDIM; c++)
{
BBDBBu[d1][d2][c] += b * BDBBu[q1][d2][c];
}
}
for (int c = 0; c < VDIM; c++)
{
y(d1, d2, c, 0, f) += BBDBBu[d1][d2][c];
y(d1, d2, c, 1, f) += -BBDBBu[d1][d2][c];
}
}
}
});
}
// Optimized PA DGTrace Apply 3D kernel for Gauss-Lobatto/Bernstein
template <int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPADGTraceApply3D(const int NF, const Array<real_t> &b,
const Array<real_t> &bt, const Vector &op_,
const Vector &x_, Vector &y_,
const int d1d = 0, const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
mfem::forall_2D_batch(NF, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE(int f)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t u0[NBZ][max_D1D][max_D1D];
MFEM_SHARED real_t u1[NBZ][max_D1D][max_D1D];
MFEM_FOREACH_THREAD(d1, x, D1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
u0[tidz][d1][d2] = x(d1, d2, 0, f);
u1[tidz][d1][d2] = x(d1, d2, 1, f);
}
}
MFEM_SYNC_THREAD;
MFEM_SHARED real_t Bu0[NBZ][max_Q1D][max_D1D];
MFEM_SHARED real_t Bu1[NBZ][max_Q1D][max_D1D];
MFEM_FOREACH_THREAD(q1, x, Q1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
real_t Bu0_ = 0.0;
real_t Bu1_ = 0.0;
for (int d1 = 0; d1 < D1D; ++d1)
{
const real_t b = B(q1, d1);
Bu0_ += b * u0[tidz][d1][d2];
Bu1_ += b * u1[tidz][d1][d2];
}
Bu0[tidz][q1][d2] = Bu0_;
Bu1[tidz][q1][d2] = Bu1_;
}
}
MFEM_SYNC_THREAD;
MFEM_SHARED real_t BBu0[NBZ][max_Q1D][max_Q1D];
MFEM_SHARED real_t BBu1[NBZ][max_Q1D][max_Q1D];
MFEM_FOREACH_THREAD(q1, x, Q1D)
{
MFEM_FOREACH_THREAD(q2, y, Q1D)
{
real_t BBu0_ = 0.0;
real_t BBu1_ = 0.0;
for (int d2 = 0; d2 < D1D; ++d2)
{
const real_t b = B(q2, d2);
BBu0_ += b * Bu0[tidz][q1][d2];
BBu1_ += b * Bu1[tidz][q1][d2];
}
BBu0[tidz][q1][q2] = BBu0_;
BBu1[tidz][q1][q2] = BBu1_;
}
}
MFEM_SYNC_THREAD;
MFEM_SHARED real_t DBBu[NBZ][max_Q1D][max_Q1D];
MFEM_FOREACH_THREAD(q1, x, Q1D)
{
MFEM_FOREACH_THREAD(q2, y, Q1D)
{
DBBu[tidz][q1][q2] = op(q1, q2, 0, 0, f) * BBu0[tidz][q1][q2] +
op(q1, q2, 1, 0, f) * BBu1[tidz][q1][q2];
}
}
MFEM_SYNC_THREAD;
MFEM_SHARED real_t BDBBu[NBZ][max_Q1D][max_D1D];
MFEM_FOREACH_THREAD(q1, x, Q1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
real_t BDBBu_ = 0.0;
for (int q2 = 0; q2 < Q1D; ++q2)
{
const real_t b = Bt(d2, q2);
BDBBu_ += b * DBBu[tidz][q1][q2];
}
BDBBu[tidz][q1][d2] = BDBBu_;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(d1, x, D1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
real_t BBDBBu_ = 0.0;
for (int q1 = 0; q1 < Q1D; ++q1)
{
const real_t b = Bt(d1, q1);
BBDBBu_ += b * BDBBu[tidz][q1][d2];
}
y(d1, d2, 0, f) += BBDBBu_;
y(d1, d2, 1, f) += -BBDBBu_;
}
}
});
}
// PA DGTrace Apply 2D kernel for Gauss-Lobatto/Bernstein
template <int T_D1D = 0, int T_Q1D = 0>
static void PADGTraceApplyTranspose2D(const int NF, const Array<real_t> &b,
const Array<real_t> &bt,
const Vector &op_, const Vector &x_,
Vector &y_, const int d1d = 0,
const int q1d = 0)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, 2, 2, NF);
auto x = Reshape(x_.Read(), D1D, VDIM, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, VDIM, 2, NF);
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
real_t u0[max_D1D][VDIM];
real_t u1[max_D1D][VDIM];
for (int d = 0; d < D1D; d++)
{
for (int c = 0; c < VDIM; c++)
{
u0[d][c] = x(d, c, 0, f);
u1[d][c] = x(d, c, 1, f);
}
}
real_t Bu0[max_Q1D][VDIM];
real_t Bu1[max_Q1D][VDIM];
for (int q = 0; q < Q1D; ++q)
{
for (int c = 0; c < VDIM; c++)
{
Bu0[q][c] = 0.0;
Bu1[q][c] = 0.0;
}
for (int d = 0; d < D1D; ++d)
{
const real_t b = B(q, d);
for (int c = 0; c < VDIM; c++)
{
Bu0[q][c] += b * u0[d][c];
Bu1[q][c] += b * u1[d][c];
}
}
}
real_t DBu0[max_Q1D][VDIM];
real_t DBu1[max_Q1D][VDIM];
for (int q = 0; q < Q1D; ++q)
{
for (int c = 0; c < VDIM; c++)
{
DBu0[q][c] =
op(q, 0, 0, f) * Bu0[q][c] + op(q, 0, 1, f) * Bu1[q][c];
DBu1[q][c] =
op(q, 1, 0, f) * Bu0[q][c] + op(q, 1, 1, f) * Bu1[q][c];
}
}
real_t BDBu0[max_D1D][VDIM];
real_t BDBu1[max_D1D][VDIM];
for (int d = 0; d < D1D; ++d)
{
for (int c = 0; c < VDIM; c++)
{
BDBu0[d][c] = 0.0;
BDBu1[d][c] = 0.0;
}
for (int q = 0; q < Q1D; ++q)
{
const real_t b = Bt(d, q);
for (int c = 0; c < VDIM; c++)
{
BDBu0[d][c] += b * DBu0[q][c];
BDBu1[d][c] += b * DBu1[q][c];
}
}
for (int c = 0; c < VDIM; c++)
{
y(d, c, 0, f) += BDBu0[d][c];
y(d, c, 1, f) += BDBu1[d][c];
}
}
});
}
// PA DGTrace Apply Transpose 3D kernel for Gauss-Lobatto/Bernstein
template <int T_D1D = 0, int T_Q1D = 0>
static void PADGTraceApplyTranspose3D(const int NF, const Array<real_t> &b,
const Array<real_t> &bt,
const Vector &op_, const Vector &x_,
Vector &y_, const int d1d = 0,
const int q1d = 0)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, 2, NF);
mfem::forall(NF, [=] MFEM_HOST_DEVICE(int f)
{
const int VDIM = 1;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
real_t u0[max_D1D][max_D1D][VDIM];
real_t u1[max_D1D][max_D1D][VDIM];
for (int d1 = 0; d1 < D1D; d1++)
{
for (int d2 = 0; d2 < D1D; d2++)
{
for (int c = 0; c < VDIM; c++)
{
u0[d1][d2][c] = x(d1, d2, c, 0, f);
u1[d1][d2][c] = x(d1, d2, c, 1, f);
}
}
}
real_t Bu0[max_Q1D][max_D1D][VDIM];
real_t Bu1[max_Q1D][max_D1D][VDIM];
for (int q1 = 0; q1 < Q1D; ++q1)
{
for (int d2 = 0; d2 < D1D; ++d2)
{
for (int c = 0; c < VDIM; c++)
{
Bu0[q1][d2][c] = 0.0;
Bu1[q1][d2][c] = 0.0;
}
for (int d1 = 0; d1 < D1D; ++d1)
{
const real_t b = B(q1, d1);
for (int c = 0; c < VDIM; c++)
{
Bu0[q1][d2][c] += b * u0[d1][d2][c];
Bu1[q1][d2][c] += b * u1[d1][d2][c];
}
}
}
}
real_t BBu0[max_Q1D][max_Q1D][VDIM];
real_t BBu1[max_Q1D][max_Q1D][VDIM];
for (int q1 = 0; q1 < Q1D; ++q1)
{
for (int q2 = 0; q2 < Q1D; ++q2)
{
for (int c = 0; c < VDIM; c++)
{
BBu0[q1][q2][c] = 0.0;
BBu1[q1][q2][c] = 0.0;
}
for (int d2 = 0; d2 < D1D; ++d2)
{
const real_t b = B(q2, d2);
for (int c = 0; c < VDIM; c++)
{
BBu0[q1][q2][c] += b * Bu0[q1][d2][c];
BBu1[q1][q2][c] += b * Bu1[q1][d2][c];
}
}
}
}
real_t DBu0[max_Q1D][max_Q1D][VDIM];
real_t DBu1[max_Q1D][max_Q1D][VDIM];
for (int q1 = 0; q1 < Q1D; ++q1)
{
for (int q2 = 0; q2 < Q1D; ++q2)
{
const real_t D00 = op(q1, q2, 0, 0, f);
const real_t D01 = op(q1, q2, 0, 1, f);
const real_t D10 = op(q1, q2, 1, 0, f);
const real_t D11 = op(q1, q2, 1, 1, f);
for (int c = 0; c < VDIM; c++)
{
DBu0[q1][q2][c] = D00 * BBu0[q1][q2][c] + D01 * BBu1[q1][q2][c];
DBu1[q1][q2][c] = D10 * BBu0[q1][q2][c] + D11 * BBu1[q1][q2][c];
}
}
}
real_t BDBu0[max_D1D][max_Q1D][VDIM];
real_t BDBu1[max_D1D][max_Q1D][VDIM];
for (int d1 = 0; d1 < D1D; ++d1)
{
for (int q2 = 0; q2 < Q1D; ++q2)
{
for (int c = 0; c < VDIM; c++)
{
BDBu0[d1][q2][c] = 0.0;
BDBu1[d1][q2][c] = 0.0;
}
for (int q1 = 0; q1 < Q1D; ++q1)
{
const real_t b = Bt(d1, q1);
for (int c = 0; c < VDIM; c++)
{
BDBu0[d1][q2][c] += b * DBu0[q1][q2][c];
BDBu1[d1][q2][c] += b * DBu1[q1][q2][c];
}
}
}
}
real_t BBDBu0[max_D1D][max_D1D][VDIM];
real_t BBDBu1[max_D1D][max_D1D][VDIM];
for (int d1 = 0; d1 < D1D; ++d1)
{
for (int d2 = 0; d2 < D1D; ++d2)
{
for (int c = 0; c < VDIM; c++)
{
BBDBu0[d1][d2][c] = 0.0;
BBDBu1[d1][d2][c] = 0.0;
}
for (int q2 = 0; q2 < Q1D; ++q2)
{
const real_t b = Bt(d2, q2);
for (int c = 0; c < VDIM; c++)
{
BBDBu0[d1][d2][c] += b * BDBu0[d1][q2][c];
BBDBu1[d1][d2][c] += b * BDBu1[d1][q2][c];
}
}
for (int c = 0; c < VDIM; c++)
{
y(d1, d2, c, 0, f) += BBDBu0[d1][d2][c];
y(d1, d2, c, 1, f) += BBDBu1[d1][d2][c];
}
}
}
});
}
// Optimized PA DGTrace Apply Transpose 3D kernel for Gauss-Lobatto/Bernstein
template <int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
static void SmemPADGTraceApplyTranspose3D(const int NF, const Array<real_t> &b,
const Array<real_t> &bt,
const Vector &op_, const Vector &x_,
Vector &y_, const int d1d = 0,
const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D, Q1D, 2, 2, NF);
auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
mfem::forall_2D_batch(NF, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE(int f)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
// the following variables are evaluated at compile time
constexpr int NBZ = T_NBZ ? T_NBZ : 1;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t u0[NBZ][max_D1D][max_D1D];
MFEM_SHARED real_t u1[NBZ][max_D1D][max_D1D];
MFEM_FOREACH_THREAD(d1, x, D1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
u0[tidz][d1][d2] = x(d1, d2, 0, f);
u1[tidz][d1][d2] = x(d1, d2, 1, f);
}
}
MFEM_SYNC_THREAD;
MFEM_SHARED real_t Bu0[NBZ][max_Q1D][max_D1D];
MFEM_SHARED real_t Bu1[NBZ][max_Q1D][max_D1D];
MFEM_FOREACH_THREAD(q1, x, Q1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
real_t Bu0_ = 0.0;
real_t Bu1_ = 0.0;
for (int d1 = 0; d1 < D1D; ++d1)
{
const real_t b = B(q1, d1);
Bu0_ += b * u0[tidz][d1][d2];
Bu1_ += b * u1[tidz][d1][d2];
}
Bu0[tidz][q1][d2] = Bu0_;
Bu1[tidz][q1][d2] = Bu1_;
}
}
MFEM_SYNC_THREAD;
MFEM_SHARED real_t BBu0[NBZ][max_Q1D][max_Q1D];
MFEM_SHARED real_t BBu1[NBZ][max_Q1D][max_Q1D];
MFEM_FOREACH_THREAD(q1, x, Q1D)
{
MFEM_FOREACH_THREAD(q2, y, Q1D)
{
real_t BBu0_ = 0.0;
real_t BBu1_ = 0.0;
for (int d2 = 0; d2 < D1D; ++d2)
{
const real_t b = B(q2, d2);
BBu0_ += b * Bu0[tidz][q1][d2];
BBu1_ += b * Bu1[tidz][q1][d2];
}
BBu0[tidz][q1][q2] = BBu0_;
BBu1[tidz][q1][q2] = BBu1_;
}
}
MFEM_SYNC_THREAD;
MFEM_SHARED real_t DBBu0[NBZ][max_Q1D][max_Q1D];
MFEM_SHARED real_t DBBu1[NBZ][max_Q1D][max_Q1D];
MFEM_FOREACH_THREAD(q1, x, Q1D)
{
MFEM_FOREACH_THREAD(q2, y, Q1D)
{
const real_t D00 = op(q1, q2, 0, 0, f);
const real_t D01 = op(q1, q2, 0, 1, f);
const real_t D10 = op(q1, q2, 1, 0, f);
const real_t D11 = op(q1, q2, 1, 1, f);
const real_t u0q = BBu0[tidz][q1][q2];
const real_t u1q = BBu1[tidz][q1][q2];
DBBu0[tidz][q1][q2] = D00 * u0q + D01 * u1q;
DBBu1[tidz][q1][q2] = D10 * u0q + D11 * u1q;
}
}
MFEM_SYNC_THREAD;
MFEM_SHARED real_t BDBBu0[NBZ][max_Q1D][max_D1D];
MFEM_SHARED real_t BDBBu1[NBZ][max_Q1D][max_D1D];
MFEM_FOREACH_THREAD(q1, x, Q1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
real_t BDBBu0_ = 0.0;
real_t BDBBu1_ = 0.0;
for (int q2 = 0; q2 < Q1D; ++q2)
{
const real_t b = Bt(d2, q2);
BDBBu0_ += b * DBBu0[tidz][q1][q2];
BDBBu1_ += b * DBBu1[tidz][q1][q2];
}
BDBBu0[tidz][q1][d2] = BDBBu0_;
BDBBu1[tidz][q1][d2] = BDBBu1_;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(d1, x, D1D)
{
MFEM_FOREACH_THREAD(d2, y, D1D)
{
real_t BBDBBu0_ = 0.0;
real_t BBDBBu1_ = 0.0;
for (int q1 = 0; q1 < Q1D; ++q1)
{
const real_t b = Bt(d1, q1);
BBDBBu0_ += b * BDBBu0[tidz][q1][d2];
BBDBBu1_ += b * BDBBu1[tidz][q1][d2];
}
y(d1, d2, 0, f) += BBDBBu0_;
y(d1, d2, 1, f) += BBDBBu1_;
}
}
});
}
} // namespace internal
template <int DIM, int D1D, int Q1D>
DGTraceIntegrator::ApplyKernelType DGTraceIntegrator::ApplyPAKernels::Kernel()
{
if constexpr (DIM == 2)
{
return internal::PADGTraceApply2D<D1D, Q1D>;
}
else if constexpr (DIM == 3)
{
if constexpr (D1D == 3 || D1D == 4)
{
return internal::SmemPADGTraceApply3D<D1D, Q1D, 2>;
}
else
{
return internal::SmemPADGTraceApply3D<D1D, Q1D>;
}
}
MFEM_ABORT("");
}
template <int DIM, int D1D, int Q1D>
DGTraceIntegrator::ApplyKernelType DGTraceIntegrator::ApplyPATKernels::Kernel()
{
if constexpr (DIM == 2)
{
return internal::PADGTraceApplyTranspose2D<D1D, Q1D>;
}
else if constexpr (DIM == 3)
{
return internal::SmemPADGTraceApplyTranspose3D<D1D, Q1D>;
}
MFEM_ABORT("");
}
} // namespace mfem
/// \endcond DO_NOT_DOCUMENT
#endif
File diff suppressed because it is too large Load Diff
+26 -2
View File
@@ -19,6 +19,8 @@ namespace mfem
DiffusionIntegrator::Kernels::Kernels()
{
// 2D
// Q = P+1
DiffusionIntegrator::AddSpecialization<2,1,1>();
DiffusionIntegrator::AddSpecialization<2,2,2>();
DiffusionIntegrator::AddSpecialization<2,3,3>();
DiffusionIntegrator::AddSpecialization<2,4,4>();
@@ -27,17 +29,39 @@ DiffusionIntegrator::Kernels::Kernels()
DiffusionIntegrator::AddSpecialization<2,7,7>();
DiffusionIntegrator::AddSpecialization<2,8,8>();
DiffusionIntegrator::AddSpecialization<2,9,9>();
// Q = P+2
DiffusionIntegrator::AddSpecialization<2,1,2>();
DiffusionIntegrator::AddSpecialization<2,2,3>();
DiffusionIntegrator::AddSpecialization<2,3,4>();
DiffusionIntegrator::AddSpecialization<2,4,5>();
DiffusionIntegrator::AddSpecialization<2,5,6>();
DiffusionIntegrator::AddSpecialization<2,6,7>();
DiffusionIntegrator::AddSpecialization<2,7,8>();
DiffusionIntegrator::AddSpecialization<2,8,9>();
DiffusionIntegrator::AddSpecialization<2,9,10>();
// others
// 3D
// Q = P+1
DiffusionIntegrator::AddSpecialization<3,1,1>();
DiffusionIntegrator::AddSpecialization<3,2,2>();
DiffusionIntegrator::AddSpecialization<3,3,3>();
DiffusionIntegrator::AddSpecialization<3,4,4>();
DiffusionIntegrator::AddSpecialization<3,5,5>();
DiffusionIntegrator::AddSpecialization<3,6,6>();
DiffusionIntegrator::AddSpecialization<3,7,7>();
DiffusionIntegrator::AddSpecialization<3,8,8>();
// Q = P+2
DiffusionIntegrator::AddSpecialization<3,1,2>();
DiffusionIntegrator::AddSpecialization<3,2,3>();
DiffusionIntegrator::AddSpecialization<3,3,4>();
DiffusionIntegrator::AddSpecialization<3,4,5>();
DiffusionIntegrator::AddSpecialization<3,4,6>();
DiffusionIntegrator::AddSpecialization<3,5,6>();
DiffusionIntegrator::AddSpecialization<3,5,8>();
DiffusionIntegrator::AddSpecialization<3,6,7>();
DiffusionIntegrator::AddSpecialization<3,7,8>();
DiffusionIntegrator::AddSpecialization<3,8,9>();
// others
DiffusionIntegrator::AddSpecialization<3,4,6>();
DiffusionIntegrator::AddSpecialization<3,5,8>();
}
namespace internal
+11 -11
View File
@@ -672,12 +672,12 @@ inline void SmemPADiffusionApply2D(const int NE,
real_t (*Gt)[MQ1] = (real_t (*)[MQ1]) (sBG+1);
MFEM_SHARED real_t Xz[NBZ][MD1][MD1];
MFEM_SHARED real_t GD[2][NBZ][MD1][MQ1];
MFEM_SHARED real_t GQ[2][NBZ][MD1][MQ1];
MFEM_SHARED real_t GQ[2][NBZ][MQ1][MQ1];
real_t (*X)[MD1] = (real_t (*)[MD1])(Xz + tidz);
real_t (*DQ0)[MD1] = (real_t (*)[MD1])(GD[0] + tidz);
real_t (*DQ1)[MD1] = (real_t (*)[MD1])(GD[1] + tidz);
real_t (*QQ0)[MD1] = (real_t (*)[MD1])(GQ[0] + tidz);
real_t (*QQ1)[MD1] = (real_t (*)[MD1])(GQ[1] + tidz);
real_t (*DQ0)[MQ1] = (real_t (*)[MQ1])(GD[0] + tidz);
real_t (*DQ1)[MQ1] = (real_t (*)[MQ1])(GD[1] + tidz);
real_t (*QQ0)[MQ1] = (real_t (*)[MQ1])(GQ[0] + tidz);
real_t (*QQ1)[MQ1] = (real_t (*)[MQ1])(GQ[1] + tidz);
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx,x,D1D)
@@ -1221,9 +1221,9 @@ using DiagonalKernelType = DiffusionIntegrator::DiagonalKernelType;
template<int DIM, int T_D1D, int T_Q1D>
ApplyKernelType DiffusionIntegrator::ApplyPAKernels::Kernel()
{
if (DIM == 2) { return internal::SmemPADiffusionApply2D<T_D1D,T_Q1D>; }
else if (DIM == 3) { return internal::SmemPADiffusionApply3D<T_D1D, T_Q1D>; }
else { MFEM_ABORT(""); }
if constexpr (DIM == 2) { return internal::SmemPADiffusionApply2D<T_D1D,T_Q1D>; }
else if constexpr (DIM == 3) { return internal::SmemPADiffusionApply3D<T_D1D, T_Q1D>; }
MFEM_ABORT("");
}
inline
@@ -1237,9 +1237,9 @@ ApplyKernelType DiffusionIntegrator::ApplyPAKernels::Fallback(int DIM, int, int)
template<int DIM, int D1D, int Q1D>
DiagonalKernelType DiffusionIntegrator::DiagonalPAKernels::Kernel()
{
if (DIM == 2) { return internal::SmemPADiffusionDiagonal2D<D1D,Q1D>; }
else if (DIM == 3) { return internal::SmemPADiffusionDiagonal3D<D1D, Q1D>; }
else { MFEM_ABORT(""); }
if constexpr (DIM == 2) { return internal::SmemPADiffusionDiagonal2D<D1D,Q1D>; }
else if constexpr (DIM == 3) { return internal::SmemPADiffusionDiagonal3D<D1D, Q1D>; }
MFEM_ABORT("");
}
inline DiagonalKernelType
+9 -16
View File
@@ -599,13 +599,11 @@ void PACurlCurlSetup3D(const int Q1D,
});
}
void PACurlCurlAssembleDiagonal2D(const int D1D,
const int Q1D,
const int NE,
const Array<real_t> &bo,
void PACurlCurlAssembleDiagonal2D(const int D1D, const int Q1D, const bool,
const int NE, const Array<real_t> &bo,
const Array<real_t> &, const Array<real_t> &,
const Array<real_t> &gc,
const Vector &pa_data,
Vector &diag)
const Vector &pa_data, Vector &diag)
{
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Gc = Reshape(gc.Read(), Q1D, D1D);
@@ -653,16 +651,11 @@ void PACurlCurlAssembleDiagonal2D(const int D1D,
}); // end of element loop
}
void PACurlCurlApply2D(const int D1D,
const int Q1D,
const int NE,
const Array<real_t> &bo,
const Array<real_t> &bot,
const Array<real_t> &gc,
const Array<real_t> &gct,
const Vector &pa_data,
const Vector &x,
Vector &y,
void PACurlCurlApply2D(const int D1D, const int Q1D, const bool, const int NE,
const Array<real_t> &bo, const Array<real_t> &,
const Array<real_t> &bot, const Array<real_t> &,
const Array<real_t> &gc, const Array<real_t> &gct,
const Vector &pa_data, const Vector &x, Vector &y,
const bool useAbs)
{
+50 -1
View File
@@ -24,7 +24,7 @@
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
namespace internal
{
@@ -426,8 +426,11 @@ void PACurlCurlSetup3D(const int Q1D,
// PA H(curl) curl-curl Diagonal 2D kernel
void PACurlCurlAssembleDiagonal2D(const int D1D,
const int Q1D,
const bool symmetric, // unused
const int NE,
const Array<real_t> &bo,
const Array<real_t> &bc, // unused
const Array<real_t> &go, // unused
const Array<real_t> &gc,
const Vector &pa_data,
Vector &diag);
@@ -831,9 +834,12 @@ inline void SmemPACurlCurlAssembleDiagonal3D(const int d1d,
// PA H(curl) curl-curl Apply/AbsApply 2D kernel
void PACurlCurlApply2D(const int D1D,
const int Q1D,
const bool symmetric, // unused
const int NE,
const Array<real_t> &bo,
const Array<real_t> &bc, // unused
const Array<real_t> &bot,
const Array<real_t> &bct, // unused
const Array<real_t> &gc,
const Array<real_t> &gct,
const Vector &pa_data,
@@ -3158,6 +3164,49 @@ inline void SmemPAHcurlL2ApplyTranspose3D(const int d1d,
} // namespace internal
template<int DIM, int T_D1D, int T_Q1D>
CurlCurlIntegrator::ApplyKernelType CurlCurlIntegrator::ApplyPAKernels::Kernel()
{
if constexpr (DIM == 2)
{
return internal::PACurlCurlApply2D;
}
else if constexpr (DIM == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
return internal::SmemPACurlCurlApply3D<T_D1D, T_Q1D>;
}
else
{
return internal::PACurlCurlApply3D;
}
}
MFEM_ABORT("");
}
template <int DIM, int T_D1D, int T_Q1D>
CurlCurlIntegrator::DiagonalKernelType
CurlCurlIntegrator::DiagonalPAKernels::Kernel()
{
if constexpr (DIM == 2)
{
return internal::PACurlCurlAssembleDiagonal2D;
}
else if constexpr (DIM == 3)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
return internal::SmemPACurlCurlAssembleDiagonal3D<T_D1D, T_Q1D>;
}
else
{
return internal::PACurlCurlAssembleDiagonal3D;
}
}
MFEM_ABORT("");
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
#endif
@@ -19,6 +19,7 @@
#include "../../linalg/vector.hpp"
#include "../bilininteg.hpp"
/// \cond DO_NOT_DOCUMENT
namespace mfem
{
@@ -819,4 +820,6 @@ inline void PAHcurlHdivApplyTranspose3D(const int d1d,
} // namespace mfem
/// \endcond DO_NOT_DOCUMENT
#endif
+32 -2
View File
@@ -17,6 +17,8 @@ namespace mfem
MassIntegrator::Kernels::Kernels()
{
// 2D
// Q=P+1
MassIntegrator::AddSpecialization<2,1,1>();
MassIntegrator::AddSpecialization<2,2,2>();
MassIntegrator::AddSpecialization<2,3,3>();
MassIntegrator::AddSpecialization<2,4,4>();
@@ -25,17 +27,45 @@ MassIntegrator::Kernels::Kernels()
MassIntegrator::AddSpecialization<2,7,7>();
MassIntegrator::AddSpecialization<2,8,8>();
MassIntegrator::AddSpecialization<2,9,9>();
// Q=P+2
MassIntegrator::AddSpecialization<2,1,2>();
MassIntegrator::AddSpecialization<2,2,3>();
MassIntegrator::AddSpecialization<2,3,4>();
MassIntegrator::AddSpecialization<2,4,5>();
MassIntegrator::AddSpecialization<2,5,6>();
MassIntegrator::AddSpecialization<2,6,7>();
MassIntegrator::AddSpecialization<2,7,8>();
MassIntegrator::AddSpecialization<2,8,9>();
MassIntegrator::AddSpecialization<2,9,10>();
// others
MassIntegrator::AddSpecialization<2,2,4>();
MassIntegrator::AddSpecialization<2,3,6>();
MassIntegrator::AddSpecialization<2,4,6>();
// 3D
// Q=P+1
MassIntegrator::AddSpecialization<3,1,1>();
MassIntegrator::AddSpecialization<3,2,2>();
MassIntegrator::AddSpecialization<3,3,3>();
MassIntegrator::AddSpecialization<3,4,4>();
MassIntegrator::AddSpecialization<3,5,5>();
MassIntegrator::AddSpecialization<3,6,6>();
MassIntegrator::AddSpecialization<3,7,7>();
MassIntegrator::AddSpecialization<3,8,8>();
MassIntegrator::AddSpecialization<3,9,9>();
// Q=P+2
MassIntegrator::AddSpecialization<3,1,2>();
MassIntegrator::AddSpecialization<3,2,3>();
MassIntegrator::AddSpecialization<3,3,4>();
MassIntegrator::AddSpecialization<3,3,6>();
MassIntegrator::AddSpecialization<3,4,5>();
MassIntegrator::AddSpecialization<3,4,6>();
MassIntegrator::AddSpecialization<3,5,6>();
MassIntegrator::AddSpecialization<3,5,8>();
MassIntegrator::AddSpecialization<3,6,7>();
MassIntegrator::AddSpecialization<3,7,8>();
MassIntegrator::AddSpecialization<3,8,9>();
// others
MassIntegrator::AddSpecialization<3,2,4>();
MassIntegrator::AddSpecialization<3,4,6>();
MassIntegrator::AddSpecialization<3,5,8>();
}
namespace internal
+8 -8
View File
@@ -1392,10 +1392,10 @@ using DiagonalKernelType = MassIntegrator::DiagonalKernelType;
template<int DIM, int T_D1D, int T_Q1D>
ApplyKernelType MassIntegrator::ApplyPAKernels::Kernel()
{
if (DIM == 1) { return internal::PAMassApply1D; }
else if (DIM == 2) { return internal::SmemPAMassApply2D<T_D1D,T_Q1D>; }
else if (DIM == 3) { return internal::SmemPAMassApply3D<T_D1D, T_Q1D>; }
else { MFEM_ABORT(""); }
if constexpr (DIM == 1) { return internal::PAMassApply1D; }
else if constexpr (DIM == 2) { return internal::SmemPAMassApply2D<T_D1D,T_Q1D>; }
else if constexpr (DIM == 3) { return internal::SmemPAMassApply3D<T_D1D, T_Q1D>; }
MFEM_ABORT("");
}
inline ApplyKernelType MassIntegrator::ApplyPAKernels::Fallback(
@@ -1410,10 +1410,10 @@ inline ApplyKernelType MassIntegrator::ApplyPAKernels::Fallback(
template<int DIM, int T_D1D, int T_Q1D>
DiagonalKernelType MassIntegrator::DiagonalPAKernels::Kernel()
{
if (DIM == 1) { return internal::PAMassAssembleDiagonal1D; }
else if (DIM == 2) { return internal::SmemPAMassAssembleDiagonal2D<T_D1D,T_Q1D>; }
else if (DIM == 3) { return internal::SmemPAMassAssembleDiagonal3D<T_D1D, T_Q1D>; }
else { MFEM_ABORT(""); }
if constexpr (DIM == 1) { return internal::PAMassAssembleDiagonal1D; }
else if constexpr (DIM == 2) { return internal::SmemPAMassAssembleDiagonal2D<T_D1D,T_Q1D>; }
else if constexpr (DIM == 3) { return internal::SmemPAMassAssembleDiagonal3D<T_D1D, T_Q1D>; }
MFEM_ABORT("");
}
inline DiagonalKernelType MassIntegrator::DiagonalPAKernels::Fallback(
+25 -56
View File
@@ -59,26 +59,23 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
const int NE = ne;
const int Q1D = quad1D;
const int NQ = static_cast<int>(std::pow(Q1D, dim));
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), NQ);
const auto J = Reshape(geom->detJ.Read(), NQ, NE);
const auto C = const_c ? Reshape(coeff.Read(), 1, 1) :
Reshape(coeff.Read(), NQ,NE);
auto v = Reshape(pa_data.Write(), NQ, NE);
mfem::forall_2D(NE, NQ, 1, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(i, x, NQ)
const int NE = ne;
const int NQ = nq;
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
const auto W = Reshape(ir->GetWeights().Read(), NQ);
const auto J = Reshape(geom->detJ.Read(), NQ, NE);
const auto C =
const_c ? Reshape(coeff.Read(), 1, 1) : Reshape(coeff.Read(), NQ, NE);
auto v = Reshape(pa_data.Write(), NQ, NE);
mfem::forall(NQ, NE, [=] MFEM_HOST_DEVICE(int q, int e)
{
const real_t detJ = J(i,e);
const real_t coeff = const_c ? C(0,0) : C(i,e);
v(i,e) = W(i) * coeff * (by_val ? detJ : 1.0/detJ);
}
});
const real_t detJ = J(q, e);
const real_t coeff = const_c ? C(0, 0) : C(q, e);
v(q, e) = W(q) * coeff * (by_val ? detJ : 1.0 / detJ);
});
}
}
void MassIntegrator::AssemblePABoundary(const FiniteElementSpace &fes)
@@ -109,50 +106,22 @@ void MassIntegrator::AssemblePABoundary(const FiniteElementSpace &fes)
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
const int NE = ne;
const int Q1D = quad1D;
const int NQ = nq;
const bool const_c = coeff.Size() == 1;
const bool by_val = map_type == FiniteElement::VALUE;
if (dim==1)
{
const auto W = Reshape(ir->GetWeights().Read(), Q1D);
const auto J = Reshape(face_geom->detJ.Read(), Q1D, NE);
const auto C = const_c ? Reshape(coeff.Read(), 1, 1) :
Reshape(coeff.Read(), Q1D, NE);
auto v = Reshape(pa_data.Write(), Q1D, NE);
mfem::forall_2D(NE, Q1D, 1, [=] MFEM_HOST_DEVICE (int e)
const auto W = Reshape(ir->GetWeights().Read(), NQ);
const auto J = Reshape(face_geom->detJ.Read(), NQ, NE);
const auto C = const_c ? Reshape(coeff.Read(), 1, 1)
: Reshape(coeff.Read(), NQ, NE);
auto v = Reshape(pa_data.Write(), NQ, NE);
mfem::forall(NQ, NE, [=] MFEM_HOST_DEVICE(int q, int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const real_t detJ = J(qx,e);
const real_t coeff = const_c ? C(0,0) : C(qx,e);
v(qx,e) = W(qx) * coeff * (by_val ? detJ : 1.0/detJ);
}
const real_t detJ = J(q, e);
const real_t coeff = const_c ? C(0, 0) : C(q, e);
v(q, e) = W(q) * coeff * (by_val ? detJ : 1.0 / detJ);
});
}
else if (dim==2)
{
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
const auto J = Reshape(face_geom->detJ.Read(), Q1D,Q1D,NE);
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
Reshape(coeff.Read(), Q1D,Q1D,NE);
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
mfem::forall_2D(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
const real_t detJ = J(qx,qy,e);
const real_t coeff = const_c ? C(0,0,0) : C(qx,qy,e);
v(qx,qy,e) = W(qx,qy) * coeff * (by_val ? detJ : 1.0/detJ);
}
}
});
}
else
{
MFEM_ABORT("Not supported.");
}
}
void MassIntegrator::AssembleDiagonalPA(Vector &diag)
@@ -0,0 +1,355 @@
// 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_BILININTEG_VECDIFFUSION_KERNELS_HPP
#define MFEM_BILININTEG_VECDIFFUSION_KERNELS_HPP
#include "../../general/forall.hpp"
#include "../bilininteg.hpp"
#include "../ceed/integrators/diffusion/diffusion.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
/// \cond DO_NOT_DOCUMENT
namespace mfem
{
namespace internal
{
// PA Diffusion Apply 2D kernel
template <int T_D1D = 0, int T_Q1D = 0, int T_VDIM = 0>
static void
PAVectorDiffusionApply2D(const int NE, const Array<real_t> &b,
const Array<real_t> &g, const Array<real_t> &bt,
const Array<real_t> &gt, const Vector &d_,
const Vector &x_, Vector &y_, const int d1d = 0,
const int q1d = 0, const int vdim = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
auto D = Reshape(d_.Read(), Q1D * Q1D, 3, NE);
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
real_t grad[max_Q1D][max_Q1D][2];
for (int c = 0; c < VDIM; c++)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
grad[qy][qx][0] = 0.0;
grad[qy][qx][1] = 0.0;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
real_t gradX[max_Q1D][2];
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] = 0.0;
gradX[qx][1] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const real_t s = x(dx, dy, c, e);
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] += s * B(qx, dx);
gradX[qx][1] += s * G(qx, dx);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t wy = B(qy, dy);
const real_t wDy = G(qy, dy);
for (int qx = 0; qx < Q1D; ++qx)
{
grad[qy][qx][0] += gradX[qx][1] * wy;
grad[qy][qx][1] += gradX[qx][0] * wDy;
}
}
}
// Calculate Dxy, xDy in plane
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const int q = qx + qy * Q1D;
const real_t O11 = D(q, 0, e);
const real_t O12 = D(q, 1, e);
const real_t O22 = D(q, 2, e);
const real_t gradX = grad[qy][qx][0];
const real_t gradY = grad[qy][qx][1];
grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
real_t gradX[max_D1D][2];
for (int dx = 0; dx < D1D; ++dx)
{
gradX[dx][0] = 0.0;
gradX[dx][1] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t gX = grad[qy][qx][0];
const real_t gY = grad[qy][qx][1];
for (int dx = 0; dx < D1D; ++dx)
{
const real_t wx = Bt(dx, qx);
const real_t wDx = Gt(dx, qx);
gradX[dx][0] += gX * wDx;
gradX[dx][1] += gY * wx;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
const real_t wy = Bt(dy, qy);
const real_t wDy = Gt(dy, qy);
for (int dx = 0; dx < D1D; ++dx)
{
y(dx, dy, c, e) +=
((gradX[dx][0] * wy) + (gradX[dx][1] * wDy));
}
}
}
}
});
}
// PA Diffusion Apply 3D kernel
template <const int T_D1D = 0, const int T_Q1D = 0>
static void
PAVectorDiffusionApply3D(const int NE, const Array<real_t> &b,
const Array<real_t> &g, const Array<real_t> &bt,
const Array<real_t> &gt, const Vector &op_,
const Vector &x_, Vector &y_, const int d1d = 0,
const int q1d = 0, const int sdim = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int VDIM = 3;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D * Q1D * Q1D, 6, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
for (int c = 0; c < VDIM; ++c)
{
real_t grad[max_Q1D][max_Q1D][max_Q1D][3];
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
grad[qz][qy][qx][0] = 0.0;
grad[qz][qy][qx][1] = 0.0;
grad[qz][qy][qx][2] = 0.0;
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
real_t gradXY[max_Q1D][max_Q1D][3];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
gradXY[qy][qx][0] = 0.0;
gradXY[qy][qx][1] = 0.0;
gradXY[qy][qx][2] = 0.0;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
real_t gradX[max_Q1D][2];
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] = 0.0;
gradX[qx][1] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const real_t s = x(dx, dy, dz, c, e);
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] += s * B(qx, dx);
gradX[qx][1] += s * G(qx, dx);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t wy = B(qy, dy);
const real_t wDy = G(qy, dy);
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t wx = gradX[qx][0];
const real_t wDx = gradX[qx][1];
gradXY[qy][qx][0] += wDx * wy;
gradXY[qy][qx][1] += wx * wDy;
gradXY[qy][qx][2] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const real_t wz = B(qz, dz);
const real_t wDz = G(qz, dz);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
grad[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
grad[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
grad[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
}
}
}
}
// Calculate Dxyz, xDyz, xyDz in plane
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const int q = qx + (qy + qz * Q1D) * Q1D;
const real_t O11 = op(q, 0, e);
const real_t O12 = op(q, 1, e);
const real_t O13 = op(q, 2, e);
const real_t O22 = op(q, 3, e);
const real_t O23 = op(q, 4, e);
const real_t O33 = op(q, 5, e);
const real_t gradX = grad[qz][qy][qx][0];
const real_t gradY = grad[qz][qy][qx][1];
const real_t gradZ = grad[qz][qy][qx][2];
grad[qz][qy][qx][0] =
(O11 * gradX) + (O12 * gradY) + (O13 * gradZ);
grad[qz][qy][qx][1] =
(O12 * gradX) + (O22 * gradY) + (O23 * gradZ);
grad[qz][qy][qx][2] =
(O13 * gradX) + (O23 * gradY) + (O33 * gradZ);
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
real_t gradXY[max_D1D][max_D1D][3];
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
gradXY[dy][dx][0] = 0;
gradXY[dy][dx][1] = 0;
gradXY[dy][dx][2] = 0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
real_t gradX[max_D1D][3];
for (int dx = 0; dx < D1D; ++dx)
{
gradX[dx][0] = 0;
gradX[dx][1] = 0;
gradX[dx][2] = 0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t gX = grad[qz][qy][qx][0];
const real_t gY = grad[qz][qy][qx][1];
const real_t gZ = grad[qz][qy][qx][2];
for (int dx = 0; dx < D1D; ++dx)
{
const real_t wx = Bt(dx, qx);
const real_t wDx = Gt(dx, qx);
gradX[dx][0] += gX * wDx;
gradX[dx][1] += gY * wx;
gradX[dx][2] += gZ * wx;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
const real_t wy = Bt(dy, qy);
const real_t wDy = Gt(dy, qy);
for (int dx = 0; dx < D1D; ++dx)
{
gradXY[dy][dx][0] += gradX[dx][0] * wy;
gradXY[dy][dx][1] += gradX[dx][1] * wDy;
gradXY[dy][dx][2] += gradX[dx][2] * wy;
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
const real_t wz = Bt(dz, qz);
const real_t wDz = Gt(dz, qz);
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
y(dx, dy, dz, c, e) +=
((gradXY[dy][dx][0] * wz) + (gradXY[dy][dx][1] * wz) +
(gradXY[dy][dx][2] * wDz));
}
}
}
}
}
});
}
} // namespace internal
template <int DIM, int VDIM, int T_D1D, int T_Q1D>
VectorDiffusionIntegrator::ApplyKernelType
VectorDiffusionIntegrator::ApplyPAKernels::Kernel()
{
if constexpr (DIM == 2)
{
return internal::PAVectorDiffusionApply2D<T_D1D, T_Q1D, VDIM>;
}
else if constexpr (DIM == 3)
{
return internal::PAVectorDiffusionApply3D;
}
MFEM_ABORT("");
}
} // namespace mfem
/// \endcond DO_NOT_DOCUMENT
#endif
+71 -336
View File
@@ -15,9 +15,58 @@
#include "../qfunction.hpp"
#include "../ceed/integrators/diffusion/diffusion.hpp"
#include "bilininteg_vecdiffusion_kernels.hpp"
namespace mfem
{
VectorDiffusionIntegrator::VectorDiffusionIntegrator(const IntegrationRule *ir)
: BilinearFormIntegrator(ir)
{
static Kernels kernels;
}
VectorDiffusionIntegrator::VectorDiffusionIntegrator(Coefficient &q)
: VectorDiffusionIntegrator()
{
Q = &q;
}
VectorDiffusionIntegrator::VectorDiffusionIntegrator(int vector_dimension)
: VectorDiffusionIntegrator()
{
vdim = vector_dimension;
}
VectorDiffusionIntegrator::VectorDiffusionIntegrator(Coefficient &q,
const IntegrationRule *ir)
: VectorDiffusionIntegrator(ir)
{
Q = &q;
}
VectorDiffusionIntegrator::VectorDiffusionIntegrator(Coefficient &q,
int vector_dimension)
: VectorDiffusionIntegrator()
{
Q = &q;
vdim = vector_dimension;
}
VectorDiffusionIntegrator::VectorDiffusionIntegrator(VectorCoefficient &vq)
: VectorDiffusionIntegrator()
{
VQ = &vq;
vdim = vq.GetVDim();
}
VectorDiffusionIntegrator::VectorDiffusionIntegrator(MatrixCoefficient &mq)
: VectorDiffusionIntegrator()
{
MQ = &mq;
vdim = mq.GetVDim();
}
// PA Diffusion Assemble 2D kernel
static void PAVectorDiffusionSetup2D(const int Q1D,
const int NE,
@@ -425,322 +474,6 @@ void VectorDiffusionIntegrator::AssembleDiagonalPA(Vector &diag)
}
}
// PA Diffusion Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0, int T_VDIM = 0> static
void PAVectorDiffusionApply2D(const int NE,
const Array<real_t> &b,
const Array<real_t> &g,
const Array<real_t> &bt,
const Array<real_t> &gt,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0,
const int vdim = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
auto D = Reshape(d_.Read(), Q1D*Q1D, 3, NE);
auto x = Reshape(x_.Read(), D1D, D1D, VDIM, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
real_t grad[max_Q1D][max_Q1D][2];
for (int c = 0; c < VDIM; c++)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
grad[qy][qx][0] = 0.0;
grad[qy][qx][1] = 0.0;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
real_t gradX[max_Q1D][2];
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] = 0.0;
gradX[qx][1] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const real_t s = x(dx,dy,c,e);
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] += s * B(qx,dx);
gradX[qx][1] += s * G(qx,dx);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t wy = B(qy,dy);
const real_t wDy = G(qy,dy);
for (int qx = 0; qx < Q1D; ++qx)
{
grad[qy][qx][0] += gradX[qx][1] * wy;
grad[qy][qx][1] += gradX[qx][0] * wDy;
}
}
}
// Calculate Dxy, xDy in plane
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const int q = qx + qy * Q1D;
const real_t O11 = D(q,0,e);
const real_t O12 = D(q,1,e);
const real_t O22 = D(q,2,e);
const real_t gradX = grad[qy][qx][0];
const real_t gradY = grad[qy][qx][1];
grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
real_t gradX[max_D1D][2];
for (int dx = 0; dx < D1D; ++dx)
{
gradX[dx][0] = 0.0;
gradX[dx][1] = 0.0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t gX = grad[qy][qx][0];
const real_t gY = grad[qy][qx][1];
for (int dx = 0; dx < D1D; ++dx)
{
const real_t wx = Bt(dx,qx);
const real_t wDx = Gt(dx,qx);
gradX[dx][0] += gX * wDx;
gradX[dx][1] += gY * wx;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
const real_t wy = Bt(dy,qy);
const real_t wDy = Gt(dy,qy);
for (int dx = 0; dx < D1D; ++dx)
{
y(dx,dy,c,e) += ((gradX[dx][0] * wy) + (gradX[dx][1] * wDy));
}
}
}
}
});
}
// PA Diffusion Apply 3D kernel
template<const int T_D1D = 0,
const int T_Q1D = 0> static
void PAVectorDiffusionApply3D(const int NE,
const Array<real_t> &b,
const Array<real_t> &g,
const Array<real_t> &bt,
const Array<real_t> &gt,
const Vector &op_,
const Vector &x_,
Vector &y_,
int d1d = 0, int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int VDIM = 3;
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
auto B = Reshape(b.Read(), Q1D, D1D);
auto G = Reshape(g.Read(), Q1D, D1D);
auto Bt = Reshape(bt.Read(), D1D, Q1D);
auto Gt = Reshape(gt.Read(), D1D, Q1D);
auto op = Reshape(op_.Read(), Q1D*Q1D*Q1D, 6, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
for (int c = 0; c < VDIM; ++ c)
{
real_t grad[max_Q1D][max_Q1D][max_Q1D][3];
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
grad[qz][qy][qx][0] = 0.0;
grad[qz][qy][qx][1] = 0.0;
grad[qz][qy][qx][2] = 0.0;
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
real_t gradXY[max_Q1D][max_Q1D][3];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
gradXY[qy][qx][0] = 0.0;
gradXY[qy][qx][1] = 0.0;
gradXY[qy][qx][2] = 0.0;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
real_t gradX[max_Q1D][2];
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] = 0.0;
gradX[qx][1] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const real_t s = x(dx,dy,dz,c,e);
for (int qx = 0; qx < Q1D; ++qx)
{
gradX[qx][0] += s * B(qx,dx);
gradX[qx][1] += s * G(qx,dx);
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t wy = B(qy,dy);
const real_t wDy = G(qy,dy);
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t wx = gradX[qx][0];
const real_t wDx = gradX[qx][1];
gradXY[qy][qx][0] += wDx * wy;
gradXY[qy][qx][1] += wx * wDy;
gradXY[qy][qx][2] += wx * wy;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const real_t wz = B(qz,dz);
const real_t wDz = G(qz,dz);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
grad[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
grad[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
grad[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
}
}
}
}
// Calculate Dxyz, xDyz, xyDz in plane
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const int q = qx + (qy + qz * Q1D) * Q1D;
const real_t O11 = op(q,0,e);
const real_t O12 = op(q,1,e);
const real_t O13 = op(q,2,e);
const real_t O22 = op(q,3,e);
const real_t O23 = op(q,4,e);
const real_t O33 = op(q,5,e);
const real_t gradX = grad[qz][qy][qx][0];
const real_t gradY = grad[qz][qy][qx][1];
const real_t gradZ = grad[qz][qy][qx][2];
grad[qz][qy][qx][0] = (O11*gradX)+(O12*gradY)+(O13*gradZ);
grad[qz][qy][qx][1] = (O12*gradX)+(O22*gradY)+(O23*gradZ);
grad[qz][qy][qx][2] = (O13*gradX)+(O23*gradY)+(O33*gradZ);
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
real_t gradXY[max_D1D][max_D1D][3];
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
gradXY[dy][dx][0] = 0;
gradXY[dy][dx][1] = 0;
gradXY[dy][dx][2] = 0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
real_t gradX[max_D1D][3];
for (int dx = 0; dx < D1D; ++dx)
{
gradX[dx][0] = 0;
gradX[dx][1] = 0;
gradX[dx][2] = 0;
}
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t gX = grad[qz][qy][qx][0];
const real_t gY = grad[qz][qy][qx][1];
const real_t gZ = grad[qz][qy][qx][2];
for (int dx = 0; dx < D1D; ++dx)
{
const real_t wx = Bt(dx,qx);
const real_t wDx = Gt(dx,qx);
gradX[dx][0] += gX * wDx;
gradX[dx][1] += gY * wx;
gradX[dx][2] += gZ * wx;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
const real_t wy = Bt(dy,qy);
const real_t wDy = Gt(dy,qy);
for (int dx = 0; dx < D1D; ++dx)
{
gradXY[dy][dx][0] += gradX[dx][0] * wy;
gradXY[dy][dx][1] += gradX[dx][1] * wDy;
gradXY[dy][dx][2] += gradX[dx][2] * wy;
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
const real_t wz = Bt(dz,qz);
const real_t wDz = Gt(dz,qz);
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
y(dx,dy,dz,c,e) +=
((gradXY[dy][dx][0] * wz) +
(gradXY[dy][dx][1] * wz) +
(gradXY[dy][dx][2] * wDz));
}
}
}
}
}
});
}
// PA Diffusion Apply kernel
void VectorDiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
@@ -757,27 +490,29 @@ void VectorDiffusionIntegrator::AddMultPA(const Vector &x, Vector &y) const
const Array<real_t> &Bt = maps->Bt;
const Array<real_t> &Gt = maps->Gt;
const Vector &D = pa_data;
if (dim == 2 && sdim == 3)
{
switch ((dofs1D << 4 ) | quad1D)
{
case 0x22: return PAVectorDiffusionApply2D<2,2,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x33: return PAVectorDiffusionApply2D<3,3,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x44: return PAVectorDiffusionApply2D<4,4,3>(ne,B,G,Bt,Gt,D,x,y);
case 0x55: return PAVectorDiffusionApply2D<5,5,3>(ne,B,G,Bt,Gt,D,x,y);
default:
return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim);
}
}
if (dim == 2 && sdim == 2)
{ return PAVectorDiffusionApply2D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D,sdim); }
if (dim == 3 && sdim == 3)
{ return PAVectorDiffusionApply3D(ne,B,G,Bt,Gt,D,x,y,D1D,Q1D); }
MFEM_ABORT("Unknown kernel.");
ApplyPAKernels::Run(dim, sdim, D1D, Q1D, ne, B, G, Bt, Gt, D, x, y, D1D,
Q1D, sdim);
}
}
/// \cond DO_NOT_DOCUMENT
VectorDiffusionIntegrator::ApplyKernelType
VectorDiffusionIntegrator::ApplyPAKernels::Fallback(int DIM, int, int, int)
{
if (DIM == 2) { return internal::PAVectorDiffusionApply2D; }
else if (DIM == 3) { return internal::PAVectorDiffusionApply3D; }
else { MFEM_ABORT(""); }
}
VectorDiffusionIntegrator::Kernels::Kernels()
{
VectorDiffusionIntegrator::AddSpecialization<2, 3, 2, 2>();
VectorDiffusionIntegrator::AddSpecialization<2, 3, 3, 3>();
VectorDiffusionIntegrator::AddSpecialization<2, 3, 4, 4>();
VectorDiffusionIntegrator::AddSpecialization<2, 3, 5, 5>();
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
+55 -204
View File
@@ -9,183 +9,19 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../../general/forall.hpp"
#include "../../fem/kernels.hpp"
#include "../../general/forall.hpp"
#include "../fem.hpp"
#include "lininteg_domain_kernels.hpp"
/// \cond DO_NOT_DOCUMENT
namespace mfem
{
template<int T_D1D = 0, int T_Q1D = 0>
static void DLFEvalAssemble2D(const int vdim, const int ne, const int d,
const int q,
const int map_type, const int *markers, const real_t *b,
const real_t *detj, const real_t *weights,
const Vector &coeff, real_t *y)
{
const auto F = coeff.Read();
const auto M = Reshape(markers, ne);
const auto B = Reshape(b, q, d);
const auto DETJ = Reshape(detj, q, q, ne);
const auto W = Reshape(weights, q, q);
const bool cst = coeff.Size() == vdim;
const auto C = cst ? Reshape(F,vdim,1,1,1) : Reshape(F,vdim,q,q,ne);
auto Y = Reshape(y, d,d, vdim, ne);
mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE (int e)
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED real_t sBt[Q*D];
MFEM_SHARED real_t sQQ[Q*Q];
MFEM_SHARED real_t sQD[Q*D];
const DeviceMatrix Bt(sBt, d, q);
kernels::internal::LoadB<D,Q>(d, q, B, sBt);
const DeviceMatrix QQ(sQQ, q, q);
const DeviceMatrix QD(sQD, q, d);
for (int c = 0; c < vdim; ++c)
{
const real_t cst_val = C(c,0,0,0);
MFEM_FOREACH_THREAD(x,x,q)
{
MFEM_FOREACH_THREAD(y,y,q)
{
const real_t detJ = (map_type == FiniteElement::VALUE) ? DETJ(x,y,e) : 1.0;
const real_t coeff_val = cst ? cst_val : C(c,x,y,e);
QQ(y,x) = W(x,y) * coeff_val * detJ;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy,y,q)
{
MFEM_FOREACH_THREAD(dx,x,d)
{
real_t u = 0.0;
for (int qx = 0; qx < q; ++qx) { u += QQ(qy,qx) * Bt(dx,qx); }
QD(qy,dx) = u;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy,y,d)
{
MFEM_FOREACH_THREAD(dx,x,d)
{
real_t u = 0.0;
for (int qy = 0; qy < q; ++qy) { u += QD(qy,dx) * Bt(dy,qy); }
Y(dx,dy,c,e) += u;
}
}
MFEM_SYNC_THREAD;
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
static void DLFEvalAssemble3D(const int vdim, const int ne, const int d,
const int q,
const int map_type, const int *markers, const real_t *b,
const real_t *detj, const real_t *weights,
const Vector &coeff, real_t *y)
{
const auto F = coeff.Read();
const auto M = Reshape(markers, ne);
const auto B = Reshape(b, q,d);
const auto DETJ = Reshape(detj, q, q, q, ne);
const auto W = Reshape(weights, q,q,q);
const bool cst_coeff = coeff.Size() == vdim;
const auto C = cst_coeff ? Reshape(F,vdim,1,1,1,1):Reshape(F,vdim,q,q,q,ne);
auto Y = Reshape(y, d,d,d, vdim, ne);
mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE (int e)
{
if (M(e) == 0) { return; } // ignore
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQD = (Q >= D) ? Q : D;
real_t u[D];
MFEM_SHARED real_t sBt[Q*D];
const DeviceMatrix Bt(sBt, d,q);
kernels::internal::LoadB<D,Q>(d,q,B,sBt);
MFEM_SHARED real_t sQQQ[MQD*MQD*MQD];
const DeviceCube QQQ(sQQQ, MQD, MQD, MQD);
for (int c = 0; c < vdim; ++c)
{
const real_t cst_val = C(c,0,0,0,0);
MFEM_FOREACH_THREAD(x,x,q)
{
MFEM_FOREACH_THREAD(y,y,q)
{
for (int z = 0; z < q; ++z)
{
const real_t detJ = (map_type == FiniteElement::VALUE) ? DETJ(x,y,z,e) : 1.0;
const real_t coeff_val = cst_coeff ? cst_val : C(c,x,y,z,e);
QQQ(z,y,x) = W(x,y,z) * coeff_val * detJ;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qx,x,q)
{
MFEM_FOREACH_THREAD(qy,y,q)
{
for (int dz = 0; dz < d; ++dz) { u[dz] = 0.0; }
for (int qz = 0; qz < q; ++qz)
{
const real_t ZYX = QQQ(qz,qy,qx);
for (int dz = 0; dz < d; ++dz) { u[dz] += ZYX * Bt(dz,qz); }
}
for (int dz = 0; dz < d; ++dz) { QQQ(dz,qy,qx) = u[dz]; }
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,y,d)
{
MFEM_FOREACH_THREAD(qx,x,q)
{
for (int dy = 0; dy < d; ++dy) { u[dy] = 0.0; }
for (int qy = 0; qy < q; ++qy)
{
const real_t zYX = QQQ(dz,qy,qx);
for (int dy = 0; dy < d; ++dy) { u[dy] += zYX * Bt(dy,qy); }
}
for (int dy = 0; dy < d; ++dy) { QQQ(dz,dy,qx) = u[dy]; }
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,y,d)
{
MFEM_FOREACH_THREAD(dy,x,d)
{
for (int dx = 0; dx < d; ++dx) { u[dx] = 0.0; }
for (int qx = 0; qx < q; ++qx)
{
const real_t zyX = QQQ(dz,dy,qx);
for (int dx = 0; dx < d; ++dx) { u[dx] += zyX * Bt(dx,qx); }
}
for (int dx = 0; dx < d; ++dx) { Y(dx,dy,dz,c,e) += u[dx]; }
}
}
MFEM_SYNC_THREAD;
}
});
}
static void DLFEvalAssemble(const FiniteElementSpace &fes,
const IntegrationRule *ir,
const Array<int> &markers,
const Vector &coeff,
const Array<int> &markers, const Vector &coeff,
Vector &y)
{
Mesh *mesh = fes.GetMesh();
@@ -197,50 +33,20 @@ static void DLFEvalAssemble(const FiniteElementSpace &fes,
constexpr int flags = GeometricFactors::DETERMINANTS;
const GeometricFactors *geom = mesh->GetGeometricFactors(*ir, flags, mt);
const int map_type = fes.GetTypicalFE()->GetMapType();
decltype(&DLFEvalAssemble2D<>) ker =
dim == 2 ? DLFEvalAssemble2D<> : DLFEvalAssemble3D<>;
if (dim==2)
{
if (d==1 && q==1) { ker=DLFEvalAssemble2D<1,1>; }
if (d==2 && q==2) { ker=DLFEvalAssemble2D<2,2>; }
if (d==3 && q==3) { ker=DLFEvalAssemble2D<3,3>; }
if (d==4 && q==4) { ker=DLFEvalAssemble2D<4,4>; }
if (d==5 && q==5) { ker=DLFEvalAssemble2D<5,5>; }
if (d==2 && q==3) { ker=DLFEvalAssemble2D<2,3>; }
if (d==3 && q==4) { ker=DLFEvalAssemble2D<3,4>; }
if (d==4 && q==5) { ker=DLFEvalAssemble2D<4,5>; }
if (d==5 && q==6) { ker=DLFEvalAssemble2D<5,6>; }
}
if (dim==3)
{
if (d==1 && q==1) { ker=DLFEvalAssemble3D<1,1>; }
if (d==2 && q==2) { ker=DLFEvalAssemble3D<2,2>; }
if (d==3 && q==3) { ker=DLFEvalAssemble3D<3,3>; }
if (d==4 && q==4) { ker=DLFEvalAssemble3D<4,4>; }
if (d==5 && q==5) { ker=DLFEvalAssemble3D<5,5>; }
if (d==2 && q==3) { ker=DLFEvalAssemble3D<2,3>; }
if (d==3 && q==4) { ker=DLFEvalAssemble3D<3,4>; }
if (d==4 && q==5) { ker=DLFEvalAssemble3D<4,5>; }
if (d==5 && q==6) { ker=DLFEvalAssemble3D<5,6>; }
}
MFEM_VERIFY(ker, "No kernel ndof " << d << " nqpt " << q);
const int vdim = fes.GetVDim();
const int ne = fes.GetMesh()->GetNE();
const int *M = markers.Read();
const real_t *B = maps.B.Read();
const int *M = markers.Read();
const real_t *detJ = geom->detJ.Read();
const real_t *W = ir->GetWeights().Read();
real_t *Y = y.ReadWrite();
ker(vdim, ne, d, q, map_type, M, B, detJ, W, coeff, Y);
DomainLFIntegrator::AssembleKernels::Run(dim, d, q, vdim, ne, d, q, map_type,
M, B, detJ, W, coeff, Y);
}
void DomainLFIntegrator::AssembleDevice(const FiniteElementSpace &fes,
const Array<int> &markers,
Vector &b)
const Array<int> &markers, Vector &b)
{
const FiniteElement &fe = *fes.GetTypicalFE();
const int qorder = oa * fe.GetOrder() + ob;
@@ -266,4 +72,49 @@ void VectorDomainLFIntegrator::AssembleDevice(const FiniteElementSpace &fes,
DLFEvalAssemble(fes, ir, markers, coeff, b);
}
DomainLFIntegrator::AssembleKernelType
DomainLFIntegrator::AssembleKernels::Fallback(int DIM, int, int)
{
switch (DIM)
{
case 1:
return DLFEvalAssemble1D<0, 0>;
case 2:
return DLFEvalAssemble2D<0, 0>;
case 3:
return DLFEvalAssemble3D<0, 0>;
}
MFEM_ABORT("");
}
DomainLFIntegrator::Kernels::Kernels()
{
// 2D
// Q = P+1
DomainLFIntegrator::AddSpecialization<2, 1, 1>();
DomainLFIntegrator::AddSpecialization<2, 2, 2>();
DomainLFIntegrator::AddSpecialization<2, 3, 3>();
DomainLFIntegrator::AddSpecialization<2, 4, 4>();
DomainLFIntegrator::AddSpecialization<2, 5, 5>();
// Q = P+2
DomainLFIntegrator::AddSpecialization<2, 2, 3>();
DomainLFIntegrator::AddSpecialization<2, 3, 4>();
DomainLFIntegrator::AddSpecialization<2, 4, 5>();
DomainLFIntegrator::AddSpecialization<2, 5, 6>();
// 3D
// Q = P+1
DomainLFIntegrator::AddSpecialization<3, 1, 1>();
DomainLFIntegrator::AddSpecialization<3, 2, 2>();
DomainLFIntegrator::AddSpecialization<3, 3, 3>();
DomainLFIntegrator::AddSpecialization<3, 4, 4>();
DomainLFIntegrator::AddSpecialization<3, 5, 5>();
// Q = P+2
DomainLFIntegrator::AddSpecialization<3, 2, 3>();
DomainLFIntegrator::AddSpecialization<3, 3, 4>();
DomainLFIntegrator::AddSpecialization<3, 4, 5>();
DomainLFIntegrator::AddSpecialization<3, 5, 6>();
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
+318
View File
@@ -0,0 +1,318 @@
// 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_LININTEG_DOMAIN_KERNELS_HPP
#define MFEM_LININTEG_DOMAIN_KERNELS_HPP
#include "../../fem/kernels.hpp"
#include "../../general/forall.hpp"
#include "../fem.hpp"
/// \cond DO_NOT_DOCUMENT
namespace mfem
{
template <int T_D1D = 0, int T_Q1D = 0>
static void DLFEvalAssemble1D(const int vdim, const int ne, const int d,
const int q, const int map_type,
const int *markers, const real_t *b,
const real_t *detj, const real_t *weights,
const Vector &coeff, real_t *y)
{
{
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_VERIFY(q <= Q, "");
MFEM_VERIFY(d <= D, "");
}
const auto F = coeff.Read();
const auto B = Reshape(b, q, d);
const auto DETJ = Reshape(detj, q, ne);
const bool cst = coeff.Size() == vdim;
const auto C = cst ? Reshape(F, vdim, 1, 1) : Reshape(F, vdim, q, ne);
auto Y = Reshape(y, d, vdim, ne);
mfem::forall_2D(ne, d, 1, [=] MFEM_HOST_DEVICE(int e)
{
if (markers[e] == 0)
{
return;
} // ignore
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED real_t sBt[Q * D];
const DeviceMatrix Bt(sBt, d, q);
kernels::internal::LoadB<D, Q>(d, q, B, sBt);
for (int c = 0; c < vdim; ++c)
{
const real_t cst_val = C(c, 0, 0);
MFEM_FOREACH_THREAD(dx, x, d)
{
real_t u = 0;
for (int qx = 0; qx < q; ++qx)
{
const real_t detJ =
(map_type == FiniteElement::VALUE) ? DETJ(qx, e) : 1.0;
const real_t coeff_val = cst ? cst_val : C(c, qx, e);
u += weights[qx] * coeff_val * detJ * Bt(dx, qx);
}
Y(dx, c, e) += u;
}
}
});
}
template <int T_D1D = 0, int T_Q1D = 0>
static void DLFEvalAssemble2D(const int vdim, const int ne, const int d,
const int q, const int map_type,
const int *markers, const real_t *b,
const real_t *detj, const real_t *weights,
const Vector &coeff, real_t *y)
{
{
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_VERIFY(q <= Q, "");
MFEM_VERIFY(d <= D, "");
}
const auto F = coeff.Read();
const auto B = Reshape(b, q, d);
const auto DETJ = Reshape(detj, q, q, ne);
const auto W = Reshape(weights, q, q);
const bool cst = coeff.Size() == vdim;
const auto C = cst ? Reshape(F, vdim, 1, 1, 1) : Reshape(F, vdim, q, q, ne);
auto Y = Reshape(y, d, d, vdim, ne);
mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE(int e)
{
if (markers[e] == 0)
{
return;
} // ignore
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_SHARED real_t sBt[Q * D];
MFEM_SHARED real_t sQQ[Q * Q];
MFEM_SHARED real_t sQD[Q * D];
const DeviceMatrix Bt(sBt, d, q);
kernels::internal::LoadB<D, Q>(d, q, B, sBt);
const DeviceMatrix QQ(sQQ, q, q);
const DeviceMatrix QD(sQD, q, d);
for (int c = 0; c < vdim; ++c)
{
const real_t cst_val = C(c, 0, 0, 0);
MFEM_FOREACH_THREAD(x, x, q)
{
MFEM_FOREACH_THREAD(y, y, q)
{
const real_t detJ =
(map_type == FiniteElement::VALUE) ? DETJ(x, y, e) : 1.0;
const real_t coeff_val = cst ? cst_val : C(c, x, y, e);
QQ(y, x) = W(x, y) * coeff_val * detJ;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qy, y, q)
{
MFEM_FOREACH_THREAD(dx, x, d)
{
real_t u = 0.0;
for (int qx = 0; qx < q; ++qx)
{
u += QQ(qy, qx) * Bt(dx, qx);
}
QD(qy, dx) = u;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dy, y, d)
{
MFEM_FOREACH_THREAD(dx, x, d)
{
real_t u = 0.0;
for (int qy = 0; qy < q; ++qy)
{
u += QD(qy, dx) * Bt(dy, qy);
}
Y(dx, dy, c, e) += u;
}
}
MFEM_SYNC_THREAD;
}
});
}
template <int T_D1D = 0, int T_Q1D = 0>
static void DLFEvalAssemble3D(const int vdim, const int ne, const int d,
const int q, const int map_type,
const int* markers, const real_t *b,
const real_t *detj, const real_t *weights,
const Vector &coeff, real_t *y)
{
{
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
MFEM_VERIFY(q <= Q, "");
MFEM_VERIFY(d <= D, "");
}
const auto F = coeff.Read();
const auto B = Reshape(b, q, d);
const auto DETJ = Reshape(detj, q, q, q, ne);
const auto W = Reshape(weights, q, q, q);
const bool cst_coeff = coeff.Size() == vdim;
const auto C =
cst_coeff ? Reshape(F, vdim, 1, 1, 1, 1) : Reshape(F, vdim, q, q, q, ne);
auto Y = Reshape(y, d, d, d, vdim, ne);
mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE(int e)
{
if (markers[e] == 0)
{
return;
} // ignore
constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQD = (Q >= D) ? Q : D;
real_t u[D];
MFEM_SHARED real_t sBt[Q * D];
const DeviceMatrix Bt(sBt, d, q);
kernels::internal::LoadB<D, Q>(d, q, B, sBt);
MFEM_SHARED real_t sQQQ[MQD * MQD * MQD];
const DeviceCube QQQ(sQQQ, MQD, MQD, MQD);
for (int c = 0; c < vdim; ++c)
{
const real_t cst_val = C(c, 0, 0, 0, 0);
MFEM_FOREACH_THREAD(x, x, q)
{
MFEM_FOREACH_THREAD(y, y, q)
{
for (int z = 0; z < q; ++z)
{
const real_t detJ = (map_type == FiniteElement::VALUE)
? DETJ(x, y, z, e)
: 1.0;
const real_t coeff_val =
cst_coeff ? cst_val : C(c, x, y, z, e);
QQQ(z, y, x) = W(x, y, z) * coeff_val * detJ;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qx, x, q)
{
MFEM_FOREACH_THREAD(qy, y, q)
{
for (int dz = 0; dz < d; ++dz)
{
u[dz] = 0.0;
}
for (int qz = 0; qz < q; ++qz)
{
const real_t ZYX = QQQ(qz, qy, qx);
for (int dz = 0; dz < d; ++dz)
{
u[dz] += ZYX * Bt(dz, qz);
}
}
for (int dz = 0; dz < d; ++dz)
{
QQQ(dz, qy, qx) = u[dz];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz, y, d)
{
MFEM_FOREACH_THREAD(qx, x, q)
{
for (int dy = 0; dy < d; ++dy)
{
u[dy] = 0.0;
}
for (int qy = 0; qy < q; ++qy)
{
const real_t zYX = QQQ(dz, qy, qx);
for (int dy = 0; dy < d; ++dy)
{
u[dy] += zYX * Bt(dy, qy);
}
}
for (int dy = 0; dy < d; ++dy)
{
QQQ(dz, dy, qx) = u[dy];
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz, y, d)
{
MFEM_FOREACH_THREAD(dy, x, d)
{
for (int dx = 0; dx < d; ++dx)
{
u[dx] = 0.0;
}
for (int qx = 0; qx < q; ++qx)
{
const real_t zyX = QQQ(dz, dy, qx);
for (int dx = 0; dx < d; ++dx)
{
u[dx] += zyX * Bt(dx, qx);
}
}
for (int dx = 0; dx < d; ++dx)
{
Y(dx, dy, dz, c, e) += u[dx];
}
}
}
MFEM_SYNC_THREAD;
}
});
}
template <int DIM, int T_D1D, int T_Q1D>
DomainLFIntegrator::AssembleKernelType
DomainLFIntegrator::AssembleKernels::Kernel()
{
switch (DIM)
{
case 1:
return DLFEvalAssemble1D<T_D1D, T_Q1D>;
case 2:
return DLFEvalAssemble2D<T_D1D, T_Q1D>;
case 3:
return DLFEvalAssemble3D<T_D1D, T_Q1D>;
}
MFEM_ABORT("");
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
#endif
+1
View File
@@ -947,6 +947,7 @@ int Quadrature1D::CheckOpen(int type)
case OpenUniform:
case ClosedUniform:
case OpenHalfUniform:
case ClosedGL:
return type; // all types can work as open
default:
return Invalid;
+29 -29
View File
@@ -346,13 +346,13 @@ private:
template<typename T>
T operator() (const blitz::TinyVector<T,3>& x) const
{
int el_order=el->GetOrder();
T u1[el_order+1];
T u2[el_order+1];
T u3[el_order+1];
TmplPoly_1D::CalcBernstein(el_order, x[0], u1);
TmplPoly_1D::CalcBernstein(el_order, x[1], u2);
TmplPoly_1D::CalcBernstein(el_order, x[2], u3);
const int el_order = el->GetOrder();
std::vector<T> u1(el_order+1);
std::vector<T> u2(el_order+1);
std::vector<T> u3(el_order+1);
TmplPoly_1D::CalcBernstein(el_order, x[0], u1.data());
TmplPoly_1D::CalcBernstein(el_order, x[1], u2.data());
TmplPoly_1D::CalcBernstein(el_order, x[2], u3.data());
const Array<int>& dof_map=el->GetDofMap();
@@ -370,17 +370,17 @@ private:
template<typename T>
blitz::TinyVector<T,3> grad(const blitz::TinyVector<T,3>& x) const
{
int el_order=el->GetOrder();
T u1[el_order+1];
T u2[el_order+1];
T u3[el_order+1];
T d1[el_order+1];
T d2[el_order+1];
T d3[el_order+1];
const int el_order = el->GetOrder();
std::vector<T> u1(el_order+1);
std::vector<T> u2(el_order+1);
std::vector<T> u3(el_order+1);
std::vector<T> d1(el_order+1);
std::vector<T> d2(el_order+1);
std::vector<T> d3(el_order+1);
TmplPoly_1D::CalcBernstein(el_order,x[0], u1, d1);
TmplPoly_1D::CalcBernstein(el_order,x[1], u2, d2);
TmplPoly_1D::CalcBernstein(el_order,x[2], u3, d3);
TmplPoly_1D::CalcBernstein(el_order,x[0], u1.data(), d1.data());
TmplPoly_1D::CalcBernstein(el_order,x[1], u2.data(), d2.data());
TmplPoly_1D::CalcBernstein(el_order,x[2], u3.data(), d3.data());
blitz::TinyVector<T,3> res(T(0.0),T(0.0),T(0.0));
@@ -415,11 +415,11 @@ private:
template<typename T>
T operator() (const blitz::TinyVector<T,2>& x) const
{
int el_order=el->GetOrder();
T u1[el_order+1];
T u2[el_order+1];
TmplPoly_1D::CalcBernstein(el_order, x[0], u1);
TmplPoly_1D::CalcBernstein(el_order, x[1], u2);
const int el_order = el->GetOrder();
std::vector<T> u1(el_order+1);
std::vector<T> u2(el_order+1);
TmplPoly_1D::CalcBernstein(el_order, x[0], u1.data());
TmplPoly_1D::CalcBernstein(el_order, x[1], u2.data());
const Array<int>& dof_map=el->GetDofMap();
@@ -437,14 +437,14 @@ private:
template<typename T>
blitz::TinyVector<T,2> grad(const blitz::TinyVector<T,2>& x) const
{
int el_order=el->GetOrder();
T u1[el_order+1];
T u2[el_order+1];
T d1[el_order+1];
T d2[el_order+1];
const int el_order = el->GetOrder();
std::vector<T> u1(el_order+1);
std::vector<T> u2(el_order+1);
std::vector<T> d1(el_order+1);
std::vector<T> d2(el_order+1);
TmplPoly_1D::CalcBernstein(el_order,x[0], u1, d1);
TmplPoly_1D::CalcBernstein(el_order,x[1], u2, d2);
TmplPoly_1D::CalcBernstein(el_order,x[0], u1.data(), d1.data());
TmplPoly_1D::CalcBernstein(el_order,x[1], u2.data(), d2.data());
blitz::TinyVector<T,2> res(T(0.0),T(0.0));
+1 -1
View File
@@ -78,7 +78,7 @@ namespace mfem
public: \
const char *kernel_name = MFEM_KERNEL_NAME(KernelName); \
using KernelSignature = KernelType; \
template <MFEM_PARAM_LIST P3> static MFEM_EXPORT KernelSignature Kernel(); \
template <MFEM_PARAM_LIST P3> static KernelSignature Kernel(); \
static MFEM_EXPORT KernelSignature Fallback(MFEM_PARAM_LIST P1); \
static MFEM_EXPORT KernelName &Get() { \
static KernelName table; \
+10 -32
View File
@@ -51,7 +51,7 @@ void LinearFormExtension::Assemble()
{
// scan the attributes to set the markers to 0 or 1
const int NE = fes.GetNE();
const auto attr = attributes.Read();
const auto attr = attributes->Read();
const auto dimk = domain_integs_marker_k->Read();
auto markers_w = markers.Write();
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
@@ -93,13 +93,14 @@ void LinearFormExtension::Assemble()
else
{
// scan the attributes to set the markers to 0 or 1
const int NBE = bdr_attributes.Size();
const auto attr = bdr_attributes.Read();
const int NBE = bdr_face_attributes->Size();
const auto attr = bdr_face_attributes->Read();
const auto attr_markers = boundary_integs_marker_k->Read();
auto markers_w = bdr_markers.Write();
mfem::forall(NBE, [=] MFEM_HOST_DEVICE (int e)
mfem::forall(NBE, [=] MFEM_HOST_DEVICE(int e)
{
markers_w[e] = attr_markers[attr[e]-1] == 1;
markers_w[e] =
attr[e] > 0 ? (attr_markers[attr[e] - 1] == 1) : false;
});
}
@@ -125,8 +126,7 @@ void LinearFormExtension::Update()
//markers.UseDevice(true);
// Gather the attributes on the host from all the elements
attributes.SetSize(NE);
for (int i = 0; i < NE; ++i) { attributes[i] = mesh.GetAttribute(i); }
attributes = &mesh.GetElementAttributes();
elem_restrict_lex = fes.GetElementRestriction(ordering);
MFEM_VERIFY(elem_restrict_lex, "Element restriction not available");
@@ -136,34 +136,12 @@ void LinearFormExtension::Update()
if (lf->boundary_integs.Size() > 0)
{
const int nf_bdr = fes.GetNFbyType(FaceType::Boundary);
bdr_face_attributes = &mesh.GetBdrFaceAttributes();
const int nf_bdr = bdr_face_attributes->Size();
bdr_markers.SetSize(nf_bdr);
// bdr_markers.UseDevice(true);
// The face restriction will give us "face E-vectors" on the boundary that
// are numbered in the order of the faces of mesh. This numbering will be
// different than the numbering of the boundary elements. We compute
// mappings so that the array `bdr_attributes[i]` gives the boundary
// attribute of the `i`th boundary face in the mesh face order.
std::unordered_map<int,int> f_to_be;
for (int i = 0; i < mesh.GetNBE(); ++i)
{
const int f = mesh.GetBdrElementFaceIndex(i);
f_to_be[f] = i;
}
MFEM_VERIFY(size_t(nf_bdr) == f_to_be.size(), "Incompatible sizes");
bdr_attributes.SetSize(nf_bdr);
int f_ind = 0;
for (int f = 0; f < mesh.GetNumFaces(); ++f)
{
if (f_to_be.find(f) != f_to_be.end())
{
const int be = f_to_be[f];
bdr_attributes[f_ind] = mesh.GetBdrAttribute(be);
++f_ind;
}
}
bdr_restrict_lex =
dynamic_cast<const FaceRestriction*>(
fes.GetFaceRestriction(ordering, FaceType::Boundary,
+2 -1
View File
@@ -25,7 +25,8 @@ class LinearForm;
class LinearFormExtension
{
/// Attributes of all mesh elements.
Array<int> attributes, bdr_attributes;
const Array<int> *attributes; // Not owned
const Array<int> *bdr_face_attributes; // Not owned
/// Temporary markers for device kernels.
Array<int> markers, bdr_markers;
+20
View File
@@ -35,6 +35,19 @@ void LinearFormIntegrator::AssembleRHSElementVect(
mfem_error("LinearFormIntegrator::AssembleRHSElementVect(...)");
}
DomainLFIntegrator::DomainLFIntegrator(Coefficient &QF, int a, int b)
: DeltaLFIntegrator(QF), Q(QF), oa(a), ob(b)
{
static Kernels kernels;
}
DomainLFIntegrator::DomainLFIntegrator(Coefficient &QF,
const IntegrationRule *ir)
: DeltaLFIntegrator(QF, ir), Q(QF), oa(1), ob(1)
{
static Kernels kernels;
}
void DomainLFIntegrator::AssembleRHSElementVect(const FiniteElement &el,
ElementTransformation &Tr,
Vector &elvect)
@@ -266,6 +279,13 @@ void BoundaryTangentialLFIntegrator::AssembleRHSElementVect(
}
}
VectorDomainLFIntegrator::VectorDomainLFIntegrator(VectorCoefficient &QF,
const IntegrationRule *ir)
: DeltaLFIntegrator(QF, ir), Q(QF)
{
static DomainLFIntegrator::Kernels kernels;
}
void VectorDomainLFIntegrator::AssembleRHSElementVect(
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
{
+32 -11
View File
@@ -18,6 +18,8 @@
#include <random>
#include "integrator.hpp"
#include "kernel_dispatch.hpp"
namespace mfem
{
@@ -109,14 +111,12 @@ class DomainLFIntegrator : public DeltaLFIntegrator
int oa, ob;
public:
/// Constructs a domain integrator with a given Coefficient
DomainLFIntegrator(Coefficient &QF, int a = 2, int b = 0)
// the old default was a = 1, b = 1
// for simple elliptic problems a = 2, b = -2 is OK
: DeltaLFIntegrator(QF), Q(QF), oa(a), ob(b) { }
/// the old default was a = 1, b = 1
/// for simple elliptic problems a = 2, b = -2 is OK
DomainLFIntegrator(Coefficient &QF, int a = 2, int b = 0);
/// Constructs a domain integrator with a given Coefficient
DomainLFIntegrator(Coefficient &QF, const IntegrationRule *ir)
: DeltaLFIntegrator(QF, ir), Q(QF), oa(1), ob(1) { }
DomainLFIntegrator(Coefficient &QF, const IntegrationRule *ir);
bool SupportsDevice() const override { return true; }
@@ -136,6 +136,22 @@ public:
Vector &elvect) override;
using LinearFormIntegrator::AssembleRHSElementVect;
/// args: vdim, ne, d1d, q1d, map_type, markers, B, detJ, W, coeff, y
using AssembleKernelType = void (*)(const int, const int, const int,
const int, const int, const int *,
const real_t *, const real_t *,
const real_t *, const Vector &coeff,
real_t *y);
/// parameters: use DIM, T_D1D, T_Q1D
MFEM_REGISTER_KERNELS(AssembleKernels, AssembleKernelType, (int, int, int));
struct Kernels { Kernels(); };
template <int DIM, int D1D, int Q1D> static void AddSpecialization()
{
AssembleKernels::Specialization<DIM, D1D, Q1D>::Add();
}
};
/// Class for domain integrator $ L(v) := (f, \nabla v) $
@@ -256,14 +272,13 @@ private:
public:
/// Constructs a domain integrator with a given VectorCoefficient
VectorDomainLFIntegrator(VectorCoefficient &QF)
: DeltaLFIntegrator(QF), Q(QF) { }
VectorDomainLFIntegrator(VectorCoefficient &QF,
const IntegrationRule *ir = nullptr);
bool SupportsDevice() const override { return true; }
/// Method defining assembly on device
void AssembleDevice(const FiniteElementSpace &fes,
const Array<int> &markers,
void AssembleDevice(const FiniteElementSpace &fes, const Array<int> &markers,
Vector &b) override;
/** Given a particular Finite Element and a transformation (Tr)
@@ -277,6 +292,12 @@ public:
Vector &elvect) override;
using LinearFormIntegrator::AssembleRHSElementVect;
template <int DIM, int D1D, int Q1D> static void AddSpecialization()
{
// uses the same kernels for assembly
DomainLFIntegrator::AssembleKernels::Specialization<DIM, D1D, Q1D>::Add();
}
};
/** Class for domain integrator $ L(v) := (f, \nabla v) $, where
@@ -544,7 +565,7 @@ public:
Specifically, given the Dirichlet data $u_D$, the linear form assembles the
following integrals on the boundary:
$$
\sigma \langle u_D, (Q \nabla v)) \cdot n \rangle + \kappa \langle {h^{-1} Q} u_D, v \rangle,
\sigma \langle u_D, (Q \nabla v) \cdot n \rangle + \kappa \langle {h^{-1} Q} u_D, v \rangle,
$$
where Q is a scalar or matrix diffusion coefficient and v is the test
function. The parameters $\sigma$ and $\kappa$ should be the same as the ones
+264 -22
View File
@@ -14,9 +14,11 @@
#include "../../general/forall.hpp"
#include <climits>
#include "../pbilinearform.hpp"
#include "../../fem/fe/face_map_utils.hpp"
// Specializations
#include "lor_h1.hpp"
#include "lor_dg.hpp"
#include "lor_nd.hpp"
#include "lor_rt.hpp"
@@ -54,17 +56,18 @@ bool BatchedLORAssembly::FormIsSupported(BilinearForm &a)
// Batched LOR requires all tensor elements
if (!UsesTensorBasis(*a.FESpace())) { return false; }
if (dynamic_cast<const H1_FECollection*>(fec))
if (dynamic_cast<const H1_FECollection*>(fec) ||
dynamic_cast<const DG_FECollection*>(fec))
{
if (HasIntegrators<DiffusionIntegrator, MassIntegrator>(a)) { return true; }
return HasIntegrators<DiffusionIntegrator, MassIntegrator>(a);
}
else if (dynamic_cast<const ND_FECollection*>(fec))
{
if (HasIntegrators<CurlCurlIntegrator, VectorFEMassIntegrator>(a)) { return true; }
return HasIntegrators<CurlCurlIntegrator, VectorFEMassIntegrator>(a);
}
else if (dynamic_cast<const RT_FECollection*>(fec))
{
if (HasIntegrators<DivDivIntegrator, VectorFEMassIntegrator>(a)) { return true; }
return HasIntegrators<DivDivIntegrator, VectorFEMassIntegrator>(a);
}
return false;
}
@@ -75,12 +78,14 @@ void BatchedLORAssembly::FormLORVertexCoordinates(FiniteElementSpace &fes_ho,
Mesh &mesh_ho = *fes_ho.GetMesh();
mesh_ho.EnsureNodes();
const bool dg = fes_ho.IsDGSpace();
// Get nodal points at the LOR vertices
const int dim = mesh_ho.Dimension();
const int sdim = mesh_ho.SpaceDimension();
const int nel_ho = mesh_ho.GetNE();
const int order = fes_ho.GetMaxElementOrder();
const int nd1d = order + 1;
const int nd1d = dg ? order + 2 : order + 1;
const int ndof_per_el = static_cast<int>(pow(nd1d, dim));
const GridFunction *nodal_gf = mesh_ho.GetNodes();
@@ -92,7 +97,8 @@ void BatchedLORAssembly::FormLORVertexCoordinates(FiniteElementSpace &fes_ho,
Vector nodal_evec(nodal_restriction->Height());
nodal_restriction->Mult(*nodal_gf, nodal_evec);
IntegrationRule ir = GetCollocatedIntRule(fes_ho);
const IntegrationRule ir = GetLobattoIntRule(
mesh_ho.GetTypicalElementGeometry(), nd1d);
// Map from nodal E-vector to Q-vector at the LOR vertex points
X_vert.SetSize(sdim*ndof_per_el*nel_ho);
@@ -159,6 +165,7 @@ int BatchedLORAssembly::FillI(SparseMatrix &A) const
const auto K = dof_glob2loc_offsets_.Read();
const auto map = Reshape(sparse_mapping.Read(), nnz_per_row, ndof_per_el);
auto I = A.WriteI();
mfem::forall(nvdof + 1, [=] MFEM_HOST_DEVICE (int ii) { I[ii] = 0; });
@@ -358,6 +365,177 @@ void BatchedLORAssembly::FillJAndData(SparseMatrix &A) const
});
}
void BatchedLORAssembly::SparseIJToCSR_DG(OperatorHandle &A) const
{
const int ndof_per_el = fes_ho.GetFE(0)->GetDof();
const int nel_ho = fes_ho.GetNE();
const int nnz_per_row = sparse_ij.Size()/ndof_per_el/nel_ho;
const int dim = fes_ho.GetMesh()->Dimension();
const int nrows = nel_ho*ndof_per_el;
const int p = fes_ho.GetMaxElementOrder();
const int pp1 = p + 1;
const int nnz = nrows*nnz_per_row;
const int face_nbr_vsize = [&]()
{
#ifdef MFEM_USE_MPI
if (auto *par_fes = dynamic_cast<ParFiniteElementSpace*>(&fes_ho))
{
return par_fes->GetFaceNbrVSize();
}
#endif
return 0;
}();
// If A contains an existing SparseMatrix, reuse it (and try to reuse its
// I, J, A arrays if they are big enough)
SparseMatrix *A_mat = A.Is<SparseMatrix>();
if (!A_mat)
{
A_mat = new SparseMatrix;
A.Reset(A_mat);
}
// The second argument (nrows + face_nbr_vsize) accounts for additional
// columns contributed by DG face neighbors in parallel finite element
// spaces. In serial, face_nbr_vsize is set to 0.
A_mat->OverrideSize(nrows, nrows + face_nbr_vsize);
EnsureCapacity(A_mat->GetMemoryI(), nrows + 1);
EnsureCapacity(A_mat->GetMemoryJ(), nnz);
EnsureCapacity(A_mat->GetMemoryData(), nnz);
Array<int> nbr_info(nel_ho*3*2*dim);
auto h_nbr_info = Reshape(nbr_info.HostWrite(), nel_ho, 2*dim, 3);
const int num_faces = fes_ho.GetMesh()->GetNumFaces();
for (int f = 0; f < num_faces; f++)
{
Mesh::FaceInformation finfo = fes_ho.GetMesh()->GetFaceInformation(f);
int e0 = finfo.element[0].index;
int f0 = finfo.element[0].local_face_id;
if (finfo.IsBoundary())
{
h_nbr_info(e0,f0,0) = -1;
h_nbr_info(e0,f0,1)= -1;
h_nbr_info(e0,f0,2)= -1;
}
else if (finfo.IsShared())
{
// Face neighbors elements are indexed after the last local element
h_nbr_info(e0,f0,0) = nel_ho + finfo.element[1].index;
h_nbr_info(e0,f0,1)= finfo.element[1].orientation;
h_nbr_info(e0,f0,2)= finfo.element[1].local_face_id;
}
else if (finfo.IsInterior())
{
int e1 = finfo.element[1].index;
int f1 = finfo.element[1].local_face_id;
h_nbr_info(e0,f0,0) = e1;
h_nbr_info(e0,f0,1)= finfo.element[1].orientation;
h_nbr_info(e0,f0,2)= f1;
h_nbr_info(e1,f1,0) = e0;
h_nbr_info(e1,f1,1) = finfo.element[1].orientation;
h_nbr_info(e1,f1,2) = f0;
}
};
auto h_I = A_mat->HostWriteI();
h_I[0] = 0;
for (int i = 0; i < nrows; ++i)
{
const int iel_ho = i / ndof_per_el;
const int iloc = i % ndof_per_el;
static const int lex_map_2[4] = {3, 1, 0, 2};
static const int lex_map_3[6] = {4, 2, 1, 3, 0, 5};
const int local_i[3] = {iloc % pp1, (iloc/pp1)%pp1, iloc/pp1/pp1};
int bdr_count = 0;
for (int n_idx = 0; n_idx < dim; ++n_idx)
{
for (int e_i = 0; e_i < 2; ++e_i)
{
const int j_lex = e_i + n_idx*2;
const int f = (dim == 3) ? lex_map_3[j_lex]:lex_map_2[j_lex];
const bool boundary = (local_i[n_idx] == e_i * p);
if (boundary)
{
int neighbor_idx = h_nbr_info(iel_ho, f, 0);
if (neighbor_idx == -1)
{
++bdr_count;
}
}
}
}
h_I[i+1] = h_I[i] + (nnz_per_row - bdr_count);
}
const auto V = Reshape(sparse_ij.Read(), nnz_per_row, ndof_per_el, nel_ho);
auto J = A_mat->WriteJ();
auto AV = A_mat->WriteData();
auto I = A_mat->ReadI();
auto d_nbr_info = Reshape(nbr_info.Read(), nel_ho, 2*dim, 3);
mfem::forall(nrows, [=] MFEM_HOST_DEVICE (int i)
{
const int e = i / ndof_per_el;
const int iloc = i % ndof_per_el;
const int local_x = iloc % pp1;
const int local_y = (iloc/pp1)%pp1;
const int local_z = iloc/pp1/pp1;
const int local_i[3] = {local_x, local_y, local_z};
int offset = I[i];
static const int lex_map_2[4] = {3, 1, 0, 2};
static const int lex_map_3[6] = {4,2,1,3,0,5};
const int *lex_map = (dim == 2) ? lex_map_2 : lex_map_3;
AV[offset] = V(0, iloc, e);
J[offset] = i;
++offset;
for (int n_idx = 0; n_idx < dim; ++n_idx)
{
// qi is the face lexicographic index, obtained by taking the
// lexicographic index of the coordinates ommiting n_idx.
int qi = 0;
int stride = 1;
for (int d = 0; d < dim; ++d)
{
if (d != n_idx)
{
qi += local_i[d]*stride;
stride *= pp1;
}
}
for (int e_i = 0; e_i < 2; ++e_i)
{
const int j_lex = e_i + n_idx*2;
const int f = lex_map[j_lex];
const bool bdr = (local_i[n_idx] == e_i * p);
if (bdr)
{
const int nbr_e = d_nbr_info(e, f, 0);
const int nbr_ori = d_nbr_info(e, f, 1);
const int nbr_f = d_nbr_info(e, f, 2);
if (nbr_e != -1)
{
const int nbr_loc_idx = internal::FaceIdxToVolIdx(
dim, qi, pp1, f, nbr_f, 1, nbr_ori);
J[offset] = nbr_e*ndof_per_el + nbr_loc_idx;
AV[offset] = V(f+1, iloc, e);
++offset;
}
}
else
{
int shift = (e_i == 0) ? -1 : 1;
for (int n = 0; n < n_idx; ++n) { shift *= pp1; }
J[offset] = i + shift;
AV[offset] = V(f+1, iloc, e);
++offset;
}
}
}
});
}
void BatchedLORAssembly::SparseIJToCSR(OperatorHandle &A) const
{
const int nvdof = fes_ho.GetVSize();
@@ -372,12 +550,11 @@ void BatchedLORAssembly::SparseIJToCSR(OperatorHandle &A) const
}
A_mat->OverrideSize(nvdof, nvdof);
EnsureCapacity(A_mat->GetMemoryI(), nvdof + 1);
A_mat->GetMemoryI().New(nvdof+1, Device::GetDeviceMemoryType());
int nnz = FillI(*A_mat);
A_mat->GetMemoryJ().New(nnz, Device::GetDeviceMemoryType());
A_mat->GetMemoryData().New(nnz, Device::GetDeviceMemoryType());
const int nnz = FillI(*A_mat);
EnsureCapacity(A_mat->GetMemoryJ(), nnz);
EnsureCapacity(A_mat->GetMemoryData(), nnz);
FillJAndData(*A_mat);
}
@@ -431,6 +608,19 @@ void BatchedLORAssembly::AssembleWithoutBC(BilinearForm &a, OperatorHandle &A)
// Assemble the matrix, depending on what the form is.
// This fills in the arrays sparse_ij and sparse_mapping.
const FiniteElementCollection *fec = fes_ho.FEColl();
// Handle DG case separately, because assembly of CSR matrix requires
// handling face terms.
if (dynamic_cast<const DG_FECollection*>(fec))
{
if (HasIntegrators<DiffusionIntegrator, MassIntegrator>(a))
{
AssemblyKernel<BatchedLOR_DG>(a);
}
SparseIJToCSR_DG(A);
return;
}
if (dynamic_cast<const H1_FECollection*>(fec))
{
if (HasIntegrators<DiffusionIntegrator, MassIntegrator>(a))
@@ -453,10 +643,47 @@ void BatchedLORAssembly::AssembleWithoutBC(BilinearForm &a, OperatorHandle &A)
}
}
return SparseIJToCSR(A);
SparseIJToCSR(A);
}
#ifdef MFEM_USE_MPI
void BatchedLORAssembly::ParAssemble_DG(SparseMatrix &A_local,
OperatorHandle &A)
{
auto &par_fes = static_cast<ParFiniteElementSpace&>(fes_ho);
// handle the case when 'a' contains off-diagonal
const int lvsize = par_fes.GetVSize();
const Array<HYPRE_BigInt> &face_nbr_glob_ldof =
par_fes.GetFaceNbrGlobalDofMapArray();
const HYPRE_BigInt ldof_offset = par_fes.GetMyDofOffset();
const int nnz_local = A_local.NumNonZeroElems();
Array<HYPRE_BigInt> glob_J(nnz_local);
const HYPRE_BigInt *d_face_nbr_glob_ldof = face_nbr_glob_ldof.Read();
const int *d_J = A_local.ReadJ();
HYPRE_BigInt *d_glob_J = glob_J.Write();
mfem::forall(nnz_local, [=] MFEM_HOST_DEVICE (int i)
{
if (d_J[i] < lvsize)
{
d_glob_J[i] = d_J[i] + ldof_offset;
}
else
{
d_glob_J[i] = d_face_nbr_glob_ldof[d_J[i] - lvsize];
}
});
A.Reset(new HypreParMatrix(
par_fes.GetComm(), lvsize, par_fes.GlobalVSize(),
par_fes.GlobalVSize(), A_local.HostReadWriteI(),
glob_J.HostReadWrite(), A_local.HostReadWriteData(),
par_fes.GetDofOffsets(), par_fes.GetDofOffsets()));
}
void BatchedLORAssembly::ParAssemble(
BilinearForm &a, const Array<int> &ess_dofs, OperatorHandle &A)
{
@@ -464,13 +691,18 @@ void BatchedLORAssembly::ParAssemble(
OperatorHandle A_local;
AssembleWithoutBC(a, A_local);
ParBilinearForm *pa =
dynamic_cast<ParBilinearForm*>(&a);
pa->ParallelRAP(*A_local.As<SparseMatrix>(), A, true);
A.As<HypreParMatrix>()->EliminateBC(ess_dofs,
Operator::DiagonalPolicy::DIAG_ONE);
if (dynamic_cast<const DG_FECollection*>(fes_ho.FEColl()))
{
ParAssemble_DG(*A_local.As<SparseMatrix>(), A);
}
else
{
ParBilinearForm *pa =
dynamic_cast<ParBilinearForm*>(&a);
pa->ParallelRAP(*A_local.As<SparseMatrix>(), A, true);
A.As<HypreParMatrix>()->EliminateBC(ess_dofs,
Operator::DiagonalPolicy::DIAG_ONE);
}
}
#endif
@@ -504,12 +736,22 @@ BatchedLORAssembly::BatchedLORAssembly(FiniteElementSpace &fes_ho_)
FormLORVertexCoordinates(fes_ho, X_vert);
}
IntegrationRule GetCollocatedIntRule(FiniteElementSpace &fes)
IntegrationRule GetLobattoIntRule(Geometry::Type geom, int nd1d)
{
IntegrationRules irs(0, Quadrature1D::GaussLobatto);
const Geometry::Type geom = fes.GetMesh()->GetTypicalElementGeometry();
const int nd1d = fes.GetMaxElementOrder() + 1;
return irs.Get(geom, 2*nd1d - 3);
}
IntegrationRule GetCollocatedIntRule(FiniteElementSpace &fes)
{
const Geometry::Type geom = fes.GetMesh()->GetTypicalElementGeometry();
return GetLobattoIntRule(geom, fes.GetMaxElementOrder() + 1);
}
IntegrationRule GetCollocatedFaceIntRule(FiniteElementSpace &fes)
{
const Geometry::Type geom = fes.GetMesh()->GetTypicalFaceGeometry();
return GetLobattoIntRule(geom, fes.GetMaxElementOrder() + 1);
}
} // namespace mfem
+32 -2
View File
@@ -25,6 +25,7 @@ namespace mfem
/// supported, currently:
///
/// - H1 diffusion + mass
/// - DG diffusion + mass (in progress)
/// - ND curl-curl + mass
/// - RT div-div + mass
///
@@ -73,6 +74,9 @@ public:
/// Return the vertices of the LOR mesh in E-vector format
const Vector &GetLORVertexCoordinates() { return X_vert; }
/// Specialized implementation of SparseIJToCSR for DG spaces.
void SparseIJToCSR_DG(OperatorHandle &A) const;
protected:
/// After assembling the "sparse IJ" format, convert it to CSR.
void SparseIJToCSR(OperatorHandle &A) const;
@@ -105,6 +109,9 @@ public:
void FillJAndData(SparseMatrix &A) const;
#ifdef MFEM_USE_MPI
/// Assemble the parallel DG matrix (with shared faces).
void ParAssemble_DG(SparseMatrix &A_local, OperatorHandle &A);
/// Assemble the system in parallel and place the result in @a A.
void ParAssemble(BilinearForm &a, const Array<int> &ess_dofs,
OperatorHandle &A);
@@ -128,9 +135,8 @@ void EnsureCapacity(Memory<T> &mem, int capacity)
/// Return the first domain integrator in the form @a i of type @a T.
template <typename T>
static T *GetIntegrator(BilinearForm &a)
static T *GetIntegrator(Array<BilinearFormIntegrator*> *integs)
{
Array<BilinearFormIntegrator*> *integs = a.GetDBFI();
if (integs != NULL)
{
for (auto *i : *integs)
@@ -144,8 +150,32 @@ static T *GetIntegrator(BilinearForm &a)
return nullptr;
}
template <typename T>
static T *GetIntegrator(BilinearForm &a)
{
return GetIntegrator<T>(a.GetDBFI());
}
template <typename T>
static T *GetInteriorFaceIntegrator(BilinearForm &a)
{
return GetIntegrator<T>(a.GetFBFI());
}
/// @brief Return the Gauss-Lobatto rule for geometry @a geom with @a nd1d
/// points per dimension.
IntegrationRule GetLobattoIntRule(Geometry::Type geom, int nd1d);
/// @brief Return the Gauss-Lobatto rule collocated with the element nodes.
///
/// Assumes @a fes uses Gauss-Lobatto basis.
IntegrationRule GetCollocatedIntRule(FiniteElementSpace &fes);
/// @brief Return the Gauss-Lobatto rule collocated with face nodes.
///
/// Assumes @a fes uses Gauss-Lobatto basis.
IntegrationRule GetCollocatedFaceIntRule(FiniteElementSpace &fes);
template <typename INTEGRATOR>
void ProjectLORCoefficient(BilinearForm &a, CoefficientVector &coeff_vector)
{
+79
View File
@@ -0,0 +1,79 @@
// 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_LOR_DG
#define MFEM_LOR_DG
#include "lor_batched.hpp"
namespace mfem
{
// BatchedLORKernel specialization for DG spaces. Not user facing. See the
// classes BatchedLORAssembly and BatchedLORKernel .
class BatchedLOR_DG : BatchedLORKernel
{
IntegrationRule ir_face; ///< Collocated Gauss-Lobatto face quadrature rule.
real_t kappa; ///< DG penalty parameter.
public:
template <int ORDER, int SDIM> void Assemble2D();
template <int ORDER> void Assemble3D();
BatchedLOR_DG(BilinearForm &a,
FiniteElementSpace &fes_ho_,
Vector &X_vert_,
Vector &sparse_ij_,
Array<int> &sparse_mapping_)
: BatchedLORKernel(fes_ho_, X_vert_, sparse_ij_, sparse_mapping_),
ir_face(GetLobattoIntRule(fes_ho_.GetMesh()->GetTypicalFaceGeometry(),
fes_ho_.GetMaxElementOrder() + 1))
{
ProjectLORCoefficient<MassIntegrator>(a, c1);
ProjectLORCoefficient<DiffusionIntegrator>(a, c2);
auto *integ = GetInteriorFaceIntegrator<DGDiffusionIntegrator>(a);
if (integ)
{
kappa = integ->GetPenaltyParameter();
}
else
{
kappa = 0.0;
}
}
/// @brief Compute and return the face info array.
///
/// The face info array has shape (6, nf), where @a nf is the number of
/// faces. For each face @a i, the column (:,i) has entries (e0, f0, o0, e1,
/// f1, o1), where @a e is adjacent element, @a f is the local face index,
/// and @a o is the orientation. For boundary and shared faces, (e1, f1, o1)
/// are all set to -1.
Array<int> GetFaceInfo() const;
/// @brief Compute and return the boundary penalty factor.
///
/// The returned vector has shape (nq, nf), where @a nq is the number of
/// nodes per face, and @a nf is the number of faces.
///
/// The boundary penalty factor is $J_f / h = J_f^2 / J_e$ (since $h = J_e /
/// J_f$), where $J_f$ is the face Jacobian determinant, and $J_e$ is the
/// element Jacobian determinant.
Vector GetBdrPenaltyFactor() const;
/// Assemble the face penalty terms in the matrix @a sparse_ij.
void AssembleFaceTerms();
};
}
#include "lor_dg_impl.hpp"
#endif
+392
View File
@@ -0,0 +1,392 @@
// 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.
#pragma once
#include "lor_dg.hpp"
#include "../fe/face_map_utils.hpp"
#include "../../linalg/dtensor.hpp"
#include "../../general/forall.hpp"
namespace mfem
{
Array<int> BatchedLOR_DG::GetFaceInfo() const
{
Mesh &mesh = *fes_ho.GetMesh();
const int nf = mesh.GetNumFaces();
Array<int> face_info(nf * 6); // (e0, f0, o0, e1, f1, o1)
auto h_face_info = Reshape(face_info.HostWrite(), 6, nf);
for (int f = 0; f < nf; ++f)
{
auto finfo = mesh.GetFaceInformation(f);
h_face_info(0, f) = finfo.element[0].index;
h_face_info(1, f) = finfo.element[0].local_face_id;
h_face_info(2, f) = finfo.element[0].orientation;
if (finfo.IsLocal()) // Interior, non-shared face
{
h_face_info(3, f) = finfo.element[1].index;
h_face_info(4, f) = finfo.element[1].local_face_id;
h_face_info(5, f) = finfo.element[1].orientation;
}
else
{
h_face_info(3, f) = -1;
h_face_info(4, f) = -1;
h_face_info(5, f) = -1;
}
}
return face_info;
}
Vector BatchedLOR_DG::GetBdrPenaltyFactor() const
{
Mesh &mesh = *fes_ho.GetMesh();
const int nf = mesh.GetNumFaces();
Array<int> f_int(mesh.GetNFbyType(FaceType::Interior));
Array<int> f_bdr(mesh.GetNFbyType(FaceType::Boundary));
{
int i_int = 0;
int i_bdr = 0;
for (int i = 0; i < nf; ++i)
{
const auto f = mesh.GetFaceInformation(i);
if (f.IsBoundary())
{
f_bdr[i_bdr] = i;
++i_bdr;
}
else if (f.IsInterior())
{
f_int[i_int] = i;
++i_int;
}
}
}
const auto geom = fes_ho.GetMesh()->GetGeometricFactors(
ir, GeometricFactors::DETERMINANTS);
const int nq = ir_face.Size();
Vector face_Jh(nq * nf);
for (const FaceType ft : {FaceType::Interior, FaceType::Boundary})
{
const int nft = mesh.GetNFbyType(ft);
auto *geom_face = mesh.GetFaceGeometricFactors(
ir_face, FaceGeometricFactors::DETERMINANTS, ft);
const L2FaceValues fv = (ft == FaceType::Interior)
? L2FaceValues::DoubleValued
: L2FaceValues::SingleValued;
const int m = (fv == L2FaceValues::DoubleValued) ? 2 : 1;
auto *r = fes_ho.GetFaceRestriction(ElementDofOrdering::LEXICOGRAPHIC, ft, fv);
Vector detJ_r(nq * m * nft);
r->Mult(geom->detJ, detJ_r);
const auto *d_i = (ft == FaceType::Interior) ? f_int.Read() : f_bdr.Read();
const auto d_detJ_face = Reshape(geom_face->detJ.Read(), nq, nft);
const auto d_detJ_r = Reshape(detJ_r.Read(), nq, m, nft);
auto d_face_Jh = Reshape(face_Jh.Write(), nq, nf);
mfem::forall(nft * nq, [=] MFEM_HOST_DEVICE (int ii)
{
const int i = ii % nq;
const int f = ii / nq;
const real_t J_el = 0.5*(d_detJ_r(i, 0, f) + d_detJ_r(i, m==2?1:0, f));
const real_t J_f = d_detJ_face(i, f);
d_face_Jh(i, d_i[f]) = J_f * J_f / J_el;
});
}
return face_Jh;
}
void BatchedLOR_DG::AssembleFaceTerms()
{
Mesh &mesh = *fes_ho.GetMesh();
const int nnz_per_row = 1 + mesh.Dimension()*2;
const int pp1 = fes_ho.GetMaxElementOrder() + 1;
const int nel_ho = mesh.GetNE();
const int nf = mesh.GetNumFaces();
const int nd_face = ir_face.Size();
const int nd = ir.Size();
const int dim = mesh.Dimension();
Array<int> face_info = GetFaceInfo();
const auto d_face_info = Reshape(face_info.Read(), 6, nf);
Vector face_Jh = GetBdrPenaltyFactor();
const auto d_face_Jh = Reshape(face_Jh.Read(), nd_face, nf);
const auto *w_face = ir_face.GetWeights().Read();
// Penalty parameter (avoid capturing *this in lambda)
const real_t d_kappa = kappa;
// Get diffusion coefficient
const bool const_dq = c2.Size() == 1;
const auto DQ = const_dq?Reshape(c2.Read(),1,1):Reshape(c2.Read(),nd,nel_ho);
// Sparse matrix entries
auto V = Reshape(sparse_ij.ReadWrite(), nnz_per_row, nd, nel_ho);
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
{
const int f_0 = d_face_info(1, f);
const int f_1 = d_face_info(4, f);
const int nsides = (f_1 >= 0) ? 2 : 1;
for (int el_i = 0; el_i < nsides; ++el_i)
{
const int e = d_face_info(3*el_i, f);
const int o = d_face_info(3*el_i + 2, f);
const int v_idx = 1 + ((el_i == 0) ? f_0 : f_1);
for (int i = 0; i < nd_face; ++i)
{
const int ii = internal::FaceIdxToVolIdx(dim, i, pp1, f_0, f_1, el_i, o);
const real_t Jh = d_face_Jh(i, f);
const real_t dq = const_dq ? DQ(0,0) : DQ(ii, e);
V(v_idx, ii, e) = -dq*d_kappa*Jh*w_face[i];
}
}
});
}
template <int ORDER, int SDIM>
void BatchedLOR_DG::Assemble2D()
{
MFEM_VERIFY(SDIM == 2, "Surface meshes not currently supported for LOR-DG.")
static constexpr int pp1 = ORDER + 1;
static constexpr int ndof_per_el = pp1*pp1;
static constexpr int nnz_per_row = 5;
const int nel_ho = fes_ho.GetNE();
// Get element geometric factors; calling before AssembleFaceTerms, since
// in AssembleFaceTerms, element Jacobian determinants are used, potentially
// saving recomputation.
const auto factors = GeometricFactors::DETERMINANTS |
GeometricFactors::JACOBIANS;
const auto *geom = fes_ho.GetMesh()->GetGeometricFactors(ir, factors);
// Sparse matrix entries
sparse_ij.SetSize(nnz_per_row*ndof_per_el*nel_ho);
sparse_ij.UseDevice(true);
sparse_ij = 0.0;
auto V = Reshape(sparse_ij.ReadWrite(), nnz_per_row, pp1, pp1, nel_ho);
AssembleFaceTerms();
// Populate Gauss-Lobatto quadrature rule of size (p+1)
IntegrationRule ir_pp1;
QuadratureFunctions1D::GaussLobatto(pp1, &ir_pp1);
Vector glx_pp1(pp1), glw_pp1(pp1);
for (int i = 0; i < pp1; ++i)
{
glx_pp1[i] = ir_pp1[i].x;
glw_pp1[i] = ir_pp1[i].weight;
}
const auto *x_pp1 = glx_pp1.Read();
const auto *w_1d = glw_pp1.Read();
// Get coefficients for mass and diffusion
const bool const_mq = c1.Size() == 1;
const auto MQ = const_mq
? Reshape(c1.Read(), 1, 1, 1)
: Reshape(c1.Read(), pp1, pp1, nel_ho);
const bool const_dq = c2.Size() == 1;
const auto DQ = const_dq
? Reshape(c2.Read(), 1, 1, 1)
: Reshape(c2.Read(), pp1, pp1, nel_ho);
const auto detJ = Reshape(geom->detJ.Read(), pp1, pp1, nel_ho);
const auto J = Reshape(geom->J.Read(), pp1, pp1, 2, 2, nel_ho);
const auto W = Reshape(ir.GetWeights().Read(), pp1, pp1);
mfem::forall(nel_ho, [=] MFEM_HOST_DEVICE (int iel_ho)
{
for (int iy = 0; iy < pp1; ++iy)
{
for (int ix = 0; ix < pp1; ++ix)
{
const real_t mq = const_mq ? MQ(0,0,0) : MQ(ix, iy, iel_ho);
const real_t dq = const_dq ? DQ(0,0,0) : DQ(ix, iy, iel_ho);
for (int n_idx = 0; n_idx < 2; ++n_idx)
{
for (int e_i = 0; e_i < 2; ++e_i)
{
const int i_0 = (n_idx == 0) ? ix + e_i : ix;
const int j_0 = (n_idx == 1) ? iy + e_i : iy;
const bool bdr = (n_idx == 0 && (i_0 == 0 || i_0 == pp1)) ||
(n_idx == 1 && (j_0 == 0 || j_0 == pp1));
if (bdr) { continue; }
static constexpr int lex_map[] = {4, 2, 1, 3};
const int v_idx_lex = e_i + n_idx*2;
const int v_idx = lex_map[v_idx_lex];
const int w_idx = (n_idx == 0) ? iy : ix;
const int x_idx = (n_idx == 0) ? i_0 : j_0;
const real_t J1 = J(ix, iy, n_idx, !n_idx, iel_ho);
const real_t J2 = J(ix, iy, !n_idx, !n_idx, iel_ho);
const real_t Jh = (J1*J1 + J2*J2) / detJ(ix, iy, iel_ho);
V(v_idx, ix, iy, iel_ho) =
-dq * Jh * w_1d[w_idx] / (x_pp1[x_idx] - x_pp1[x_idx -1]);
}
}
V(0, ix, iy, iel_ho) = mq * detJ(ix, iy, iel_ho) * W(ix, iy);
for (int i = 1; i < nnz_per_row; ++i)
{
V(0, ix, iy, iel_ho) -= V(i, ix, iy, iel_ho);
}
}
}
});
}
template <int ORDER>
void BatchedLOR_DG::Assemble3D()
{
static constexpr int pp1 = ORDER + 1;
static constexpr int ndof_per_el = pp1*pp1*pp1;
static constexpr int nnz_per_row = 7;
const int nel_ho = fes_ho.GetNE();
// Get element geometric factors; calling before AssembleFaceTerms, since
// in AssembleFaceTerms, element Jacobian determinants are used, potentially
// saving recomputation.
const auto factors = GeometricFactors::DETERMINANTS |
GeometricFactors::JACOBIANS;
const auto geom = fes_ho.GetMesh()->GetGeometricFactors(ir, factors);
sparse_ij.SetSize(nnz_per_row*ndof_per_el*nel_ho);
sparse_ij.UseDevice(true);
sparse_ij = 0.0;
auto V = Reshape(sparse_ij.Write(), nnz_per_row, pp1, pp1, pp1, nel_ho);
AssembleFaceTerms();
// Populate Gauss-Lobatto quadrature rule of size (p+1)
IntegrationRule ir_pp1;
QuadratureFunctions1D::GaussLobatto(pp1, &ir_pp1);
Vector glx_pp1(pp1), glw_pp1(pp1);
for (int i = 0; i < pp1; ++i)
{
glx_pp1[i] = ir_pp1[i].x;
glw_pp1[i] = ir_pp1[i].weight;
}
const auto *x_pp1 = glx_pp1.Read();
const auto *w_1d = glw_pp1.Read();
const bool const_mq = c1.Size() == 1;
const auto MQ = const_mq
? Reshape(c1.Read(), 1, 1, 1, 1)
: Reshape(c1.Read(), pp1, pp1, pp1, nel_ho);
const bool const_dq = c2.Size() == 1;
const auto DQ = const_dq
? Reshape(c2.Read(), 1, 1, 1, 1)
: Reshape(c2.Read(), pp1, pp1, pp1, nel_ho);
const auto W = Reshape(ir.GetWeights().Read(), pp1, pp1, pp1);
const auto detJ = Reshape(geom->detJ.Read(), pp1, pp1, pp1, nel_ho);
const auto J = Reshape(geom->J.Read(), pp1, pp1, pp1, 3, 3, nel_ho);
mfem::forall(nel_ho, [=] MFEM_HOST_DEVICE (int iel_ho)
{
for (int iz = 0; iz < pp1; ++iz)
{
for (int iy = 0; iy < pp1; ++iy)
{
for (int ix = 0; ix < pp1; ++ix)
{
const real_t mq = const_mq ? MQ(0,0,0,0) : MQ(ix, iy, iz, iel_ho);
const real_t dq = const_dq ? DQ(0,0,0,0) : DQ(ix, iy, iz, iel_ho);
const real_t DETJ = detJ(ix, iy, iz, iel_ho);
for (int n_idx = 0; n_idx < 3; ++n_idx)
{
for (int e_i = 0; e_i < 2; ++e_i)
{
static constexpr int lex_map[] = {5,3,2,4,1,6};
const int v_idx_lex = e_i + n_idx*2;
const int v_idx = lex_map[v_idx_lex];
const int i_0 = (n_idx == 0) ? ix + e_i : ix;
const int j_0 = (n_idx == 1) ? iy + e_i : iy;
const int k_0 = (n_idx == 2) ? iz + e_i : iz;
const bool bdr =
(n_idx == 0 && (i_0 == 0 || i_0 == pp1)) ||
(n_idx == 1 && (j_0 == 0 || j_0 == pp1)) ||
(n_idx == 2 && (k_0 == 0 || k_0 == pp1));
if (bdr) { continue; }
int x_idx = (n_idx == 0) ? i_0 : (n_idx == 1) ? j_0 : k_0;
int w_idx_1 = (n_idx == 0) ? iy : (n_idx == 1) ? iz : ix;
int w_idx_2 = (n_idx == 0) ? iz : (n_idx == 1) ? ix : iy;
const real_t J00 = J(ix, iy, iz, 0, 0, iel_ho);
const real_t J01 = J(ix, iy, iz, 0, 1, iel_ho);
const real_t J02 = J(ix, iy, iz, 0, 2, iel_ho);
const real_t J10 = J(ix, iy, iz, 1, 0, iel_ho);
const real_t J11 = J(ix, iy, iz, 1, 1, iel_ho);
const real_t J12 = J(ix, iy, iz, 1, 2, iel_ho);
const real_t J20 = J(ix, iy, iz, 2, 0, iel_ho);
const real_t J21 = J(ix, iy, iz, 2, 1, iel_ho);
const real_t J22 = J(ix, iy, iz, 2, 2, iel_ho);
real_t JinvJinvT_diag = 0.0;
if (n_idx == 0)
{
JinvJinvT_diag = J02*J02*(J11*J11 + J21*J21) + (J12*J21 - J11*J22)*
(J12*J21 - J11*J22) - 2*J01*J02*(J11*J12 + J21*J22) + J01*J01*
(J12*J12 + J22*J22);
}
else if (n_idx == 1)
{
JinvJinvT_diag = J02*J02*(J10*J10 + J20*J20) + (J12*J20 - J10*J22)*
(J12*J20 - J10*J22) - 2*J00*J02*(J10*J12 + J20*J22) + J00*J00*
(J12*J12 + J22*J22);
}
else if (n_idx == 2)
{
JinvJinvT_diag = J01*J01*(J10*J10 + J20*J20) + (J11*J20 - J10*J21)*
(J11*J20 - J10*J21) - 2*J00*J01*(J10*J11 + J20*J21) + J00*J00*
(J11*J11 + J21*J21);
}
const real_t Jh = JinvJinvT_diag / DETJ;
V(v_idx, ix, iy, iz, iel_ho) = -dq * Jh * w_1d[w_idx_1] * w_1d[w_idx_2] /
(x_pp1[x_idx] - x_pp1[x_idx -1]);
}
}
V(0, ix, iy, iz, iel_ho) = mq * DETJ * W(ix, iy, iz);
for (int i = 1; i < 7; ++i)
{
V(0, ix, iy, iz, iel_ho) -= V(i, ix, iy, iz, iel_ho);
}
}
}
}
});
}
} // namespace mfem
+49 -8
View File
@@ -436,7 +436,7 @@ void NonlinearForm::Mult(const Vector &x, Vector &y) const
// In parallel, the result is in 'py' which is an alias for 'aux2'.
}
Operator &NonlinearForm::GetGradient(const Vector &x) const
Operator &NonlinearForm::GetGradient(const Vector &x, bool finalize) const
{
if (ext)
{
@@ -644,6 +644,8 @@ Operator &NonlinearForm::GetGradient(const Vector &x) const
}
}
if (!finalize) { return *Grad; }
if (!Grad->Finalized())
{
Grad->Finalize(skip_zeros);
@@ -788,12 +790,10 @@ BlockNonlinearForm::BlockNonlinearForm(Array<FiniteElementSpace *> &f) :
}
void BlockNonlinearForm::SetEssentialBC(
const Array<Array<int> *> &bdr_attr_is_ess, Array<Vector *> &rhs)
const Array<Array<int>*> &bdr_attr_is_ess, Array<Vector*> &rhs)
{
for (int s = 0; s < fes.Size(); ++s)
{
ess_tdofs[s]->SetSize(ess_tdofs.Size());
fes[s]->GetEssentialTrueDofs(*bdr_attr_is_ess[s], *ess_tdofs[s]);
if (rhs[s])
@@ -803,6 +803,19 @@ void BlockNonlinearForm::SetEssentialBC(
}
}
void BlockNonlinearForm::SetEssentialTrueDofs(
const Array<Array<int>*> &ess_tdof_list, Array<Vector*> &rhs)
{
for (int s = 0; s < fes.Size(); ++s)
{
*ess_tdofs[s] = *ess_tdof_list[s];
if (rhs[s])
{
rhs[s]->SetSubVector(*ess_tdofs[s], 0.0);
}
}
}
real_t BlockNonlinearForm::GetEnergyBlocked(const BlockVector &bx) const
{
Array<Array<int> *> vdofs(fes.Size());
@@ -1192,7 +1205,14 @@ const BlockVector &BlockNonlinearForm::Prolongate(const BlockVector &bx) const
aux1.Update(block_offsets);
for (int s = 0; s < fes.Size(); s++)
{
P[s]->Mult(bx.GetBlock(s), aux1.GetBlock(s));
if (P[s])
{
P[s]->Mult(bx.GetBlock(s), aux1.GetBlock(s));
}
else
{
aux1.GetBlock(s) = bx.GetBlock(s);
}
}
return aux1;
}
@@ -1221,11 +1241,16 @@ void BlockNonlinearForm::Mult(const Vector &x, Vector &y) const
{
cP[s]->MultTranspose(pby.GetBlock(s), by.GetBlock(s));
}
else if (needs_prolongation)
{
by.GetBlock(s) = pby.GetBlock(s);
}
by.GetBlock(s).SetSubVector(*ess_tdofs[s], 0.0);
}
}
void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx,
bool finalize) const
{
const int skip_zeros = 0;
Array<Array<int> *> vdofs(fes.Size());
@@ -1479,7 +1504,7 @@ void BlockNonlinearForm::ComputeGradientBlocked(const BlockVector &bx) const
}
}
if (!Grads(0,0)->Finalized())
if (finalize && !Grads(0,0)->Finalized())
{
for (int i=0; i<fes.Size(); ++i)
{
@@ -1518,7 +1543,23 @@ Operator &BlockNonlinearForm::GetGradient(const Vector &x) const
for (int s2 = 0; s2 < fes.Size(); ++s2)
{
delete cGrads(s1, s2);
cGrads(s1, s2) = RAP(*cP[s1], *Grads(s1, s2), *cP[s2]);
if (cP[s1] && cP[s2])
{
cGrads(s1, s2) = RAP(*cP[s1], *Grads(s1, s2), *cP[s2]);
}
else if (cP[s1])
{
cGrads(s1, s2) = TransposeMult(*cP[s1], *Grads(s1, s2));
}
else if (cP[s2])
{
cGrads(s1, s2) = mfem::Mult(*Grads(s1, s2), *cP[s2]);
}
else
{
cGrads(s1, s2) = NULL;
continue;
}
mGrads(s1, s2) = cGrads(s1, s2);
}
}
+40 -4
View File
@@ -217,7 +217,12 @@ public:
In general, @a x may have non-homogeneous essential boundary values.
The state @a x must be a true-dof vector. */
Operator &GetGradient(const Vector &x) const override;
Operator &GetGradient(const Vector &x) const override { return GetGradient(x, true); }
/** @brief Compute the gradient Operator of the NonlinearForm corresponding
to the state @a x with optional finalization and elimintaion. */
/** @see GetGradient(const Vector &) */
Operator &GetGradient(const Vector &x, bool finalize) const;
/// Update the NonlinearForm to propagate updates of the associated FE space.
/** After calling this method, the essential boundary conditions need to be
@@ -308,7 +313,7 @@ protected:
void MultBlocked(const BlockVector &bx, BlockVector &by) const;
/// Specialized version of GetGradient() for BlockVector
void ComputeGradientBlocked(const BlockVector &bx) const;
void ComputeGradientBlocked(const BlockVector &bx, bool finalize = true) const;
public:
/// Construct an empty BlockNonlinearForm. Initialize with SetSpaces().
@@ -363,8 +368,39 @@ public:
Array<int> &bdr_marker)
{ bfnfi.Append(nlfi); bfnfi_marker.Append(&bdr_marker); }
virtual void SetEssentialBC(const Array<Array<int> *>&bdr_attr_is_ess,
Array<Vector *> &rhs);
/** @brief Set essential boundary conditions to each finite element space
using boundary attribute markers.
This method calls `FiniteElementSpace::GetEssentialTrueDofs()` for each
space and stores ess_tdof_lists internally.
If `rhs` vectors are non-null, the entries corresponding to these
essential DoFs are set to zero. This ensures compatibility with the
output of the `Mult()` method, which also zeroes out these entries.
@param[in] bdr_attr_is_ess A list of boundary attribute markers for each
space.
@param[in,out] rhs An array of optional right-hand side vectors.
If a vector at `rhs[i]` is non-null, its essential DoFs will be set
to zero. */
virtual void SetEssentialBC(const Array<Array<int>*> &bdr_attr_is_ess,
Array<Vector*> &rhs);
/** @brief Set essential boundary conditions to each finite element space
using essential true dof lists.
This method stores a copy of the provided essential true dof lists.
If `rhs` vectors are non-null, the entries corresponding to these
essential DoFs are set to zero. This ensures compatibility with the
output of the `Mult()` method, which also zeroes out these entries.
@param[in] ess_tdof_list A list of essential true dofs for each space.
@param[in,out] rhs An array of optional right-hand side vectors.
If a vector at `rhs[i]` is non-null, its essential DoFs will be set
to zero. */
virtual void SetEssentialTrueDofs(const Array<Array<int>*> &ess_tdof_list,
Array<Vector*> &rhs);
virtual real_t GetEnergy(const Vector &x) const;

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