Compare commits

...
Author SHA1 Message Date
Stowell, Mark L. eabe69a4a4 Merge remote-tracking branch 'origin/master' into eqdsk-dev
# Conflicts:
#	makefile
#	miniapps/plasma/CMakeLists.txt
#	miniapps/plasma/makefile
#	miniapps/plasma/plasma.hpp
2026-08-10 13:54:40 -07:00
Tzanio Kolev 0a76b8bfb2 Merge pull request #5434 from adamqc/fix-integrated-gll-bdr-projection
Fix IntegratedGLL projection for Nedelec segment elements
2026-08-10 09:11:24 -07:00
Tzanio Kolev 6116b49933 Merge branch 'master' into fix-integrated-gll-bdr-projection
Conflicts:
	tests/unit/fem/test_project_bdr.cpp
2026-08-10 09:09:05 -07:00
Tzanio Kolev 09f6023468 Merge pull request #5426 from mfem/najlkin/fix-getedgetrans
[BUG] Fixed projection on periodic NC meshes
2026-08-10 09:03:48 -07:00
Veselin Dobrev f7056be951 Merge pull request #5334 from mfem/hcurl_mass_pa
VectorFEMassIntegrator ApplyPA improvements
2026-08-09 22:54:07 -07:00
Tzanio Kolev 01b146ab01 Merge pull request #5385 from mfem/specialization-tests
Extra Specialization Tests
2026-08-08 11:01:03 -07:00
Tzanio Kolev ae87b89f16 Merge branch 'master' into specialization-tests 2026-08-07 11:54:45 -07:00
Will Pazner 28e0f3569a Merge pull request #5351 from mfem/batched-lu-fix-5342
Batched LU failure handling consistency
2026-08-07 09:32:12 -07:00
Andrew Ho f49b9a58e8 missed the 2d case 2026-08-07 08:41:28 -07:00
Andrew HoandJohn Camier 905696021a Update tests/unit/fem/specializations/test_qinterp_det.cpp
Co-authored-by: John Camier <camierjs@gmail.com>
2026-08-06 10:01:56 -07:00
Andrew HoandJohn Camier dc6e1ff4ea Update tests/unit/fem/specializations/test_qinterp_grad.cpp
Co-authored-by: John Camier <camierjs@gmail.com>
2026-08-06 10:01:47 -07:00
Ce Qin 51f2f5dd78 Simplify integrated ND shape evaluation and tests 2026-08-06 21:33:14 +08:00
Tzanio Kolev 4e828b9240 Merge pull request #5437 from mfem/grad-kernel-sm0-size
Grad kernel bug
2026-08-06 03:46:47 -07:00
Veselin Dobrev d627b19f06 Merge pull request #5297 from mfem/pncmesh-spacing
General NC mesh spacing in parallel
2026-08-05 14:35:52 -07:00
Jan Nikl 9b35464986 Added a tet unit test. 2026-08-05 13:27:48 -07:00
Jan Nikl 4eafaaa628 Added doxygen to GetTraceCollection(). 2026-08-05 11:35:44 -07:00
Jan Nikl bcab63b41c Added an assert for local edge index. 2026-08-05 11:25:48 -07:00
Jan Nikl 28c1f905b6 Removed non-L2 case from GetEdgeTransformation(). 2026-08-05 11:20:30 -07:00
Jan Nikl c566a165b2 Added a check for 3D. 2026-08-04 14:44:57 -07:00
Andrew Ho 733d0bd177 Merge branch 'master' into hcurl_mass_pa 2026-08-04 14:05:34 -07:00
Andrew Ho 6e2bd88274 fallback version appears to still be faster for CPU for ND to ND 2026-08-04 14:00:38 -07:00
Andrew Ho 7a0a7bd1da style 2026-08-04 13:58:10 -07:00
Jan Nikl db42eb3255 Added edge to face table and used it for GetEdgeTransformation(). 2026-08-04 12:20:38 -07:00
Veselin Dobrev 1c19aba72a Merge pull request #5405 from mfem/jdongg/fix-gauss-jacobi-mpfr
Remove Gauss-Jacobi warning for missing MPFR implementation
2026-08-04 12:11:34 -07:00
Veselin Dobrev 1631ec67fa Merge pull request #5251 from Heinrich-BR/mixed-sesquilinear-dev
Mixed Sesquilinear Forms
2026-08-04 12:09:49 -07:00
Andrew Ho d4b59fe357 appears to always be better to call the smem version even for CPU paths 2026-08-04 11:47:27 -07:00
Andrew Ho cdf077b560 Merge branch 'master' into hcurl_mass_pa 2026-08-04 11:06:42 -07:00
Andrew Ho 50ce940dee changelog 2026-08-04 11:04:54 -07:00
Jan Nikl d3307a6957 Added constexpr in the unit test. 2026-08-04 10:58:02 -07:00
Jan Nikl bde4cbbccd Changed parameters of the unit test. 2026-08-04 10:55:51 -07:00
Dylan Copeland 4c16395398 CHANGELOG 2026-08-04 09:05:44 -07:00
Jan Nikl cfb05a4a60 Added a unit test for boundary projection on nodal NC mesh. 2026-08-03 17:50:12 -07:00
Vlado Tomov LOFT e9cce62beb bug then d1d > q1d (happens in 3d for q1 remhos test) 2026-08-03 12:03:34 -07:00
Andrew Ho 7bb2d30100 Merge branch 'master' into batched-lu-fix-5342 2026-08-03 08:00:30 -07:00
Tzanio Kolev 7f061c7531 Merge pull request #5396 from mfem/pyramid-type-dev
Unit Test for High-Order Mixed Meshes [pyramid-type-dev]
2026-08-02 09:18:52 -07:00
Tzanio Kolev da7aaf8044 Merge pull request #5404 from mfem/gitlab-reporting-fix
In Gitlab CI, report a failure to run the `baseline` test as an error
2026-08-01 11:27:50 -07:00
Tzanio Kolev ca71605cf2 Merge branch 'master' into pyramid-type-dev 2026-08-01 11:26:19 -07:00
Tzanio Kolev ddea622f2c Merge pull request #5317 from mfem/nlconvpa
VectorConvectionNLFIntegrator PA support
2026-08-01 11:24:57 -07:00
Ce Qin fd223f68b5 Fix integrated ND segment projection 2026-08-01 12:27:12 +08:00
camierjs c08f6a6262 Revert whitespace style in tests/unit/CMakeLists.txt 2026-07-31 12:34:06 -07:00
camierjs acf62776a0 Merge branch 'master' into nlconvpa 2026-07-31 12:24:45 -07:00
Mark L. Stowell 28dff525f2 Merge branch 'master' into pyramid-type-dev 2026-07-31 10:39:03 -07:00
Stowell, Mark L. e0b326633e Using consistent variable names 2026-07-31 10:38:10 -07:00
Stowell, Mark L. 7e5f9ed0db Merge branch 'pyramid-type-dev' of github.com:mfem/mfem into pyramid-type-dev 2026-07-31 10:35:33 -07:00
Stowell, Mark L. 29eb764386 Fixing pyramid type in FEC Clone methods 2026-07-31 10:34:45 -07:00
Stowell, Mark L. d01ed701be Fixing symmetry of L2 interpolation points 2026-07-31 10:20:56 -07:00
Stowell, Mark L. fabaf8a71c Updating offset when skipping certain element types 2026-07-31 10:17:44 -07:00
Stowell, Mark L. 2e746a45a2 Adding default pyramid basis type as a user-defined static variable 2026-07-31 10:14:22 -07:00
Stowell, Mark L. add500e73d Adding new unit test to CMake file 2026-07-31 10:13:18 -07:00
Stowell, Mark L. 8355f2b506 Adding apex limit test to H1 Pyramid c'tor 2026-07-31 10:11:52 -07:00
Tzanio Kolev d3cb97afb9 Merge pull request #5343 from mfem/vecdivpa
Improved PA VectorDivergenceIntegrator
2026-07-31 10:07:49 -07:00
Tzanio Kolev 7ad772ba05 Merge branch 'master' into vecdivpa 2026-07-31 10:06:34 -07:00
Tzanio Kolev 5c916241dc Merge pull request #5344 from mfem/vecmasspa
Improved VectorMassAssembleDiagonalPA
2026-07-31 10:05:53 -07:00
Tzanio Kolev e527b4aaac Merge pull request #5427 from mfem/tdrwenski/shadow-warnings
Align debug build warnings with CI
2026-07-31 10:04:07 -07:00
Tzanio Kolev 4e0479ef61 Merge pull request #5429 from mfem/bugfix/kweiss/mfem-1d-nurbs-patch
Skips comments when parsing nurbs patch controlpoints sections
2026-07-31 10:03:03 -07:00
Andrew Ho ad962de425 fix merge 2026-07-30 10:18:23 -07:00
Andrew Ho c44c2f0cdf Merge branch 'master' into specialization-tests 2026-07-30 10:09:56 -07:00
Tzanio Kolev e3bae63ad3 Merge pull request #5381 from mfem/gpu-qinterp-integ
Integral space QuadratureInterpolator
2026-07-30 09:58:46 -07:00
Tzanio Kolev 1133560e56 Merge pull request #5094 from mfem/pgf-save-dev
Adding [Par]GridFunction::Save unit test (and bug fix)
2026-07-30 09:58:06 -07:00
Tzanio Kolev b08082488a Merge pull request #5424 from mfem/raja-hip-fix
Fixed a missing GetRajaResource() for hip
2026-07-30 09:56:37 -07:00
Tzanio Kolev a1532a029f Merge pull request #5052 from mfem/paraview-min-order-1
Ensure ParaViewDataCollection has minimum order 1
2026-07-30 09:55:34 -07:00
John Camier 4b4b18f76b Merge branch 'master' into pyramid-type-dev 2026-07-30 11:56:39 -04:00
camierjs 34ff2399d0 Merge branch 'master' into nlconvpa 2026-07-29 09:24:51 -07:00
camierjs e95e86ce89 Fix warning missing return statement 2026-07-29 09:24:43 -07:00
camierjs ecd7134521 Fix warning missing return statement 2026-07-29 09:20:26 -07:00
camierjs 500936a816 Merge branch 'master' into vecdivpa 2026-07-29 09:18:40 -07:00
camierjs 48bcf417af Fix warning missing return statement at end of non-void function 2026-07-29 09:18:01 -07:00
camierjs e9826ac778 Merge branch 'master' into vecmasspa 2026-07-29 09:16:38 -07:00
Kenneth Weiss c057a95552 unit test for skipping comments in nurbs patch sections 2026-07-28 18:46:23 -07:00
Kenneth Weiss a58cfe3b79 skips comments while parsing nurbs patch sections 2026-07-28 18:42:02 -07:00
Tara Drwenski 52e3b40633 Simplify default debug flags 2026-07-28 15:31:47 -07:00
Veselin Dobrev 5c7073d4ea Merge pull request #5407 from mfem/skip-branch-history
Add option to skip branch-history check
2026-07-28 12:17:52 -07:00
Andrew Ho 0909dc634a Merge branch 'master' into specialization-tests 2026-07-28 11:23:20 -07:00
Tzanio Kolev dc68ebcf57 Merge pull request #5387 from mfem/tdrwenski/add-ccache-ci
Add ccache to GitHub CI builds
2026-07-28 10:17:25 -07:00
Stowell, Mark L. 6c0caaf161 Removing an overlooked output file 2026-07-27 10:26:28 -07:00
Stowell, Mark L. 5f3ee49bf4 Tweaking the implementation and documentation 2026-07-24 13:54:22 -07:00
Stowell, Mark L. 3bcca9155b Adding unit test for ParGridFunction c'tor from multiple GridFunction objects 2026-07-24 12:01:04 -07:00
Stowell, Mark L. 90a6b33249 Merge branch 'pgf-save-dev' of github.com:mfem/mfem into pgf-save-dev 2026-07-24 11:21:35 -07:00
Stowell, Mark L. eda259eb3e Adding preserve option to ParGridFunction c'tor 2026-07-24 11:19:48 -07:00
Tara Drwenski 719f53828c Add -pedantic to debug builds (make and CMake) 2026-07-24 10:46:07 -07:00
Tara Drwenski bfbbee112c Enable -Wshadow in debug builds with clang (make and CMake) 2026-07-24 10:46:07 -07:00
Jan Nikl b9c960cc0d Removed separate edge transformation basis type. 2026-07-24 10:29:48 -07:00
Jan Nikl 0aa392a4ea Implemented GetEdgeTransformation for L2 elements. 2026-07-23 23:42:02 -07:00
Andrew Ho 0c4b6b76f6 style 2026-07-23 18:55:21 -07:00
Andrew Ho a3dc2f8850 Missed a missing GetRajaResource() 2026-07-23 14:48:56 -07:00
John Camier f1440636d1 Merge branch 'master' into nlconvpa 2026-07-23 13:28:32 -04:00
John Camier 3ce8b9e250 Merge branch 'master' into hcurl_mass_pa 2026-07-23 13:28:17 -04:00
John Camier 073891f99e Merge branch 'master' into vecdivpa 2026-07-23 13:28:02 -04:00
John Camier e52671cf77 Merge branch 'master' into vecmasspa 2026-07-23 13:27:52 -04:00
John Camier 43dc6cb530 Merge branch 'master' into gpu-qinterp-integ 2026-07-23 13:27:35 -04:00
John Camier bbecf57ea0 Merge branch 'master' into tdrwenski/add-ccache-ci 2026-07-23 13:27:08 -04:00
John Camier 278e7f1fe6 Merge branch 'master' into skip-branch-history 2026-07-23 13:26:46 -04:00
jdongg eaf91c9c08 Rebase onto master 2026-07-22 16:13:24 -07:00
jdongg 8330565463 Fix horizontal overflow of warning message 2026-07-22 16:00:15 -07:00
Mark L. Stowell b3c1651ddf Merge branch 'master' into pgf-save-dev 2026-07-22 14:53:07 -07:00
Justin Dong 6a6e9b5d6b Merge branch 'master' into jdongg/fix-gauss-jacobi-mpfr 2026-07-22 13:11:36 -07:00
Veselin Dobrev 9c17c781e1 Merge pull request #5274 from AnnevanGils/complexgridfunction_Lp_error
ComplexGridFunction Lp error implementation
2026-07-22 11:12:17 -07:00
Veselin Dobrev f72b0151e2 Merge pull request #5406 from mfem/gslib-uint-fix
Bug fix for GSLIB: undefined type uint in  header file
2026-07-22 11:07:26 -07:00
Will Pazner c8ef9676e8 Merge pull request #5402 from nmnobre/output
Fix output of H(curl) vars in 1d
2026-07-21 11:22:03 -07:00
Andrew Ho a8edefc027 review comments 2026-07-21 10:28:05 -07:00
Andrew Ho 340fe85001 review comments 2026-07-20 20:46:47 -07:00
Will Pazner 10e95b9246 Add note about branch-history to README 2026-07-20 10:02:33 -07:00
Will Pazner 57dd7a5c9a Change branch-history check logic 2026-07-20 10:00:41 -07:00
John Camier 4c6291f018 Merge branch 'master' into hcurl_mass_pa 2026-07-17 13:18:09 -07:00
“Henrique c6378788af Add guard fix to (Par)SesquilinearForm 2026-07-17 18:22:08 +01:00
John Camier 41b4008f93 Merge branch 'master' into gpu-qinterp-integ 2026-07-17 09:31:50 -07:00
Tara Drwenski 1f551b5aac Add ccache for enzyme to CI 2026-07-17 09:02:59 -07:00
“Henrique d65409fdc0 Fix FormRectangularLinearSystem guard 2026-07-17 15:16:40 +01:00
Tara Drwenski 5d909dbcf1 Inject ccache via OMPI_CXX for MPI builds 2026-07-16 11:00:48 -07:00
Tara Drwenski 896c3bbe30 Improve cleanup cache workflow to ensure all caches get removed 2026-07-16 11:00:48 -07:00
“Henrique 8b14357249 Added MixedSesquilinearForm changes to CHANGELOG 2026-07-16 15:42:55 +01:00
“Henrique cc1c6daed3 Fix ParMixedSesquilinearForm::FormRectangularLinearSystem bug 2026-07-16 15:39:06 +01:00
Sohail Reddy b1def1e3fa Added check to ensure gslib's integer-type 'uint' is 'unsigned int' 2026-07-15 20:50:59 -07:00
Dylan Copeland 28b6c85b44 Using mt19937. 2026-07-15 16:01:46 -07:00
Veselin Dobrev 891b675c7f Use 'hypot' instead of 'sqrt' + squares. 2026-07-15 15:50:01 -07:00
“Henrique 0a43f3ca1f Formatting fix 2026-07-15 21:07:46 +01:00
“Henrique 212edacfd1 Linting 2026-07-15 21:07:46 +01:00
“Henrique 45cd0db146 More review suggestions 2026-07-15 21:07:46 +01:00
Henrique BRandJan Nikl f0505ec6eb Apply suggestions from code review
Co-authored-by: Jan Nikl <nikl1@llnl.gov>
2026-07-15 21:07:46 +01:00
“Henrique d3fda1ed30 Comment fixes 2026-07-15 21:07:46 +01:00
“Henrique f63e95a7a1 Expand tests to cover more cases 2026-07-15 21:07:46 +01:00
“Henrique 24e63e6802 Fix serial indexing bug 2026-07-15 21:07:46 +01:00
“Henrique e8961b32ff Fix indexing issue 2026-07-15 21:07:46 +01:00
“Henrique 9c4fa75530 Remove redundant code 2026-07-15 21:07:46 +01:00
“Henrique b904dd0131 More review fixes 2026-07-15 21:07:45 +01:00
“Henrique 24652e2a36 Linting 2026-07-15 21:07:45 +01:00
“Henrique 529209bcf2 Review suggestions 2026-07-15 21:07:45 +01:00
“Henrique 501e37d105 Small fixes 2026-07-15 21:07:45 +01:00
“Henrique d48384f9f4 Linting 2026-07-15 21:07:45 +01:00
“Henrique 94a815d9c9 Added unit test 2026-07-15 21:07:45 +01:00
“Henrique 1a03792398 Add Update method 2026-07-15 21:07:45 +01:00
“Henrique 118e97772c Change Hypre_ParCSR to MFEM_SPARSEMAT 2026-07-15 21:07:45 +01:00
Henrique BRandSocratis Petrides f1138eae7a Apply suggestions from code review
Co-authored-by: Socratis Petrides <petrides1@llnl.gov>
2026-07-15 21:07:45 +01:00
“Henrique 449199525b Added (Par)MixedSesquilinearForms 2026-07-15 21:07:45 +01:00
John Camier 6e26615ef9 Merge branch 'master' into tdrwenski/add-ccache-ci 2026-07-15 08:31:36 -07:00
John Camier 861f629b58 Merge branch 'master' into skip-branch-history 2026-07-15 07:40:30 -07:00
John Camier de1a876e39 Merge branch 'master' into jdongg/fix-gauss-jacobi-mpfr 2026-07-15 07:38:48 -07:00
John Camier 866b6922b3 Merge branch 'master' into vecmasspa 2026-07-15 06:01:29 -07:00
John Camier ee57be0c4e Merge branch 'master' into vecdivpa 2026-07-15 06:01:22 -07:00
John Camier d90a1c6662 Merge branch 'master' into nlconvpa 2026-07-15 06:01:17 -07:00
Will Pazner 951cf8886b Merge pull request #5411 from Pennycook/cudss-0.8.0
Add support for cuDSS 0.8.0
2026-07-14 18:18:46 -07:00
Dylan Copeland 538711c13f Merge branch 'master' of github.com:mfem/mfem into pncmesh-spacing 2026-07-14 15:36:04 -07:00
Dylan Copeland 412cc42685 Added new miniapps to doxygen html documentation. 2026-07-14 15:35:42 -07:00
John Camier 1871a7122e Merge branch 'master' into vecdivpa 2026-07-14 14:03:30 -07:00
John Camier cff5d989f7 Merge branch 'master' into nlconvpa 2026-07-14 14:03:26 -07:00
Ketan Mittal f0f1052c99 Merge branch 'master' into gslib-uint-fix 2026-07-14 13:45:26 -07:00
camierjs 86aebd39dc Add AddSpecialization to register all VectorConvectionNLF kernels: AddMultPA, AddMultGrad & GradDiag 2026-07-14 11:20:44 -07:00
Andrew Ho b0cc0a9b8c fix specializations
this works for the default for linear, quadratic, and cubic meshes
2026-07-13 18:42:33 -07:00
camierjs f2fa9f1295 Use CoefficientVector constructor directly, use COMPRESSED storage 2026-07-13 16:34:27 -07:00
camierjs 572cda7deb Remove duplicate 'VectorConvectionNLF' prefix for nonlininteg registered kernels 2026-07-13 16:23:52 -07:00
camierjs 3f5dfc8bfd Avoid the std::exchange in test_pa_nlvc unit tests 2026-07-13 16:02:23 -07:00
John Pennycook 1416665dc3 Add support for cuDSS 0.8.0
cuDSS 0.8.0 includes some API breaking changes, as described here:
https://docs.nvidia.com/cuda/cudss/migration_guide.html

This commit adds support for the new 0.8.0 API, guarded by #ifdef
macros to ensure compatibility for previous 0.7.x builds.
2026-07-13 02:44:16 -07:00
Andrew Ho 4b1852e924 revert whitespace changes 2026-07-10 11:00:44 -07:00
Andrew Ho 1471e1dcae review comments 2026-07-10 10:59:05 -07:00
Andrew Ho e839a5e8ab Merge remote-tracking branch 'origin/hcurl_mass_pa' into hcurl_mass_pa 2026-07-10 10:29:00 -07:00
Andrew Ho 9d40c8b40c Merge branch 'master' into hcurl_mass_pa 2026-07-10 10:28:35 -07:00
Andrew Ho 069c618def review comments 2026-07-10 10:27:05 -07:00
Will Pazner 10868379f8 Add skip check output 2026-07-09 17:55:11 -07:00
Will Pazner 8c25b2f8c3 Add skip-branch-history option 2026-07-09 17:50:25 -07:00
Sohail Reddy f0d4d84a91 Bug fix for type uint = unsigned in, defined in gslib's internal header 2026-07-09 16:08:44 -07:00
jdongg e6d5e98a06 Remove error message for missing Gauss-Jacobi MPFR implementation and use double precision. Add warning. 2026-07-09 13:42:07 -07:00
Dylan Copeland cfa3440178 Merge branch 'master' of github.com:mfem/mfem into pncmesh-spacing 2026-07-09 13:19:50 -07:00
Veselin Dobrev dc00e63579 In Gitlab CI, report a failure to run the 'baseline' test as an error. 2026-07-09 11:57:22 -07:00
Nuno Nobre d7c781a6f9 Fix output of H(curl) vars in 1d 2026-07-09 01:49:26 +01:00
camierjs 1066ef593f CHANGELOG, 2D mixed-order specializations, 3D MFEM_VERIFY & cleanup 2026-07-08 15:30:22 -07:00
camierjs a5ece9c0ca Add abort for ConvectiveVectorConvectionNLFIntegrator and SkewSymmetricVectorConvectionNLFIntegrator 2026-07-08 15:15:19 -07:00
camierjs 3718cb8248 CHANGELOG, nlvc bench in makefile, align instantiations 2026-07-08 15:10:26 -07:00
camierjs f0fe1796bf Fix header file kernels so users can instantiate their own specializations 2026-07-08 14:40:44 -07:00
Stowell, Mark L. e7f4b88a09 Merge branch 'pyramid-type-dev' of github.com:mfem/mfem into pyramid-type-dev 2026-07-08 14:30:13 -07:00
Stowell, Mark L. 7e620ad313 Fixing more apex issues 2026-07-08 14:29:59 -07:00
camierjs 89460c70ca Add tests with different orders for the vector and scalar space
Fix header file kernels so users can instantiate their own specializations
2026-07-08 14:17:39 -07:00
John Camier de5ccf68ad Merge branch 'master' into vecdivpa 2026-07-08 06:55:01 -07:00
John Camier d3238fe235 Merge branch 'master' into nlconvpa 2026-07-08 06:54:48 -07:00
Tzanio Kolev 9b8f799ac5 Merge branch 'master' into pyramid-type-dev 2026-07-07 13:31:23 -07:00
Tzanio Kolev a53c446dd7 Merge branch 'master' into hcurl_mass_pa 2026-07-07 13:31:12 -07:00
Andrew Ho 3c8c8c21a9 Merge branch 'master' into hcurl_mass_pa 2026-07-07 11:19:23 -07:00
Mark L. Stowell 8374b84bff Merge branch 'master' into pyramid-type-dev 2026-07-07 09:23:25 -07:00
John Camier eb04f3c1ea Merge branch 'master' into vecdivpa 2026-07-07 17:05:56 +02:00
John Camier 7c50e9f807 Merge branch 'master' into nlconvpa 2026-07-07 17:05:48 +02:00
Stowell, Mark L. db727de78b Adding 1D mesh to the new unit test 2026-07-06 15:09:52 -07:00
Stowell, Mark L. e5106b52f1 Merge remote-tracking branch 'origin/master' into pyramid-type-dev
# Conflicts:
#	mesh/pmesh.cpp
2026-07-06 11:31:11 -07:00
Stowell, Mark L. 64cc5a98bd Documenting a new parameter 2026-07-06 11:18:03 -07:00
Stowell, Mark L. 485a0f2ce8 Changing assumptions in Mesh::DoNodeReorder for high order mixed meshes 2026-07-06 10:55:32 -07:00
Stowell, Mark L. 4c95e84e53 Handling pyramid apex more robustly in Bergot H1 and L2 bases 2026-07-06 10:53:54 -07:00
Stowell, Mark L. bd2f74f25b Correcting comments 2026-07-06 10:53:07 -07:00
Stowell, Mark L. 14826adf5d Adding support for selecting the Bergot pyramids in meshes and FE collections 2026-07-06 10:52:48 -07:00
Stowell, Mark L. 48c7debfce Adding unit test for read/write high order and mixed meshes 2026-07-06 10:50:06 -07:00
John Camier 6302cd37b7 Merge branch 'master' into gpu-qinterp-integ 2026-07-03 19:02:40 +02:00
Andrew Ho cf1cfb5881 applied detJ at the wrong place 2026-07-02 18:09:44 -07:00
camierjs 9f4c3f8cbf Use max D1D/Q1D instead of T1D 2026-07-02 10:01:36 -07:00
camierjs 28eb5906f2 Use DofQuadLimits instead of local T_MDQ 2026-07-02 09:49:47 -07:00
camierjs 8c9987e63a With style 2026-07-02 09:34:49 -07:00
camierjs 3495617be6 Cleanup nlvc tests and add libCEED verifications 2026-07-02 09:17:02 -07:00
camierjs 07ebe7889e Cleanup & use MFEM_GENERATE_RANGES instead of overload functions 2026-07-02 07:53:46 -07:00
camierjs 18668ddca6 Direct threads and cmath for win32 2026-07-01 15:55:18 -07:00
camierjs 5e4b69f3d8 Cleanup bilininteg_vecdiv_pa 2026-07-01 14:32:50 -07:00
camierjs bfe77c97f2 Simplify tests unit test_pa_vecdiv 2026-07-01 14:12:11 -07:00
camierjs 7091d4ceb1 Improved PA VectorDivergenceIntegrator
Add shared-memory PA kernels with kernel registration, transpose support,
and unit tests.
2026-07-01 13:34:44 -07:00
camierjs e0ecd9b8ff Bring stacked changes from vecdivpa 2026-07-01 13:32:29 -07:00
John Camier af0f8520d6 Merge branch 'master' into nlconvpa 2026-07-01 21:46:46 +02:00
Dylan Copeland fbb0e44dce Merge branch 'master' of github.com:mfem/mfem into pncmesh-spacing 2026-06-30 17:43:43 -07:00
Jan Nikl a5fca573a9 Merge branch 'master' into pgf-save-dev 2026-06-30 13:28:19 -07:00
Tara Drwenski 43de095a2d Decrease ccache max size to 1G 2026-06-30 13:18:51 -07:00
LwhJesse cc585df285 Apply batched LU code style 2026-07-01 03:23:06 +08:00
LwhJesse c7f2950458 Address batched LU review feedback 2026-07-01 03:02:31 +08:00
Tara Drwenski b25f438922 Delete a PR's caches when it is closed 2026-06-30 10:42:48 -07:00
Tara Drwenski 49310d0260 Increase ccache max size to 2G 2026-06-30 09:39:18 -07:00
Tara Drwenski a9bc59fdd5 Add ccache sloppiness and basedir for direct-mode hits 2026-06-30 09:38:28 -07:00
Tara Drwenski 17fa9b844c Shorten comment 2026-06-30 08:51:51 -07:00
Jesse Li 068b61eb3f Merge branch 'master' into batched-lu-fix-5342 2026-06-30 17:41:40 +08:00
LwhJesse 3419a50655 Make batched LU failure test robust on GPU 2026-06-30 17:24:25 +08:00
Tara Drwenski 821a899d50 Add ccache to GitHub CI builds 2026-06-29 17:11:06 -07:00
Andrew Ho 7d91917d7a missing paren wrapper 2026-06-29 14:08:47 -07:00
Andrew Ho 82f03e136d Merge branch 'master' into hcurl_mass_pa 2026-06-29 11:08:31 -07:00
Andrew Ho 46a84f6417 Merge branch 'hcurl_domain_lf' into hcurl_mass_pa 2026-06-29 11:06:31 -07:00
John Camier f0d9a81fd4 Merge branch 'master' into nlconvpa 2026-06-27 20:13:25 +02:00
Andrew Ho f6b333681f duplicate test names 2026-06-26 14:00:23 -07:00
Andrew Ho 644b4ef141 fix formatting 2026-06-26 13:22:42 -07:00
Andrew Ho 08d6dd777a add tests which mimic users adding their own specializations 2026-06-26 13:16:06 -07:00
Andrew Ho 879413e774 Merge branch 'gpu-qinterp-integ' into specialization-tests 2026-06-26 11:57:24 -07:00
Andrew Ho 4e55e73c4e remove stubs for derivatives for integral quad interpolator 2026-06-25 19:51:21 -07:00
Andrew Ho 3a35c8fdf2 Added tests for integral map types
had detJ applied incorrectly
2026-06-25 18:48:01 -07:00
Andrew Ho 877e201ff6 fixes for collocated derivative kernels 2026-06-25 13:34:29 -07:00
Andrew Ho 94a0ae36a8 document args, fix miniapp 2026-06-25 12:20:47 -07:00
Andrew Ho 2b02cdc518 shadowed variable, use real_t 2026-06-25 11:52:29 -07:00
Andrew Ho 8a42a46709 refactored code to reduce amount of duplicate code 2026-06-25 11:46:48 -07:00
camierjs e1f7df8d44 Merge branch 'master' into nlconvpa 2026-06-25 10:48:31 +02:00
Andrew Ho 63cfe75a99 unused 2026-06-24 20:34:02 -07:00
Andrew Ho 6e1e64c2d2 Merge branch 'master' into gpu-qinterp-integ 2026-06-24 20:02:30 -07:00
Andrew Ho cce7af170b Implemented remaining integral quadinterp kernels 2026-06-24 20:00:02 -07:00
Andrew Ho b2c10265e6 implemented integral value quad interpolators 2026-06-24 17:54:46 -07:00
Andrew Ho ed197fae14 added stubs for INTEGRAL fespace quadrature interpolator 2026-06-24 17:39:00 -07:00
Stowell, Mark L. db0c173012 Merge remote-tracking branch 'origin/master' into pgf-save-dev
# Conflicts:
#	fem/pgridfunc.cpp
2026-06-23 11:57:23 -07:00
Jesse Li ce80de49d0 Merge branch 'master' into batched-lu-fix-5342 2026-06-18 20:09:31 +08:00
Andrew Ho 45a62e8bcd include a mesh with curvature, use MFEM_Approx instead of tol 2026-06-17 22:00:33 -07:00
Andrew Ho 4ee2e40d34 Add test comparing partial assembly vs. full assembly results 2026-06-17 13:12:58 -07:00
LwhJesse c529d34eea Fix GPU BLAS helper build guard 2026-06-17 20:09:21 +08:00
LwhJesse 742d043ead Improve batched LU failure checks 2026-06-17 20:06:14 +08:00
Dylan Copeland a67c93d0b8 Merge branch 'master' of github.com:mfem/mfem into pncmesh-spacing 2026-06-15 13:50:23 -07:00
Andrew Ho 43532923f7 missing parenthesis protection wrappers 2026-06-14 18:44:02 -07:00
Andrew Ho 9980f767f8 bugfixes for wrappers 2026-06-12 12:53:14 -07:00
Andrew Ho 3b89be0ec6 Added wrappers for simplifying mod/div usage in flattened 3D thread blocks 2026-06-12 09:09:46 -07:00
John Camier f51b8c2047 Merge branch 'master' into nlconvpa 2026-06-10 17:01:51 -07:00
Andrew Ho 4c12e3815b Merge remote-tracking branch 'base/hcurl_mass_pa' into hcurl_mass_pa 2026-06-10 15:32:57 -07:00
Andrew Ho 44d2d0c75b Merge remote-tracking branch 'base/hcurl_domain_lf' into hcurl_mass_pa 2026-06-10 15:28:57 -07:00
John Camier 8d512c82f4 Merge branch 'master' into nlconvpa 2026-06-09 06:42:23 -07:00
Andrew Ho 620e49aea6 Merge branch 'master' into hcurl_mass_pa 2026-06-08 12:42:10 -07:00
John Camier 8feb690d6d Merge branch 'master' into nlconvpa 2026-06-06 06:27:04 -07:00
LwhJesse 006855bec2 Handle batched LU failures in GPU backends 2026-06-03 13:09:17 +08:00
John Camier fd55dc64d0 Merge branch 'master' into nlconvpa 2026-06-02 06:08:29 -07:00
Dylan Copeland 96f9456a7d Reformatting. 2026-05-31 17:38:46 -07:00
John Camier 16af7365a2 Merge branch 'master' into nlconvpa 2026-05-27 06:30:56 -07:00
Dylan Copeland c26f1937a9 Minor fixes suggested by copilot. 2026-05-26 22:06:49 -07:00
Dylan Copeland 8431604228 Merge branch 'master' of github.com:mfem/mfem into pncmesh-spacing 2026-05-26 21:28:49 -07:00
John Camier b67b1af8f8 Merge branch 'master' into nlconvpa 2026-05-24 20:13:45 -07:00
John Camier 0d3b658dc4 Merge branch 'master' into nlconvpa 2026-05-21 06:05:13 -07:00
camierjs bd4504d7ae Simplify MDQ for NLVC PA kernels 2026-05-19 11:12:50 -07:00
camierjs f622b53731 Simplify nlvc unit tests 2026-05-19 10:13:31 -07:00
Andrew Ho 24bc9d48a1 extracted vector fe mass integrator changes from gpu-maxwell 2026-05-18 11:23:00 -07:00
John Camier 60eb714229 Merge branch 'master' into nlconvpa 2026-05-18 06:04:17 -07:00
John Camier 1d3a723af9 Merge branch 'master' into nlconvpa 2026-05-14 13:20:27 -07:00
John Camier 2e8e4a5377 Merge branch 'master' into nlconvpa 2026-05-09 11:31:10 -07:00
Dylan Copeland 27deb9cdd2 Merge branch 'master' of github.com:mfem/mfem into pncmesh-spacing 2026-05-06 12:02:19 -07:00
John Camier 139c3ddaa6 Merge branch 'master' into nlconvpa 2026-05-05 15:32:54 -07:00
John Camier 24f1022f7d Merge branch 'master' into nlconvpa 2026-05-05 06:19:01 -07:00
John Camier edc4d9a187 Merge branch 'master' into nlconvpa 2026-04-29 17:04:08 -07:00
Stowell, Mark L. 6a169432fa Adding [Pyraqmid] tag to unit tests 2026-04-27 12:03:26 -07:00
Tzanio Kolev 03c576d1ea Merge branch 'master' into pgf-save-dev 2026-04-26 14:35:44 -06:00
camierjs 2277decd8c With style 2026-04-25 14:24:05 -07:00
camierjs 36f6ff983a VectorConvectionNLFAddMultGradPA3D fallback checks, fix copilot reviews and Win32 math defines 2026-04-25 14:23:22 -07:00
camierjs 6fc6cf9186 Fix Windows compile-time constant expressions 2026-04-25 13:39:08 -07:00
camierjs bb06604dac Avoid narrowing non-constant-expression in initializer list 2026-04-25 13:24:06 -07:00
camierjs 058c6b2dee Avoid documenting NLVC registered kernels 2026-04-25 13:13:51 -07:00
camierjs 94135f3ed2 Merge branch 'camierjs-NLConvPA' into mfem-NLConvPA 2026-04-25 12:56:25 -07:00
camierjs 47c1d6230a Simplify NLVC diagonal kernels 2026-04-25 12:52:57 -07:00
camierjs a22c2c8d72 Cleanup instantiated NLVC registered kernels 2026-04-25 12:21:08 -07:00
camierjs 65f6ade43d Remove low order 3D VectorConvection kernels 2026-04-25 11:29:10 -07:00
camierjs 64cf121310 Meld back MFEM header 2026-04-25 11:07:13 -07:00
camierjs 92e1eace88 Revert test_nl_convection_nd 2026-04-25 11:06:24 -07:00
camierjs e6a3835983 Meld back toward master, rename nlvc unit tests 2026-04-25 11:01:45 -07:00
camierjs d97c8ec672 Cleanup debug traces 2026-04-25 10:33:20 -07:00
camierjs 6d9f34a3d7 Cleanup debug traces, nlvc benchmarks & use transposed adjugate 2026-04-25 08:50:32 -07:00
camierjs 5b73d20291 Cleanup NLF VConv diagonal 2026-04-25 07:15:07 -07:00
camierjs 4febbb7721 Merge branch 'master' into mfem-NLConvPA 2026-04-25 06:08:49 -07:00
camierjs ab81de5bf5 Merge branch 'master' into camierjs-NLConvPA 2026-04-25 05:49:57 -07:00
camierjs 23814cc1fa nlvc diagonal tests & benchmarks 2026-04-24 20:44:59 -07:00
camierjs 6307cef7cb Merge branch 'NLConvPA' of github.com:camierjs/mfem-NLConvPA into camierjs-NLConvPA 2026-04-24 17:51:37 -07:00
camierjs 156f7f930d NVTX marks 2026-04-24 17:51:35 -07:00
camierjs 0d5f21188d Add missing low order specializations 2026-04-24 17:48:28 -07:00
camierjs a786d4f293 SmemPAConvectionNLGradDiagonal 2026-04-24 17:46:27 -07:00
camierjs 018ab7b974 wip SmemPAConvectionNLGradDiagonalPA2D 2026-04-24 14:21:49 -07:00
Dylan Copeland a7b30bed56 Merge branch 'master' of github.com:mfem/mfem into pncmesh-spacing 2026-04-21 19:20:03 -07:00
camierjs f66aaa46bd Merge branch 'camierjs-NLConvPA' into nlconvpa 2026-04-20 14:42:09 -07:00
camierjs eff6bc5abc Probe for ConstantCoefficient first 2026-04-16 10:52:14 -07:00
camierjs baf29bff27 Add NVTX marks and fmt::fmt 2026-04-15 16:12:35 -07:00
camierjs 9969e42270 Split LOVectorConvectionNLFAddMultGradPA3DType 2026-04-15 16:02:13 -07:00
camierjs 4936834c5e Split LO/HO VectorConvectionNLF Grad kernels 2026-04-15 15:46:30 -07:00
camierjs da51f42c90 H100x runs 2026-04-15 15:33:31 -07:00
camierjs a7dd90466e Register VectorConvectionNLFAddMultPA, benchmarks 2026-04-15 14:35:32 -07:00
camierjs d231431ca7 LOSmemPAConvectionNLGradApply3D 2026-04-15 09:50:20 -07:00
camierjs e55b49b932 Ini kernels LO 2026-04-15 06:52:21 -07:00
camierjs e480c5f37b Register VectorConvectionNLFAddMultGradPA 2026-04-14 13:07:16 -07:00
camierjs 3911f44906 SmemPAConvectionNLGradApply3D and FunctionCoefficient 2026-04-14 11:59:05 -07:00
camierjs 6fa3bc57eb SmemPAConvectionNLGradApply2D running 2026-04-13 22:45:16 -07:00
camierjs 157a1f04f9 wip SmemPAConvectionNLGradApply2D 2nd part 2026-04-13 22:20:31 -07:00
camierjs 7bc531ba39 wip SmemPAConvectionNLGradApply2D 2026-04-13 21:47:37 -07:00
Dylan Copeland fd63847904 Merge branch 'master' of github.com:mfem/mfem into pncmesh-spacing 2026-04-13 20:09:16 -07:00
camierjs 9343b54c89 Added SmemPAConvectionNLApply2D 2026-04-13 18:28:46 -07:00
camierjs 0ec3e1d21a wip SmemPAConvectionNLApply3D new kernels 2026-04-13 17:12:57 -07:00
camierjs 4aa44a9b39 Merge remote-tracking branch 'refs/remotes/origin/NLConvPA' into NLConvPA 2026-04-13 13:20:34 -07:00
camierjs d191d332f8 Merge remote-tracking branch 'refs/remotes/origin/NLConvPA' into NLConvPA 2026-04-13 13:19:06 -07:00
camierjs 9dd104c211 fix fmt_FOUND 2026-04-13 13:18:33 -07:00
camierjs e62d26a450 wip Q_adj 2026-04-13 13:18:10 -07:00
camierjs 7ee86d6e75 wip SmemPAConvectionNLGradApply2D 2026-04-13 12:48:49 -07:00
camierjs 3d0878ded5 Setup PA NLConv tests 2026-04-12 15:24:11 -07:00
Dylan Copeland 5269fc2bf2 gitignore 2026-04-09 16:08:14 -07:00
Dylan Copeland 4036a7d0c2 Remove unused variable. 2026-04-09 15:22:56 -07:00
Dylan Copeland 8099ca947e General spacing for refinement of parallel NC meshes. Added a parallel miniapp, demonstrating 3:1 refinement. 2026-04-09 14:44:53 -07:00
AnnevanGils 02822e620a Merge branch 'master' into complexgridfunction_Lp_error 2026-03-24 10:49:26 +01:00
Anne 25a26b5e6f fix variable names shadowing members 2026-03-19 12:29:06 +01:00
Anne d6aacb95cf fix typo in documentation 2026-03-19 12:07:53 +01:00
Anne 0466624b21 apply astyle format 2026-03-19 12:03:54 +01:00
Anne 42e2d0b9a4 Add Lp error implementation to ComplexGridFunction using the modulus of complex values. Add interface ComputeMaxError for special case p = infinity. 2026-03-18 11:17:08 +01:00
Mark L. Stowell 3d8a58fc90 Merge branch 'master' into pgf-save-dev 2025-10-30 00:06:32 -07:00
Stowell, Mark L. ed472cba47 More file closures 2025-10-29 15:13:50 -07:00
Stowell, Mark L. 1449e5f9d3 Closing files in unit test 2025-10-29 14:41:39 -07:00
Stowell, Mark L. 89d94457fe Adding [Par]GridFunction::Save unit test (and bug fix) 2025-10-29 12:33:02 -07:00
Will Pazner c4e4c21951 Ensure ParaViewDataCollection has minimum order 1
This is the minimum order that is supported by ParaView
2025-10-01 12:55:51 -07:00
Stowell, Mark L. 6f1c0c5eb2 make style 2025-06-11 19:53:44 -07:00
Stowell, Mark L. c3a596d494 Fixing 1D interpolation when Psi has its maximum on the boundary or on the axis 2025-06-11 16:40:16 -07:00
Stowell, Mark L. f22b8dab9f Setting ranges for gnuplot plots 2025-06-11 16:38:16 -07:00
Stowell, Mark L. 8a32d5d16e Calculating the mesh shift for clarity 2025-06-11 16:29:23 -07:00
Stowell, Mark L. 0522b8efaf Adding three sample data files 2025-06-11 16:27:21 -07:00
Stowell, Mark L. 6e9152a7d1 Adding class documentation with references to format and algorithm documentation 2025-05-23 11:00:05 -07:00
Stowell, Mark L. 48336c157b Adding missing accessor methods 2025-05-23 10:59:03 -07:00
Stowell, Mark L. 66df4f64b1 Removing obsolete functions 2025-05-23 10:58:25 -07:00
Stowell, Mark L. 172b323f0c Improving documentation and removing obsolete functions 2025-05-22 16:35:48 -07:00
Stowell, Mark L. b24f79cfce Correcting the check on boundary value of Psi and adding logging 2025-05-22 16:35:11 -07:00
Stowell, Mark L. e1a8e57f78 Fixing definition of toroidal current density 2025-05-21 15:58:40 -07:00
Stowell, Mark L. ede9c97f99 Adding header file with plasma relevant constants 2025-05-21 15:57:34 -07:00
Mark L. Stowell 279f9ef9c6 Merge branch 'master' into eqdsk-dev 2025-05-20 14:09:58 -07:00
Stowell, Mark L. 3a88d7401c Adding miniapps/plasma to gitignore 2025-05-20 13:08:56 -07:00
Stowell, Mark L. bb128fbf5b double -> real_t 2025-05-20 10:58:34 -07:00
Stowell, Mark L. 93cc223080 Switching to numeric_limits 2025-05-20 10:47:02 -07:00
Stowell, Mark L. 0e15d796f8 No miniapp tests yet 2025-05-20 10:46:39 -07:00
Stowell, Mark L. 0dcbd41328 make style 2025-05-20 10:11:06 -07:00
Stowell, Mark L. 74ba5790eb Adding support for arbitrary mesh files 2025-05-20 10:01:48 -07:00
Stowell, Mark L. b51d069584 Adding more viewer options 2025-04-28 17:22:32 -07:00
Stowell, Mark L. 3aeb28ae55 Adding first drafts of file reader and viewer 2025-04-25 13:00:12 -07:00
126 changed files with 12139 additions and 3393 deletions
+56 -1
View File
@@ -142,6 +142,10 @@ jobs:
continue-on-error: ${{ matrix.enzyme && true || false }}
# Enable ccache for all jobs except Windows (would need sccache).
env:
USE_CCACHE: ${{ matrix.os != 'windows-latest' }}
steps:
# Fix 'No space left on device' errors for Ubuntu builds.
- name: Run Actions Cleaner
@@ -290,6 +294,52 @@ jobs:
echo "OMPI_CC=$LLVM_PREFIX/bin/clang" >> $GITHUB_ENV
echo "OMPI_CXX=$LLVM_PREFIX/bin/clang++" >> $GITHUB_ENV
# Restore the compiler cache (ccache). The key embeds the run id, so new
# runs save a fresh snapshot; the restore-keys prefix warm-starts from the
# most recent prior run (incl. the base branch for PRs).
- name: cache ccache
if: ${{ env.USE_CCACHE == 'true' }}
uses: actions/cache@v5
with:
path: .ccache
key: ccache-${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}-${{ matrix.precision }}${{ matrix.enzyme && '-enzyme' || '' }}-${{ github.run_id }}
restore-keys: |
ccache-${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}-${{ matrix.precision }}${{ matrix.enzyme && '-enzyme' || '' }}-
# Configure ccache and select how it is injected into the MFEM build:
# - make: set CXX="ccache g++"; for MPI, OMPI_CXX="ccache g++" so mpicxx
# runs ccache around g++ (not ccache around the mpicxx wrapper).
# - cmake: set CMAKE_<LANG>_COMPILER_LAUNCHER=ccache.
# - enzyme: wrap the brew clang++ via OMPI_CXX.
# The chosen options are passed through build-mfem's 'config-options'
# input (see the build step below).
- name: configure ccache
if: ${{ env.USE_CCACHE == 'true' }}
run: |
command -v ccache >/dev/null 2>&1 || {
if [[ "${{ runner.os }}" == "Linux" ]]; then
sudo apt-get update && sudo apt-get install -y ccache
else
brew install ccache
fi
}
echo "CCACHE_DIR=${{ github.workspace }}/.ccache" >> $GITHUB_ENV
echo "CCACHE_MAXSIZE=1G" >> $GITHUB_ENV
echo "CCACHE_COMPILERCHECK=content" >> $GITHUB_ENV
# Ignore header timestamps (restamped by each checkout) so direct mode hits.
echo "CCACHE_SLOPPINESS=include_file_mtime,include_file_ctime,time_macros" >> $GITHUB_ENV
# Hash absolute paths relative to the workspace.
echo "CCACHE_BASEDIR=${{ github.workspace }}" >> $GITHUB_ENV
if [[ "${{ matrix.enzyme }}" == "true" ]]; then
echo "OMPI_CXX=ccache $LLVM_PREFIX/bin/clang++" >> $GITHUB_ENV
elif [[ "${{ matrix.build-system }}" == "cmake" ]]; then
echo 'CCACHE_CONFIG_OPTS=-DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache' >> $GITHUB_ENV
else
echo "OMPI_CXX=ccache g++" >> $GITHUB_ENV
echo 'CCACHE_CONFIG_OPTS=CXX="ccache g++" MPICXX="mpicxx"' >> $GITHUB_ENV
fi
shell: bash
# MFEM build and test
- name: build
uses: mfem/github-actions/build-mfem@v2.7
@@ -305,9 +355,14 @@ jobs:
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: ${{ env.MFEM_TOP_DIR }}
precision: ${{ matrix.precision }}
config-options: ${{ matrix.config-opts }}
config-options: ${{ matrix.config-opts }} ${{ env.CCACHE_CONFIG_OPTS }}
library-only: ${{ matrix.target == 'dbg' && matrix.os != 'ubuntu-latest' }}
- name: ccache stats
if: ${{ env.USE_CCACHE == 'true' }}
run: ccache -s
shell: bash
# Run checks (and only checks) on debug targets
- name: checks
if: matrix.build-system == 'make' && matrix.target == 'dbg'
+42
View File
@@ -0,0 +1,42 @@
# 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.
---
# A closed PR's caches can never be restored again, so delete them to free
# space against the 10 GB per-repo cache limit.
name: Cleanup PR caches
on:
pull_request:
types: [closed]
permissions:
actions: write
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Delete caches for the closed PR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
PR_REF: refs/pull/${{ github.event.pull_request.number }}/merge
run: |
echo "Deleting caches for $PR_REF"
while :; do
ids=$(gh cache list --ref "$PR_REF" --limit 100 --json id --jq '.[].id')
[ -n "$ids" ] || break
echo "$ids" | while read -r id; do
[ -n "$id" ] || continue
echo "Deleting cache $id"
gh cache delete "$id" || echo " (already gone)"
done
done
+33 -4
View File
@@ -13,6 +13,7 @@ name: "Checks"
permissions:
actions: write
pull-requests: read
on:
push:
@@ -29,6 +30,11 @@ concurrency:
# by checking if the workflow trigger is 'push' ("github.event_name == 'push'")
# and if we are in a fork ("github.event.pull_request.head.repo.full_name !=
# github.repository").
#
# The logic for the branch-history check is slightly different, since that check
# also inspects the PR's labels to allow for overriding failures. In this case,
# we run on all 'pull_request' triggers, but only run for 'push' triggers that
# do not correspond to any open PRs.
jobs:
file-headers-check:
@@ -128,10 +134,7 @@ jobs:
branch-history:
if: |
github.ref != 'refs/heads/next' &&
github.ref != 'refs/heads/master' &&
(github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository)
github.ref != 'refs/heads/next' && github.ref != 'refs/heads/master'
runs-on: ubuntu-latest
steps:
- name: checkout mfem
@@ -139,7 +142,27 @@ jobs:
with:
fetch-depth: 0
- name: check for pull request
id: check_pr
if: github.event_name == 'push'
env:
GH_TOKEN: ${{ github.token }}
run: |
pr_exists=$(gh pr list --repo "$GITHUB_REPOSITORY" \
--head "$GITHUB_REF_NAME" \
--state open \
--json number \
--jq 'length > 0')
echo "pr_exists=$pr_exists" >> "$GITHUB_OUTPUT"
- name: branch-history
id: branch_history
if: |
(github.event_name == 'pull_request' ||
github.event_name == 'workflow_dispatch' ||
steps.check_pr.outputs.pr_exists == 'false')
continue-on-error: ${{ contains(github.event.pull_request.labels.*.name,
'branch-history-override') }}
run: |
# We override origin to make sure we point to the main repo.
# This is to have consistent test results on PRs from forks.
@@ -147,3 +170,9 @@ jobs:
git remote add origin https://github.com/mfem/mfem.git
git checkout -b gh-actions-branch-history
./config/githooks/pre-push --history
- name: report branch-history override
if: steps.branch_history.outcome == 'failure'
run: |
echo "::warning::branch-history check failed, but the" \
"'branch-history-override' label is set."
+6
View File
@@ -260,6 +260,7 @@ miniapps/meshing/polar-nc
miniapps/meshing/mesh-quality
miniapps/meshing/hpref
miniapps/meshing/phpref
miniapps/meshing/pref321
miniapps/meshing/mobius-strip.mesh
miniapps/meshing/klein-bottle.mesh
miniapps/meshing/toroid-*.mesh
@@ -355,6 +356,11 @@ miniapps/performance/refined.mesh
miniapps/performance/mesh.*
miniapps/performance/sol.*
miniapps/plasma/g_eqdsk_viewer
miniapps/plasma/gnuplot_eqdsk.*
miniapps/plasma/G_EQDSK_Viewer*
miniapps/plasma/ParaView
miniapps/shifted/distance
miniapps/shifted/ParaViewDistance
miniapps/shifted/ParaViewLSF
+4 -2
View File
@@ -102,12 +102,14 @@ report_baseline:
mkdir -p ${MACHINE_NAME}
rundir="${MACHINE_NAME}/$(date +%Y-%m-%d)-gitlab-${BASELINE_TEST}-${CI_COMMIT_REF_SLUG}"
rundir=$(${CI_PROJECT_DIR}/.gitlab/scripts/safe_create_rundir ${rundir})
cp ${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/* ${rundir}
status=0
cp ${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/* ${rundir} || { status=1; }
printf "%s\n" "" "Pipeline URL:" "$CI_PIPELINE_URL" \
>> ${rundir}/pipeline.txt
# We create an autotest-email.html file, because that's how we signal
# that there was an error / diff (temporary).
if [[ -f ${rundir}/${BASELINE_TEST}.err ]] || \
if [[ $status -ne 0 ]] || \
[[ -f ${rundir}/${BASELINE_TEST}.err ]] || \
[[ -f ${rundir}/${BASELINE_TEST}-${MACHINE_NAME}.diff ]]; then
cp ${rundir}/pipeline.txt ${rundir}/autotest-email.html
fi
+23
View File
@@ -46,8 +46,19 @@ Discretization improvements
- Extend FindPointsGSLIB to support surface meshes.
- Added support for complex-valued mixed bilinear forms via the new classes
MixedSesquilinearForm and ParMixedSesquilinearForm, mirroring the existing
SesquilinearForm classes. Rectangular complex operators are now also
handled correctly by ComplexSparseMatrix::GetSystemMatrix and
ComplexHypreParMatrix::GetSystemMatrix, which previously assumed equal
trial and test spaces.
Meshing improvements
--------------------
- Added support for nonuniform anisotropic mesh refinement on parallel quad/hex
meshes with arbitrary spacing in each direction. This enables in particular
3:1 refinement in parallel, as demonstrated in the new meshing miniapp pref321.
- Added option to guarantee mesh validity during TMOP-based r-adaptivity, using
bounds on the determinant of the mesh transformation Jacobian.
@@ -70,9 +81,15 @@ Linear and nonlinear solvers
GPU computing
-------------
- Improved partial assembly for VectorDivergenceIntegrator with shared-memory
kernels, kernel registration, and transpose support.
- Improved partial-assembly diagonal kernels for VectorMassIntegrator (shared-
memory specializations) and ElasticityIntegrator (no scratch Q-vector).
- Added PA gradient and diagonal support for VectorConvectionNLFIntegrator
(AssembleGradPA, AddMultGradPA, AssembleGradDiagonalPA).
- Added device assembly support for 3D H(curl) VectorFEDomainLFIntegrator.
- Added NVIDIA cuDSS library interface. Implementation examples have been
@@ -81,6 +98,12 @@ GPU computing
- Allow specifying GPU kernel launch bounds for native and RAJA GPU backends.
- Changed VectorFEMassIntegrator to use kernel specialization dispatch for
partial assembly.
- Added support for FiniteElement::MapType::INTEGRAL spaces to
QuadratureInterpolator.
New and updated examples and miniapps
-------------------------------------
- The Lorentz miniapp (in miniapps/electromagnetics) has been updated to
+7
View File
@@ -239,6 +239,13 @@ else()
set(MFEM_DEBUG OFF)
endif()
# Shadow warnings for clang only; GCC's -Wshadow flags more.
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pedantic -Wall -Wshadow")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pedantic -Wall")
endif()
# Shared build on Windows
if (WIN32 AND BUILD_SHARED_LIBS)
# CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS works only with MSVC?
+7 -1
View File
@@ -27,7 +27,13 @@ MPICXX = mpicxx
BASE_FLAGS = -std=c++17
OPTIM_FLAGS = -O3 $(BASE_FLAGS)
DEBUG_FLAGS = -g $(XCOMPILER)-Wall $(BASE_FLAGS)
# Shadow warnings for clang only; GCC's -Wshadow flags more.
SHADOW_WARNING_FLAG = $(if $(findstring clang,\
$(shell $(MFEM_HOST_CXX) --version 2>/dev/null)),-Wshadow,)
WARNING_FLAGS = -pedantic -Wall $(SHADOW_WARNING_FLAG)
DEBUG_FLAGS = $(strip -g $(addprefix $(XCOMPILER),$(WARNING_FLAGS)) $(BASE_FLAGS))
# Prefixes for passing flags to the compiler and linker when using CXX or MPICXX
CXX_XCOMPILER =
+5
View File
@@ -39,3 +39,8 @@ when a picture was added for documentation.
If that is the case, make sure the failure is indeed justified, and rerun the
push command with the `--no-verify` option. This will skip the hooks, allowing
you to push those changes.
The `branch-history` check is run automatically through GitHub Actions. If a
branch is known to have a large number of changes that are legitimate, the
check can be overridden by setting the label 'branch-history-override' on the
pull request.
+38
View File
@@ -0,0 +1,38 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see fem/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
# PYRAMID = 7
dimension
2
elements
2
1 3 0 1 4 3
1 2 1 2 4
boundary
5
1 1 0 1
1 1 1 2
1 1 2 4
1 1 4 3
1 1 3 0
vertices
5
2
0 0
1 0
2 0
0 1
1 1
+4
View File
@@ -201,6 +201,7 @@ namespace mfem {
* - <a class="el" href="nurbs__naca__cmesh_8cpp_source.html">NURBS NACA Mesher</a>: generate NURBS based mesh around a NACA foil
* - <a class="el" href="nurbs__printfunc_8cpp_source.html">NURBS Printer</a>: print the NURBS-basis
* - <a class="el" href="nurbs__mesh_info_8cpp_source.html">NURBS Mesh info</a>: print the info of a NURBS mesh
* - <a class="el" href="nurbs__surface_8cpp_source.html">NURBS Surface</a>: interpolate a 3D Surface in a NURBS Patch
*
* <H3>Miniapps</H3>
* - <a class="el" href="volta_8cpp_source.html">Volta</a>: simple electrostatics simulation code
@@ -245,6 +246,9 @@ namespace mfem {
* - <a class="el" href="pdiffusion_8cpp_source.html">DPG Diffusion example</a>: DPG formulation for the diffusion problem
* - <a class="el" href="pmaxwell_8cpp_source.html">DPG Maxwell example</a>: DPG formulation for the indefinite Maxwell problem
* - <a class="el" href="lor__elast_8cpp_source.html">LOR Elasticity</a>: solve linear elasticity with LOR preconditioning on GPUs
* - <a class="el" href="reflector_8cpp_source.html">Reflector Miniapp</a>: reflect a mesh about a plane
* - <a class="el" href="ref321_8cpp_source.html">3:1 Refinement Miniapp</a>: perform 3:1 anisotropic mesh refinements
* - <a class="el" href="pref321_8cpp_source.html">3:1 Refinement Miniapp</a>: parallel 3:1 anisotropic mesh refinements
*
* See also the <a class="el" href="https://mfem.org/examples/">examples documentation</a> online.
*/
+6
View File
@@ -57,6 +57,8 @@ set(SRCS
integ/lininteg_domain_grad.cpp
integ/lininteg_domain_vectorfe.cpp
integ/nonlininteg_vecconvection_pa.cpp
integ/nonlininteg_vecconvection_pa_diag.cpp
integ/nonlininteg_vecconvection_pa_grad.cpp
integ/nonlininteg_vecconvection_mf.cpp
coefficient.cpp
complex_fem.cpp
@@ -204,7 +206,11 @@ set(HDRS
integ/bilininteg_mass_kernels.hpp
integ/bilininteg_mass_pa_simplices.hpp
integ/bilininteg_vecdiffusion_pa.hpp
integ/bilininteg_vecdiv_pa.hpp
integ/bilininteg_vecmass_pa.hpp
integ/nonlininteg_vecconvection_pa.hpp
integ/nonlininteg_vecconvection_pa_diag.hpp
integ/nonlininteg_vecconvection_pa_grad.hpp
coefficient.hpp
complex_fem.hpp
convergence.hpp
+45 -4
View File
@@ -3003,11 +3003,10 @@ public:
vector (diagonal matrix), or matrix), trial function $u$ is in $H(curl$ or
$H(div)$, and test function $v$ is in $H(curl$, $H(div)$, or $v=(v_1,\dots,v_n)$, where
$v_i$ are in $H^1$. */
class VectorFEMassIntegrator: public BilinearFormIntegrator
class VectorFEMassIntegrator : public BilinearFormIntegrator
{
private:
void Init(Coefficient *q, DiagonalMatrixCoefficient *dq, MatrixCoefficient *mq)
{ Q = q; DQ = dq; MQ = mq; }
void Init(Coefficient *q, DiagonalMatrixCoefficient *dq, MatrixCoefficient *mq);
#ifndef MFEM_THREAD_SAFE
Vector shape;
@@ -3030,7 +3029,8 @@ protected:
const DofToQuad *mapsOtest; ///< Not owned. DOF-to-quad map, open.
const DofToQuad *mapsCtest; ///< Not owned. DOF-to-quad map, closed.
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq, dofs1D, dofs1Dtest, quad1D, trial_fetype, test_fetype;
int dim, ne, nq, dofs1D, dofs1Dtest, quad1D;
FiniteElement::DerivType trial_fetype, test_fetype;
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
public:
@@ -3061,6 +3061,29 @@ public:
const bool add) override;
const Coefficient *GetCoefficient() const { return Q; }
using ApplyKernelType =
void (*)(const int NE, bool symmetric, const bool scalar_coeff,
const Array<real_t> &trialBO, const Array<real_t> &trialBC,
const Array<real_t> &testBOt, const Array<real_t> &testBCt,
const Vector &pa_data, const Vector &x, Vector &y,
const int triald1d, const int testd1d, const int q1d);
/// parameters: trial_fetype, test_fetype, ndims, trial_d1d, test_d1d, q1d
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType,
(FiniteElement::DerivType, FiniteElement::DerivType,
int, int, int, int));
struct Kernels { Kernels(); };
template <FiniteElement::DerivType TrialType,
FiniteElement::DerivType TestType, int DIM, int TRIAL_D1D,
int TEST_D1D, int Q1D>
static void AddSpecialization()
{
ApplyPAKernels::Specialization<TrialType, TestType, DIM, TRIAL_D1D,
TEST_D1D, Q1D>::Add();
}
};
/** Integrator for $(Q \nabla \cdot u, v)$ where $u=(u_1,\cdots,u_n)$ and all $u_i$ are in the same
@@ -3106,6 +3129,24 @@ public:
void AddMultPA(const Vector &x, Vector &y) const override;
void AddMultTransposePA(const Vector &x, Vector &y) const override;
using VectorDivergenceAddMultPAType =
void (*)(const int ne,
const Array<real_t> &b, const Array<real_t> &g, const Array<real_t> &bt,
const Vector &op, const Vector &x, Vector &y,
const int tr_d1d, const int te_d1d, const int q1d);
MFEM_REGISTER_KERNELS(VectorDivergenceAddMultPA,
VectorDivergenceAddMultPAType,
(int, int, int, int));
using VectorDivergenceAddMultTransposePAType =
void (*)(const int ne,
const Array<real_t> &bt, const Array<real_t> &gt, const Array<real_t> &b,
const Vector &q, const Vector &x, Vector &y,
const int tr_d1d, const int te_d1d, const int q1d);
MFEM_REGISTER_KERNELS(VectorDivergenceAddMultTransposePA,
VectorDivergenceAddMultTransposePAType,
(int, int, int, int));
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
const FiniteElement &test_fe,
const ElementTransformation &Trans);
+931 -8
View File
@@ -237,6 +237,81 @@ ComplexGridFunction::ProjectBdrCoefficientTangent(VectorCoefficient
gfi->SyncAliasMemory(*this);
}
real_t
ComplexGridFunction::ComputeLpError(const real_t p,
Coefficient &exsolr,
Coefficient &exsoli,
Coefficient *weight,
const IntegrationRule *irs[],
const Array<int> *elems) const
{
real_t error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
Vector valsr;
Vector valsi;
const GridFunction& gf_r = real();
const GridFunction& gf_i = imag();
for (int i = 0; i < fes->GetNE(); i++)
{
if (elems != NULL && (*elems)[i] == 0) { continue; }
fe = fes->GetFE(i);
const IntegrationRule *ir;
if (irs)
{
ir = irs[fe->GetGeomType()];
}
else
{
int intorder = 2*fe->GetOrder() + 3;
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
}
real_t elem_error = 0.0;
gf_r.GetValues(i, *ir, valsr);
gf_i.GetValues(i, *ir, valsi);
T = fes->GetElementTransformation(i);
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
T->SetIntPoint(&ip);
real_t diffr = valsr(j) - exsolr.Eval(*T, ip);
real_t diffi = valsi(j) - exsoli.Eval(*T, ip);
real_t diff = hypot(diffr, diffi);
if (p < infinity())
{
diff = pow(diff, p);
if (weight)
{
diff *= weight->Eval(*T, ip);
}
elem_error += ip.weight * T->Weight() * diff;
}
else
{
if (weight)
{
diff *= weight->Eval(*T, ip);
}
error = std::max(error, diff);
}
}
if (p < infinity())
{
// negative quadrature weights may cause the error to be negative
error += fabs(elem_error);
}
}
if (p < infinity())
{
error = pow(error, 1./p);
}
return error;
}
void ComplexGridFunction::Save(std::ostream &os) const
{
os << "ComplexGridFunction\n";
@@ -643,8 +718,8 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::MFEM_SPARSEMAT ||
A_i.Type() == Operator::MFEM_SPARSEMAT )
if ((!A_r.Ptr() || A_r.Type() == Operator::MFEM_SPARSEMAT) &&
(!A_i.Ptr() || A_i.Type() == Operator::MFEM_SPARSEMAT))
{
ComplexSparseMatrix * A_sp =
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
@@ -704,8 +779,8 @@ SesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::MFEM_SPARSEMAT ||
A_i.Type() == Operator::MFEM_SPARSEMAT )
if ((!A_r.Ptr() || A_r.Type() == Operator::MFEM_SPARSEMAT) &&
(!A_i.Ptr() || A_i.Type() == Operator::MFEM_SPARSEMAT))
{
ComplexSparseMatrix * A_sp =
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
@@ -768,6 +843,426 @@ SesquilinearForm::Update(FiniteElementSpace *nfes)
if ( blfi ) { blfi->Update(nfes); }
}
bool
MixedSesquilinearForm::RealInteg()
{
int nint = mblfr->GetDBFI()->Size() + mblfr->GetBBFI()->Size() +
mblfr->GetFBFI()->Size() + mblfr->GetBFBFI()->Size() +
mblfr->GetTFBFI()->Size() + mblfr->GetBTFBFI()->Size();
return (nint != 0);
}
bool
MixedSesquilinearForm::ImagInteg()
{
int nint = mblfi->GetDBFI()->Size() + mblfi->GetBBFI()->Size() +
mblfi->GetFBFI()->Size() + mblfi->GetBFBFI()->Size() +
mblfi->GetTFBFI()->Size() + mblfi->GetBTFBFI()->Size();
return (nint != 0);
}
MixedSesquilinearForm::MixedSesquilinearForm(FiniteElementSpace * trial_fes,
FiniteElementSpace * test_fes,
ComplexOperator::Convention convention)
: conv(convention),
mblfr(new mfem::MixedBilinearForm(trial_fes, test_fes)),
mblfi(new mfem::MixedBilinearForm(trial_fes, test_fes))
{
}
MixedSesquilinearForm::MixedSesquilinearForm(FiniteElementSpace * trial_fes,
FiniteElementSpace * test_fes,
MixedBilinearForm * bfr,
MixedBilinearForm * bfi,
ComplexOperator::Convention convention)
: conv(convention),
mblfr(new MixedBilinearForm(trial_fes, test_fes, bfr)),
mblfi(new MixedBilinearForm(trial_fes, test_fes, bfi))
{
}
MixedSesquilinearForm::~MixedSesquilinearForm()
{
delete mblfr;
delete mblfi;
}
void
MixedSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
mblfr->AddDomainIntegrator(bfi_real);
}
if (bfi_imag)
{
mblfi->AddDomainIntegrator(bfi_imag);
}
}
void
MixedSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & elem_marker)
{
if (bfi_real)
{
mblfr->AddDomainIntegrator(bfi_real, elem_marker);
}
if (bfi_imag)
{
mblfi->AddDomainIntegrator(bfi_imag, elem_marker);
}
}
void
MixedSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
mblfr->AddBoundaryIntegrator(bfi_real);
}
if (bfi_imag)
{
mblfi->AddBoundaryIntegrator(bfi_imag);
}
}
void
MixedSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & bdr_marker)
{
if (bfi_real)
{
mblfr->AddBoundaryIntegrator(bfi_real, bdr_marker);
}
if (bfi_imag)
{
mblfi->AddBoundaryIntegrator(bfi_imag, bdr_marker);
}
}
void
MixedSesquilinearForm::AddInteriorFaceIntegrator(BilinearFormIntegrator *
bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
mblfr->AddInteriorFaceIntegrator(bfi_real);
}
if (bfi_imag)
{
mblfi->AddInteriorFaceIntegrator(bfi_imag);
}
}
void
MixedSesquilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
mblfr->AddBdrFaceIntegrator(bfi_real);
}
if (bfi_imag)
{
mblfi->AddBdrFaceIntegrator(bfi_imag);
}
}
void
MixedSesquilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & bdr_marker)
{
if (bfi_real)
{
mblfr->AddBdrFaceIntegrator(bfi_real, bdr_marker);
}
if (bfi_imag)
{
mblfi->AddBdrFaceIntegrator(bfi_imag, bdr_marker);
}
}
void MixedSesquilinearForm::AddTraceFaceIntegrator(BilinearFormIntegrator *
bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
mblfr->AddTraceFaceIntegrator(bfi_real);
}
if (bfi_imag)
{
mblfi->AddTraceFaceIntegrator(bfi_imag);
}
}
void MixedSesquilinearForm::AddBdrTraceFaceIntegrator(BilinearFormIntegrator
*bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real)
{
mblfr->AddBdrTraceFaceIntegrator(bfi_real);
}
if (bfi_imag)
{
mblfi->AddBdrTraceFaceIntegrator(bfi_imag);
}
}
void MixedSesquilinearForm::AddBdrTraceFaceIntegrator(BilinearFormIntegrator
*bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> &bdr_marker)
{
if (bfi_real)
{
mblfr->AddBdrTraceFaceIntegrator(bfi_real, bdr_marker);
}
if (bfi_imag)
{
mblfi->AddBdrTraceFaceIntegrator(bfi_imag, bdr_marker);
}
}
void
MixedSesquilinearForm::Assemble(int skip_zeros)
{
mblfr->Assemble(skip_zeros);
mblfi->Assemble(skip_zeros);
}
void
MixedSesquilinearForm::Finalize(int skip_zeros)
{
mblfr->Finalize(skip_zeros);
mblfi->Finalize(skip_zeros);
}
ComplexSparseMatrix *
MixedSesquilinearForm::AssembleComplexSparseMatrix()
{
return new mfem::ComplexSparseMatrix(
&mblfr->SpMat(), &mblfi->SpMat(), false, false, conv);
}
void
MixedSesquilinearForm::FormRectangularLinearSystem(const Array<int> &
ess_trial_tdof_list,
const Array<int> & ess_test_tdof_list,
Vector & x,
Vector & b,
OperatorHandle & A,
Vector & X,
Vector & B)
{
FiniteElementSpace * fes_trial = mblfr->TrialFESpace();
FiniteElementSpace * fes_test = mblfr->TestFESpace();
const int vsize_trial = fes_trial->GetVSize();
const int vsize_test = fes_test->GetVSize();
// Allocate temporary Vector
Vector b_0;
b_0.UseDevice(true);
b_0.SetSize(vsize_test);
b_0 = 0.0;
// Extract the real and imaginary parts of the input Vectors
MFEM_ASSERT(x.Size() == 2 * vsize_trial,
"Input GridFunction of incorrect size!");
x.Read();
Vector x_r;
x_r.MakeRef(x, 0, vsize_trial);
Vector x_i;
x_i.MakeRef(x, vsize_trial, vsize_trial);
MFEM_ASSERT(b.Size() == 2 * vsize_test, "Input LinearForm of incorrect size!");
b.Read();
Vector b_r;
b_r.MakeRef(b, 0, vsize_test);
Vector b_i;
b_i.MakeRef(b, vsize_test, vsize_test);
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
b_i *= -1.0;
}
const int tvsize_trial = fes_trial->GetTrueVSize();
const int tvsize_test = fes_test->GetTrueVSize();
OperatorHandle A_r, A_i;
X.UseDevice(true);
X.SetSize(2 * tvsize_trial);
X = 0.0;
B.UseDevice(true);
B.SetSize(2 * tvsize_test);
B = 0.0;
Vector X_r;
X_r.MakeRef(X, 0, tvsize_trial);
Vector X_i;
X_i.MakeRef(X, tvsize_trial, tvsize_trial);
Vector B_r;
B_r.MakeRef(B, 0, tvsize_test);
Vector B_i;
B_i.MakeRef(B, tvsize_test, tvsize_test);
Vector X_0, B_0;
if (RealInteg())
{
b_0 = b_r;
mblfr->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_r, b_0, A_r, X_0, B_0);
X_r = X_0;
B_r = B_0;
b_0 = b_i;
mblfr->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_i, b_0, A_r, X_0, B_0);
X_i = X_0;
B_i = B_0;
if (ImagInteg())
{
b_0 = 0.0;
mblfi->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_i, b_0, A_i, X_0, B_0);
B_r -= B_0;
b_0 = 0.0;
mblfi->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_r, b_0, A_i, X_0, B_0);
B_i += B_0;
}
}
else if (ImagInteg())
{
b_0 = b_i;
mblfi->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_r, b_0, A_i, X_0, B_0);
X_r = X_0;
B_i = B_0;
b_0 = b_r;
b_0 *= -1.0;
mblfi->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_i, b_0, A_i, X_0, B_0);
X_i = X_0;
B_r = B_0;
B_r *= -1.0;
}
else
{
MFEM_ABORT("Real and Imaginary part of the Mixed Sesquilinear form are empty");
}
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
B_i *= -1.0;
b_i *= -1.0;
}
x_r.SyncAliasMemory(x);
x_i.SyncAliasMemory(x);
b_r.SyncAliasMemory(b);
b_i.SyncAliasMemory(b);
X_r.SyncAliasMemory(X);
X_i.SyncAliasMemory(X);
B_r.SyncAliasMemory(B);
B_i.SyncAliasMemory(B);
// A = A_r + i A_i
A.Clear();
if ((!A_r.Ptr() || A_r.Type() == Operator::MFEM_SPARSEMAT) &&
(!A_i.Ptr() || A_i.Type() == Operator::MFEM_SPARSEMAT))
{
ComplexSparseMatrix * A_hyp =
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
A_i.As<SparseMatrix>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexSparseMatrix>(A_hyp, true);
}
else
{
ComplexOperator * A_op = new ComplexOperator(A_r.As<Operator>(),
A_i.As<Operator>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexOperator>(A_op, true);
}
A_r.SetOperatorOwner(false);
A_i.SetOperatorOwner(false);
}
void
MixedSesquilinearForm::FormRectangularSystemMatrix(const mfem::Array<int> &
ess_trial_tdof_list,
const mfem::Array<int> & ess_test_tdof_list,
mfem::OperatorHandle & A)
{
OperatorHandle A_r, A_i;
if (RealInteg())
{
mblfr->FormRectangularSystemMatrix(ess_trial_tdof_list, ess_test_tdof_list,
A_r);
}
if (ImagInteg())
{
mblfi->FormRectangularSystemMatrix(ess_trial_tdof_list, ess_test_tdof_list,
A_i);
}
if (!RealInteg() && !ImagInteg())
{
MFEM_ABORT("Both Real and Imaginary part of the Mixed Sesquilinear form are empty");
}
// A = A_r + i A_i
A.Clear();
if ((!A_r.Ptr() || A_r.Type() == Operator::MFEM_SPARSEMAT) &&
(!A_i.Ptr() || A_i.Type() == Operator::MFEM_SPARSEMAT))
{
ComplexSparseMatrix * A_hyp =
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
A_i.As<SparseMatrix>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexSparseMatrix>(A_hyp, true);
}
else
{
ComplexOperator * A_op = new ComplexOperator(A_r.As<Operator>(),
A_i.As<Operator>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexOperator>(A_op, true);
}
A_r.SetOperatorOwner(false);
A_i.SetOperatorOwner(false);
}
void
MixedSesquilinearForm::Update()
{
mblfr->Update();
mblfi->Update();
}
#ifdef MFEM_USE_MPI
@@ -1539,8 +2034,8 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::Hypre_ParCSR ||
A_i.Type() == Operator::Hypre_ParCSR )
if ((!A_r.Ptr() || A_r.Type() == Operator::Hypre_ParCSR) &&
(!A_i.Ptr() || A_i.Type() == Operator::Hypre_ParCSR))
{
ComplexHypreParMatrix * A_hyp =
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
@@ -1607,8 +2102,8 @@ ParSesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
// A = A_r + i A_i
A.Clear();
if ( A_r.Type() == Operator::Hypre_ParCSR ||
A_i.Type() == Operator::Hypre_ParCSR )
if ((!A_r.Ptr() || A_r.Type() == Operator::Hypre_ParCSR) &&
(!A_i.Ptr() || A_i.Type() == Operator::Hypre_ParCSR))
{
ComplexHypreParMatrix * A_hyp =
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
@@ -1666,6 +2161,434 @@ ParSesquilinearForm::Update(FiniteElementSpace *nfes)
if ( pblfi ) { pblfi->Update(nfes); }
}
bool
ParMixedSesquilinearForm::RealInteg()
{
int nint = pmblfr->GetDBFI()->Size() + pmblfr->GetBBFI()->Size() +
pmblfr->GetFBFI()->Size() + pmblfr->GetBFBFI()->Size() +
pmblfr->GetTFBFI()->Size() + pmblfr->GetBTFBFI()->Size();
return (nint != 0);
}
bool
ParMixedSesquilinearForm::ImagInteg()
{
int nint = pmblfi->GetDBFI()->Size() + pmblfi->GetBBFI()->Size() +
pmblfi->GetFBFI()->Size() + pmblfi->GetBFBFI()->Size() +
pmblfi->GetTFBFI()->Size() + pmblfi->GetBTFBFI()->Size();
return (nint != 0);
}
ParMixedSesquilinearForm::ParMixedSesquilinearForm(ParFiniteElementSpace *
trial_fes,
ParFiniteElementSpace * test_fes,
ComplexOperator::Convention convention)
: conv(convention),
pmblfr(new ParMixedBilinearForm(trial_fes, test_fes)),
pmblfi(new ParMixedBilinearForm(trial_fes, test_fes))
{
}
ParMixedSesquilinearForm::ParMixedSesquilinearForm(ParFiniteElementSpace *
trial_fes,
ParFiniteElementSpace * test_fes,
ParMixedBilinearForm * pbfr,
ParMixedBilinearForm * pbfi,
ComplexOperator::Convention convention)
: conv(convention),
pmblfr(new ParMixedBilinearForm(trial_fes, test_fes, pbfr)),
pmblfi(new ParMixedBilinearForm(trial_fes, test_fes, pbfi))
{
}
ParMixedSesquilinearForm::~ParMixedSesquilinearForm()
{
delete pmblfr;
delete pmblfi;
}
void
ParMixedSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
pmblfr->AddDomainIntegrator(bfi_real);
}
if (bfi_imag)
{
pmblfi->AddDomainIntegrator(bfi_imag);
}
}
void
ParMixedSesquilinearForm::AddDomainIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & elem_marker)
{
if (bfi_real)
{
pmblfr->AddDomainIntegrator(bfi_real, elem_marker);
}
if (bfi_imag)
{
pmblfi->AddDomainIntegrator(bfi_imag, elem_marker);
}
}
void
ParMixedSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *
bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
pmblfr->AddBoundaryIntegrator(bfi_real);
}
if (bfi_imag)
{
pmblfi->AddBoundaryIntegrator(bfi_imag);
}
}
void
ParMixedSesquilinearForm::AddBoundaryIntegrator(BilinearFormIntegrator *
bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & bdr_marker)
{
if (bfi_real)
{
pmblfr->AddBoundaryIntegrator(bfi_real, bdr_marker);
}
if (bfi_imag)
{
pmblfi->AddBoundaryIntegrator(bfi_imag, bdr_marker);
}
}
void
ParMixedSesquilinearForm::AddInteriorFaceIntegrator(BilinearFormIntegrator *
bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
pmblfr->AddInteriorFaceIntegrator(bfi_real);
}
if (bfi_imag)
{
pmblfi->AddInteriorFaceIntegrator(bfi_imag);
}
}
void
ParMixedSesquilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *
bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
pmblfr->AddBdrFaceIntegrator(bfi_real);
}
if (bfi_imag)
{
pmblfi->AddBdrFaceIntegrator(bfi_imag);
}
}
void
ParMixedSesquilinearForm::AddBdrFaceIntegrator(BilinearFormIntegrator *
bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & bdr_marker)
{
if (bfi_real)
{
pmblfr->AddBdrFaceIntegrator(bfi_real, bdr_marker);
}
if (bfi_imag)
{
pmblfi->AddBdrFaceIntegrator(bfi_imag, bdr_marker);
}
}
void ParMixedSesquilinearForm::AddTraceFaceIntegrator(BilinearFormIntegrator *
bfi_real,
BilinearFormIntegrator * bfi_imag)
{
if (bfi_real)
{
pmblfr->AddTraceFaceIntegrator(bfi_real);
}
if (bfi_imag)
{
pmblfi->AddTraceFaceIntegrator(bfi_imag);
}
}
void ParMixedSesquilinearForm::AddBdrTraceFaceIntegrator(
BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag)
{
if (bfi_real)
{
pmblfr->AddBdrTraceFaceIntegrator(bfi_real);
}
if (bfi_imag)
{
pmblfi->AddBdrTraceFaceIntegrator(bfi_imag);
}
}
void ParMixedSesquilinearForm::AddBdrTraceFaceIntegrator(
BilinearFormIntegrator *bfi_real,
BilinearFormIntegrator *bfi_imag,
Array<int> &bdr_marker)
{
if (bfi_real)
{
pmblfr->AddBdrTraceFaceIntegrator(bfi_real, bdr_marker);
}
if (bfi_imag)
{
pmblfi->AddBdrTraceFaceIntegrator(bfi_imag, bdr_marker);
}
}
void
ParMixedSesquilinearForm::Assemble(int skip_zeros)
{
pmblfr->Assemble(skip_zeros);
pmblfi->Assemble(skip_zeros);
}
void
ParMixedSesquilinearForm::Finalize(int skip_zeros)
{
pmblfr->Finalize(skip_zeros);
pmblfi->Finalize(skip_zeros);
}
ComplexHypreParMatrix *
ParMixedSesquilinearForm::ParallelAssemble()
{
return new ComplexHypreParMatrix(
pmblfr->ParallelAssemble(), pmblfi->ParallelAssemble(), true, true, conv);
}
void
ParMixedSesquilinearForm::FormRectangularLinearSystem(const Array<int> &
ess_trial_tdof_list,
const Array<int> & ess_test_tdof_list,
Vector & x,
Vector & b,
OperatorHandle & A,
Vector & X,
Vector & B)
{
FiniteElementSpace * pfes_trial = pmblfr->TrialFESpace();
FiniteElementSpace * pfes_test = pmblfr->TestFESpace();
const int vsize_trial = pfes_trial->GetVSize();
const int vsize_test = pfes_test->GetVSize();
// Allocate temporary Vector
Vector b_0;
b_0.UseDevice(true);
b_0.SetSize(vsize_test);
b_0 = 0.0;
// Extract the real and imaginary parts of the input Vectors
MFEM_ASSERT(x.Size() == 2 * vsize_trial,
"Input GridFunction of incorrect size!");
x.Read();
Vector x_r;
x_r.MakeRef(x, 0, vsize_trial);
Vector x_i;
x_i.MakeRef(x, vsize_trial, vsize_trial);
MFEM_ASSERT(b.Size() == 2 * vsize_test, "Input LinearForm of incorrect size!");
b.Read();
Vector b_r;
b_r.MakeRef(b, 0, vsize_test);
Vector b_i;
b_i.MakeRef(b, vsize_test, vsize_test);
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
b_i *= -1.0;
}
const int tvsize_trial = pfes_trial->GetTrueVSize();
const int tvsize_test = pfes_test->GetTrueVSize();
OperatorHandle A_r, A_i;
X.UseDevice(true);
X.SetSize(2 * tvsize_trial);
X = 0.0;
B.UseDevice(true);
B.SetSize(2 * tvsize_test);
B = 0.0;
Vector X_r;
X_r.MakeRef(X, 0, tvsize_trial);
Vector X_i;
X_i.MakeRef(X, tvsize_trial, tvsize_trial);
Vector B_r;
B_r.MakeRef(B, 0, tvsize_test);
Vector B_i;
B_i.MakeRef(B, tvsize_test, tvsize_test);
Vector X_0, B_0;
if (RealInteg())
{
b_0 = b_r;
pmblfr->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_r, b_0, A_r, X_0, B_0);
X_r = X_0;
B_r = B_0;
b_0 = b_i;
pmblfr->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_i, b_0, A_r, X_0, B_0);
X_i = X_0;
B_i = B_0;
if (ImagInteg())
{
b_0 = 0.0;
pmblfi->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_i, b_0, A_i, X_0, B_0);
B_r -= B_0;
b_0 = 0.0;
pmblfi->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_r, b_0, A_i, X_0, B_0);
B_i += B_0;
}
}
else if (ImagInteg())
{
b_0 = b_i;
pmblfi->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_r, b_0, A_i, X_0, B_0);
X_r = X_0;
B_i = B_0;
b_0 = b_r;
b_0 *= -1.0;
pmblfi->FormRectangularLinearSystem(
ess_trial_tdof_list, ess_test_tdof_list, x_i, b_0, A_i, X_0, B_0);
X_i = X_0;
B_r = B_0;
B_r *= -1.0;
}
else
{
MFEM_ABORT("Real and Imaginary part of the Mixed Sesquilinear form are empty");
}
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
{
B_i *= -1.0;
b_i *= -1.0;
}
x_r.SyncAliasMemory(x);
x_i.SyncAliasMemory(x);
b_r.SyncAliasMemory(b);
b_i.SyncAliasMemory(b);
X_r.SyncAliasMemory(X);
X_i.SyncAliasMemory(X);
B_r.SyncAliasMemory(B);
B_i.SyncAliasMemory(B);
// A = A_r + i A_i
A.Clear();
if ((!A_r.Ptr() || A_r.Type() == Operator::Hypre_ParCSR) &&
(!A_i.Ptr() || A_i.Type() == Operator::Hypre_ParCSR))
{
ComplexHypreParMatrix * A_hyp =
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
A_i.As<HypreParMatrix>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexHypreParMatrix>(A_hyp, true);
}
else
{
ComplexOperator * A_op = new ComplexOperator(A_r.As<Operator>(),
A_i.As<Operator>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexOperator>(A_op, true);
}
A_r.SetOperatorOwner(false);
A_i.SetOperatorOwner(false);
}
void
ParMixedSesquilinearForm::FormRectangularSystemMatrix(const Array<int> &
ess_trial_tdof_list,
const Array<int> & ess_test_tdof_list,
OperatorHandle & A)
{
OperatorHandle A_r, A_i;
if (RealInteg())
{
pmblfr->FormRectangularSystemMatrix(ess_trial_tdof_list, ess_test_tdof_list,
A_r);
}
if (ImagInteg())
{
pmblfi->FormRectangularSystemMatrix(ess_trial_tdof_list, ess_test_tdof_list,
A_i);
}
if (!RealInteg() && !ImagInteg())
{
MFEM_ABORT("Both Real and Imaginary part of the Mixed Sesquilinear form are empty");
}
// A = A_r + i A_i
A.Clear();
if ((!A_r.Ptr() || A_r.Type() == Operator::Hypre_ParCSR) &&
(!A_i.Ptr() || A_i.Type() == Operator::Hypre_ParCSR))
{
ComplexHypreParMatrix * A_hyp =
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
A_i.As<HypreParMatrix>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexHypreParMatrix>(A_hyp, true);
}
else
{
ComplexOperator * A_op = new ComplexOperator(A_r.As<Operator>(),
A_i.As<Operator>(),
A_r.OwnsOperator(),
A_i.OwnsOperator(),
conv);
A.Reset<ComplexOperator>(A_op, true);
}
A_r.SetOperatorOwner(false);
A_i.SetOperatorOwner(false);
}
void
ParMixedSesquilinearForm::Update()
{
pmblfr->Update();
pmblfi->Update();
}
#endif // MFEM_USE_MPI
}
+412
View File
@@ -166,6 +166,75 @@ public:
return sqrt(err_r * err_r + err_i * err_i);
}
/// @brief Returns Max|u_ex - u_h| error for complex-valued H1 or L2 elements
///
/// Compute the $L_\infty$ error across the entire domain.
///
/// @param[in] exsolr Coefficient object reproducing the real part of the
/// anticipated values of the scalar field, Re(u_ex).
/// @param[in] exsoli Coefficient object reproducing the imaginary part of
/// the anticipated values of the scalar field, Im(u_ex).
/// @param[in] irs Optional pointer to an array of custom integration
/// rules e.g. higher order than the default rules. If
/// present the array will be indexed by
/// Geometry::Type.
///
/// @note Uses ComputeLpError internally. See the ComputeLpError
/// documentation for generalizations of this error computation.
///
/// @note If an array of integration rules is provided through @a irs, be
/// sure to include valid rules for each element type that may occur
/// in the list of elements.
///
virtual real_t ComputeMaxError(Coefficient &exsolr,
Coefficient &exsoli,
const IntegrationRule *irs[] = NULL) const
{
return ComputeLpError(infinity(), exsolr, exsoli, NULL, irs);
}
/// @brief Returns ||u_ex - u_h||_Lp for complex-valued H1 or L2 elements
///
/// Computes:
/// $$(\sum_{elems} \int_{elem} w \, |u_{ex} - u_h|^p)^{1/p}$$
/// Where:
/// $$|u_{ex} - u_h| = \sqrt{Re(u_{ex} - u_h)^2 + Im(u_{ex} - u_h)^2}$$
///
/// @param[in] p Real value indicating the exponent of the $L^p$ norm.
/// To avoid domain errors p should have a positive value,
/// either finite or infinite.
/// @param[in] exsolr Coefficient object reproducing the real part of the
/// anticipated values of the scalar field, Re(u_ex).
/// @param[in] exsoli Coefficient object reproducing the imaginary part of
/// the anticipated values of the scalar field, Im(u_ex).
/// @param[in] weight Optional pointer to a Coefficient object reproducing
/// a weighting function, w.
/// @param[in] irs Optional pointer to an array of custom integration
/// rules e.g. higher order than the default rules. If
/// present the array will be indexed by Geometry::Type.
/// @param[in] elems Optional pointer to a marker array, with a length
/// equal to the number of local elements, indicating
/// which elements to integrate over. Only those elements
/// corresponding to non-zero entries in @a elems will
/// contribute to the computed L2 error.
///
/// @note If an array of integration rules is provided through @a irs, be
/// sure to include valid rules for each element type that may occur
/// in the list of elements.
///
/// @note Quadratures with negative weights (as in some simplex integration
/// rules in MFEM) can produce negative integrals even with
/// non-negative integrands. To avoid returning negative errors this
/// function uses the absolute values of the element-wise integrals.
/// This may lead to results which are not entirely consistent with
/// such integration rules.
virtual real_t ComputeLpError(const real_t p,
Coefficient &exsolr,
Coefficient &exsoli,
Coefficient *weight = NULL,
const IntegrationRule *irs[] = NULL,
const Array<int> *elems = NULL) const;
/// Save the ComplexGridFunction to an output stream.
virtual void Save(std::ostream &out) const;
@@ -436,6 +505,186 @@ public:
virtual ~SesquilinearForm();
};
/** Class for a mixed sesquilinear form
A mixed sesquilinear form is a generalization of a mixed bilinear form to
complex-valued fields. Mixed sesquilinear forms are linear in the second
argument but the first argument involves a complex conjugate in the sense
that:
a(alpha u, beta v) = conj(alpha) beta a(u, v)
The @a convention argument in the class's constructor is documented in the
mfem::ComplexOperator class found in linalg/complex_operator.hpp.
When supplying integrators to the MixedSesquilinearForm either the real or
imaginary integrator can be NULL. This indicates that the corresponding
portion of the complex-valued material coefficient is equal to zero.
*/
class MixedSesquilinearForm
{
private:
ComplexOperator::Convention conv;
MixedBilinearForm * mblfr;
MixedBilinearForm * mblfi;
/* These methods check if the real/imag parts of the sesqulinear form are not
empty */
bool RealInteg();
bool ImagInteg();
public:
MixedSesquilinearForm(
FiniteElementSpace * trial_fes,
FiniteElementSpace * test_fes,
ComplexOperator::Convention convention = ComplexOperator::HERMITIAN);
/** @brief Create a MixedSesquilinearForm on the given trial and test
FiniteElementSpaces, using the same integrators as the
MixedBilinearForms @a bfr and @a bfi.
The FiniteElementSpace pointers are not owned by the newly constructed
object.
The integrators are copied as pointers and they are not owned by the
newly constructed MixedSesquilinearForm. */
MixedSesquilinearForm(
FiniteElementSpace * trial_fes,
FiniteElementSpace * test_fes,
MixedBilinearForm * bfr,
MixedBilinearForm * bfi,
ComplexOperator::Convention convention = ComplexOperator::HERMITIAN);
ComplexOperator::Convention GetConvention() const { return conv; }
void SetConvention(const ComplexOperator::Convention & convention) { conv = convention; }
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::LEGACY (default)
- AssemblyLevel::FULL
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level)
{
mblfr->SetAssemblyLevel(assembly_level);
mblfi->SetAssemblyLevel(assembly_level);
}
MixedBilinearForm & real() { return *mblfr; }
MixedBilinearForm & imag() { return *mblfi; }
const MixedBilinearForm & real() const { return *mblfr; }
const MixedBilinearForm & imag() const { return *mblfi; }
/// Adds new Domain Integrator.
void AddDomainIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/// Adds new Domain Integrator, restricted to specific attributes.
void AddDomainIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & elem_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/** @brief Adds new boundary Integrator, restricted to specific boundary
attributes.
Assumes ownership of @a bfi.
The mfem::array @a bdr_marker is stored internally as a pointer to the given
mfem::Array<int> object. */
void AddBoundaryIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & bdr_marker);
/// Adds new interior Face Integrator. Assumes ownership of @a bfi.
void AddInteriorFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/// Adds new boundary Face Integrator. Assumes ownership of @a bfi.
void AddBdrFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/** @brief Adds new boundary Face Integrator, restricted to specific boundary
attributes.
Assumes ownership of @a bfi.
The mfem::array @a bdr_marker is stored internally as a pointer to the given
mfem::Array<int> object. */
void AddBdrFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & bdr_marker);
/** @brief Add a trace face integrator. Assumes ownership of @a bfi.
This type of integrator assembles terms over all faces of the mesh using
the face FE from the trial space and the two adjacent volume FEs from
the test space. */
void AddTraceFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/// Adds a boundary trace face integrator. Assumes ownership of @a bfi.
void AddBdrTraceFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/// Adds a boundary trace face integrator. Assumes ownership of @a bfi.
void AddBdrTraceFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> &bdr_marker);
/// Assemble the local matrix
void Assemble(int skip_zeros = 1);
/// Finalizes the matrix initialization.
void Finalize(int skip_zeros = 1);
/// Updates the internal mixed forms with the new finite element space.
virtual void Update();
/** @brief Return a ComplexSparseMatrix wrapping the local (L-dof) real
and imaginary matrices of the form.
The returned wrapper has to be deleted by the caller, but it does not
own the wrapped real and imaginary matrices, which remain owned by
this form. */
ComplexSparseMatrix *AssembleComplexSparseMatrix();
/// Return the trial FE space associated with the MixedSesquilinearForm.
FiniteElementSpace *TrialFESpace() { return mblfr->TrialFESpace(); }
/// Read-only access to the associated trial FiniteElementSpace.
const FiniteElementSpace *TrialFESpace() const { return mblfr->TrialFESpace(); }
/// Return the test FE space associated with the MixedSesquilinearForm.
FiniteElementSpace *TestFESpace() { return mblfr->TestFESpace(); }
/// Read-only access to the associated test FiniteElementSpace.
const FiniteElementSpace *TestFESpace() const { return mblfr->TestFESpace(); }
void FormRectangularLinearSystem(const Array<int> & ess_trial_tdof_list,
const Array<int> & ess_test_tdof_list,
Vector & x,
Vector & b,
OperatorHandle & A,
Vector & X,
Vector & B);
void FormRectangularSystemMatrix(const Array<int> & ess_trial_tdof_list,
const Array<int> & ess_test_tdof_list,
OperatorHandle & A);
virtual ~MixedSesquilinearForm();
};
#ifdef MFEM_USE_MPI
/// Class for parallel complex-valued grid function - real + imaginary part
@@ -852,6 +1101,169 @@ public:
virtual ~ParSesquilinearForm();
};
/** Class for a parallel mixed sesquilinear form
A mixed sesquilinear form is a generalization of a mixed bilinear form to
complex-valued fields. Mixed sesquilinear forms are linear in the second
argument but the first argument involves a complex conjugate in the sense
that:
a(alpha u, beta v) = conj(alpha) beta a(u, v)
The @a convention argument in the class's constructor is documented in the
mfem::ComplexOperator class found in linalg/complex_operator.hpp.
When supplying integrators to the ParMixedSesquilinearForm either the real
or imaginary integrator can be NULL. This indicates that the corresponding
portion of the complex-valued material coefficient is equal to zero.
*/
class ParMixedSesquilinearForm
{
private:
ComplexOperator::Convention conv;
ParMixedBilinearForm * pmblfr;
ParMixedBilinearForm * pmblfi;
/* These methods check if the real/imag parts of the sesqulinear form are
not empty */
bool RealInteg();
bool ImagInteg();
public:
ParMixedSesquilinearForm(
ParFiniteElementSpace * trial_fes,
ParFiniteElementSpace * test_fes,
ComplexOperator::Convention convention = ComplexOperator::HERMITIAN);
/** @brief Create a ParMixedSesquilinearForm on the given trial and test
ParFiniteElementSpaces, using the same integrators as the
ParMixedBilinearForms @a pbfr and @a pbfi.
The ParFiniteElementSpace pointers are not owned by the newly
constructed object.
The integrators are copied as pointers and they are not owned by the
newly constructed ParMixedSesquilinearForm. */
ParMixedSesquilinearForm(
ParFiniteElementSpace * trial_fes,
ParFiniteElementSpace * test_fes,
ParMixedBilinearForm * pbfr,
ParMixedBilinearForm * pbfi,
ComplexOperator::Convention convention = ComplexOperator::HERMITIAN);
ComplexOperator::Convention GetConvention() const { return conv; }
void SetConvention(const ComplexOperator::Convention & convention) { conv = convention; }
/// Set the desired assembly level.
/** Valid choices are:
- AssemblyLevel::LEGACY (default)
- AssemblyLevel::FULL
- AssemblyLevel::PARTIAL
- AssemblyLevel::ELEMENT
- AssemblyLevel::NONE
This method must be called before assembly. */
void SetAssemblyLevel(AssemblyLevel assembly_level)
{
pmblfr->SetAssemblyLevel(assembly_level);
pmblfi->SetAssemblyLevel(assembly_level);
}
ParMixedBilinearForm & real() { return *pmblfr; }
ParMixedBilinearForm & imag() { return *pmblfi; }
const ParMixedBilinearForm & real() const { return *pmblfr; }
const ParMixedBilinearForm & imag() const { return *pmblfi; }
/// Adds new Domain Integrator.
void AddDomainIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/// Adds new Domain Integrator, restricted to specific attributes.
void AddDomainIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & elem_marker);
/// Adds new Boundary Integrator.
void AddBoundaryIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/** @brief Adds new boundary Integrator, restricted to specific boundary
attributes.
Assumes ownership of @a bfi.
The mfem::array @a bdr_marker is stored internally as a pointer to the given
mfem::Array<int> object. */
void AddBoundaryIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & bdr_marker);
/// Adds new interior Face Integrator. Assumes ownership of @a bfi.
void AddInteriorFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/// Adds new boundary Face Integrator. Assumes ownership of @a bfi.
void AddBdrFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/** @brief Adds new boundary Face Integrator, restricted to specific boundary
attributes.
Assumes ownership of @a bfi.
The mfem::array @a bdr_marker is stored internally as a pointer to the given
mfem::Array<int> object. */
void AddBdrFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> & bdr_marker);
/** @brief Add a trace face integrator. Assumes ownership of @a bfi.
This type of integrator assembles terms over all faces of the mesh using
the face FE from the trial space and the two adjacent volume FEs from
the test space. */
void AddTraceFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/// Adds a boundary trace face integrator. Assumes ownership of @a bfi.
void AddBdrTraceFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag);
/// Adds a boundary trace face integrator. Assumes ownership of @a bfi.
void AddBdrTraceFaceIntegrator(BilinearFormIntegrator * bfi_real,
BilinearFormIntegrator * bfi_imag,
Array<int> &bdr_marker);
/// Assemble the local matrix
void Assemble(int skip_zeros = 1);
/// Finalizes the matrix initialization.
void Finalize(int skip_zeros = 1);
/// Updates the internal mixed forms with the new finite element space.
virtual void Update();
/// Returns the matrix assembled on the true dofs, i.e. P^t A P.
/** The returned matrix has to be deleted by the caller. */
ComplexHypreParMatrix * ParallelAssemble();
void FormRectangularLinearSystem(const Array<int> & ess_trial_tdof_list,
const Array<int> & ess_test_tdof_list,
Vector & x,
Vector & b,
OperatorHandle & A,
Vector & X,
Vector & B);
void FormRectangularSystemMatrix(const Array<int> & ess_trial_tdof_list,
const Array<int> & ess_test_tdof_list,
OperatorHandle & A);
virtual ~ParMixedSesquilinearForm();
};
#endif // MFEM_USE_MPI
}
+4 -2
View File
@@ -809,7 +809,7 @@ ParaViewDataCollectionBase::ParaViewDataCollectionBase(
void ParaViewDataCollectionBase::SetLevelsOfDetail(int levels_of_detail_)
{
levels_of_detail = levels_of_detail_;
levels_of_detail = std::max(levels_of_detail_, 1);
}
void ParaViewDataCollectionBase::SetHighOrderOutput(bool high_order_output_)
@@ -1181,12 +1181,14 @@ void ParaViewDataCollection::SaveGFieldVTU(std::ostream &os, int ref_,
DenseMatrix vval, pmat;
std::vector<char> buf;
int vec_dim = it->second->VectorDim();
int map_type = it->second->FESpace()->GetTypicalFE()->GetMapType();
os << "<DataArray type=\"" << GetDataTypeString()
<< "\" Name=\"" << it->first
<< "\" NumberOfComponents=\"" << vec_dim << "\" "
<< VTKComponentLabels(vec_dim) << " "
<< "format=\"" << GetDataFormatString() << "\" >" << '\n';
if (vec_dim == 1)
if (vec_dim == 1 && (map_type == FiniteElement::VALUE ||
map_type == FiniteElement::INTEGRAL))
{
for (int i = 0; i < mesh->GetNE(); i++)
{
+4 -4
View File
@@ -307,12 +307,12 @@ public:
/** @brief virtual function which evaluates the values of all
shape functions at a given point ip and stores
them in the vector shape of dimension Dof (4) */
them in the vector shape of dimension Dof (6) */
void CalcShape(const IntegrationPoint &ip, Vector &shape) const override;
/** @brief virtual function which evaluates the values of all
partial derivatives of all shape functions at a given
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
point ip and stores them in the matrix dshape (Dof x Dim) (6 x 3)
so that each row contains the derivatives of one shape function */
void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const override;
@@ -336,12 +336,12 @@ public:
/** @brief virtual function which evaluates the values of all
shape functions at a given point ip and stores
them in the vector shape of dimension Dof (4) */
them in the vector shape of dimension Dof (5) */
void CalcShape(const IntegrationPoint &ip, Vector &shape) const override;
/** @brief virtual function which evaluates the values of all
partial derivatives of all shape functions at a given
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
point ip and stores them in the matrix dshape (Dof x Dim) (5 x 3)
so that each row contains the derivatives of one shape function */
void CalcDShape(const IntegrationPoint &ip,
DenseMatrix &dshape) const override;
+131 -58
View File
@@ -1757,22 +1757,45 @@ H1_BergotPyramidElement::H1_BergotPyramidElement(const int p, const int btype)
real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
o = 0;
for (int i = 0; i <= p; i++)
if (std::abs(z - 1.0) < apex_tol)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0, shape_z);
for (int k = 0; k <= p - maxij; k++)
// Compute the limit of the basis functions as z->1 with x and y on the
// line between the center of the base and the apex
o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
T(o++, m) = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
int maxij = std::max(i, j);
for (int k = 0; k <= p - maxij; k++)
if (i == 0 && j == 0)
{
T(o++, m) = ((k + 3.) * k + 2.) / 2.;
}
else
{
T(o++, m) = 0.;
}
}
}
else
{
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
o = 0;
for (int i = 0; i <= p; i++)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0, shape_z);
for (int k = 0; k <= p - maxij; k++)
{
T(o++, m) = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
}
}
}
@@ -1793,25 +1816,44 @@ void H1_BergotPyramidElement::CalcShape(const IntegrationPoint &ip,
Vector u(dof);
#endif
real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
real_t z = ip.z;
const real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
const real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
const real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0), z, 1.0,
shape_z);
for (int k = 0; k <= p - maxij; k++)
u[o++] = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
if (std::abs(z - 1.0) < apex_tol)
{
// Compute the limit of the basis functions as z->1 with x and y on the
// line between the center of the base and the apex
u = 0.;
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
for (int k = 0; k <= p - maxij; k++, o++)
if (i == 0 && j == 0)
{
u(o) = ((k + 3.) * k + 2.) / 2.;
}
}
}
else
{
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0, shape_z);
for (int k = 0; k <= p - maxij; k++)
u[o++] = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
}
Ti.Mult(u, shape);
}
@@ -1830,37 +1872,68 @@ void H1_BergotPyramidElement::CalcDShape(const IntegrationPoint &ip,
Vector dshape_z(order+1);
Vector dshape_z_dt(order+1);
#endif
real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
real_t z = ip.z;
const real_t x = (ip.z < 1.0) ? (ip.x / (1.0 - ip.z)) : 0.0;
const real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
const real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData(), dshape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData(), dshape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0), z, 1.0,
shape_z, dshape_z, dshape_z_dt);
for (int k = 0; k <= p - maxij; k++, o++)
if (std::abs(z - 1.0) < apex_tol)
{
// Compute the limit of the gradients of the basis functions as
// z->1 with x and y on the line between the center of the base and the
// apex
du = 0.;
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
du(o,0) = dshape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,1) = shape_x(i) * dshape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,2) = shape_x(i) * shape_y(j) * dshape_z(k) *
pow(1.0 - ip.z, maxij) +
(ip.x * dshape_x(i) * shape_y(j) +
ip.y * shape_x(i) * dshape_y(j)) *
shape_z(k) * pow(1.0 - ip.z, maxij - 2) -
maxij * shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
int maxij = std::max(i, j);
for (int k = 0; k <= p - maxij; k++, o++)
{
if (i == 0 && j == 0)
{
du(o,2) = (((k + 6.) * k + 11.) * k + 6.) * k / 6.;
}
else if (i == 1 && j == 0)
{
du(o,0) = ((((k + 10.) * k + 35.) * k + 50.) * k + 24.) / 24.;
}
else if (i == 0 && j == 1)
{
du(o,1) = ((((k + 10.) * k + 35.) * k + 50.) * k + 24.) / 24.;
}
}
}
}
}
else
{
poly1d.CalcLegendre(p, x, shape_x.GetData(), dshape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData(), dshape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0,
shape_z, dshape_z, dshape_z_dt);
for (int k = 0; k <= p - maxij; k++, o++)
{
du(o,0) = dshape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,1) = shape_x(i) * dshape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,2) = shape_x(i) * shape_y(j) * dshape_z(k) *
pow(1.0 - ip.z, maxij) +
(ip.x * dshape_x(i) * shape_y(j) +
ip.y * shape_x(i) * dshape_y(j)) *
shape_z(k) * pow(1.0 - ip.z, maxij - 2) -
maxij * shape_x(i) * shape_y(j) * shape_z(k) *
(maxij > 0 ? pow(1.0 - ip.z, maxij - 1) : 0.0);
}
}
}
Ti.Mult(du, dshape);
}
+2
View File
@@ -208,6 +208,8 @@ private:
#endif
DenseMatrixInverse Ti;
static constexpr real_t apex_tol = 1e-8;
public:
H1_BergotPyramidElement(const int p,
const int btype = BasisType::GaussLobatto);
+130 -56
View File
@@ -1106,9 +1106,16 @@ L2_BergotPyramidElement::L2_BergotPyramidElement(const int p, const int btype)
{
const real_t wik = op[i] + op[k] + op[p-i-k];
const real_t w = wik * wjk * op[p-k];
Nodes.IntPoint(o++).Set3(op[i] * (op[j] + op[p-j-k]) / w,
op[j] * (op[j] + op[p-j-k]) / w,
op[k] * op[p-k] / w);
if (std::abs(w) < apex_tol)
{
Nodes.IntPoint(o++).Set3(0.,0.,1.);
}
else
{
Nodes.IntPoint(o++).Set3(op[i] * (op[j] + op[p-j-k]) / w,
op[j] * (op[i] + op[p-i-k]) / w,
op[k] * op[p-k] / w);
}
}
}
@@ -1125,22 +1132,45 @@ L2_BergotPyramidElement::L2_BergotPyramidElement(const int p, const int btype)
const real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
const real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
o = 0;
for (int i = 0; i <= p; i++)
if (std::abs(z - 1.0) < apex_tol)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0, shape_z);
for (int k = 0; k <= p - maxij; k++)
// Compute the limit of the basis functions as z->1 with x and y on the
// line between the center of the base and the apex
o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
T(o++, m) = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
int maxij = std::max(i, j);
for (int k = 0; k <= p - maxij; k++)
if (i == 0 && j == 0)
{
T(o++, m) = ((k + 3.) * k + 2.) / 2.;
}
else
{
T(o++, m) = 0.;
}
}
}
else
{
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
o = 0;
for (int i = 0; i <= p; i++)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0, shape_z);
for (int k = 0; k <= p - maxij; k++)
{
T(o++, m) = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
}
}
}
@@ -1165,26 +1195,41 @@ void L2_BergotPyramidElement::CalcShape(const IntegrationPoint &ip,
const real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
const real_t z = ip.z;
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
if (std::abs(z - 1.0) < apex_tol)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0), z, 1.0,
shape_z);
for (int k = 0; k <= p - maxij; k++)
// Compute the limit of the basis functions as z->1 with x and y on the
// line between the center of the base and the apex
u = 0.;
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
u[o++] = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
int maxij = std::max(i, j);
for (int k = 0; k <= p - maxij; k++, o++)
if (i == 0 && j == 0)
{
u(o) = ((k + 3.) * k + 2.) / 2.;
}
}
}
}
else
{
poly1d.CalcLegendre(p, x, shape_x.GetData());
poly1d.CalcLegendre(p, y, shape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0, shape_z);
for (int k = 0; k <= p - maxij; k++)
u[o++] = shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij);
}
}
Ti.Mult(u, shape);
}
@@ -1208,35 +1253,64 @@ void L2_BergotPyramidElement::CalcDShape(const IntegrationPoint &ip,
const real_t y = (ip.z < 1.0) ? (ip.y / (1.0 - ip.z)) : 0.0;
const real_t z = ip.z;
Poly_1D::CalcLegendre(p, x, shape_x.GetData(), dshape_x.GetData());
Poly_1D::CalcLegendre(p, y, shape_y.GetData(), dshape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
if (std::abs(z - 1.0) < apex_tol)
{
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0), z, 1.0,
shape_z, dshape_z, dshape_z_dt);
for (int k = 0; k <= p - maxij; k++, o++)
// Compute the limit of the gradients of the basis functions as
// z->1 with x and y on the line between the center of the base and the
// apex
du = 0.;
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
du(o,0) = dshape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,1) = shape_x(i) * dshape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,2) = shape_x(i) * shape_y(j) * dshape_z(k) *
pow(1.0 - ip.z, maxij) +
(ip.x * dshape_x(i) * shape_y(j) +
ip.y * shape_x(i) * dshape_y(j)) *
shape_z(k) * pow(1.0 - ip.z, maxij - 2) -
((maxij > 0) ? (maxij * shape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1)) : 0.0);
int maxij = std::max(i, j);
for (int k = 0; k <= p - maxij; k++, o++)
{
if (i == 0 && j == 0)
{
du(o,2) = (((k + 6.) * k + 11.) * k + 6.) * k / 6.;
}
else if (i == 1 && j == 0)
{
du(o,0) = ((((k + 10.) * k + 35.) * k + 50.) * k + 24.) / 24.;
}
else if (i == 0 && j == 1)
{
du(o,1) = ((((k + 10.) * k + 35.) * k + 50.) * k + 24.) / 24.;
}
}
}
}
}
else
{
Poly_1D::CalcLegendre(p, x, shape_x.GetData(), dshape_x.GetData());
Poly_1D::CalcLegendre(p, y, shape_y.GetData(), dshape_y.GetData());
int o = 0;
for (int i = 0; i <= p; i++)
for (int j = 0; j <= p; j++)
{
int maxij = std::max(i, j);
FuentesPyramid::CalcScaledJacobi(p-maxij, 2.0 * (maxij + 1.0),
z, 1.0,
shape_z, dshape_z, dshape_z_dt);
for (int k = 0; k <= p - maxij; k++, o++)
{
du(o,0) = dshape_x(i) * shape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,1) = shape_x(i) * dshape_y(j) * shape_z(k) *
pow(1.0 - ip.z, maxij - 1);
du(o,2) = shape_x(i) * shape_y(j) * dshape_z(k) *
pow(1.0 - ip.z, maxij) +
(ip.x * dshape_x(i) * shape_y(j) +
ip.y * shape_x(i) * dshape_y(j)) *
shape_z(k) * pow(1.0 - ip.z, maxij - 2) -
maxij * shape_x(i) * shape_y(j) * shape_z(k) *
(maxij > 0 ? pow(1.0 - ip.z, maxij - 1) : 0.0);
}
}
}
Ti.Mult(du, dshape);
}
+2
View File
@@ -225,6 +225,8 @@ private:
#endif
DenseMatrixInverse Ti;
static constexpr real_t apex_tol = 1e-8;
public:
/// Construct the L2_PyramidElement of order @a p and BasisType @a btype
L2_BergotPyramidElement(const int p,
+38 -1
View File
@@ -1282,12 +1282,49 @@ ND_SegmentElement::ND_SegmentElement(const int p, const int ob_type)
}
}
void ND_SegmentElement::CalcShape(const IntegrationPoint &ip,
Vector &shape) const
{
if (obasis1d.IsIntegratedType()) { obasis1d.ScaleIntegrated(false); }
obasis1d.Eval(ip.x, shape);
}
void ND_SegmentElement::CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const
{
Vector vshape(shape.Data(), dof);
obasis1d.Eval(ip.x, vshape);
CalcShape(ip, vshape);
}
void ND_SegmentElement::ProjectIntegrated(VectorCoefficient &vc,
ElementTransformation &Trans,
Vector &dofs) const
{
MFEM_ASSERT(obasis1d.IsIntegratedType(), "Not integrated type");
real_t vk[Geometry::MaxDim];
Vector xk(vk, vc.GetVDim());
const real_t *cp = poly1d.ClosedPoints(dof, BasisType::GaussLobatto);
const IntegrationRule &ir = IntRules.Get(Geometry::SEGMENT, dof);
IntegrationPoint ip;
for (int i = 0; i < dof; i++)
{
const real_t h = cp[i+1] - cp[i];
real_t val = 0.0;
for (int q = 0; q < ir.GetNPoints(); q++)
{
const IntegrationPoint &ip1d = ir.IntPoint(q);
ip.x = cp[i] + h*ip1d.x;
Trans.SetIntPoint(&ip);
vc.Eval(xk, Trans, ip);
val += ip1d.weight*Trans.Jacobian().InnerProduct(tk, vk);
}
dofs(i) = val*h;
}
}
const real_t ND_WedgeElement::tk[15] =
+10 -3
View File
@@ -303,8 +303,7 @@ public:
/** @brief Construct the ND_SegmentElement of order @a p and open
BasisType @a ob_type */
ND_SegmentElement(const int p, const int ob_type = BasisType::GaussLegendre);
void CalcShape(const IntegrationPoint &ip, Vector &shape) const override
{ obasis1d.Eval(ip.x, shape); }
void CalcShape(const IntegrationPoint &ip, Vector &shape) const override;
void CalcVShape(const IntegrationPoint &ip,
DenseMatrix &shape) const override;
void CalcVShape(ElementTransformation &Trans,
@@ -325,7 +324,10 @@ public:
using FiniteElement::Project;
void Project(VectorCoefficient &vc,
ElementTransformation &Trans, Vector &dofs) const override
{ Project_ND(tk, dof2tk, vc, Trans, dofs); }
{
if (obasis1d.IsIntegratedType()) { ProjectIntegrated(vc, Trans, dofs); }
else { Project_ND(tk, dof2tk, vc, Trans, dofs); }
}
void ProjectMatrixCoefficient(MatrixCoefficient &mc,
ElementTransformation &T,
Vector &dofs) const override
@@ -338,6 +340,11 @@ public:
ElementTransformation &Trans,
DenseMatrix &grad) const override
{ ProjectGrad_ND(tk, dof2tk, fe, Trans, grad); }
protected:
void ProjectIntegrated(VectorCoefficient &vc,
ElementTransformation &Trans,
Vector &dofs) const;
};
class ND_WedgeElement : public VectorFiniteElement
+6
View File
@@ -17,6 +17,12 @@
namespace mfem
{
struct ScalarPyramid
{
// Default basis type for H1 and L2 pyramids
static inline int DefaultType = 1; // Bergot(0) or Fuentes(1)
};
/** Base class for arbitrary order basis functions on pyramid-shaped elements
This base class provides a common class to store temporary vectors,
+88 -30
View File
@@ -228,7 +228,19 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
}
else if (!strncmp(name, "H1_", 3))
{
fec = new H1_FECollection(atoi(name + 7), atoi(name + 3));
// Parse pyramid basis type if included in the name
const char *pyr = strstr(name, "Pyr");
if (pyr == NULL)
{
// Use default pyramid type elements
fec = new H1_FECollection(atoi(name + 7), atoi(name + 3));
}
else
{
// Use specific pyramid type elements
fec = new H1_FECollection(atoi(name + 7), atoi(name + 3),
BasisType::GaussLobatto, atoi(pyr + 3));
}
}
else if (!strncmp(name, "H1Pos_Trace_", 12))
{
@@ -245,26 +257,44 @@ FiniteElementCollection *FiniteElementCollection::New(const char *name)
}
else if (!strncmp(name, "H1@", 3))
{
fec = new H1_FECollection(atoi(name + 9), atoi(name + 5),
BasisType::GetType(name[3]));
// Parse pyramid basis type if included in the name
const char *pyr = strstr(name, "Pyr");
if (pyr == NULL)
{
// Use default pyramid type elements
fec = new H1_FECollection(atoi(name + 9), atoi(name + 5),
BasisType::GetType(name[3]));
}
else
{
// Use specific pyramid type elements
fec = new H1_FECollection(atoi(name + 9), atoi(name + 5),
BasisType::GetType(name[3]),
atoi(pyr + 3));
}
}
else if (!strncmp(name, "L2_T", 4))
fec = new L2_FECollection(atoi(name + 10), atoi(name + 6),
atoi(name + 4));
else if (!strncmp(name, "L2_", 3))
else if (!strncmp(name, "L2", 2))
{
fec = new L2_FECollection(atoi(name + 7), atoi(name + 3));
}
else if (!strncmp(name, "L2Int_T", 7))
{
fec = new L2_FECollection(atoi(name + 13), atoi(name + 9),
atoi(name + 7), FiniteElement::INTEGRAL);
}
else if (!strncmp(name, "L2Int_", 6))
{
fec = new L2_FECollection(atoi(name + 10), atoi(name + 6),
BasisType::GaussLegendre,
FiniteElement::INTEGRAL);
// Parse Map Type
const int mtype = strstr(name, "Int") == NULL ?
FiniteElement::VALUE : FiniteElement::INTEGRAL;
// Parse the base order
const int p = atoi(strstr(name, "_P") + 2);
// Parse the mesh dimension
const int dim = atoi(strstr(name, "D") - 1);
// Parse basis type if specified
const char *t = strstr(name, "_T");
const int btype = t == NULL ? BasisType::GaussLegendre : atoi(t + 2);
// Parse the pyramid type if specified
const char *pyr = strstr(name, "Pyr");
const int ptype = pyr == NULL ? 1 : atoi(pyr + 3);
// Create collection
fec = new L2_FECollection(p, dim, btype, mtype, ptype);
}
else if (!strncmp(name, "RT_Trace_", 9))
{
@@ -1709,9 +1739,10 @@ const int *RT1_3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
H1_FECollection::H1_FECollection(const int p, const int dim, const int btype,
const int pyrtype)
const int pyr_type)
: FiniteElementCollection(p)
, dim(dim)
, p_type(pyr_type)
{
MFEM_VERIFY(p >= 1, "H1_FECollection requires order >= 1.");
MFEM_VERIFY(dim >= 0 && dim <= 3, "H1_FECollection requires 0 <= dim <= 3.");
@@ -1724,7 +1755,14 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype,
{
case BasisType::GaussLobatto:
{
snprintf(h1_name, 32, "H1_%dD_P%d", dim, p);
if (pyr_type == ScalarPyramid::DefaultType)
{
snprintf(h1_name, 32, "H1_%dD_P%d", dim, p);
}
else
{
snprintf(h1_name, 32, "H1_%dD_P%d_Pyr%d", dim, p, pyr_type);
}
break;
}
case BasisType::Positive:
@@ -1910,11 +1948,11 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype,
H1_dof[Geometry::TETRAHEDRON] = (TriDof*pm3)/3;
H1_dof[Geometry::CUBE] = QuadDof*pm1;
H1_dof[Geometry::PRISM] = TriDof*pm1;
if (pyrtype == 0 || b_type == BasisType::Positive)
if (pyr_type == 0 || b_type == BasisType::Positive)
{
H1_dof[Geometry::PYRAMID] = pm2*pm1*(2*p-3)/6; // Bergot (JSC)
}
else if (pyrtype == 1)
else if (pyr_type == 1)
{
H1_dof[Geometry::PYRAMID] = pm1*pm1*pm1; // Fuentes
}
@@ -1935,13 +1973,15 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype,
new H1_TetrahedronElement(p, btype);
H1_Elements[Geometry::CUBE] = new H1_HexahedronElement(p, btype);
H1_Elements[Geometry::PRISM] = new H1_WedgeElement(p, btype);
if (pyrtype == 0)
if (pyr_type == 0)
{
H1_Elements[Geometry::PYRAMID] = new H1_BergotPyramidElement(p, btype);
H1_Elements[Geometry::PYRAMID] =
new H1_BergotPyramidElement(p, btype);
}
else
{
H1_Elements[Geometry::PYRAMID] = new H1_FuentesPyramidElement(p, btype);
H1_Elements[Geometry::PYRAMID] =
new H1_FuentesPyramidElement(p, btype);
}
}
@@ -2148,6 +2188,7 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
: FiniteElementCollection(p)
, dim(dim)
, m_type(map_type)
, p_type(pyr_type)
{
MFEM_VERIFY(p >= 0, "L2_FECollection requires order >= 0.");
@@ -2163,10 +2204,25 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
switch (btype)
{
case BasisType::GaussLegendre:
snprintf(d_name, 32, "%s_%dD_P%d", prefix, dim, p);
if (pyr_type == ScalarPyramid::DefaultType)
{
snprintf(d_name, 32, "%s_%dD_P%d", prefix, dim, p);
}
else
{
snprintf(d_name, 32, "%s_%dD_P%d_Pyr%d", prefix, dim, p, pyr_type);
}
break;
default:
snprintf(d_name, 32, "%s_T%d_%dD_P%d", prefix, btype, dim, p);
if (pyr_type == ScalarPyramid::DefaultType)
{
snprintf(d_name, 32, "%s_T%d_%dD_P%d", prefix, btype, dim, p);
}
else
{
snprintf(d_name, 32, "%s_T%d_%dD_P%d_Pyr%d",
prefix, btype, dim, p, pyr_type);
}
}
for (int g = 0; g < Geometry::NumGeom; g++)
@@ -2285,11 +2341,13 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
L2_Elements[Geometry::PRISM] = new L2_WedgeElement(p, btype);
if (pyr_type == 0)
{
L2_Elements[Geometry::PYRAMID] = new L2_BergotPyramidElement(p, btype);
L2_Elements[Geometry::PYRAMID] =
new L2_BergotPyramidElement(p, btype);
}
else
{
L2_Elements[Geometry::PYRAMID] = new L2_FuentesPyramidElement(p, btype);
L2_Elements[Geometry::PYRAMID] =
new L2_FuentesPyramidElement(p, btype);
}
}
+10 -5
View File
@@ -100,6 +100,10 @@ public:
return FiniteElementForGeometry(GeomType);
}
/** @brief Returns a collection of the trace elements.
@note The collection is owned by the caller and is NOT deleted in the
destructor. */
virtual FiniteElementCollection *GetTraceCollection() const;
virtual ~FiniteElementCollection();
@@ -286,7 +290,7 @@ protected:
class H1_FECollection : public FiniteElementCollection
{
protected:
int dim, b_type;
int dim, b_type, p_type;
char h1_name[32];
FiniteElement *H1_Elements[Geometry::NumGeom];
int H1_dof[Geometry::NumGeom];
@@ -295,7 +299,7 @@ protected:
public:
explicit H1_FECollection(const int p, const int dim = 3,
const int btype = BasisType::GaussLobatto,
const int pyrtype = 1);
const int pyr_type = ScalarPyramid::DefaultType);
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
@@ -320,7 +324,7 @@ public:
const int *GetDofMap(Geometry::Type GeomType, int p) const;
FiniteElementCollection *Clone(int p) const override
{ return new H1_FECollection(p, dim, b_type); }
{ return new H1_FECollection(p, dim, b_type, p_type); }
int GetConstructorOrder() const override
{ return base_p; }
@@ -367,6 +371,7 @@ private:
int dim;
int b_type; // BasisType
int m_type; // map type
int p_type; // Pyramid type (0 -> Bergot, 1 -> Fuentes)
char d_name[32];
ScalarFiniteElement *L2_Elements[Geometry::NumGeom];
ScalarFiniteElement *Tr_Elements[Geometry::NumGeom];
@@ -379,7 +384,7 @@ public:
L2_FECollection(const int p, const int dim,
const int btype = BasisType::GaussLegendre,
const int map_type = FiniteElement::VALUE,
const int pyrtype = 1);
const int pyr_type = ScalarPyramid::DefaultType);
const FiniteElement *
FiniteElementForGeometry(Geometry::Type GeomType) const override;
@@ -409,7 +414,7 @@ public:
int GetBasisType() const { return b_type; }
FiniteElementCollection *Clone(int p) const override
{ return new L2_FECollection(p, dim, b_type, m_type); }
{ return new L2_FECollection(p, dim, b_type, m_type, p_type); }
int GetConstructorOrder() const override
{ return base_p; }
+3
View File
@@ -76,6 +76,9 @@ namespace gslib
#ifndef GSLIB_RELEASE_VERSION //gslib v1.0.7
#define GSLIB_RELEASE_VERSION 10007
#endif
static_assert(std::is_same_v<uint,unsigned int>,
"GSLIB's integer-type, 'uint', defined in gslib.h, must be the same as 'unsigned int'!");
extern "C" {
struct hash_data_3
{
+6 -6
View File
@@ -326,22 +326,22 @@ protected:
void findptsedge_setup_2(DEV_STRUCT &devs,
const double *const elx[2],
const unsigned n,
const uint nel,
const unsigned int nel,
const unsigned m,
const double bbox_rel_size_inc,
const uint local_hash_size,
const uint global_hash_size,
const unsigned int local_hash_size,
const unsigned int global_hash_size,
const Vector *aabb_sz_inc);
/// Preprocess 3D surface mesh needed for FindPoints.
void findptssurf_setup_3(DEV_STRUCT &devs,
const double *const elx[3],
const unsigned n,
const uint nel,
const unsigned int nel,
const unsigned m,
const double bbox_rel_size_inc,
const uint local_hash_size,
const uint global_hash_size,
const unsigned int local_hash_size,
const unsigned int global_hash_size,
const int rD,
const Vector *aabb_sz_inc);
+18 -22
View File
@@ -147,18 +147,16 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
}); // end of element loop
}
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &bo,
const Array<real_t> &bc,
const Array<real_t> &bot,
const Array<real_t> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y)
void PAHcurlMassApply2D(const int NE, const bool symmetric,
[[maybe_unused]] const bool scalar_coeff,
const Array<real_t> &bo, const Array<real_t> &bc,
const Array<real_t> &bot, const Array<real_t> &bct,
const Vector &pa_data, const Vector &x, Vector &y,
const int D1D, [[maybe_unused]] const int TestD1D,
const int Q1D)
{
MFEM_ASSERT(D1D == TestD1D,
"Trial and Test space must have the same number of dofs");
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
@@ -277,18 +275,16 @@ void PAHcurlMassApply2D(const int D1D,
}); // end of element loop
}
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &bo,
const Array<real_t> &bc,
const Array<real_t> &bot,
const Array<real_t> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y)
void PAHcurlMassApply3D(const int NE, const bool symmetric,
[[maybe_unused]] const bool scalar_coeff,
const Array<real_t> &bo, const Array<real_t> &bc,
const Array<real_t> &bot, const Array<real_t> &bct,
const Vector &pa_data, const Vector &x, Vector &y,
const int D1D, [[maybe_unused]] const int TestD1D,
const int Q1D)
{
MFEM_VERIFY(D1D == TestD1D,
"Trial and test spaces must have same number of dofs");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: D1D > MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
+273 -189
View File
@@ -181,228 +181,312 @@ inline void SmemPAHcurlMassAssembleDiagonal3D(const int d1d,
}
// PA H(curl) Mass Apply 2D kernel
void PAHcurlMassApply2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &bo,
const Array<real_t> &bc,
const Array<real_t> &bot,
const Array<real_t> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y);
void PAHcurlMassApply2D(const int NE, const bool symmetric,
const bool scalar_coeff, const Array<real_t> &bo,
const Array<real_t> &bc, const Array<real_t> &bot,
const Array<real_t> &bct, const Vector &pa_data,
const Vector &x, Vector &y, const int TrialD1D,
const int TestD1D, const int Q1D);
// PA H(curl) Mass Apply 3D kernel
void PAHcurlMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &bo,
const Array<real_t> &bc,
const Array<real_t> &bot,
const Array<real_t> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y);
void PAHcurlMassApply3D(const int NE, const bool symmetric,
[[maybe_unused]] const bool scalar_coeff,
const Array<real_t> &bo, const Array<real_t> &bc,
const Array<real_t> &bot, const Array<real_t> &bct,
const Vector &pa_data, const Vector &x, Vector &y,
const int TrialD1D, [[maybe_unused]] const int TestD1D,
const int Q1D);
// Shared memory PA H(curl) Mass Apply 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAHcurlMassApply3D(const int d1d,
const int q1d,
const int NE,
const bool symmetric,
const Array<real_t> &bo,
const Array<real_t> &bc,
const Array<real_t> &bot,
const Array<real_t> &bct,
const Vector &pa_data,
const Vector &x,
Vector &y)
template <int T_D1D = 0, int T_Q1D = 0, int TBATCH = 0, bool ACCUMULATE = true>
inline void SmemPAHcurlMassApply3D(
const int NE, const bool symmetric, [[maybe_unused]] const bool scalar_coeff,
const Array<real_t> &bo, const Array<real_t> &bc,
[[maybe_unused]] const Array<real_t> &bot,
[[maybe_unused]] const Array<real_t> &bct, const Vector &pa_data,
const Vector &x, Vector &y, const int d1d = 0,
[[maybe_unused]] const int test_d1d = 0, const int q1d = 0)
{
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(T_D1D || d1d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
"Error: d1d > HCURL_MAX_D1D");
MFEM_VERIFY(T_Q1D || q1d <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
"Error: q1d > HCURL_MAX_Q1D");
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_ASSERT(Q1D >= D1D, "Expected Q1D >= D1D");
const int dataSize = symmetric ? 6 : 9;
auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
auto Bc = Reshape(bc.Read(), Q1D, D1D);
auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, dataSize, NE);
auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
// assume trial space == test space
auto Bo = bo.Read();
auto Bc = bc.Read();
auto op =
Reshape(pa_data.Read(), Q1D, Q1D, Q1D, dataSize, NE);
auto X_ = Reshape(x.Read(), 3 * (D1D - 1) * D1D * D1D, NE);
auto y_ = y.ReadWrite();
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
constexpr int MD_ = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ_ = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
constexpr int MDQ_ = std::max(MD_, MQ_);
constexpr int MB_ = TBATCH ? TBATCH : 1;
mfem::forall_2D_batch<MDQ_ * MDQ_ * MDQ_ * MB_>(
NE, MDQ_ * MDQ_ * MDQ_, 1, MB_, [=] MFEM_HOST_DEVICE(int e)
{
#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)
constexpr int nbz = TBATCH ? TBATCH : 1;
int tidz = MFEM_THREAD_ID(z);
#else
constexpr int nbz = 1;
constexpr int tidz = 0;
#endif
constexpr int VDIM = 3;
constexpr int MD1D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
constexpr int MQ1D = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MDQ = std::max(MD1D, MQ1D);
MFEM_SHARED real_t sBo[MQ1D][MD1D];
MFEM_SHARED real_t sBc[MQ1D][MD1D];
// nvcc limit work-around: can't have Y_ be captured first in
// if constexpr, so capture y_ and construct Y_ locally
// only works on GPU
auto Y = Reshape(y_, VDIM * (D1D - 1) * D1D * D1D, NE);
real_t op9[9];
MFEM_SHARED real_t sop[9*MQ1D*MQ1D];
MFEM_SHARED real_t mass[MQ1D][MQ1D][3];
MFEM_SHARED real_t sBo[MDQ * (MD1D - 1)];
MFEM_SHARED real_t sBc[MDQ * MD1D];
auto BO = Reshape(sBo, Q1D, D1D - 1);
auto BC = Reshape(sBc, Q1D, D1D);
MFEM_SHARED real_t sX[MD1D][MD1D][MD1D];
MFEM_SHARED real_t sX[nbz * VDIM * (MD1D - 1) * MD1D * MD1D];
MFEM_SHARED real_t sm0[nbz * VDIM * MDQ * MDQ * MDQ];
MFEM_SHARED real_t sm1[nbz * VDIM * MDQ * MDQ * MDQ];
MFEM_FOREACH_THREAD(qx,x,Q1D)
real_t(*X)[nbz][(MD1D - 1) * MD1D * MD1D] =
(real_t(*)[nbz][(MD1D - 1) * MD1D * MD1D])(sX);
// shapes of buffers always use MQ1D to mitigate shared memory bank
// conflicts
real_t(*DDQ)[nbz][MQ1D][MQ1D][MQ1D] =
(real_t(*)[nbz][MQ1D][MQ1D][MQ1D])(sm0);
real_t(*DQQ)[nbz][MQ1D][MQ1D][MQ1D] =
(real_t(*)[nbz][MQ1D][MQ1D][MQ1D])(sm1);
real_t(*QQQ)[nbz][MQ1D][MQ1D][MQ1D] =
(real_t(*)[nbz][MQ1D][MQ1D][MQ1D])(sm0);
real_t(*QQD)[nbz][MQ1D][MQ1D][MQ1D] =
(real_t(*)[nbz][MQ1D][MQ1D][MQ1D])(sm1);
real_t(*QDD)[nbz][MQ1D][MQ1D][MQ1D] =
(real_t(*)[nbz][MQ1D][MQ1D][MQ1D])(sm0);
// load dofs into smem
const int offset = (D1D - 1) * D1D * D1D;
MFEM_FOREACH_THREAD_DIRECT(ix, x, offset)
{
MFEM_FOREACH_THREAD(qy,y,Q1D)
for (int dim = 0; dim < VDIM; ++dim)
{
MFEM_FOREACH_THREAD(qz,z,Q1D)
{
for (int i=0; i<dataSize; ++i)
{
op9[i] = op(qx,qy,qz,i,e);
}
}
X[dim][tidz][ix] = X_(ix + dim * offset, e);
}
}
const int tidx = MFEM_THREAD_ID(x);
const int tidy = MFEM_THREAD_ID(y);
const int tidz = MFEM_THREAD_ID(z);
// load basis functions data
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d,y,D1D)
MFEM_FOREACH_THREAD_DIRECT(ix, x, D1D * Q1D) { sBc[ix] = Bc[ix]; }
MFEM_FOREACH_THREAD_DIRECT(ix, x, (D1D - 1) * Q1D)
{
MFEM_FOREACH_THREAD(q,x,Q1D)
sBo[ix] = Bo[ix];
}
}
for (int dim0 = 0; dim0 < VDIM; ++dim0)
{
MFEM_SYNC_THREAD;
// sum factor to QQQ = Q_{dim0,dim1} B X_{dim1}
for (int dim1 = 0; dim1 < VDIM; ++dim1)
{
const int D1Dz = (dim1 == 2) ? D1D - 1 : D1D;
const int D1Dy = (dim1 == 1) ? D1D - 1 : D1D;
const int D1Dx = (dim1 == 0) ? D1D - 1 : D1D;
// threads assigned to mitigate bank conflicts
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, dy, dz, x, Q1D, D1Dy, D1Dz,
Q1D, Q1D, Q1D)
{
sBc[q][d] = Bc(q,d);
if (d < D1D-1)
real_t u = 0;
for (int dx = 0; dx < D1Dx; ++dx)
{
sBo[q][d] = Bo(q,d);
real_t b;
if (dim1 == 0)
{
b = BO(qx, dx);
}
else
{
b = BC(qx, dx);
}
u += X[dim1][tidz][dx + (dy + dz * D1Dy) * D1Dx] * b;
}
DDQ[dim1][tidz][dz][dy][qx] = u;
}
}
MFEM_SYNC_THREAD;
for (int dim1 = 0; dim1 < VDIM; ++dim1)
{
const int D1Dz = (dim1 == 2) ? D1D - 1 : D1D;
const int D1Dy = (dim1 == 1) ? D1D - 1 : D1D;
// const int D1Dx = (dim1 == 0) ? D1D - 1 : D1D;
// threads assigned to mitigate bank conflicts
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, dz, x, Q1D, Q1D, D1Dz,
Q1D, Q1D, Q1D)
{
real_t u = 0;
for (int dy = 0; dy < D1Dy; ++dy)
{
real_t b;
if (dim1 == 1)
{
b = BO(qy, dy);
}
else
{
b = BC(qy, dy);
}
u += DDQ[dim1][tidz][dz][dy][qx] * b;
}
DQQ[dim1][tidz][dz][qy][qx] = u;
}
}
MFEM_SYNC_THREAD;
for (int dim1 = 0; dim1 < VDIM; ++dim1)
{
const int D1Dz = (dim1 == 2) ? D1D - 1 : D1D;
// const int D1Dy = (dim1 == 1) ? D1D - 1 : D1D;
// const int D1Dx = (dim1 == 0) ? D1D - 1 : D1D;
MFEM_FOREACH_THREAD_DIRECT_3D(qx, qy, qz, x, Q1D, Q1D, Q1D)
{
real_t u = 0;
for (int dz = 0; dz < D1Dz; ++dz)
{
real_t b;
if (dim1 == 2)
{
b = BO(qz, dz);
}
else
{
b = BC(qz, dz);
}
u += DQQ[dim1][tidz][dz][qy][qx] * b;
}
// pa_data is row major
int idx;
if (symmetric)
{
int row;
int col;
if (dim0 > dim1)
{
row = dim1;
col = dim0;
}
else
{
row = dim0;
col = dim1;
}
idx = col + VDIM * row - row * (row + 1) / 2;
}
else
{
idx = dim0 * VDIM + dim1;
}
QQQ[dim1][tidz][qz][qy][qx] = op(qx, qy, qz, idx, e) * u;
}
}
MFEM_SYNC_THREAD;
// sum factor back to Y
// Assume bot and bct == bo^t and bc^t respectively (i.e. test ==
// trial functions), skip loading them again.
{
const int D1Dz = (dim0 == 2) ? D1D - 1 : D1D;
const int D1Dy = (dim0 == 1) ? D1D - 1 : D1D;
const int D1Dx = (dim0 == 0) ? D1D - 1 : D1D;
// threads assigned to mitigate bank conflicts
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dz, qx, qy, x, D1Dz, Q1D, Q1D,
Q1D, Q1D, Q1D)
{
for (int dim1 = 0; dim1 < VDIM; ++dim1)
{
real_t u = 0;
for (int qz = 0; qz < Q1D; ++qz)
{
real_t b = 0;
if (dim0 == 2)
{
b = BO(qz, dz);
}
else
{
b = BC(qz, dz);
}
u += QQQ[dim1][tidz][qz][qy][qx] * b;
}
QQD[dim1][tidz][qy][qx][dz] = u;
}
}
MFEM_SYNC_THREAD;
// threads assigned to mitigate bank conflicts
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dy, dz, qx, x, D1Dy, D1Dz, Q1D,
Q1D, Q1D, Q1D)
{
for (int dim1 = 0; dim1 < VDIM; ++dim1)
{
real_t u = 0;
for (int qy = 0; qy < Q1D; ++qy)
{
real_t b;
if (dim0 == 1)
{
b = BO(qy, dy);
}
else
{
b = BC(qy, dy);
}
u += QQD[dim1][tidz][qy][qx][dz] * b;
}
QDD[dim1][tidz][qx][dz][dy] = u;
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD_DIRECT_3D(dx, dy, dz, x, D1Dx, D1Dy, D1Dz)
{
int ix = dx + D1Dx * (dy + D1Dy * dz);
real_t u = 0;
for (int qx = 0; qx < Q1D; ++qx)
{
real_t b;
if (dim0 == 0)
{
b = BO(qx, dx);
}
else
{
b = BC(qx, dx);
}
for (int dim1 = 0; dim1 < VDIM; ++dim1)
{
u += QDD[dim1][tidz][qx][dz][dy] * b;
}
}
if constexpr (ACCUMULATE)
{
Y(ix + dim0 * offset, e) += u;
}
else
{
Y(ix + dim0 * offset, e) = u;
}
}
}
}
MFEM_SYNC_THREAD;
for (int qz=0; qz < Q1D; ++qz)
{
int osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
{
const int D1Dz = (c == 2) ? D1D - 1 : D1D;
const int D1Dy = (c == 1) ? D1D - 1 : D1D;
const int D1Dx = (c == 0) ? D1D - 1 : D1D;
MFEM_FOREACH_THREAD(dz,z,D1Dz)
{
MFEM_FOREACH_THREAD(dy,y,D1Dy)
{
MFEM_FOREACH_THREAD(dx,x,D1Dx)
{
sX[dz][dy][dx] = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
}
}
}
MFEM_SYNC_THREAD;
if (tidz == qz)
{
for (int i=0; i<dataSize; ++i)
{
sop[i + (dataSize*tidx) + (dataSize*Q1D*tidy)] = op9[i];
}
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
real_t u = 0.0;
for (int dz = 0; dz < D1Dz; ++dz)
{
const real_t wz = (c == 2) ? sBo[qz][dz] : sBc[qz][dz];
for (int dy = 0; dy < D1Dy; ++dy)
{
const real_t wy = (c == 1) ? sBo[qy][dy] : sBc[qy][dy];
for (int dx = 0; dx < D1Dx; ++dx)
{
const real_t t = sX[dz][dy][dx];
const real_t wx = (c == 0) ? sBo[qx][dx] : sBc[qx][dx];
u += t * wx * wy * wz;
}
}
}
mass[qy][qx][c] = u;
} // qx
} // qy
} // tidz == qz
osc += D1Dx * D1Dy * D1Dz;
MFEM_SYNC_THREAD;
} // c
MFEM_SYNC_THREAD; // Sync mass[qy][qx][d] and sop
osc = 0;
for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
{
const int D1Dz = (c == 2) ? D1D - 1 : D1D;
const int D1Dy = (c == 1) ? D1D - 1 : D1D;
const int D1Dx = (c == 0) ? D1D - 1 : D1D;
real_t dxyz = 0.0;
MFEM_FOREACH_THREAD(dz,z,D1Dz)
{
const real_t wz = (c == 2) ? sBo[qz][dz] : sBc[qz][dz];
MFEM_FOREACH_THREAD(dy,y,D1Dy)
{
MFEM_FOREACH_THREAD(dx,x,D1Dx)
{
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t wy = (c == 1) ? sBo[qy][dy] : sBc[qy][dy];
for (int qx = 0; qx < Q1D; ++qx)
{
const int os = (dataSize*qx) + (dataSize*Q1D*qy);
const int id1 = os + ((c == 0) ? 0 : ((c == 1) ? (symmetric ? 1 : 3) :
(symmetric ? 2 : 6))); // O11, O21, O31
const int id2 = os + ((c == 0) ? 1 : ((c == 1) ? (symmetric ? 3 : 4) :
(symmetric ? 4 : 7))); // O12, O22, O32
const int id3 = os + ((c == 0) ? 2 : ((c == 1) ? (symmetric ? 4 : 5) :
(symmetric ? 5 : 8))); // O13, O23, O33
const real_t m_c = (sop[id1] * mass[qy][qx][0]) + (sop[id2] * mass[qy][qx][1]) +
(sop[id3] * mass[qy][qx][2]);
const real_t wx = (c == 0) ? sBo[qx][dx] : sBc[qx][dx];
dxyz += m_c * wx * wy * wz;
}
}
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz,z,D1Dz)
{
MFEM_FOREACH_THREAD(dy,y,D1Dy)
{
MFEM_FOREACH_THREAD(dx,x,D1Dx)
{
Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += dxyz;
}
}
}
osc += D1Dx * D1Dy * D1Dz;
} // c loop
} // qz
}); // end of element loop
}
@@ -62,6 +62,30 @@ void PAHcurlHdivMassApply2D(const int D1D,
const Vector &x_,
Vector &y_);
/// H(curl) test, H(div) trial
inline void
PAHcurlHdivMassApply2D(const int NE, const bool, const bool scalarCoeff,
const Array<real_t> &Bo_, const Array<real_t> &Bc_,
const Array<real_t> &Bot_, const Array<real_t> &Bct_,
const Vector &op_, const Vector &x_, Vector &y_,
const int D1D, const int D1Dtest, const int Q1D)
{
return PAHcurlHdivMassApply2D(D1D, D1Dtest, Q1D, NE, scalarCoeff, false,
false, Bo_, Bc_, Bot_, Bct_, op_, x_, y_);
}
/// H(div) test, H(curl) trial
inline void
PAHdivHcurlMassApply2D(const int NE, const bool, const bool scalarCoeff,
const Array<real_t> &Bo_, const Array<real_t> &Bc_,
const Array<real_t> &Bot_, const Array<real_t> &Bct_,
const Vector &op_, const Vector &x_, Vector &y_,
const int D1D, const int D1Dtest, const int Q1D)
{
return PAHcurlHdivMassApply2D(D1D, D1Dtest, Q1D, NE, scalarCoeff, true,
false, Bo_, Bc_, Bot_, Bct_, op_, x_, y_);
}
// PA H(curl)-H(div) Mass Apply 3D kernel
void PAHcurlHdivMassApply3D(const int D1D,
const int D1Dtest,
@@ -78,6 +102,30 @@ void PAHcurlHdivMassApply3D(const int D1D,
const Vector &x_,
Vector &y_);
/// H(curl) test, H(div) trial
inline void
PAHcurlHdivMassApply3D(const int NE, const bool, const bool scalarCoeff,
const Array<real_t> &Bo_, const Array<real_t> &Bc_,
const Array<real_t> &Bot_, const Array<real_t> &Bct_,
const Vector &op_, const Vector &x_, Vector &y_,
const int D1D, const int D1Dtest, const int Q1D)
{
PAHcurlHdivMassApply3D(D1D, D1Dtest, Q1D, NE, scalarCoeff, false, false, Bo_,
Bc_, Bot_, Bct_, op_, x_, y_);
}
/// H(div) test, H(curl) trial
inline void
PAHdivHcurlMassApply3D(const int NE, const bool, const bool scalarCoeff,
const Array<real_t> &Bo_, const Array<real_t> &Bc_,
const Array<real_t> &Bot_, const Array<real_t> &Bct_,
const Vector &op_, const Vector &x_, Vector &y_,
const int D1D, const int D1Dtest, const int Q1D)
{
PAHcurlHdivMassApply3D(D1D, D1Dtest, Q1D, NE, scalarCoeff, true, false, Bo_,
Bc_, Bot_, Bct_, op_, x_, y_);
}
// PA H(curl)-H(div) Curl Apply 3D kernel
template<int T_D1D = 0, int T_D1D_TEST = 0, int T_Q1D = 0>
inline void PAHcurlHdivApply3D(const int d1d,
+14 -65
View File
@@ -294,61 +294,14 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
}); // end of element loop
}
void PAHdivMassApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &Bo,
const Array<real_t> &Bc,
const Array<real_t> &Bot,
const Array<real_t> &Bct,
const Vector &op,
const Vector &x,
Vector &y)
{
const int id = (D1D << 4) | Q1D;
if (dim == 2)
{
switch (id)
{
case 0x22: return SmemPAHdivMassApply2D<2,2>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x33: return SmemPAHdivMassApply2D<3,3>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x44: return SmemPAHdivMassApply2D<4,4>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x55: return SmemPAHdivMassApply2D<5,5>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
default: // fallback
return PAHdivMassApply2D(D1D,Q1D,NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
}
}
else if (dim == 3)
{
switch (id)
{
case 0x23: return SmemPAHdivMassApply3D<2,3>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x34: return SmemPAHdivMassApply3D<3,4>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x45: return SmemPAHdivMassApply3D<4,5>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x56: return SmemPAHdivMassApply3D<5,6>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x67: return SmemPAHdivMassApply3D<6,7>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
case 0x78: return SmemPAHdivMassApply3D<7,8>(NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
default: // fallback
return PAHdivMassApply3D(D1D,Q1D,NE,symmetric,Bo,Bc,Bot,Bct,op,x,y);
}
}
}
void PAHdivMassApply2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &Bo_,
const Array<real_t> &Bc_,
const Array<real_t> &Bot_,
const Array<real_t> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_)
void PAHdivMassApply2D(const int NE, const bool symmetric, const bool,
const Array<real_t> &Bo_, const Array<real_t> &Bc_,
const Array<real_t> &Bot_, const Array<real_t> &Bct_,
const Vector &op_, const Vector &x_, Vector &y_,
const int D1D, const int TestD1D, const int Q1D)
{
MFEM_VERIFY(D1D == TestD1D,
"Trial and test spaces must have same number of dofs");
auto Bo = Reshape(Bo_.Read(), Q1D, D1D-1);
auto Bc = Reshape(Bc_.Read(), Q1D, D1D);
auto Bot = Reshape(Bot_.Read(), D1D-1, Q1D);
@@ -468,18 +421,14 @@ void PAHdivMassApply2D(const int D1D,
}); // end of element loop
}
void PAHdivMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &Bo_,
const Array<real_t> &Bc_,
const Array<real_t> &Bot_,
const Array<real_t> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_)
void PAHdivMassApply3D(const int NE, const bool symmetric, const bool,
const Array<real_t> &Bo_, const Array<real_t> &Bc_,
const Array<real_t> &Bot_, const Array<real_t> &Bct_,
const Vector &op_, const Vector &x_, Vector &y_,
const int D1D, const int TestD1D, const int Q1D)
{
MFEM_VERIFY(D1D == TestD1D,
"Trial and test spaces must have same number of dofs");
MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
"Error: D1D > HDIV_MAX_D1D");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
+25 -59
View File
@@ -66,58 +66,29 @@ void PAHdivMassAssembleDiagonal3D(const int D1D,
const Vector &op_,
Vector &diag_);
void PAHdivMassApply(const int dim,
const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &Bo,
const Array<real_t> &Bc,
const Array<real_t> &Bot,
const Array<real_t> &Bct,
const Vector &op,
const Vector &x,
Vector &y);
// PA H(div) Mass Apply 2D kernel
void PAHdivMassApply2D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &Bo_,
const Array<real_t> &Bc_,
const Array<real_t> &Bot_,
const Array<real_t> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
void PAHdivMassApply2D(const int NE, const bool symmetric,
const bool scalar_coeff, const Array<real_t> &Bo_,
const Array<real_t> &Bc_, const Array<real_t> &Bot_,
const Array<real_t> &Bct_, const Vector &op_,
const Vector &x_, Vector &y_, const int D1D,
const int TestD1D, const int Q1D);
// PA H(div) Mass Apply 3D kernel
void PAHdivMassApply3D(const int D1D,
const int Q1D,
const int NE,
const bool symmetric,
const Array<real_t> &Bo_,
const Array<real_t> &Bc_,
const Array<real_t> &Bot_,
const Array<real_t> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_);
void PAHdivMassApply3D(const int NE, const bool symmetric,
const bool scalar_coeff, const Array<real_t> &Bo_,
const Array<real_t> &Bc_, const Array<real_t> &Bot_,
const Array<real_t> &Bct_, const Vector &op_,
const Vector &x_, Vector &y_, const int D1D,
const int TestD1D, const int Q1D);
// Shared memory PA H(div) Mass Apply 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAHdivMassApply2D(const int NE,
const bool symmetric,
const Array<real_t> &Bo_,
const Array<real_t> &Bc_,
const Array<real_t> &Bot_,
const Array<real_t> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
template <int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAHdivMassApply2D(
const int NE, const bool symmetric, const bool, const Array<real_t> &Bo_,
const Array<real_t> &Bc_, const Array<real_t> &Bot_,
const Array<real_t> &Bct_, const Vector &op_, const Vector &x_, Vector &y_,
const int d1d = 0, const int = 0, const int q1d = 0)
{
MFEM_CONTRACT_VAR(Bot_);
MFEM_CONTRACT_VAR(Bct_);
@@ -280,18 +251,13 @@ inline void SmemPAHdivMassApply2D(const int NE,
}
// Shared memory PA H(div) Mass Apply 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAHdivMassApply3D(const int NE,
const bool symmetric,
const Array<real_t> &Bo_,
const Array<real_t> &Bc_,
const Array<real_t> &Bot_,
const Array<real_t> &Bct_,
const Vector &op_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
template <int T_D1D = 0, int T_Q1D = 0>
inline void
SmemPAHdivMassApply3D(const int NE, const bool symmetric, const bool,
const Array<real_t> &Bo_, const Array<real_t> &Bc_,
const Array<real_t> &Bot_, const Array<real_t> &Bct_,
const Vector &op_, const Vector &x_, Vector &y_,
const int d1d = 0, const int = 0, const int q1d = 0)
{
MFEM_CONTRACT_VAR(Bot_);
MFEM_CONTRACT_VAR(Bct_);
File diff suppressed because it is too large Load Diff
+365
View File
@@ -0,0 +1,365 @@
// 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 "../../config/config.hpp"
#include "../../general/array.hpp"
#include "../../general/forall.hpp"
#include "../../linalg/dtensor.hpp"
#include "../../linalg/vector.hpp"
#include "../bilininteg.hpp"
#include "../kernels.hpp"
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
namespace internal
{
// Shared memory PA Divergence Apply 2D kernel
template<int T_TR_D1D = 0, int T_TE_D1D = 0, int T_Q1D = 0>
inline void SmemPADivergenceApply2D(const int NE,
const Array<real_t> &b_,
const Array<real_t> &g_,
const Array<real_t> &bt_,
const Vector &q_,
const Vector &x_,
Vector &y_,
const int tr_d1d = 0,
const int te_d1d = 0,
const int q1d = 0)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
const auto B = b_.Read(), G = g_.Read(), Bt = bt_.Read();
const auto Q = Reshape(q_.Read(), Q1D, Q1D, 2, 2, NE);
const auto X = Reshape(x_.Read(), TR_D1D, TR_D1D, 2, NE);
auto Y = Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, 1, NE);
mfem::forall_2D<T_Q1D * T_Q1D>(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t smem[MQ1][MQ1];
MFEM_SHARED real_t sB[MQ1][MQ1], sG[MQ1][MQ1];
kernels::internal::vd_regs2d_t<2, 2, MQ1> g0, g1;
kernels::internal::v_regs2d_t<1, MQ1> r0, r1;
kernels::internal::LoadMatrix(TR_D1D, Q1D, B, sB);
kernels::internal::LoadMatrix(TR_D1D, Q1D, G, sG);
kernels::internal::LoadDofs2d(e, TR_D1D, X, g0);
kernels::internal::Grad2d(TR_D1D, Q1D, smem, sB, sG, g0, g1);
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
r0[0][qy][qx] =
g1[0][0][qy][qx] * Q(qx, qy, 0, 0, e) +
g1[0][1][qy][qx] * Q(qx, qy, 1, 0, e) +
g1[1][0][qy][qx] * Q(qx, qy, 0, 1, e) +
g1[1][1][qy][qx] * Q(qx, qy, 1, 1, e);
}
}
MFEM_SYNC_THREAD;
kernels::internal::LoadMatrix<MQ1,true>(TE_D1D, Q1D, Bt, sB);
kernels::internal::EvalTranspose2d(TE_D1D, Q1D, smem, sB, r0, r1);
kernels::internal::WriteDofs2d(e, TE_D1D, r1, Y);
});
}
// Shared memory PA Divergence Apply 2D kernel transpose
template<int T_TR_D1D = 0, int T_TE_D1D = 0, int T_Q1D = 0>
inline void SmemPADivergenceApplyTranspose2D(const int NE,
const Array<real_t> &bt,
const Array<real_t> &gt,
const Array<real_t> &b,
const Vector &q_,
const Vector &x_,
Vector &y_,
const int tr_d1d = 0,
const int te_d1d = 0,
const int q1d = 0)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
const auto Bt = bt.Read(), Gt = gt.Read(), B = b.Read();
const auto Q = Reshape(q_.Read(), Q1D, Q1D, 2, 2, NE);
const auto X = Reshape(x_.Read(), TE_D1D, TE_D1D, 1, NE);
auto Y = Reshape(y_.ReadWrite(), TR_D1D, TR_D1D, 2, NE);
mfem::forall_2D<T_Q1D * T_Q1D>(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t smem[MQ1][MQ1];
MFEM_SHARED real_t sB[MQ1][MQ1], sG[MQ1][MQ1];
kernels::internal::v_regs2d_t<1, MQ1> r0, r1;
kernels::internal::vd_regs2d_t<2, 2, MQ1> g0, g1;
kernels::internal::LoadMatrix(TE_D1D, Q1D, B, sB);
kernels::internal::LoadDofs2d(e, TE_D1D, X, r0);
kernels::internal::Eval2d(TE_D1D, Q1D, smem, sB, r0, r1);
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
g0[0][0][qy][qx] = r1[0][qy][qx] * Q(qx, qy, 0, 0, e);
g0[0][1][qy][qx] = r1[0][qy][qx] * Q(qx, qy, 1, 0, e);
g0[1][0][qy][qx] = r1[0][qy][qx] * Q(qx, qy, 0, 1, e);
g0[1][1][qy][qx] = r1[0][qy][qx] * Q(qx, qy, 1, 1, e);
}
}
MFEM_SYNC_THREAD;
kernels::internal::LoadMatrix<MQ1,true>(TR_D1D, Q1D, Bt, sB);
kernels::internal::LoadMatrix<MQ1,true>(TR_D1D, Q1D, Gt, sG);
kernels::internal::GradTranspose2d(TR_D1D, Q1D, smem, sB, sG, g0, g1);
kernels::internal::WriteDofs2d(e, TR_D1D, g1, Y);
});
}
// Shared memory PA Divergence Apply 3D kernel transpose
template<int T_TR_D1D = 0, int T_TE_D1D = 0, int T_Q1D = 0>
inline void SmemPADivergenceApplyTranspose3D(const int NE,
const Array<real_t> &bt,
const Array<real_t> &gt,
const Array<real_t> &b,
const Vector &q_,
const Vector &x_,
Vector &y_,
int tr_d1d = 0,
int te_d1d = 0,
int q1d = 0)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
const auto Bt = bt.Read(), Gt = gt.Read(), B = b.Read();
const auto Q = Reshape(q_.Read(), Q1D, Q1D, Q1D, 3, 3, NE);
const auto X = Reshape(x_.Read(), TE_D1D, TE_D1D, TE_D1D, 1, NE);
auto Y = Reshape(y_.ReadWrite(), TR_D1D, TR_D1D, TR_D1D, 3, NE);
mfem::forall_2D<T_Q1D * T_Q1D>(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t smem[MQ1][MQ1];
MFEM_SHARED real_t sB[MQ1][MQ1], sG[MQ1][MQ1];
kernels::internal::v_regs3d_t<1, MQ1> r0, r1;
kernels::internal::vd_regs3d_t<3, 3, MQ1> g0, g1;
kernels::internal::LoadMatrix(TE_D1D, Q1D, B, sB);
kernels::internal::LoadDofs3d(e, TE_D1D, X, r0);
kernels::internal::Eval3d(TE_D1D, Q1D, smem, sB, r0, r1);
for (int qz = 0; qz < Q1D; qz++)
{
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
const auto r = r1[0][qz][qy][qx];
g0[0][0][qz][qy][qx] = r * Q(qx, qy, qz, 0, 0, e);
g0[0][1][qz][qy][qx] = r * Q(qx, qy, qz, 1, 0, e);
g0[0][2][qz][qy][qx] = r * Q(qx, qy, qz, 2, 0, e);
g0[1][0][qz][qy][qx] = r * Q(qx, qy, qz, 0, 1, e);
g0[1][1][qz][qy][qx] = r * Q(qx, qy, qz, 1, 1, e);
g0[1][2][qz][qy][qx] = r * Q(qx, qy, qz, 2, 1, e);
g0[2][0][qz][qy][qx] = r * Q(qx, qy, qz, 0, 2, e);
g0[2][1][qz][qy][qx] = r * Q(qx, qy, qz, 1, 2, e);
g0[2][2][qz][qy][qx] = r * Q(qx, qy, qz, 2, 2, e);
}
}
}
MFEM_SYNC_THREAD;
kernels::internal::LoadMatrix<MQ1,true>(TR_D1D, Q1D, Bt, sB);
kernels::internal::LoadMatrix<MQ1,true>(TR_D1D, Q1D, Gt, sG);
kernels::internal::GradTranspose3d(TR_D1D, Q1D, smem, sB, sG, g0, g1);
kernels::internal::WriteDofs3d(e, TR_D1D, g1, Y);
});
}
// Shared memory PA Divergence Apply 3D kernel
template<int T_TR_D1D = 0, int T_TE_D1D = 0, int T_Q1D = 0>
inline void SmemPADivergenceApply3D(const int NE,
const Array<real_t> &b_,
const Array<real_t> &g_,
const Array<real_t> &bt_,
const Vector &q_,
const Vector &x_,
Vector &y_,
const int tr_d1d = 0,
const int te_d1d = 0,
const int q1d = 0)
{
const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
MFEM_VERIFY(TR_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(TE_D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
const auto B = b_.Read(), G = g_.Read(), Bt = bt_.Read();
const auto Q = Reshape(q_.Read(), Q1D, Q1D, Q1D, 3,3, NE);
const auto X = Reshape(x_.Read(), TR_D1D, TR_D1D, TR_D1D, 3, NE);
auto Y = Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, TE_D1D, 1, NE);
mfem::forall_2D<T_Q1D*T_Q1D>(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t smem[MQ1][MQ1];
MFEM_SHARED real_t sB[MQ1][MQ1], sG[MQ1][MQ1];
kernels::internal::vd_regs3d_t<3, 3, MQ1> g0, g1;
kernels::internal::v_regs3d_t<1, MQ1> r0, r1;
kernels::internal::LoadMatrix(TR_D1D, Q1D, B, sB);
kernels::internal::LoadMatrix(TR_D1D, Q1D, G, sG);
kernels::internal::LoadDofs3d(e, TR_D1D, X, g0);
kernels::internal::Grad3d(TR_D1D, Q1D, smem, sB, sG, g0, g1);
for (int qz = 0; qz < Q1D; qz++)
{
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
r0[0][qz][qy][qx] =
// c = 0
g1[0][0][qz][qy][qx] * Q(qx, qy, qz, 0, 0, e) +
g1[0][1][qz][qy][qx] * Q(qx, qy, qz, 1, 0, e) +
g1[0][2][qz][qy][qx] * Q(qx, qy, qz, 2, 0, e) +
// c = 1
g1[1][0][qz][qy][qx] * Q(qx, qy, qz, 0, 1, e) +
g1[1][1][qz][qy][qx] * Q(qx, qy, qz, 1, 1, e) +
g1[1][2][qz][qy][qx] * Q(qx, qy, qz, 2, 1, e) +
// c = 2
g1[2][0][qz][qy][qx] * Q(qx, qy, qz, 0, 2, e) +
g1[2][1][qz][qy][qx] * Q(qx, qy, qz, 1, 2, e) +
g1[2][2][qz][qy][qx] * Q(qx, qy, qz, 2, 2, e);
}
}
}
MFEM_SYNC_THREAD;
kernels::internal::LoadMatrix<MQ1, true>(TE_D1D, Q1D, Bt, sB);
kernels::internal::EvalTranspose3d(TE_D1D, Q1D, smem, sB, r0, r1);
kernels::internal::WriteDofs3d(e, TE_D1D, r1, Y);
});
}
} // namespace internal
template<int DIM, int T_TR_D1D, int T_TE_D1D, int T_Q1D>
VectorDivergenceIntegrator::VectorDivergenceAddMultPAType
VectorDivergenceIntegrator::VectorDivergenceAddMultPA::Kernel()
{
static_assert(T_TR_D1D <= T_Q1D && T_TE_D1D <= T_Q1D);
if constexpr (DIM == 2)
{
return internal::SmemPADivergenceApply2D<T_TR_D1D, T_TE_D1D, T_Q1D>;
}
else if constexpr (DIM == 3)
{
return internal::SmemPADivergenceApply3D<T_TR_D1D, T_TE_D1D, T_Q1D>;
}
MFEM_ABORT("Unsupported kernel");
}
inline VectorDivergenceIntegrator::VectorDivergenceAddMultPAType
VectorDivergenceIntegrator::VectorDivergenceAddMultPA::Fallback
(int dim, int tr_d1d, int te_d1d, int q1d)
{
MFEM_VERIFY(tr_d1d <= q1d && te_d1d <= q1d, "");
MFEM_VERIFY(tr_d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(te_d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
if (dim == 2)
{
return internal::SmemPADivergenceApply2D;
}
else if (dim == 3)
{
return internal::SmemPADivergenceApply3D;
}
MFEM_ABORT("Unsupported kernel");
}
template<int DIM, int T_TR_D1D, int T_TE_D1D, int T_Q1D>
VectorDivergenceIntegrator::VectorDivergenceAddMultTransposePAType
VectorDivergenceIntegrator::VectorDivergenceAddMultTransposePA::Kernel()
{
static_assert(T_TR_D1D <= T_Q1D && T_TE_D1D <= T_Q1D);
if constexpr (DIM == 2)
{
return internal::SmemPADivergenceApplyTranspose2D<T_TR_D1D, T_TE_D1D, T_Q1D>;
}
else if constexpr (DIM == 3)
{
return internal::SmemPADivergenceApplyTranspose3D<T_TR_D1D, T_TE_D1D, T_Q1D>;
}
MFEM_ABORT("Unsupported kernel");
}
inline VectorDivergenceIntegrator::VectorDivergenceAddMultTransposePAType
VectorDivergenceIntegrator::VectorDivergenceAddMultTransposePA::Fallback
(int dim, int tr_d1d, int te_d1d, int q1d)
{
MFEM_VERIFY(tr_d1d <= q1d && te_d1d <= q1d, "");
MFEM_VERIFY(tr_d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(te_d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
if (dim == 2)
{
return internal::SmemPADivergenceApplyTranspose2D;
}
else if (dim == 3)
{
return internal::SmemPADivergenceApplyTranspose3D;
}
MFEM_ABORT("Unsupported kernel");
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
+4 -4
View File
@@ -328,7 +328,7 @@ VectorMassIntegrator::VectorMassAddMultPA::Kernel()
{
return internal::SmemPAVectorMassApply3D<T_D1D, T_Q1D>;
}
else { MFEM_ABORT("Unsupported kernel"); }
MFEM_ABORT("Unsupported kernel");
}
inline VectorMassIntegrator::VectorMassAddMultPAType
@@ -342,7 +342,7 @@ VectorMassIntegrator::VectorMassAddMultPA::Fallback(int dim, int, int)
{
return internal::SmemPAVectorMassApply3D;
}
else { MFEM_ABORT("Unsupported kernel"); }
MFEM_ABORT("Unsupported kernel");
}
// DiagonalPA kernels
@@ -358,7 +358,7 @@ VectorMassIntegrator::VectorMassAssembleDiagonalPA::Kernel()
{
return internal::SmemPAVectorMassAssembleDiagonal3D<T_Q1D>;
}
else { MFEM_ABORT("Unsupported kernel"); }
MFEM_ABORT("Unsupported kernel");
}
inline VectorMassIntegrator::VectorMassAssembleDiagonalPAType
@@ -372,7 +372,7 @@ VectorMassIntegrator::VectorMassAssembleDiagonalPA::Fallback(int dim, int)
{
return internal::SmemPAVectorMassAssembleDiagonal3D;
}
else { MFEM_ABORT("Unsupported kernel"); }
MFEM_ABORT("Unsupported kernel");
}
/// \endcond DO_NOT_DOCUMENT
@@ -0,0 +1,113 @@
// 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_VECTORFEMASS_KERNELS_HPP
#define MFEM_BILININTEG_VECTORFEMASS_KERNELS_HPP
#include "../../config/config.hpp"
#include "../bilininteg.hpp"
#include "bilininteg_diffusion_kernels.hpp"
#include "bilininteg_hcurl_kernels.hpp"
#include "bilininteg_hdiv_kernels.hpp"
#include "bilininteg_hcurlhdiv_kernels.hpp"
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
namespace internal
{
namespace hcurlmass
{
constexpr int NBZ3D(int d1d, int q1d)
{
if (d1d <= 1 || q1d <= 0)
{
return 1;
}
// assume q1d >= d1d
// z dimension is capped at 64 on nvidia and amd gpus
int tmp = std::min((128 + q1d * q1d * q1d - 1) / (q1d * q1d * q1d), 64);
int smem_req =
sizeof(mfem::real_t) *
(3 * ((d1d - 1) * d1d * d1d + 2 * q1d * q1d * q1d) * tmp +
q1d * (d1d - 1) + q1d * d1d);
// assume GPU has at least 48k shared memory
return std::max(std::min(tmp, (48 * 1024 + smem_req - 1) / smem_req), 1);
}
} // namespace hcurlmass
} // namespace internal
template <FiniteElement::DerivType TrialType, FiniteElement::DerivType TestType,
int DIM, int TrialD1D, int TestD1D, int Q1D>
VectorFEMassIntegrator::ApplyKernelType
VectorFEMassIntegrator::ApplyPAKernels::Kernel()
{
constexpr bool trial_curl = (TrialType == mfem::FiniteElement::CURL);
constexpr bool trial_div = (TrialType == mfem::FiniteElement::DIV);
constexpr bool test_curl = (TestType == mfem::FiniteElement::CURL);
constexpr bool test_div = (TestType == mfem::FiniteElement::DIV);
if constexpr (DIM == 3)
{
if constexpr (trial_curl && test_curl)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
// assume TrialD1D == TestD1D
return internal::SmemPAHcurlMassApply3D<
TrialD1D, Q1D, internal::hcurlmass::NBZ3D(TrialD1D, Q1D)>;
}
else
{
return internal::PAHcurlMassApply3D;
}
}
else if constexpr (trial_div && test_div)
{
// assumes TrialD1D == TestD1D
return internal::SmemPAHdivMassApply3D<TrialD1D, Q1D>;
}
else if constexpr (trial_curl && test_div)
{
return internal::PAHdivHcurlMassApply3D;
}
else if constexpr (trial_div && test_curl)
{
return internal::PAHcurlHdivMassApply3D;
}
}
else if constexpr (DIM == 2) // 2D
{
if constexpr (trial_curl && test_curl)
{
return internal::PAHcurlMassApply2D;
}
else if constexpr (trial_div && test_div)
{
// assumes TrialD1D == TestD1D
return internal::SmemPAHdivMassApply2D<TrialD1D, Q1D>;
}
else if constexpr (trial_curl && test_div)
{
return internal::PAHdivHcurlMassApply2D;
}
else if constexpr (trial_div && test_curl)
{
return internal::PAHcurlHdivMassApply2D;
}
}
MFEM_ABORT("Unknown kernel.");
}
/// \endcond DO_NOT_DOCUMENT
}
#endif
+126 -209
View File
@@ -10,15 +10,123 @@
// CONTRIBUTING.md for details.
#include "../bilininteg.hpp"
#include "../gridfunc.hpp"
#include "../qfunction.hpp"
#include "bilininteg_diffusion_kernels.hpp"
#include "bilininteg_hcurl_kernels.hpp"
#include "bilininteg_hdiv_kernels.hpp"
#include "bilininteg_hcurlhdiv_kernels.hpp"
#include "bilininteg_vectorfemass_kernels.hpp"
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
VectorFEMassIntegrator::ApplyKernelType
VectorFEMassIntegrator::ApplyPAKernels::Fallback(
FiniteElement::DerivType TrialType, FiniteElement::DerivType TestType,
int dim, int, int, int)
{
const bool trial_curl = (TrialType == mfem::FiniteElement::CURL);
const bool trial_div = (TrialType == mfem::FiniteElement::DIV);
const bool test_curl = (TestType == mfem::FiniteElement::CURL);
const bool test_div = (TestType == mfem::FiniteElement::DIV);
if (dim == 3)
{
if (trial_curl && test_curl)
{
return internal::PAHcurlMassApply3D;
}
else if (trial_div && test_div)
{
return internal::PAHdivMassApply3D;
}
else if (trial_curl && test_div)
{
return internal::PAHdivHcurlMassApply3D;
}
else if (trial_div && test_curl)
{
return internal::PAHcurlHdivMassApply3D;
}
}
else if (dim == 2) // 2D
{
if (trial_curl && test_curl)
{
return internal::PAHcurlMassApply2D;
}
else if (trial_div && test_div)
{
return internal::PAHdivMassApply2D;
}
else if (trial_curl && test_div)
{
return internal::PAHdivHcurlMassApply2D;
}
else if (trial_div && test_curl)
{
return internal::PAHcurlHdivMassApply2D;
}
}
MFEM_ABORT("Unknown kernel.");
}
/// \endcond DO_NOT_DOCUMENT
VectorFEMassIntegrator::Kernels::Kernels()
{
// h(curl), h(curl)
// Q = P + 1 (3D)
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 2, 2, 3>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 3, 3, 4>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 4, 4, 5>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 5, 5, 6>();
// Q = P + 2 (3D)
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 2, 2, 4>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 3, 3, 5>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 4, 4, 6>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 5, 5, 7>();
// Q = P + 4 (3D)
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 2, 2, 6>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 3, 3, 7>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 4, 4, 8>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::CURL,
FiniteElement::CURL, 3, 5, 5, 9>();
// h(div), h(div)
// Q = P (2D)
VectorFEMassIntegrator::AddSpecialization<FiniteElement::DIV,
FiniteElement::DIV, 2, 2, 2, 2>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::DIV,
FiniteElement::DIV, 2, 3, 3, 3>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::DIV,
FiniteElement::DIV, 2, 4, 4, 4>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::DIV,
FiniteElement::DIV, 2, 5, 5, 5>();
// Q = P + 1 (3D)
VectorFEMassIntegrator::AddSpecialization<FiniteElement::DIV,
FiniteElement::DIV, 3, 2, 2, 3>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::DIV,
FiniteElement::DIV, 3, 3, 3, 4>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::DIV,
FiniteElement::DIV, 3, 4, 4, 5>();
VectorFEMassIntegrator::AddSpecialization<FiniteElement::DIV,
FiniteElement::DIV, 3, 5, 5, 6>();
}
void VectorFEMassIntegrator::Init(Coefficient *q, DiagonalMatrixCoefficient *dq,
MatrixCoefficient *mq)
{
static Kernels kernels{};
Q = q;
DQ = dq;
MQ = mq;
}
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
@@ -67,8 +175,8 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
trial_fetype = trial_el->GetDerivType();
test_fetype = test_el->GetDerivType();
trial_fetype = static_cast<FiniteElement::DerivType>(trial_el->GetDerivType());
test_fetype = static_cast<FiniteElement::DerivType>(test_el->GetDerivType());
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
@@ -215,225 +323,34 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
{
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
if (dim == 3)
{
if (trial_curl && test_curl)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPAHcurlMassApply3D<2,3>(
dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
case 0x34:
return internal::SmemPAHcurlMassApply3D<3,4>(
dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
case 0x45:
return internal::SmemPAHcurlMassApply3D<4,5>(
dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
case 0x56:
return internal::SmemPAHcurlMassApply3D<5,6>(
dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
default:
return internal::SmemPAHcurlMassApply3D(
dofs1D, quad1D, ne, symmetric,
mapsO->B, mapsC->B, mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
}
else
{
internal::PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
}
else if (trial_div && test_div)
{
internal::PAHdivMassApply(3, dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
else if (trial_curl && test_div)
{
const bool scalarCoeff = !(DQ || MQ);
internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
true, false, mapsO->B, mapsC->B, mapsOtest->Bt,
mapsCtest->Bt, pa_data, x, y);
}
else if (trial_div && test_curl)
{
const bool scalarCoeff = !(DQ || MQ);
internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
false, false, mapsO->B, mapsC->B, mapsOtest->Bt,
mapsCtest->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
else // 2D
{
if (trial_curl && test_curl)
{
internal::PAHcurlMassApply2D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
mapsO->Bt, mapsC->Bt, pa_data, x, y);
}
else if (trial_div && test_div)
{
internal::PAHdivMassApply(2, dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
mapsO->Bt,
mapsC->Bt, pa_data, x, y);
}
else if ((trial_curl && test_div) || (trial_div && test_curl))
{
const bool scalarCoeff = !(DQ || MQ);
internal::PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
trial_curl, false, mapsO->B, mapsC->B,
mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
const bool scalar_coeff = !(DQ || MQ);
ApplyPAKernels::Run(trial_fetype, test_fetype, dim, dofs1D, dofs1Dtest,
quad1D, ne, symmetric, scalar_coeff, mapsO->B, mapsC->B,
mapsOtest->Bt, mapsCtest->Bt, pa_data, x, y, dofs1D,
dofs1Dtest, quad1D);
}
void VectorFEMassIntegrator::AddAbsMultPA(const Vector &x, Vector &y) const
{
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
const bool scalar_coeff = !(DQ || MQ);
Vector abs_pa_data(pa_data);
abs_pa_data.Abs();
Array<real_t> absBo(mapsO->B);
Array<real_t> absBc(mapsC->B);
Array<real_t> absBto(mapsO->Bt);
Array<real_t> absBtc(mapsC->Bt);
Array<real_t> absBto_t(mapsOtest->Bt);
Array<real_t> absBtc_t(mapsCtest->Bt);
absBo.Abs();
absBc.Abs();
absBto.Abs();
absBtc.Abs();
absBto_t.Abs();
absBtc_t.Abs();
if (dim == 3)
{
if (trial_curl && test_curl)
{
if (Device::Allows(Backend::DEVICE_MASK))
{
const int ID = (dofs1D << 4) | quad1D;
switch (ID)
{
case 0x23:
return internal::SmemPAHcurlMassApply3D<2,3>(
dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
case 0x34:
return internal::SmemPAHcurlMassApply3D<3,4>(
dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
case 0x45:
return internal::SmemPAHcurlMassApply3D<4,5>(
dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
case 0x56:
return internal::SmemPAHcurlMassApply3D<5,6>(
dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
default:
return internal::SmemPAHcurlMassApply3D(
dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
}
}
else
{
internal::PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
}
}
else if (trial_div && test_div)
{
internal::PAHdivMassApply(3, dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
}
else if (trial_curl && test_div)
{
const bool scalarCoeff = !(DQ || MQ);
internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne,
scalarCoeff, true, false,
absBo, absBc, absBto_t, absBtc_t,
abs_pa_data, x, y);
}
else if (trial_div && test_curl)
{
const bool scalarCoeff = !(DQ || MQ);
internal::PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne,
scalarCoeff, false, false,
absBo, absBc, absBto_t, absBtc_t,
abs_pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
else // 2D
{
if (trial_curl && test_curl)
{
internal::PAHcurlMassApply2D(dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
}
else if (trial_div && test_div)
{
internal::PAHdivMassApply(2, dofs1D, quad1D, ne, symmetric,
absBo, absBc, absBto, absBtc,
abs_pa_data, x, y);
}
else if ((trial_curl && test_div) || (trial_div && test_curl))
{
const bool scalarCoeff = !(DQ || MQ);
internal::PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne,
scalarCoeff, trial_curl, false,
absBo, absBc, absBto_t, absBtc_t,
abs_pa_data, x, y);
}
else
{
MFEM_ABORT("Unknown kernel.");
}
}
ApplyPAKernels::Run(trial_fetype, test_fetype, dim, dofs1D, dofs1Dtest,
quad1D, ne, symmetric, scalar_coeff, absBo, absBc,
absBto_t, absBtc_t, abs_pa_data, x, y, dofs1D,
dofs1Dtest, quad1D);
}
void VectorFEMassIntegrator::AddMultTransposePA(const Vector &x,
+143 -771
View File
@@ -9,21 +9,51 @@
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../../general/forall.hpp"
#include "../nonlininteg.hpp"
#include "../ceed/integrators/nlconvection/nlconvection.hpp"
#include "./nonlininteg_vecconvection_pa.hpp" // IWYU pragma: keep
#include "./nonlininteg_vecconvection_pa_grad.hpp" // IWYU pragma: keep
#include "./nonlininteg_vecconvection_pa_diag.hpp" // IWYU pragma: keep
namespace mfem
{
VectorConvectionNLFIntegrator::Kernels::Kernels()
{
// 2D
VectorConvectionNLFIntegrator::AddSpecialization<2, 2, 2>();
VectorConvectionNLFIntegrator::AddSpecialization<2, 2, 3>();
VectorConvectionNLFIntegrator::AddSpecialization<2, 3, 4>();
VectorConvectionNLFIntegrator::AddSpecialization<2, 3, 5>();
VectorConvectionNLFIntegrator::AddSpecialization<2, 4, 5>();
VectorConvectionNLFIntegrator::AddSpecialization<2, 4, 6>();
VectorConvectionNLFIntegrator::AddSpecialization<2, 5, 7>();
VectorConvectionNLFIntegrator::AddSpecialization<2, 5, 8>();
VectorConvectionNLFIntegrator::AddSpecialization<2, 6, 8>();
// 3D
VectorConvectionNLFIntegrator::AddSpecialization<3, 2, 3>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 2, 4>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 2, 5>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 3, 4>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 3, 5>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 3, 6>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 4, 5>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 4, 6>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 4, 7>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 4, 8>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 5, 6>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 5, 7>();
VectorConvectionNLFIntegrator::AddSpecialization<3, 5, 8>();
}
void VectorConvectionNLFIntegrator::AssemblePA(const FiniteElementSpace &fes)
{
MFEM_ASSERT(fes.GetOrdering() == Ordering::byNODES,
"PA Only supports Ordering::byNODES!");
Mesh *mesh = fes.GetMesh();
const FiniteElement &el = *fes.GetTypicalFE();
ElementTransformation &T = *mesh->GetTypicalElementTransformation();
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, T);
ElementTransformation &Tr = *mesh->GetTypicalElementTransformation();
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, Tr);
if (DeviceCanUseCeed())
{
delete ceedOp;
@@ -39,769 +69,124 @@ void VectorConvectionNLFIntegrator::AssemblePA(const FiniteElementSpace &fes)
}
return;
}
dim = mesh->Dimension();
ne = fes.GetMesh()->GetNE();
ne = mesh->GetNE();
nq = ir->GetNPoints();
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
dim = mesh->Dimension();
MFEM_VERIFY(dim == 2 || dim == 3, "Dimension not supported");
const MemoryType mt = pa_mt == MemoryType::DEFAULT
? Device::GetDeviceMemoryType()
: pa_mt;
pa_adj.SetSize(ne * nq * dim * dim, mt);
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS, mt);
maps = &el.GetDofToQuad(*ir, DofToQuad::TENSOR);
pa_data.SetSize(ne * nq * dim * dim, Device::GetMemoryType());
real_t COEFF = 1.0;
if (Q)
{
ConstantCoefficient *cQ = dynamic_cast<ConstantCoefficient *>(Q);
MFEM_VERIFY(cQ != NULL, "only ConstantCoefficient is supported!");
COEFF = cQ->constant;
}
const int NE = ne;
const int NQ = nq;
auto W = ir->GetWeights().Read();
if (dim == 1)
{
MFEM_ABORT("dim==1 not supported!");
}
d1d = maps->ndof;
q1d = maps->nqpt;
QuadratureSpace qs(*mesh, *ir);
CoefficientVector coeff(Q, qs, CoefficientStorage::COMPRESSED);
const int nq1d = q1d * q1d * (dim==3 ? q1d : 1);
MFEM_VERIFY(coeff.Size() == 1 || coeff.Size() == nq1d*ne, "Invalid coeff");
MFEM_VERIFY(ir->GetWeights().Size() == nq1d, "Invalid weights size");
const auto w_r = ir->GetWeights().Read();
const bool const_coeff = coeff.Size() == 1;
if (dim == 2)
{
auto J = Reshape(geom->J.Read(), NQ, 2, 2, NE);
auto G = Reshape(pa_data.Write(), NQ, 2, 2, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
const int Q1D = q1d;
constexpr int VDIM = 2, DIM = 2;
const auto W = Reshape(w_r, Q1D, Q1D);
const auto C = const_coeff ?
Reshape(coeff.Read(), 1, 1, 1) :
Reshape(coeff.Read(), Q1D, Q1D, ne);
const auto J = Reshape(geom->J.Read(), Q1D, Q1D, VDIM, DIM, ne);
auto A = Reshape(pa_adj.Write(), VDIM, DIM, Q1D, Q1D, ne);
mfem::forall_2D(ne, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
const real_t J11 = J(q, 0, 0, e);
const real_t J12 = J(q, 0, 1, e);
const real_t J21 = J(q, 1, 0, e);
const real_t J22 = J(q, 1, 1, e);
// Store wq * Q * adj(J)
G(q, 0, 0, e) = W[q] * COEFF * J22; // 1,1
G(q, 0, 1, e) = W[q] * COEFF * -J12; // 1,2
G(q, 1, 0, e) = W[q] * COEFF * -J21; // 2,1
G(q, 1, 1, e) = W[q] * COEFF * J11; // 2,2
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
const real_t J11 = J(qx, qy, 0, 0, e), J12 = J(qx, qy, 0, 1, e);
const real_t J21 = J(qx, qy, 1, 0, e), J22 = J(qx, qy, 1, 1, e);
// adj(J)
const real_t A11 = +J22, A12 = -J12;
const real_t A21 = -J21, A22 = +J11;
// Store w * coeff * adj(J)
const real_t w = W(qx, qy);
const real_t c = const_coeff ? C(0, 0, 0) : C(qx, qy, e);
A(0, 0, qx, qy, e) = w * c * A11;
A(1, 0, qx, qy, e) = w * c * A12;
A(0, 1, qx, qy, e) = w * c * A21;
A(1, 1, qx, qy, e) = w * c * A22;
}
}
});
}
if (dim == 3)
else if (dim == 3)
{
auto J = Reshape(geom->J.Read(), NQ, 3, 3, NE);
auto G = Reshape(pa_data.Write(), NQ, 3, 3, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
const int Q1D = q1d;
constexpr int VDIM = 3, DIM = 3;
const auto W = Reshape(w_r, Q1D, Q1D, Q1D);
const auto C = const_coeff ?
Reshape(coeff.Read(), 1, 1, 1, 1) :
Reshape(coeff.Read(), Q1D, Q1D, Q1D, ne);
const auto J = Reshape(geom->J.Read(), Q1D, Q1D, Q1D, VDIM, DIM, ne);
auto A = Reshape(pa_adj.Write(), VDIM, DIM, Q1D, Q1D, Q1D, ne);
mfem::forall_3D(ne, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
for (int q = 0; q < NQ; ++q)
MFEM_FOREACH_THREAD_DIRECT(qz, z, Q1D)
{
const real_t J11 = J(q, 0, 0, e);
const real_t J21 = J(q, 1, 0, e);
const real_t J31 = J(q, 2, 0, e);
const real_t J12 = J(q, 0, 1, e);
const real_t J22 = J(q, 1, 1, e);
const real_t J32 = J(q, 2, 1, e);
const real_t J13 = J(q, 0, 2, e);
const real_t J23 = J(q, 1, 2, e);
const real_t J33 = J(q, 2, 2, e);
const real_t cw = W[q] * COEFF;
// adj(J)
const real_t A11 = (J22 * J33) - (J23 * J32);
const real_t A12 = (J32 * J13) - (J12 * J33);
const real_t A13 = (J12 * J23) - (J22 * J13);
const real_t A21 = (J31 * J23) - (J21 * J33);
const real_t A22 = (J11 * J33) - (J13 * J31);
const real_t A23 = (J21 * J13) - (J11 * J23);
const real_t A31 = (J21 * J32) - (J31 * J22);
const real_t A32 = (J31 * J12) - (J11 * J32);
const real_t A33 = (J11 * J22) - (J12 * J21);
// Store wq * Q * adj(J)
G(q, 0, 0, e) = cw * A11; // 1,1
G(q, 0, 1, e) = cw * A12; // 1,2
G(q, 0, 2, e) = cw * A13; // 1,3
G(q, 1, 0, e) = cw * A21; // 2,1
G(q, 1, 1, e) = cw * A22; // 2,2
G(q, 1, 2, e) = cw * A23; // 2,3
G(q, 2, 0, e) = cw * A31; // 3,1
G(q, 2, 1, e) = cw * A32; // 3,2
G(q, 2, 2, e) = cw * A33; // 3,3
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
const real_t J11 = J(qx, qy, qz, 0, 0, e),
J12 = J(qx, qy, qz, 0, 1, e),
J13 = J(qx, qy, qz, 0, 2, e);
const real_t J21 = J(qx, qy, qz, 1, 0, e),
J22 = J(qx, qy, qz, 1, 1, e),
J23 = J(qx, qy, qz, 1, 2, e);
const real_t J31 = J(qx, qy, qz, 2, 0, e),
J32 = J(qx, qy, qz, 2, 1, e),
J33 = J(qx, qy, qz, 2, 2, e);
const real_t c =
const_coeff ? C(0, 0, 0, 0) : C(qx, qy, qz, e);
const real_t cw = W(qx, qy, qz) * c;
// adj(J)
const real_t A11 = (J22 * J33) - (J23 * J32);
const real_t A12 = (J32 * J13) - (J12 * J33);
const real_t A13 = (J12 * J23) - (J22 * J13);
const real_t A21 = (J31 * J23) - (J21 * J33);
const real_t A22 = (J11 * J33) - (J13 * J31);
const real_t A23 = (J21 * J13) - (J11 * J23);
const real_t A31 = (J21 * J32) - (J31 * J22);
const real_t A32 = (J31 * J12) - (J11 * J32);
const real_t A33 = (J11 * J22) - (J12 * J21);
// Store wq * coeff * adj(J)
A(0, 0, qx, qy, qz, e) = cw * A11;
A(1, 0, qx, qy, qz, e) = cw * A12;
A(2, 0, qx, qy, qz, e) = cw * A13;
A(0, 1, qx, qy, qz, e) = cw * A21;
A(1, 1, qx, qy, qz, e) = cw * A22;
A(2, 1, qx, qy, qz, e) = cw * A23;
A(0, 2, qx, qy, qz, e) = cw * A31;
A(1, 2, qx, qy, qz, e) = cw * A32;
A(2, 2, qx, qy, qz, e) = cw * A33;
}
}
}
});
}
}
// PA Convection NL 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void PAConvectionNLApply2D(const int NE,
const Array<real_t> &b,
const Array<real_t> &g,
const Array<real_t> &bt,
const Vector &q_,
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;
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 Q = Reshape(q_.Read(), Q1D * Q1D, 2, 2, NE);
auto x = Reshape(x_.Read(), D1D, D1D, 2, NE);
auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
else
{
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;
real_t data[max_Q1D][max_Q1D][2];
real_t grad0[max_Q1D][max_Q1D][2];
real_t grad1[max_Q1D][max_Q1D][2];
real_t Z[max_Q1D][max_Q1D][2];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
data[qy][qx][0] = 0.0;
data[qy][qx][1] = 0.0;
grad0[qy][qx][0] = 0.0;
grad0[qy][qx][1] = 0.0;
grad1[qy][qx][0] = 0.0;
grad1[qy][qx][1] = 0.0;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
real_t dataX[max_Q1D][2];
real_t gradX0[max_Q1D][2];
real_t gradX1[max_Q1D][2];
for (int qx = 0; qx < Q1D; ++qx)
{
dataX[qx][0] = 0.0;
dataX[qx][1] = 0.0;
gradX0[qx][0] = 0.0;
gradX0[qx][1] = 0.0;
gradX1[qx][0] = 0.0;
gradX1[qx][1] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const real_t s0 = x(dx, dy, 0, e);
const real_t s1 = x(dx, dy, 1, e);
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t Bx = B(qx, dx);
const real_t Gx = G(qx, dx);
dataX[qx][0] += s0 * Bx;
dataX[qx][1] += s1 * Bx;
gradX0[qx][0] += s0 * Gx;
gradX0[qx][1] += s0 * Bx;
gradX1[qx][0] += s1 * Gx;
gradX1[qx][1] += s1 * Bx;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t By = B(qy, dy);
const real_t Gy = G(qy, dy);
for (int qx = 0; qx < Q1D; ++qx)
{
data[qy][qx][0] += dataX[qx][0] * By;
data[qy][qx][1] += dataX[qx][1] * By;
grad0[qy][qx][0] += gradX0[qx][0] * By;
grad0[qy][qx][1] += gradX0[qx][1] * Gy;
grad1[qy][qx][0] += gradX1[qx][0] * By;
grad1[qy][qx][1] += gradX1[qx][1] * Gy;
}
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
const int q = qx + qy * Q1D;
const real_t u1 = data[qy][qx][0];
const real_t u2 = data[qy][qx][1];
const real_t grad00 = grad0[qy][qx][0];
const real_t grad01 = grad0[qy][qx][1];
const real_t grad10 = grad1[qy][qx][0];
const real_t grad11 = grad1[qy][qx][1];
const real_t Dxu1 = grad00 * Q(q, 0, 0, e) + grad01 * Q(q, 1, 0, e);
const real_t Dyu1 = grad00 * Q(q, 0, 1, e) + grad01 * Q(q, 1, 1, e);
const real_t Dxu2 = grad10 * Q(q, 0, 0, e) + grad11 * Q(q, 1, 0, e);
const real_t Dyu2 = grad10 * Q(q, 0, 1, e) + grad11 * Q(q, 1, 1, e);
Z[qy][qx][0] = u1 * Dxu1 + u2 * Dyu1;
Z[qy][qx][1] = u1 * Dxu2 + u2 * Dyu2;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
real_t Y[max_D1D][2];
for (int dx = 0; dx < D1D; ++dx)
{
Y[dx][0] = 0.0;
Y[dx][1] = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t Btx = Bt(dx, qx);
Y[dx][0] += Btx * Z[qy][qx][0];
Y[dx][1] += Btx * Z[qy][qx][1];
}
}
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
const real_t Bty = Bt(dy, qy);
y(dx, dy, 0, e) += Bty * Y[dx][0];
y(dx, dy, 1, e) += Bty * Y[dx][1];
}
}
}
});
}
// PA Convection NL 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
static void PAConvectionNLApply3D(const int NE,
const Array<real_t> &b,
const Array<real_t> &g,
const Array<real_t> &bt,
const Vector &q_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
constexpr int VDIM = 3;
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 Bt = Reshape(bt.Read(), D1D, Q1D);
auto Q = Reshape(q_.Read(), Q1D * Q1D * Q1D, VDIM, VDIM, 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)
{
constexpr int VDIM = 3;
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;
real_t data[max_Q1D][max_Q1D][max_Q1D][VDIM];
real_t grad0[max_Q1D][max_Q1D][max_Q1D][VDIM];
real_t grad1[max_Q1D][max_Q1D][max_Q1D][VDIM];
real_t grad2[max_Q1D][max_Q1D][max_Q1D][VDIM];
real_t Z[max_Q1D][max_Q1D][max_Q1D][VDIM];
for (int qz = 0; qz < Q1D; ++qz)
{
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
data[qz][qy][qx][0] = 0.0;
data[qz][qy][qx][1] = 0.0;
data[qz][qy][qx][2] = 0.0;
grad0[qz][qy][qx][0] = 0.0;
grad0[qz][qy][qx][1] = 0.0;
grad0[qz][qy][qx][2] = 0.0;
grad1[qz][qy][qx][0] = 0.0;
grad1[qz][qy][qx][1] = 0.0;
grad1[qz][qy][qx][2] = 0.0;
grad2[qz][qy][qx][0] = 0.0;
grad2[qz][qy][qx][1] = 0.0;
grad2[qz][qy][qx][2] = 0.0;
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
real_t dataXY[max_Q1D][max_Q1D][VDIM];
real_t gradXY0[max_Q1D][max_Q1D][VDIM];
real_t gradXY1[max_Q1D][max_Q1D][VDIM];
real_t gradXY2[max_Q1D][max_Q1D][VDIM];
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
dataXY[qy][qx][0] = 0.0;
dataXY[qy][qx][1] = 0.0;
dataXY[qy][qx][2] = 0.0;
gradXY0[qy][qx][0] = 0.0;
gradXY0[qy][qx][1] = 0.0;
gradXY0[qy][qx][2] = 0.0;
gradXY1[qy][qx][0] = 0.0;
gradXY1[qy][qx][1] = 0.0;
gradXY1[qy][qx][2] = 0.0;
gradXY2[qy][qx][0] = 0.0;
gradXY2[qy][qx][1] = 0.0;
gradXY2[qy][qx][2] = 0.0;
}
}
for (int dy = 0; dy < D1D; ++dy)
{
real_t dataX[max_Q1D][VDIM];
real_t gradX0[max_Q1D][VDIM];
real_t gradX1[max_Q1D][VDIM];
real_t gradX2[max_Q1D][VDIM];
for (int qx = 0; qx < Q1D; ++qx)
{
dataX[qx][0] = 0.0;
dataX[qx][1] = 0.0;
dataX[qx][2] = 0.0;
gradX0[qx][0] = 0.0;
gradX0[qx][1] = 0.0;
gradX0[qx][2] = 0.0;
gradX1[qx][0] = 0.0;
gradX1[qx][1] = 0.0;
gradX1[qx][2] = 0.0;
gradX2[qx][0] = 0.0;
gradX2[qx][1] = 0.0;
gradX2[qx][2] = 0.0;
}
for (int dx = 0; dx < D1D; ++dx)
{
const real_t s0 = x(dx, dy, dz, 0, e);
const real_t s1 = x(dx, dy, dz, 1, e);
const real_t s2 = x(dx, dy, dz, 2, e);
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t Bx = B(qx, dx);
const real_t Gx = G(qx, dx);
dataX[qx][0] += s0 * Bx;
dataX[qx][1] += s1 * Bx;
dataX[qx][2] += s2 * Bx;
gradX0[qx][0] += s0 * Gx;
gradX0[qx][1] += s0 * Bx;
gradX0[qx][2] += s0 * Bx;
gradX1[qx][0] += s1 * Gx;
gradX1[qx][1] += s1 * Bx;
gradX1[qx][2] += s1 * Bx;
gradX2[qx][0] += s2 * Gx;
gradX2[qx][1] += s2 * Bx;
gradX2[qx][2] += s2 * Bx;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t By = B(qy, dy);
const real_t Gy = G(qy, dy);
for (int qx = 0; qx < Q1D; ++qx)
{
dataXY[qy][qx][0] += dataX[qx][0] * By;
dataXY[qy][qx][1] += dataX[qx][1] * By;
dataXY[qy][qx][2] += dataX[qx][2] * By;
gradXY0[qy][qx][0] += gradX0[qx][0] * By;
gradXY0[qy][qx][1] += gradX0[qx][1] * Gy;
gradXY0[qy][qx][2] += gradX0[qx][2] * By;
gradXY1[qy][qx][0] += gradX1[qx][0] * By;
gradXY1[qy][qx][1] += gradX1[qx][1] * Gy;
gradXY1[qy][qx][2] += gradX1[qx][2] * By;
gradXY2[qy][qx][0] += gradX2[qx][0] * By;
gradXY2[qy][qx][1] += gradX2[qx][1] * Gy;
gradXY2[qy][qx][2] += gradX2[qx][2] * By;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
const real_t Bz = B(qz, dz);
const real_t Gz = G(qz, dz);
for (int qy = 0; qy < Q1D; ++qy)
{
for (int qx = 0; qx < Q1D; ++qx)
{
data[qz][qy][qx][0] += dataXY[qy][qx][0] * Bz;
data[qz][qy][qx][1] += dataXY[qy][qx][1] * Bz;
data[qz][qy][qx][2] += dataXY[qy][qx][2] * Bz;
grad0[qz][qy][qx][0] += gradXY0[qy][qx][0] * Bz;
grad0[qz][qy][qx][1] += gradXY0[qy][qx][1] * Bz;
grad0[qz][qy][qx][2] += gradXY0[qy][qx][2] * Gz;
grad1[qz][qy][qx][0] += gradXY1[qy][qx][0] * Bz;
grad1[qz][qy][qx][1] += gradXY1[qy][qx][1] * Bz;
grad1[qz][qy][qx][2] += gradXY1[qy][qx][2] * Gz;
grad2[qz][qy][qx][0] += gradXY2[qy][qx][0] * Bz;
grad2[qz][qy][qx][1] += gradXY2[qy][qx][1] * Bz;
grad2[qz][qy][qx][2] += gradXY2[qy][qx][2] * Gz;
}
}
}
}
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 + Q1D * (qy + qz * Q1D);
const real_t u1 = data[qz][qy][qx][0];
const real_t u2 = data[qz][qy][qx][1];
const real_t u3 = data[qz][qy][qx][2];
const real_t grad00 = grad0[qz][qy][qx][0];
const real_t grad01 = grad0[qz][qy][qx][1];
const real_t grad02 = grad0[qz][qy][qx][2];
const real_t grad10 = grad1[qz][qy][qx][0];
const real_t grad11 = grad1[qz][qy][qx][1];
const real_t grad12 = grad1[qz][qy][qx][2];
const real_t grad20 = grad2[qz][qy][qx][0];
const real_t grad21 = grad2[qz][qy][qx][1];
const real_t grad22 = grad2[qz][qy][qx][2];
const real_t Dxu1 = grad00 * Q(q, 0, 0, e)
+ grad01 * Q(q, 1, 0, e)
+ grad02 * Q(q, 2, 0, e);
const real_t Dyu1 = grad00 * Q(q, 0, 1, e)
+ grad01 * Q(q, 1, 1, e)
+ grad02 * Q(q, 2, 1, e);
const real_t Dzu1 = grad00 * Q(q, 0, 2, e)
+ grad01 * Q(q, 1, 2, e)
+ grad02 * Q(q, 2, 2, e);
const real_t Dxu2 = grad10 * Q(q, 0, 0, e)
+ grad11 * Q(q, 1, 0, e)
+ grad12 * Q(q, 2, 0, e);
const real_t Dyu2 = grad10 * Q(q, 0, 1, e)
+ grad11 * Q(q, 1, 1, e)
+ grad12 * Q(q, 2, 1, e);
const real_t Dzu2 = grad10 * Q(q, 0, 2, e)
+ grad11 * Q(q, 1, 2, e)
+ grad12 * Q(q, 2, 2, e);
const real_t Dxu3 = grad20 * Q(q, 0, 0, e)
+ grad21 * Q(q, 1, 0, e)
+ grad22 * Q(q, 2, 0, e);
const real_t Dyu3 = grad20 * Q(q, 0, 1, e)
+ grad21 * Q(q, 1, 1, e)
+ grad22 * Q(q, 2, 1, e);
const real_t Dzu3 = grad20 * Q(q, 0, 2, e)
+ grad21 * Q(q, 1, 2, e)
+ grad22 * Q(q, 2, 2, e);
Z[qz][qy][qx][0] = u1 * Dxu1 + u2 * Dyu1 + u3 * Dzu1;
Z[qz][qy][qx][1] = u1 * Dxu2 + u2 * Dyu2 + u3 * Dzu2;
Z[qz][qy][qx][2] = u1 * Dxu3 + u2 * Dyu3 + u3 * Dzu3;
}
}
}
for (int qz = 0; qz < Q1D; ++qz)
{
real_t opXY[max_D1D][max_D1D][VDIM];
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
opXY[dy][dx][0] = 0.0;
opXY[dy][dx][1] = 0.0;
opXY[dy][dx][2] = 0.0;
}
}
for (int qy = 0; qy < Q1D; ++qy)
{
real_t opX[max_D1D][VDIM];
for (int dx = 0; dx < D1D; ++dx)
{
opX[dx][0] = 0.0;
opX[dx][1] = 0.0;
opX[dx][2] = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t Btx = Bt(dx, qx);
opX[dx][0] += Btx * Z[qz][qy][qx][0];
opX[dx][1] += Btx * Z[qz][qy][qx][1];
opX[dx][2] += Btx * Z[qz][qy][qx][2];
}
}
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
const real_t Bty = Bt(dy, qy);
opXY[dy][dx][0] += Bty * opX[dx][0];
opXY[dy][dx][1] += Bty * opX[dx][1];
opXY[dy][dx][2] += Bty * opX[dx][2];
}
}
}
for (int dz = 0; dz < D1D; ++dz)
{
for (int dy = 0; dy < D1D; ++dy)
{
for (int dx = 0; dx < D1D; ++dx)
{
const real_t Btz = Bt(dz, qz);
y(dx, dy, dz, 0, e) += Btz * opXY[dy][dx][0];
y(dx, dy, dz, 1, e) += Btz * opXY[dy][dx][1];
y(dx, dy, dz, 2, e) += Btz * opXY[dy][dx][2];
}
}
}
}
});
}
template<int T_D1D = 0, int T_Q1D = 0, int T_MAX_D1D = 0, int T_MAX_Q1D = 0>
static void SmemPAConvectionNLApply3D(const int NE,
const Array<real_t> &b_,
const Array<real_t> &g_,
const Vector &d_,
const Vector &x_,
Vector &y_,
const int d1d = 0,
const int q1d = 0)
{
constexpr int VDIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : T_MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX_Q1D;
MFEM_VERIFY(D1D <= MD1, "");
MFEM_VERIFY(Q1D <= MQ1, "");
auto b = Reshape(b_.Read(), Q1D, D1D);
auto g = Reshape(g_.Read(), Q1D, D1D);
auto D = Reshape(d_.Read(), Q1D * Q1D * Q1D, VDIM, VDIM, NE);
auto x = Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
auto Y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
{
const int tidz = MFEM_THREAD_ID(z);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
constexpr int MD1 = T_D1D ? T_D1D : T_MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : T_MAX_Q1D;
MFEM_SHARED real_t BG[2][MQ1 * MD1];
real_t(*B)[MD1] = (real_t(*)[MD1])(BG + 0);
real_t(*G)[MD1] = (real_t(*)[MD1])(BG + 1);
real_t(*Bt)[MQ1] = (real_t(*)[MQ1])(BG + 0);
MFEM_SHARED real_t U[2][MQ1][MQ1][MQ1];
MFEM_SHARED real_t sm0[3][MQ1 * MQ1 * MQ1];
MFEM_SHARED real_t sm1[3][MQ1 * MQ1 * MQ1];
real_t(*DDQ0)[MD1][MQ1] = (real_t(*)[MD1][MQ1])(sm0 + 0);
real_t(*DDQ1)[MD1][MQ1] = (real_t(*)[MD1][MQ1])(sm0 + 1);
real_t(*X)[MD1][MD1] = (real_t(*)[MD1][MD1])(sm0 + 2);
real_t(*DQQ0)[MQ1][MQ1] = (real_t(*)[MQ1][MQ1])(sm1 + 0);
real_t(*DQQ1)[MQ1][MQ1] = (real_t(*)[MQ1][MQ1])(sm1 + 1);
real_t(*DQQ2)[MQ1][MQ1] = (real_t(*)[MQ1][MQ1])(sm1 + 2);
real_t(*QQQ0)[MQ1][MQ1] = (real_t(*)[MQ1][MQ1])(sm0 + 0);
real_t(*QQQ1)[MQ1][MQ1] = (real_t(*)[MQ1][MQ1])(sm0 + 1);
real_t(*QQQ2)[MQ1][MQ1] = (real_t(*)[MQ1][MQ1])(sm0 + 2);
real_t(*QQD0)[MQ1][MD1] = (real_t(*)[MQ1][MD1])(sm1 + 0);
real_t(*QDD0)[MD1][MD1] = (real_t(*)[MD1][MD1])(sm0 + 0);
MFEM_SHARED real_t Z[MQ1][MQ1][MQ1];
for (int cy = 0; cy < VDIM; ++cy)
{
if (tidz == 0)
{
MFEM_FOREACH_THREAD(q, x, Q1D)
{
MFEM_FOREACH_THREAD(d, y, D1D)
{
B[q][d] = b(q, d);
G[q][d] = g(q, d);
}
}
}
MFEM_FOREACH_THREAD(qz, z, Q1D)
{
MFEM_FOREACH_THREAD(qy, y, Q1D)
{
MFEM_FOREACH_THREAD(qx, x, Q1D) { Z[qz][qy][qx] = 0.0; }
}
}
MFEM_SYNC_THREAD;
for (int c = 0; c < VDIM; ++c)
{
MFEM_FOREACH_THREAD(dz, z, D1D)
{
MFEM_FOREACH_THREAD(dy, y, D1D)
{
MFEM_FOREACH_THREAD(dx, x, D1D)
{
X[dz][dy][dx] = x(dx, dy, dz, cy, e);
U[0][dz][dy][dx] = x(dx, dy, dz, c, e);
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz, z, D1D)
{
MFEM_FOREACH_THREAD(dy, y, D1D)
{
MFEM_FOREACH_THREAD(qx, x, Q1D)
{
real_t u = 0.0;
real_t v = 0.0;
real_t z = 0.0;
for (int dx = 0; dx < D1D; ++dx)
{
const real_t coord = X[dz][dy][dx];
const real_t value = U[0][dz][dy][dx];
u += coord * B[qx][dx];
v += coord * G[qx][dx];
z += value * B[qx][dx];
}
DDQ0[dz][dy][qx] = u;
DDQ1[dz][dy][qx] = v;
U[1][dz][dy][qx] = z;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz, z, D1D)
{
MFEM_FOREACH_THREAD(qy, y, Q1D)
{
MFEM_FOREACH_THREAD(qx, x, Q1D)
{
real_t u = 0.0;
real_t v = 0.0;
real_t w = 0.0;
real_t z = 0.0;
for (int dy = 0; dy < D1D; ++dy)
{
u += DDQ1[dz][dy][qx] * B[qy][dy];
v += DDQ0[dz][dy][qx] * G[qy][dy];
w += DDQ0[dz][dy][qx] * B[qy][dy];
z += U[1][dz][dy][qx] * B[qy][dy];
}
DQQ0[dz][qy][qx] = u;
DQQ1[dz][qy][qx] = v;
DQQ2[dz][qy][qx] = w;
U[0][dz][qy][qx] = z;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz, z, Q1D)
{
MFEM_FOREACH_THREAD(qy, y, Q1D)
{
MFEM_FOREACH_THREAD(qx, x, Q1D)
{
real_t u = 0.0;
real_t v = 0.0;
real_t w = 0.0;
real_t z = 0.0;
for (int dz = 0; dz < D1D; ++dz)
{
u += DQQ0[dz][qy][qx] * B[qz][dz];
v += DQQ1[dz][qy][qx] * B[qz][dz];
w += DQQ2[dz][qy][qx] * G[qz][dz];
z += U[0][dz][qy][qx] * B[qz][dz];
}
QQQ0[qz][qy][qx] = u;
QQQ1[qz][qy][qx] = v;
QQQ2[qz][qy][qx] = w;
U[1][qz][qy][qx] = z;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz, z, Q1D)
{
MFEM_FOREACH_THREAD(qy, y, Q1D)
{
MFEM_FOREACH_THREAD(qx, x, Q1D)
{
const int q = qx + (qy + qz * Q1D) * Q1D;
const real_t z = U[1][qz][qy][qx];
const real_t gX = QQQ0[qz][qy][qx];
const real_t gY = QQQ1[qz][qy][qx];
const real_t gZ = QQQ2[qz][qy][qx];
const real_t d = gX * D(q, 0, c, e) + gY * D(q, 1, c, e)
+ gZ * D(q, 2, c, e);
Z[qz][qy][qx] += z * d;
}
}
}
MFEM_SYNC_THREAD;
} // for each conv component
if (tidz == 0)
{
MFEM_FOREACH_THREAD(d, y, D1D)
{
MFEM_FOREACH_THREAD(q, x, Q1D) { Bt[d][q] = b(q, d); }
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz, z, Q1D)
{
MFEM_FOREACH_THREAD(qy, y, Q1D)
{
MFEM_FOREACH_THREAD(dx, x, D1D)
{
real_t u = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
u += Z[qz][qy][qx] * Bt[dx][qx];
}
QQD0[qz][qy][dx] = u;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(qz, z, Q1D)
{
MFEM_FOREACH_THREAD(dy, y, D1D)
{
MFEM_FOREACH_THREAD(dx, x, D1D)
{
real_t u = 0.0;
for (int qy = 0; qy < Q1D; ++qy)
{
u += QQD0[qz][qy][dx] * Bt[dy][qy];
}
QDD0[qz][dy][dx] = u;
}
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(dz, z, D1D)
{
MFEM_FOREACH_THREAD(dy, y, D1D)
{
MFEM_FOREACH_THREAD(dx, x, D1D)
{
real_t u = 0.0;
for (int qz = 0; qz < Q1D; ++qz)
{
u += QDD0[qz][dy][dx] * Bt[dz][qz];
}
Y(dx, dy, dz, cy, e) += u;
}
}
}
MFEM_SYNC_THREAD;
}
});
MFEM_ABORT("dim " << dim << " not supported!");
}
}
void VectorConvectionNLFIntegrator::AddMultPA(const Vector &x, Vector &y) const
@@ -812,26 +197,13 @@ void VectorConvectionNLFIntegrator::AddMultPA(const Vector &x, Vector &y) const
}
else
{
const int NE = ne;
const int D1D = maps->ndof;
const int Q1D = maps->nqpt;
const Vector &QV = pa_data;
const Array<real_t> &B = maps->B;
const Array<real_t> &G = maps->G;
const Array<real_t> &Bt = maps->Bt;
if (dim == 2)
{
return PAConvectionNLApply2D(NE, B, G, Bt, QV, x, y, D1D, Q1D);
}
if (dim == 3)
{
constexpr int T_MAX_D1D = 8;
constexpr int T_MAX_Q1D = 8;
MFEM_VERIFY(D1D <= T_MAX_D1D && Q1D <= T_MAX_Q1D, "Not yet implemented!");
return SmemPAConvectionNLApply3D<0, 0, T_MAX_D1D, T_MAX_Q1D>
(NE, B, G, QV, x, y, D1D, Q1D);
}
MFEM_ABORT("Not yet implemented!");
AddMultPAKernels::Run(dim, d1d, q1d, ne,
maps->B.Read(),
maps->G.Read(),
pa_adj.Read(),
x.Read(),
y.ReadWrite(),
d1d, q1d);
}
}
+209
View File
@@ -0,0 +1,209 @@
// 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 "../../config/config.hpp"
#include "../../general/forall.hpp"
#include "../../linalg/dtensor.hpp"
#include "../kernels.hpp"
#include "../nonlininteg.hpp"
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
namespace internal
{
// PA Convection NL 2D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAConvectionNLApply2D(const int NE,
const real_t *b,
const real_t *g,
const real_t *a,
const real_t *x,
real_t *y,
const int d1d = 0,
const int q1d = 0)
{
static constexpr int VDIM = 2, DIM = 2;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto B = Reshape(b, Q1D, D1D);
const auto G = Reshape(g, Q1D, D1D);
const auto A = Reshape(a, VDIM, DIM, Q1D, Q1D, NE);
const auto X = Reshape(x, D1D, D1D, VDIM, NE);
auto Y = Reshape(y, D1D, D1D, VDIM, NE);
mfem::forall_2D<T_Q1D * T_Q1D>(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t smem[MQ1][MQ1], sB[MD1][MQ1], sG[MD1][MQ1];
kernels::internal::vd_regs2d_t<VDIM, DIM, MQ1> g0, g1;
kernels::internal::v_regs2d_t<VDIM, MQ1> r0, r1;
kernels::internal::v_regs2d_t<VDIM, MQ1> s0, s1;
kernels::internal::LoadMatrix(D1D, Q1D, B, sB);
kernels::internal::LoadMatrix(D1D, Q1D, G, sG);
kernels::internal::LoadDofs2d(e, D1D, X, r0);
kernels::internal::Eval2d(D1D, Q1D, smem, sB, r0, r1); // u vector-value
kernels::internal::LoadDofs2d(e, D1D, X, g0);
kernels::internal::Grad2d(D1D, Q1D, smem, sB, sG, g0, g1); // u vector-gradient
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
const future::tensor<real_t, 2> U =
{
r1[0][qy][qx], r1[1][qy][qx]
};
const future::tensor<real_t, 2,2> gradU = {{
{g1[0][0][qy][qx], g1[1][0][qy][qx]},
{g1[0][1][qy][qx], g1[1][1][qy][qx]},
}
};
const future::tensor<real_t, 2,2> Q = {{
{A(0,0,qx,qy,e), A(1,0,qx,qy,e)},
{A(0,1,qx,qy,e), A(1,1,qx,qy,e)},
}
};
const future::tensor<real_t, 2> conv = transpose(gradU) * (Q * U);
s0[0][qy][qx] = conv[0];
s0[1][qy][qx] = conv[1];
}
}
MFEM_SYNC_THREAD;
kernels::internal::EvalTranspose2d(D1D, Q1D, smem, sB, s0, s1);
kernels::internal::WriteDofs2d(e, D1D, s1, Y);
});
}
// PA Convection NL 3D kernel
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAConvectionNLApply3D(const int NE,
const real_t *b,
const real_t *g,
const real_t *a,
const real_t *x,
real_t *y,
const int d1d = 0,
const int q1d = 0)
{
static constexpr int VDIM = 3, DIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto B = Reshape(b, Q1D, D1D);
const auto G = Reshape(g, Q1D, D1D);
const auto A = Reshape(a, VDIM, DIM, Q1D, Q1D, Q1D, NE);
const auto X = Reshape(x, D1D, D1D, D1D, VDIM, NE);
auto Y = Reshape(y, D1D, D1D, D1D, VDIM, NE);
mfem::forall_2D<T_Q1D*T_Q1D>(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t smem[MQ1][MQ1], sB[MD1][MQ1], sG[MD1][MQ1];
kernels::internal::vd_regs3d_t<VDIM, DIM, MQ1> g0, g1;
kernels::internal::v_regs3d_t<VDIM, MQ1> r0, r1;
kernels::internal::v_regs3d_t<VDIM, MQ1> s0, s1;
kernels::internal::LoadMatrix(D1D, Q1D, B, sB);
kernels::internal::LoadMatrix(D1D, Q1D, G, sG);
kernels::internal::LoadDofs3d(e, D1D, X, r0);
kernels::internal::Eval3d(D1D, Q1D, smem, sB, r0, r1); // u vector-value
kernels::internal::LoadDofs3d(e, D1D, X, g0);
kernels::internal::Grad3d(D1D, Q1D, smem, sB, sG, g0, g1); // u vector-gradient
for (int qz = 0; qz < Q1D; qz++)
{
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
const future::tensor<real_t, 3> U =
{
r1[0][qz][qy][qx], r1[1][qz][qy][qx], r1[2][qz][qy][qx]
};
const future::tensor<real_t, 3,3> gradU = {{
{g1[0][0][qz][qy][qx], g1[1][0][qz][qy][qx], g1[2][0][qz][qy][qx]},
{g1[0][1][qz][qy][qx], g1[1][1][qz][qy][qx], g1[2][1][qz][qy][qx]},
{g1[0][2][qz][qy][qx], g1[1][2][qz][qy][qx], g1[2][2][qz][qy][qx]}
}
};
const future::tensor<real_t, 3,3> Q = {{
{A(0,0,qx,qy,qz,e), A(1,0,qx,qy,qz,e), A(2,0,qx,qy,qz,e)},
{A(0,1,qx,qy,qz,e), A(1,1,qx,qy,qz,e), A(2,1,qx,qy,qz,e)},
{A(0,2,qx,qy,qz,e), A(1,2,qx,qy,qz,e), A(2,2,qx,qy,qz,e)}
}
};
const future::tensor<real_t, 3> conv = transpose(gradU) * (Q * U);
s0[0][qz][qy][qx] = conv[0];
s0[1][qz][qy][qx] = conv[1];
s0[2][qz][qy][qx] = conv[2];
}
}
}
MFEM_SYNC_THREAD;
kernels::internal::EvalTranspose3d(D1D, Q1D, smem, sB, s0, s1);
kernels::internal::WriteDofs3d(e, D1D, s1, Y);
});
}
} // namespace internal
template<int DIM, int T_D1D, int T_Q1D>
VectorConvectionNLFIntegrator::AddMultPAType
VectorConvectionNLFIntegrator::AddMultPAKernels::Kernel()
{
static_assert(T_D1D <= T_Q1D, "d1d > q1d is not supported");
if constexpr (DIM == 2)
{
return internal::SmemPAConvectionNLApply2D<T_D1D, T_Q1D>;
}
else if constexpr (DIM == 3)
{
return internal::SmemPAConvectionNLApply3D<T_D1D, T_Q1D>;
}
MFEM_ABORT("Unsupported kernel");
}
inline VectorConvectionNLFIntegrator::AddMultPAType
VectorConvectionNLFIntegrator::AddMultPAKernels::Fallback
(int dim, int d1d, int q1d)
{
MFEM_VERIFY(d1d <= q1d, "d1d > q1d is not supported");
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
if (dim == 2)
{
return internal::SmemPAConvectionNLApply2D<>;
}
else if (dim == 3)
{
return internal::SmemPAConvectionNLApply3D<>;
}
MFEM_ABORT("Unsupported kernel");
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
@@ -0,0 +1,50 @@
// 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 "../ceed/interface/util.hpp"
#include "./nonlininteg_vecconvection_pa_diag.hpp" // IWYU pragma: keep
namespace mfem
{
void VectorConvectionNLFIntegrator::AssembleGradDiagonalPA(Vector &de) const
{
MFEM_VERIFY(!DeviceCanUseCeed(),
"VectorConvectionNLFIntegrator PA gradients are not supported "
"with the libCEED backend");
if (dim == 2)
{
GradDiagPA2D::Run(d1d, q1d, ne,
maps->B.Read(),
maps->G.Read(),
pa_adj.Read(),
pa_u.Read(),
de.ReadWrite(),
d1d, q1d);
}
else if (dim == 3)
{
GradDiagPA3D::Run(d1d, q1d, ne,
maps->B.Read(),
maps->G.Read(),
pa_adj.Read(),
pa_u.Read(),
de.ReadWrite(),
d1d, q1d);
}
else
{
MFEM_ABORT("Unsupported dimension");
}
}
} // namespace mfem
@@ -0,0 +1,302 @@
// 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 "../../config/config.hpp"
#include "../../general/forall.hpp"
#include "../../linalg/dtensor.hpp"
#include "../kernels.hpp"
#include "../nonlininteg.hpp"
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
namespace internal
{
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAConvectionNLGradDiagonal2D(const int NE,
const real_t *b,
const real_t *g,
const real_t *a,
const real_t *u,
real_t *de,
const int d1d,
const int q1d)
{
static constexpr int VDIM = 2, DIM = 2;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto A = Reshape(a, VDIM, DIM, Q1D, Q1D, NE);
const auto U = Reshape(u, D1D, D1D, VDIM, NE);
auto D = Reshape(de, D1D, D1D, VDIM, NE);
mfem::forall_2D<T_Q1D * T_Q1D>(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t sM[3][MQ1][MQ1], sQ[3][MQ1][MQ1];
MFEM_SHARED real_t sB[MD1][MQ1], sG[MD1][MQ1];
kernels::internal::v_regs2d_t<VDIM, MQ1> r0, r1;
kernels::internal::vd_regs2d_t<VDIM, DIM, MQ1> g0, g1;
kernels::internal::LoadMatrix(D1D, Q1D, b, sB);
kernels::internal::LoadMatrix(D1D, Q1D, g, sG);
kernels::internal::LoadDofs2d(e, D1D, U, r0);
kernels::internal::Eval2d(D1D, Q1D, sM[0], sB, r0, r1);
kernels::internal::LoadDofs2d(e, D1D, U, g0);
kernels::internal::Grad2d(D1D, Q1D, sM[0], sB, sG, g0, g1);
for (int v = 0; v < VDIM; ++v)
{
future::tensor<real_t, VDIM> e_v = {};
e_v[v] = real_t(1);
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
const future::tensor<real_t, VDIM> u_val =
{
r1[0][qy][qx], r1[1][qy][qx]
};
const future::tensor<real_t, VDIM, DIM> Q_adj =
{
{ { A(0, 0, qx, qy, e), A(1, 0, qx, qy, e) },
{ A(0, 1, qx, qy, e), A(1, 1, qx, qy, e) }
}
};
const future::tensor<real_t, VDIM, DIM> grad_U =
{
{ { g1[0][0][qy][qx], g1[1][0][qy][qx] },
{ g1[0][1][qy][qx], g1[1][1][qy][qx] }
}
};
const auto one = Q_adj * u_val;
const auto two = transpose(grad_U) * (Q_adj * e_v);
sQ[0][qx][qy] = one[0];
sQ[1][qx][qy] = one[1];
sQ[2][qx][qy] = two[v];
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(dy, y, D1D)
{
real_t s[3] = {};
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t By = sB[dy][qy], Gy = sG[dy][qy];
s[0] += By * By * sQ[0][qx][qy];
s[1] += Gy * By * sQ[1][qx][qy];
s[2] += By * By * sQ[2][qx][qy];
}
sM[0][qx][dy] = s[0];
sM[1][qx][dy] = s[1];
sM[2][qx][dy] = s[2];
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD_DIRECT(dy, y, D1D)
{
MFEM_FOREACH_THREAD_DIRECT(dx, x, D1D)
{
real_t d = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t Bx = sB[dx][qx], Gx = sG[dx][qx];
d += Gx * Bx * sM[0][qx][dy] +
Bx * Bx * sM[1][qx][dy] +
Bx * Bx * sM[2][qx][dy];
}
D(dx, dy, v, e) += d;
}
}
MFEM_SYNC_THREAD;
}
});
}
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAConvectionNLGradDiagonal3D(const int NE,
const real_t *b,
const real_t *g,
const real_t *a,
const real_t *u,
real_t *de,
const int d1d,
const int q1d)
{
static constexpr int VDIM = 3, DIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto A = Reshape(a, VDIM, DIM, Q1D, Q1D, Q1D, NE);
const auto U = Reshape(u, D1D, D1D, D1D, VDIM, NE);
auto D = Reshape(de, D1D, D1D, D1D, VDIM, NE);
mfem::forall_2D<T_Q1D * T_Q1D>(NE, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t sM[4][MQ1][MQ1], sQ[4][MQ1][MQ1];
MFEM_SHARED real_t sB[MD1][MQ1], sG[MD1][MQ1];
kernels::internal::v_regs3d_t<VDIM, MQ1> r0, r1;
kernels::internal::vd_regs3d_t<VDIM, DIM, MQ1> g0, g1;
kernels::internal::LoadMatrix(D1D, Q1D, b, sB);
kernels::internal::LoadMatrix(D1D, Q1D, g, sG);
kernels::internal::LoadDofs3d(e, D1D, U, r0);
kernels::internal::Eval3d(D1D, Q1D, sM[0], sB, r0, r1);
kernels::internal::LoadDofs3d(e, D1D, U, g0);
kernels::internal::Grad3d(D1D, Q1D, sM[0], sB, sG, g0, g1);
for (int v = 0; v < VDIM; ++v)
{
future::tensor<real_t, VDIM> e_v = {};
e_v[v] = real_t(1);
for (int dz = 0; dz < D1D; ++dz)
{
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
real_t s[4] = {};
for (int qz = 0; qz < Q1D; ++qz)
{
const future::tensor<real_t, VDIM> u_val =
{
r1[0][qz][qy][qx], r1[1][qz][qy][qx], r1[2][qz][qy][qx]
};
const future::tensor<real_t, VDIM, DIM> Q_adj = {{
{A(0,0,qx,qy,qz,e), A(1,0,qx,qy,qz,e), A(2,0,qx,qy,qz,e)},
{A(0,1,qx,qy,qz,e), A(1,1,qx,qy,qz,e), A(2,1,qx,qy,qz,e)},
{A(0,2,qx,qy,qz,e), A(1,2,qx,qy,qz,e), A(2,2,qx,qy,qz,e)}
}
};
const future::tensor<real_t, VDIM, DIM> grad_U = {{
{g1[0][0][qz][qy][qx], g1[1][0][qz][qy][qx], g1[2][0][qz][qy][qx]},
{g1[0][1][qz][qy][qx], g1[1][1][qz][qy][qx], g1[2][1][qz][qy][qx]},
{g1[0][2][qz][qy][qx], g1[1][2][qz][qy][qx], g1[2][2][qz][qy][qx]}
}
};
const auto one = Q_adj * u_val;
const auto two = transpose(grad_U) * (Q_adj * e_v);
const real_t Bz = sB[dz][qz], Gz = sG[dz][qz];
s[0] += one[0] * Bz * Bz;
s[1] += one[1] * Bz * Bz;
s[2] += one[2] * Bz * Gz;
s[3] += two[v] * Bz * Bz;
}
sQ[0][qx][qy] = s[0];
sQ[1][qx][qy] = s[1];
sQ[2][qx][qy] = s[2];
sQ[3][qx][qy] = s[3];
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD_DIRECT(dy, y, D1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
real_t s[4] = {};
for (int qy = 0; qy < Q1D; ++qy)
{
const real_t By = sB[dy][qy], Gy = sG[dy][qy];
s[0] += By * By * sQ[0][qx][qy];
s[1] += Gy * By * sQ[1][qx][qy];
s[2] += By * By * sQ[2][qx][qy];
s[3] += By * By * sQ[3][qx][qy];
}
sM[0][dy][qx] = s[0];
sM[1][dy][qx] = s[1];
sM[2][dy][qx] = s[2];
sM[3][dy][qx] = s[3];
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD_DIRECT(dy, y, D1D)
{
MFEM_FOREACH_THREAD_DIRECT(dx, x, D1D)
{
real_t d = 0.0;
for (int qx = 0; qx < Q1D; ++qx)
{
const real_t Bx = sB[dx][qx], Gx = sG[dx][qx];
d += Gx * Bx * sM[0][dy][qx];
d += Bx * Bx * sM[1][dy][qx];
d += Bx * Bx * sM[2][dy][qx];
d += Bx * Bx * sM[3][dy][qx];
}
D(dx, dy, dz, v, e) += d;
}
}
MFEM_SYNC_THREAD;
}
}
});
}
} // namespace internal
template<int T_D1D, int T_Q1D>
VectorConvectionNLFIntegrator::GradDiagPAType
VectorConvectionNLFIntegrator::GradDiagPA2D::Kernel()
{
static_assert(T_D1D <= T_Q1D, "d1d > q1d is not supported");
return internal::SmemPAConvectionNLGradDiagonal2D<T_D1D, T_Q1D>;
}
inline VectorConvectionNLFIntegrator::GradDiagPAType
VectorConvectionNLFIntegrator::GradDiagPA2D::Fallback(int d1d, int q1d)
{
MFEM_VERIFY(d1d <= q1d, "d1d > q1d is not supported");
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
return internal::SmemPAConvectionNLGradDiagonal2D<>;
}
template<int T_D1D, int T_Q1D>
VectorConvectionNLFIntegrator::GradDiagPAType
VectorConvectionNLFIntegrator::GradDiagPA3D::Kernel()
{
static_assert(T_D1D <= T_Q1D, "d1d > q1d is not supported");
return internal::SmemPAConvectionNLGradDiagonal3D<T_D1D, T_Q1D>;
}
inline VectorConvectionNLFIntegrator::GradDiagPAType
VectorConvectionNLFIntegrator::GradDiagPA3D::Fallback(int d1d, int q1d)
{
MFEM_VERIFY(d1d <= q1d, "d1d > q1d is not supported");
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
return internal::SmemPAConvectionNLGradDiagonal3D<>;
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
@@ -0,0 +1,64 @@
// 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 "../ceed/interface/util.hpp"
#include "./nonlininteg_vecconvection_pa_grad.hpp" // IWYU pragma: keep
namespace mfem
{
void VectorConvectionNLFIntegrator::AssembleGradPA(
const Vector &u, const FiniteElementSpace &fes)
{
MFEM_VERIFY(!DeviceCanUseCeed(),
"VectorConvectionNLFIntegrator PA gradients are not supported "
"with the libCEED backend");
this->pa_u = u;
AssemblePA(fes);
}
void VectorConvectionNLFIntegrator::AddMultGradPA(const Vector &x,
Vector &y) const
{
MFEM_VERIFY(!DeviceCanUseCeed(),
"VectorConvectionNLFIntegrator PA gradients are not supported "
"with the libCEED backend");
if (dim == 2)
{
AddMultGradPA2D::Run(d1d, q1d, ne,
maps->B.Read(),
maps->G.Read(),
pa_adj.Read(),
pa_u.Read(),
x.Read(),
y.ReadWrite(),
d1d, q1d);
}
else if (dim == 3)
{
AddMultGradPA3D::Run(d1d, q1d, ne,
maps->B.Read(),
maps->G.Read(),
pa_adj.Read(),
pa_u.Read(),
x.Read(),
y.ReadWrite(),
d1d, q1d);
}
else
{
MFEM_ABORT("Unsupported dimension");
}
}
} // namespace mfem
@@ -0,0 +1,257 @@
// 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 "../../config/config.hpp"
#include "../../general/forall.hpp"
#include "../../linalg/dtensor.hpp"
#include "../kernels.hpp"
#include "../nonlininteg.hpp"
namespace mfem
{
/// \cond DO_NOT_DOCUMENT
namespace internal
{
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAConvectionNLGradApply2D(const int ne,
const real_t *b,
const real_t *g,
const real_t *a,
const real_t *u,
const real_t *du,
real_t *y,
const int d1d,
const int q1d)
{
static constexpr int VDIM = 2, DIM = 2;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto A = Reshape(a, VDIM, DIM, Q1D, Q1D, ne);
const auto U = Reshape(u, D1D, D1D, VDIM, ne);
const auto dU = Reshape(du, D1D, D1D, VDIM, ne);
auto Y = Reshape(y, D1D, D1D, VDIM, ne);
mfem::forall_2D<T_Q1D * T_Q1D>(ne, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t smem[MQ1][MQ1];
MFEM_SHARED real_t sB[MD1][MQ1], sG[MD1][MQ1];
kernels::internal::vd_regs2d_t<VDIM, DIM, MQ1> g0, g1, g2;
kernels::internal::v_regs2d_t<DIM, MQ1> r0, r1, r2;
kernels::internal::LoadMatrix(D1D, Q1D, b, sB);
kernels::internal::LoadMatrix(D1D, Q1D, g, sG);
kernels::internal::LoadDofs2d(e, D1D, dU, g0);
kernels::internal::Grad2d(D1D, Q1D, smem, sB, sG, g0, g1); // δu gradient
kernels::internal::LoadDofs2d(e, D1D, U, r0);
kernels::internal::Eval2d(D1D, Q1D, smem, sB, r0, r2); // u value
kernels::internal::LoadDofs2d(e, D1D, dU, r0);
kernels::internal::Eval2d(D1D, Q1D, smem, sB, r0, r1); // δu value
kernels::internal::LoadDofs2d(e, D1D, U, g0);
kernels::internal::Grad2d(D1D, Q1D, smem, sB, sG, g0, g2); // u gradient
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
// First part of the Jacobian: u·∇δu
const future::tensor<real_t, DIM> u_val =
{
r2[0][qy][qx], r2[1][qy][qx]
};
const future::tensor<real_t, VDIM, DIM> Q_adj =
{
{ { A(0, 0, qx, qy, e), A(1, 0, qx, qy, e) },
{ A(0, 1, qx, qy, e), A(1, 1, qx, qy, e) }
}
};
const future::tensor<real_t, VDIM, DIM> grad_dU =
{
{ { g1[0][0][qy][qx], g1[1][0][qy][qx] },
{ g1[0][1][qy][qx], g1[1][1][qy][qx] }
}
};
const auto one = transpose(grad_dU) * (Q_adj * u_val);
// Second part of the Jacobian: δu·∇u
const future::tensor<real_t, DIM> du_val =
{
r1[0][qy][qx], r1[1][qy][qx]
};
const future::tensor<real_t, VDIM, DIM> grad_U =
{
{ { g2[0][0][qy][qx], g2[1][0][qy][qx] },
{ g2[0][1][qy][qx], g2[1][1][qy][qx] }
}
};
const auto two = transpose(grad_U) * (Q_adj * du_val);
// u⋅∇δu + δu⋅∇u
r0[0][qy][qx] = one[0] + two[0];
r0[1][qy][qx] = one[1] + two[1];
}
}
MFEM_SYNC_THREAD;
kernels::internal::EvalTranspose2d(D1D, Q1D, smem, sB, r0, r1);
kernels::internal::WriteDofs2d(e, D1D, r1, Y);
});
}
template<int T_D1D = 0, int T_Q1D = 0>
inline void SmemPAConvectionNLGradApply3D(const int ne,
const real_t *b,
const real_t *g,
const real_t *a,
const real_t *u,
const real_t *du,
real_t *y,
const int d1d,
const int q1d)
{
static constexpr int VDIM = 3, DIM = 3;
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const auto A = Reshape(a, VDIM, DIM, Q1D, Q1D, Q1D, ne);
const auto U = Reshape(u, D1D, D1D, D1D, VDIM, ne);
const auto dU = Reshape(du, D1D, D1D, D1D, VDIM, ne);
auto Y = Reshape(y, D1D, D1D, D1D, VDIM, ne);
mfem::forall_2D<T_Q1D * T_Q1D>(ne, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
MFEM_SHARED real_t smem[MQ1][MQ1];
MFEM_SHARED real_t sB[MD1][MQ1], sG[MD1][MQ1];
kernels::internal::v_regs3d_t<VDIM, MQ1> r0, r1, r2;
kernels::internal::vd_regs3d_t<VDIM, DIM, MQ1> g0, g1, g2;
kernels::internal::LoadMatrix(D1D, Q1D, b, sB);
kernels::internal::LoadMatrix(D1D, Q1D, g, sG);
kernels::internal::LoadDofs3d(e, D1D, dU, g0);
kernels::internal::Grad3d(D1D, Q1D, smem, sB, sG, g0, g1); // δu gradient
kernels::internal::LoadDofs3d(e, D1D, U, r0);
kernels::internal::Eval3d(D1D, Q1D, smem, sB, r0, r2); // u value
kernels::internal::LoadDofs3d(e, D1D, dU, r0);
kernels::internal::Eval3d(D1D, Q1D, smem, sB, r0, r1); // δu value
kernels::internal::LoadDofs3d(e, D1D, U, g0);
kernels::internal::Grad3d(D1D, Q1D, smem, sB, sG, g0, g2); // u gradient
for (int qz = 0; qz < Q1D; qz++)
{
MFEM_FOREACH_THREAD_DIRECT(qy, y, Q1D)
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, Q1D)
{
// First part of the Jacobian: u·∇δu
const future::tensor<real_t, DIM> u_val =
{
r2[0][qz][qy][qx],
r2[1][qz][qy][qx],
r2[2][qz][qy][qx]
};
const future::tensor<real_t, VDIM, DIM> Q_adj = {{
{A(0,0,qx,qy,qz,e), A(1,0,qx,qy,qz,e), A(2,0,qx,qy,qz,e)},
{A(0,1,qx,qy,qz,e), A(1,1,qx,qy,qz,e), A(2,1,qx,qy,qz,e)},
{A(0,2,qx,qy,qz,e), A(1,2,qx,qy,qz,e), A(2,2,qx,qy,qz,e)}
}
};
const future::tensor<real_t, DIM, DIM> grad_dU = {{
{g1[0][0][qz][qy][qx], g1[1][0][qz][qy][qx], g1[2][0][qz][qy][qx]},
{g1[0][1][qz][qy][qx], g1[1][1][qz][qy][qx], g1[2][1][qz][qy][qx]},
{g1[0][2][qz][qy][qx], g1[1][2][qz][qy][qx], g1[2][2][qz][qy][qx]}
}
};
const auto one = transpose(grad_dU) * (Q_adj * u_val);
// Second part of the Jacobian: δu·∇u
const future::tensor<real_t, DIM> du_val =
{
r1[0][qz][qy][qx], r1[1][qz][qy][qx], r1[2][qz][qy][qx]
};
const future::tensor<real_t, VDIM, DIM> grad_U = {{
{g2[0][0][qz][qy][qx], g2[1][0][qz][qy][qx], g2[2][0][qz][qy][qx]},
{g2[0][1][qz][qy][qx], g2[1][1][qz][qy][qx], g2[2][1][qz][qy][qx]},
{g2[0][2][qz][qy][qx], g2[1][2][qz][qy][qx], g2[2][2][qz][qy][qx]}
}
};
const auto two = transpose(grad_U) * (Q_adj * du_val);
// u⋅∇δu + δu⋅∇u
r0[0][qz][qy][qx] = one[0] + two[0];
r0[1][qz][qy][qx] = one[1] + two[1];
r0[2][qz][qy][qx] = one[2] + two[2];
}
}
}
MFEM_SYNC_THREAD;
kernels::internal::EvalTranspose3d(D1D, Q1D, smem, sB, r0, r1);
kernels::internal::WriteDofs3d(e, D1D, r1, Y);
});
}
} // namespace internal
template<int T_D1D, int T_Q1D>
VectorConvectionNLFIntegrator::AddMultGradPAType
VectorConvectionNLFIntegrator::AddMultGradPA2D::Kernel()
{
static_assert(T_D1D <= T_Q1D, "d1d > q1d is not supported");
return internal::SmemPAConvectionNLGradApply2D<T_D1D, T_Q1D>;
}
inline VectorConvectionNLFIntegrator::AddMultGradPAType
VectorConvectionNLFIntegrator::AddMultGradPA2D::Fallback(int d1d, int q1d)
{
MFEM_VERIFY(d1d <= q1d, "d1d > q1d is not supported");
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
return internal::SmemPAConvectionNLGradApply2D<>;
}
template<int T_D1D, int T_Q1D>
VectorConvectionNLFIntegrator::AddMultGradPAType
VectorConvectionNLFIntegrator::AddMultGradPA3D::Kernel()
{
static_assert(T_D1D <= T_Q1D, "d1d > q1d is not supported");
return internal::SmemPAConvectionNLGradApply3D<T_D1D, T_Q1D>;
}
inline VectorConvectionNLFIntegrator::AddMultGradPAType
VectorConvectionNLFIntegrator::AddMultGradPA3D::Fallback(int d1d, int q1d)
{
MFEM_VERIFY(d1d <= q1d, "d1d > q1d is not supported");
MFEM_VERIFY(d1d <= DeviceDofQuadLimits::Get().MAX_D1D, "");
MFEM_VERIFY(q1d <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
return internal::SmemPAConvectionNLGradApply3D<>;
}
/// \endcond DO_NOT_DOCUMENT
} // namespace mfem
+4 -8
View File
@@ -542,7 +542,10 @@ void QuadratureFunctions1D::GaussJacobi(const int np, const real_t alpha,
return;
}
#ifndef MFEM_USE_MPFR
#ifdef MFEM_USE_MPFR
MFEM_WARNING("MPFR implementation of Gauss-Jacobi quadrature not implemented yet. Falling "
"back to double precision implementation...");
#endif
const int n = np;
// common constants for Jacobi polynomials
@@ -611,13 +614,6 @@ void QuadratureFunctions1D::GaussJacobi(const int np, const real_t alpha,
ab + 1) / ((1.0 - xi*xi)*pp*pp) / pow(2, ab);
// map nodes and weights to the interval [0,1]
}
#else // MFEM_USE_MPFR is defined
MFEM_ABORT("MPFR implementation of Gauss-Jacobi quadrature not defined yet");
#endif // MFEM_USE_MPFR
}
+1 -1
View File
@@ -61,7 +61,7 @@ namespace mfem
#define MFEM_REGISTER_KERNELS_1(KernelName, KernelType, Params) \
MFEM_REGISTER_KERNELS_(KernelName, KernelType, Params, (), Params)
// Version of MFEM_REGISTER_KERNELS without any optional (non-dispatch)
// Version of MFEM_REGISTER_KERNELS with optional (non-dispatch)
// parameters (e.g. NBZ).
#define MFEM_REGISTER_KERNELS_2(KernelName, KernelType, Params, OptParams) \
MFEM_REGISTER_KERNELS_(KernelName, KernelType, Params, OptParams, \
+9 -2
View File
@@ -83,7 +83,7 @@ constexpr int SetMaxOf(int n) { return NextMultipleOf<4>(n); }
#endif // CUDA/HIP && DEVICE_COMPILE
/// Load 2D matrix into shared memory
template <int MQ1>
template <int MQ1, bool TRANSPOSE = false>
inline MFEM_HOST_DEVICE void LoadMatrix(const int d1d, const int q1d,
const real_t *M, real_t (*N)[MQ1])
{
@@ -91,7 +91,14 @@ inline MFEM_HOST_DEVICE void LoadMatrix(const int d1d, const int q1d,
{
MFEM_FOREACH_THREAD_DIRECT(qx, x, q1d)
{
N[dy][qx] = M[dy * q1d + qx];
if constexpr (TRANSPOSE)
{
N[dy][qx] = M[qx * d1d + dy];
}
else
{
N[dy][qx] = M[dy * q1d + qx];
}
}
}
MFEM_SYNC_THREAD;
+11
View File
@@ -100,6 +100,17 @@ PANonlinearFormExtension::Gradient::Gradient(const PANonlinearFormExtension &e):
void PANonlinearFormExtension::Gradient::AssembleGrad(const Vector &g)
{
if (DeviceCanUseCeed())
{
for (int i = 0; i < ext.dnfi.Size(); ++i)
{
MFEM_VERIFY(dynamic_cast<VectorConvectionNLFIntegrator *>
(ext.dnfi[i]) == nullptr,
"VectorConvectionNLFIntegrator PA gradients are not supported "
"with the libCEED backend");
}
}
ext.elemR->Mult(g, ext.xe);
for (int i = 0; i < ext.dnfi.Size(); ++i)
{
+70
View File
@@ -954,4 +954,74 @@ void SkewSymmetricVectorConvectionNLFIntegrator::AssembleElementGrad(
}
}
void ConvectiveVectorConvectionNLFIntegrator::AssemblePA(
const FiniteElementSpace &)
{
MFEM_ABORT("ConvectiveVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void ConvectiveVectorConvectionNLFIntegrator::AssembleGradPA(
const Vector &, const FiniteElementSpace &)
{
MFEM_ABORT("ConvectiveVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void ConvectiveVectorConvectionNLFIntegrator::AddMultPA(
const Vector &, Vector &) const
{
MFEM_ABORT("ConvectiveVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void ConvectiveVectorConvectionNLFIntegrator::AddMultGradPA(
const Vector &, Vector &) const
{
MFEM_ABORT("ConvectiveVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void ConvectiveVectorConvectionNLFIntegrator::AssembleGradDiagonalPA(
Vector &) const
{
MFEM_ABORT("ConvectiveVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void SkewSymmetricVectorConvectionNLFIntegrator::AssemblePA(
const FiniteElementSpace &)
{
MFEM_ABORT("SkewSymmetricVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void SkewSymmetricVectorConvectionNLFIntegrator::AssembleGradPA(
const Vector &, const FiniteElementSpace &)
{
MFEM_ABORT("SkewSymmetricVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void SkewSymmetricVectorConvectionNLFIntegrator::AddMultPA(
const Vector &, Vector &) const
{
MFEM_ABORT("SkewSymmetricVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void SkewSymmetricVectorConvectionNLFIntegrator::AddMultGradPA(
const Vector &, Vector &) const
{
MFEM_ABORT("SkewSymmetricVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
void SkewSymmetricVectorConvectionNLFIntegrator::AssembleGradDiagonalPA(
Vector &) const
{
MFEM_ABORT("SkewSymmetricVectorConvectionNLFIntegrator does not support "
"partial assembly; use VectorConvectionNLFIntegrator");
}
}
+70 -8
View File
@@ -18,6 +18,7 @@
#include "fespace.hpp"
#include "ceed/interface/operator.hpp"
#include "integrator.hpp"
#include "kernel_dispatch.hpp"
namespace mfem
{
@@ -384,15 +385,17 @@ private:
DenseMatrix dshape, dshapex, EF, gradEF, ELV, elmat_comp;
Vector shape;
// PA extension
Vector pa_data;
int dim, ne, nq, d1d, q1d;
Vector pa_adj, pa_u;
const DofToQuad *maps; ///< Not owned
const GeometricFactors *geom; ///< Not owned
int dim, ne, nq;
public:
VectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { }
struct Kernels { Kernels(); };
VectorConvectionNLFIntegrator() = default;
VectorConvectionNLFIntegrator(Coefficient &q): Q(&q) { static Kernels kernels; }
VectorConvectionNLFIntegrator() { static Kernels kernels; }
static const IntegrationRule &GetRule(const FiniteElement &fe,
const ElementTransformation &T);
@@ -411,12 +414,55 @@ public:
void AssemblePA(const FiniteElementSpace &fes) override;
void AssembleMF(const FiniteElementSpace &fes) override;
void AssembleGradPA(const Vector &x, const FiniteElementSpace &fes) override;
void AddMultPA(const Vector &x, Vector &y) const override;
void AddMultMF(const Vector &x, Vector &y) const override;
using AddMultPAType =
void(*)(const int ne, const real_t *B, const real_t *G, const real_t *A,
const real_t *x, real_t *y,
const int d1d, const int q1d);
MFEM_REGISTER_KERNELS(AddMultPAKernels, AddMultPAType, (int, int, int));
void AddMultGradPA(const Vector &x, Vector &y) const override;
using AddMultGradPAType =
void(*)(const int ne, const real_t *B, const real_t *G, const real_t *A,
const real_t *u, const real_t *x, real_t *y,
const int d1d, const int q1d);
MFEM_REGISTER_KERNELS(AddMultGradPA2D, AddMultGradPAType, (int, int));
MFEM_REGISTER_KERNELS(AddMultGradPA3D, AddMultGradPAType, (int, int));
void AssembleGradDiagonalPA(Vector &) const override;
using GradDiagPAType =
void (*)(const int ne, const real_t *B, const real_t *G, const real_t *A,
const real_t *u, real_t *y,
const int d1d, const int q1d);
MFEM_REGISTER_KERNELS(GradDiagPA2D, GradDiagPAType, (int, int));
MFEM_REGISTER_KERNELS(GradDiagPA3D, GradDiagPAType, (int, int));
template <int DIM, int D1D, int Q1D>
static void AddSpecialization()
{
AddMultPAKernels::Specialization<DIM, D1D, Q1D>::Add();
if constexpr (DIM == 2)
{
AddMultGradPA2D::Specialization<D1D, Q1D>::Add();
GradDiagPA2D::Specialization<D1D, Q1D>::Add();
}
else if constexpr (DIM == 3)
{
AddMultGradPA3D::Specialization<D1D, Q1D>::Add();
GradDiagPA3D::Specialization<D1D, Q1D>::Add();
}
}
void AssembleMF(const FiniteElementSpace &fes) override;
void AddMultMF(const Vector &x, Vector &y) const override;
protected:
const IntegrationRule* GetDefaultIntegrationRule(
@@ -430,7 +476,8 @@ protected:
/** This class is used to assemble the convective form of the nonlinear term
arising in the Navier-Stokes equations $(u \cdot \nabla v, w )$ */
arising in the Navier-Stokes equations $(u \cdot \nabla v, w )$.
Partial assembly is not supported; use VectorConvectionNLFIntegrator. */
class ConvectiveVectorConvectionNLFIntegrator :
public VectorConvectionNLFIntegrator
{
@@ -448,12 +495,20 @@ public:
ElementTransformation &trans,
const Vector &elfun,
DenseMatrix &elmat) override;
using NonlinearFormIntegrator::AssemblePA;
void AssemblePA(const FiniteElementSpace &fes) override;
void AssembleGradPA(const Vector &x, const FiniteElementSpace &fes) override;
void AddMultPA(const Vector &x, Vector &y) const override;
void AddMultGradPA(const Vector &x, Vector &y) const override;
void AssembleGradDiagonalPA(Vector &diag) const override;
};
/** This class is used to assemble the skew-symmetric form of the nonlinear term
arising in the Navier-Stokes equations
$.5*(u \cdot \nabla v, w ) - .5*(u \cdot \nabla w, v )$ */
$.5*(u \cdot \nabla v, w ) - .5*(u \cdot \nabla w, v )$.
Partial assembly is not supported; use VectorConvectionNLFIntegrator. */
class SkewSymmetricVectorConvectionNLFIntegrator :
public VectorConvectionNLFIntegrator
{
@@ -471,6 +526,13 @@ public:
ElementTransformation &trans,
const Vector &elfun,
DenseMatrix &elmat) override;
using NonlinearFormIntegrator::AssemblePA;
void AssemblePA(const FiniteElementSpace &fes) override;
void AssembleGradPA(const Vector &x, const FiniteElementSpace &fes) override;
void AddMultPA(const Vector &x, Vector &y) const override;
void AddMultGradPA(const Vector &x, Vector &y) const override;
void AssembleGradDiagonalPA(Vector &diag) const override;
};
}
+11 -1
View File
@@ -22,10 +22,20 @@ using namespace std;
namespace mfem
{
ParGridFunction::ParGridFunction(ParFiniteElementSpace *pf, GridFunction *gf)
ParGridFunction::ParGridFunction(ParFiniteElementSpace *pf, GridFunction *gf,
bool preserve)
{
fes = pfes = pf;
SetDataAndSize(gf->GetData(), gf->Size());
if (pfes->HaveDofSigns())
{
MFEM_VERIFY(!preserve, "Differing sign conventions for the serial and "
"parallel grid functions will prevent preserving the serial "
"GridFunctions in this context.");
pfes->ApplyDofSigns(HostReadWrite());
}
}
ParGridFunction::ParGridFunction(ParFiniteElementSpace *pf, HypreParVector *tv)
+6 -2
View File
@@ -100,8 +100,12 @@ public:
/// Construct a ParGridFunction using a GridFunction as external data.
/** The parallel space @a *pf and the space used by @a *gf should match. The
data from @a *gf is used as the local data of the ParGridFunction on each
processor. The ParGridFunction does not assume ownership of the data. */
ParGridFunction(ParFiniteElementSpace *pf, GridFunction *gf);
processor. The ParGridFunction does not assume ownership of the data.
The boolean, @a preserve, indicates that the data stored in @a *gf should
remain unchanged. An error will occur if @a preserve is true and
construction of a valid ParGridFunction requires the data to change. */
ParGridFunction(ParFiniteElementSpace *pf, GridFunction *gf,
bool preserve = true);
/** @brief Creates grid function on (all) dofs from a given vector on the
true dofs, i.e. P tv. */
+17 -18
View File
@@ -21,24 +21,23 @@ namespace quadrature_interpolator
void InitDetKernels()
{
using k = QuadratureInterpolator::DetKernels;
// 2D
k::Specialization<2,2,2,2>::Add();
k::Specialization<2,2,2,3>::Add();
k::Specialization<2,2,2,4>::Add();
k::Specialization<2,2,2,6>::Add();
k::Specialization<2,2,3,4>::Add();
k::Specialization<2,2,3,6>::Add();
k::Specialization<2,2,4,4>::Add();
k::Specialization<2,2,4,6>::Add();
k::Specialization<2,2,5,6>::Add();
QuadratureInterpolator::AddDetSpecializations<2,2,2,2>();
QuadratureInterpolator::AddDetSpecializations<2,2,2,3>();
QuadratureInterpolator::AddDetSpecializations<2,2,2,4>();
QuadratureInterpolator::AddDetSpecializations<2,2,2,6>();
QuadratureInterpolator::AddDetSpecializations<2,2,3,4>();
QuadratureInterpolator::AddDetSpecializations<2,2,3,6>();
QuadratureInterpolator::AddDetSpecializations<2,2,4,4>();
QuadratureInterpolator::AddDetSpecializations<2,2,4,6>();
QuadratureInterpolator::AddDetSpecializations<2,2,5,6>();
// 3D
k::Specialization<3,3,2,4>::Add();
k::Specialization<3,3,3,3>::Add();
k::Specialization<3,3,3,5>::Add();
k::Specialization<3,3,3,6>::Add();
k::Specialization<3,3,4,6>::Add();
k::Specialization<3,3,3,4>::Add();
QuadratureInterpolator::AddDetSpecializations<3,3,2,4>();
QuadratureInterpolator::AddDetSpecializations<3,3,3,3>();
QuadratureInterpolator::AddDetSpecializations<3,3,3,5>();
QuadratureInterpolator::AddDetSpecializations<3,3,3,6>();
QuadratureInterpolator::AddDetSpecializations<3,3,4,6>();
QuadratureInterpolator::AddDetSpecializations<3,3,3,4>();
}
} // namespace quadrature_interpolator
@@ -47,8 +46,8 @@ void InitDetKernels()
/// @cond Suppress_Doxygen_warnings
QuadratureInterpolator::DetKernelType
QuadratureInterpolator::DetKernels::Fallback(
int DIM, int SDIM, int D1D, int Q1D)
QuadratureInterpolator::DetKernels::Fallback(int DIM, int SDIM, int D1D,
int Q1D)
{
if (DIM == 1)
{
+548 -56
View File
@@ -30,23 +30,18 @@ namespace internal
namespace quadrature_interpolator
{
template<QVectorLayout Q_LAYOUT>
static void Values1D(const int NE,
const real_t *b_,
const real_t *x_,
real_t *y_,
const int vdim,
const int d1d,
const int q1d)
template <QVectorLayout Q_LAYOUT, bool Integral>
static void ImplValues1D(const int NE, const real_t *b_, const real_t *detJ_,
const real_t *x_, real_t *y_, const int vdim,
const int d1d, const int q1d)
{
const auto b = Reshape(b_, q1d, d1d);
const auto x = Reshape(x_, d1d, vdim, NE);
auto y = Q_LAYOUT == QVectorLayout::byNODES ?
Reshape(y_, q1d, vdim, NE):
Reshape(y_, vdim, q1d, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
{
const auto b = Reshape(b_, q1d, d1d);
const auto x = Reshape(x_, d1d, vdim, NE);
const auto detJ = Reshape(detJ_, q1d, NE);
auto y = Q_LAYOUT == QVectorLayout::byNODES ? Reshape(y_, q1d, vdim, NE)
: Reshape(y_, vdim, q1d, NE);
for (int c = 0; c < vdim; c++)
{
for (int q = 0; q < q1d; q++)
@@ -56,24 +51,36 @@ static void Values1D(const int NE,
{
u += b(q, d) * x(d, c, e);
}
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c, q, e) = u; }
if (Q_LAYOUT == QVectorLayout::byNODES) { y(q, c, e) = u; }
if constexpr (Integral)
{
u /= detJ(q, e);
}
if constexpr (Q_LAYOUT == QVectorLayout::byVDIM)
{
y(c, q, e) = u;
}
if constexpr (Q_LAYOUT == QVectorLayout::byNODES)
{
y(q, c, e) = u;
}
}
}
});
}
template <QVectorLayout Q_LAYOUT>
static void Values1D(const int NE, const real_t *b_, const real_t *x_,
real_t *y_, const int vdim, const int d1d, const int q1d)
{
ImplValues1D<Q_LAYOUT, false>(NE, b_, nullptr, x_, y_, vdim, d1d, q1d);
}
// Template compute kernel for Values in 2D: tensor product version.
template<QVectorLayout Q_LAYOUT,
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
int T_NBZ = 1>
static void Values2D(const int NE,
const real_t *b_,
const real_t *x_,
real_t *y_,
const int vdim = 0,
const int d1d = 0,
const int q1d = 0)
template <QVectorLayout Q_LAYOUT, bool Integral, int T_VDIM = 0, int T_D1D = 0,
int T_Q1D = 0, int T_NBZ = 1>
static void ImplValues2D(const int NE, const real_t *b_, const real_t *detJ_,
const real_t *x_, real_t *y_, const int vdim = 0,
const int d1d = 0, const int q1d = 0)
{
static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
@@ -82,13 +89,14 @@ static void Values2D(const int NE,
const int VDIM = T_VDIM ? T_VDIM : vdim;
const auto b = Reshape(b_, Q1D, D1D);
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
auto y = Q_LAYOUT == QVectorLayout::byNODES ?
Reshape(y_, Q1D, Q1D, VDIM, NE):
Reshape(y_, VDIM, Q1D, Q1D, NE);
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE(int e)
{
const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
const auto detJ = Reshape(detJ_, Q1D, Q1D, NE);
auto y = Q_LAYOUT == QVectorLayout::byNODES
? Reshape(y_, Q1D, Q1D, VDIM, NE)
: Reshape(y_, VDIM, Q1D, Q1D, NE);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
@@ -110,16 +118,33 @@ static void Values2D(const int NE,
for (int c = 0; c < VDIM; c++)
{
kernels::internal::LoadX(e,D1D,c,x,DD);
MFEM_FOREACH_THREAD(dy,y,D1D)
{
MFEM_FOREACH_THREAD(dx, x, D1D)
{
DD(dx, dy) = x(dx, dy, c, e);
}
}
MFEM_SYNC_THREAD;
kernels::internal::EvalX(D1D,Q1D,B,DD,DQ);
kernels::internal::EvalY(D1D,Q1D,B,DQ,QQ);
MFEM_FOREACH_THREAD(qy,y,Q1D)
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
real_t u = QQ(qx,qy);
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c,qx,qy,e) = u; }
if (Q_LAYOUT == QVectorLayout::byNODES) { y(qx,qy,c,e) = u; }
real_t u = QQ(qx, qy);
if constexpr (Integral)
{
u /= detJ(qx, qy, e);
}
if constexpr (Q_LAYOUT == QVectorLayout::byVDIM)
{
y(c, qx, qy, e) = u;
}
if constexpr (Q_LAYOUT == QVectorLayout::byNODES)
{
y(qx, qy, c, e) = u;
}
}
}
MFEM_SYNC_THREAD;
@@ -127,29 +152,37 @@ static void Values2D(const int NE,
});
}
// Template compute kernel for Values in 3D: tensor product version.
template<QVectorLayout Q_LAYOUT,
int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0>
static void Values3D(const int NE,
const real_t *b_,
const real_t *x_,
real_t *y_,
const int vdim = 0,
const int d1d = 0,
// Template compute kernel for Values in 2D: tensor product version.
template <QVectorLayout Q_LAYOUT, int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
int T_NBZ = 1>
static void Values2D(const int NE, const real_t *b_, const real_t *x_,
real_t *y_, const int vdim = 0, const int d1d = 0,
const int q1d = 0)
{
return ImplValues2D<Q_LAYOUT, false, T_VDIM, T_D1D, T_Q1D, T_NBZ>(
NE, b_, nullptr, x_, y_, vdim, d1d, q1d);
}
// Template compute kernel for Values in 3D: tensor product version.
template <QVectorLayout Q_LAYOUT, bool Integral, int T_VDIM = 0, int T_D1D = 0,
int T_Q1D = 0>
static void ImplValues3D(const int NE, const real_t *b_, const real_t *detJ_,
const real_t *x_, real_t *y_, const int vdim = 0,
const int d1d = 0, const int q1d = 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;
const auto b = Reshape(b_, Q1D, D1D);
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
Reshape(y_, Q1D, Q1D, Q1D, VDIM, NE):
Reshape(y_, VDIM, Q1D, Q1D, Q1D, NE);
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
{
const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
const auto detJ = Reshape(detJ_, Q1D, Q1D, Q1D, NE);
auto y = Q_LAYOUT == QVectorLayout::byNODES
? Reshape(y_, Q1D, Q1D, Q1D, VDIM, NE)
: Reshape(y_, VDIM, Q1D, Q1D, Q1D, NE);
const int D1D = T_D1D ? T_D1D : d1d;
const int Q1D = T_Q1D ? T_Q1D : q1d;
const int VDIM = T_VDIM ? T_VDIM : vdim;
@@ -171,7 +204,17 @@ static void Values3D(const int NE,
for (int c = 0; c < VDIM; c++)
{
kernels::internal::LoadX(e,D1D,c,x,DDD);
MFEM_FOREACH_THREAD(dz, z, D1D)
{
MFEM_FOREACH_THREAD(dy, y, D1D)
{
MFEM_FOREACH_THREAD(dx, x, D1D)
{
DDD(dx, dy, dz) = x(dx, dy, dz, c, e);
}
}
}
MFEM_SYNC_THREAD;
kernels::internal::EvalX(D1D,Q1D,B,DDD,DDQ);
kernels::internal::EvalY(D1D,Q1D,B,DDQ,DQQ);
kernels::internal::EvalZ(D1D,Q1D,B,DQQ,QQQ);
@@ -181,9 +224,19 @@ static void Values3D(const int NE,
{
MFEM_FOREACH_THREAD(qx,x,Q1D)
{
const real_t u = QQQ(qz,qy,qx);
if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c,qx,qy,qz,e) = u; }
if (Q_LAYOUT == QVectorLayout::byNODES) { y(qx,qy,qz,c,e) = u; }
real_t u = QQQ(qz,qy,qx);
if constexpr (Integral)
{
u /= detJ(qx, qy, qz, e);
}
if constexpr (Q_LAYOUT == QVectorLayout::byVDIM)
{
y(c, qx, qy, qz, e) = u;
}
if constexpr (Q_LAYOUT == QVectorLayout::byNODES)
{
y(qx, qy, qz, c, e) = u;
}
}
}
}
@@ -192,14 +245,431 @@ static void Values3D(const int NE,
});
}
// Template compute kernel for Values in 3D: tensor product version.
template <QVectorLayout Q_LAYOUT, int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0>
static void Values3D(const int NE, const real_t *b_, const real_t *x_,
real_t *y_, const int vdim = 0, const int d1d = 0,
const int q1d = 0)
{
return ImplValues3D<Q_LAYOUT, false, T_VDIM, T_D1D, T_Q1D>(
NE, b_, nullptr, x_, y_, vdim, d1d, q1d);
}
template <bool Integral>
void ImplEval1D(const int NE, const int vdim, const QVectorLayout q_layout,
const real_t *detJ, const GeometricFactors *geom,
const DofToQuad &maps, const Vector &e_vec, Vector &q_val,
Vector &q_der, Vector &q_det, const int eval_flags);
inline void Eval1D(const int NE, const int vdim, const QVectorLayout q_layout,
const GeometricFactors *geom, const DofToQuad &maps,
const Vector &e_vec, Vector &q_val, Vector &q_der, Vector &q_det,
const int eval_flags)
{
ImplEval1D<false>(NE, vdim, q_layout, nullptr, geom, maps, e_vec, q_val,
q_der, q_det, eval_flags);
}
// Template compute kernel for 2D quadrature interpolation:
// * non-tensor product version,
// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
// * assumes 'maps.mode == FULL'.
template <bool Integral, const int T_VDIM, const int T_ND, const int T_NQ>
static void ImplEval2D(const int NE, const int vdim,
const QVectorLayout q_layout, const real_t *detJ_,
const GeometricFactors *geom, const DofToQuad &maps,
const Vector &e_vec, Vector &q_val, Vector &q_der,
Vector &q_det, const int eval_flags)
{
using QI = QuadratureInterpolator;
const int nd = maps.ndof;
const int nq = maps.nqpt;
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int NMAX = NQ > ND ? NQ : ND;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_ASSERT(maps.mode == DofToQuad::FULL, "internal error");
MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 2, "");
MFEM_VERIFY(ND <= QI::MAX_ND2D, "");
MFEM_VERIFY(NQ <= QI::MAX_NQ2D, "");
if constexpr(Integral)
{
MFEM_VERIFY(!(eval_flags & (QI::DERIVATIVES | QI::PHYSICAL_DERIVATIVES |
QI::DETERMINANTS)),
"Integral FE does not support computing derivatives");
}
const auto B = Reshape(maps.B.Read(), NQ, ND);
const auto G = Reshape(maps.G.Read(), NQ, 2, ND);
const auto J = Reshape(geom ? geom->J.Read() : nullptr, NQ, 2, 2, NE);
const auto E_ = e_vec.Read();
auto val = q_layout == QVectorLayout::byNODES ?
Reshape(q_val.Write(), NQ, VDIM, NE):
Reshape(q_val.Write(), VDIM, NQ, NE);
auto der = q_layout == QVectorLayout::byNODES ?
Reshape(q_der.Write(), NQ, VDIM, 2, NE):
Reshape(q_der.Write(), VDIM, 2, NQ, NE);
auto det = Reshape(q_det.Write(), NQ, NE);
mfem::forall_2D(NE, NMAX, 1, [=] MFEM_HOST_DEVICE(int e)
{
const auto E = Reshape(E_, ND, VDIM, NE);
const auto detJ = Reshape(detJ_, NQ, NE);
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int max_ND = T_ND ? T_ND : QI::MAX_ND2D;
constexpr int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM2D;
MFEM_SHARED real_t s_E[max_VDIM*max_ND];
MFEM_FOREACH_THREAD(d, x, ND)
{
for (int c = 0; c < VDIM; c++)
{
s_E[c + d * VDIM] = E(d, c, e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(q, x, NQ)
{
if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
{
real_t ed[max_VDIM];
for (int c = 0; c < VDIM; c++)
{
ed[c] = 0.0;
}
for (int d = 0; d < ND; ++d)
{
const real_t b = B(q,d);
for (int c = 0; c < VDIM; c++)
{
ed[c] += b * s_E[c + d * VDIM];
}
}
for (int c = 0; c < VDIM; c++)
{
if constexpr (Integral)
{
ed[c] /= detJ(q, e);
}
if (q_layout == QVectorLayout::byVDIM)
{
val(c, q, e) = ed[c];
}
if (q_layout == QVectorLayout::byNODES)
{
val(q, c, e) = ed[c];
}
}
}
if ((eval_flags & QI::DERIVATIVES) ||
(eval_flags & QI::PHYSICAL_DERIVATIVES) ||
(eval_flags & QI::DETERMINANTS))
{
// use MAX_VDIM2D to avoid "subscript out of range" warnings
real_t D[QI::MAX_VDIM2D*2];
for (int i = 0; i < 2*VDIM; i++)
{
D[i] = 0.0;
}
for (int d = 0; d < ND; ++d)
{
const real_t wx = G(q,0,d);
const real_t wy = G(q,1,d);
for (int c = 0; c < VDIM; c++)
{
real_t s_e = s_E[c+d*VDIM];
D[c+VDIM*0] += s_e * wx;
D[c+VDIM*1] += s_e * wy;
}
}
if (eval_flags & QI::DERIVATIVES)
{
for (int c = 0; c < VDIM; c++)
{
if (q_layout == QVectorLayout::byVDIM)
{
der(c,0,q,e) = D[c+VDIM*0];
der(c,1,q,e) = D[c+VDIM*1];
}
if (q_layout == QVectorLayout::byNODES)
{
der(q,c,0,e) = D[c+VDIM*0];
der(q,c,1,e) = D[c+VDIM*1];
}
}
}
if (eval_flags & QI::PHYSICAL_DERIVATIVES)
{
real_t Jloc[4], Jinv[4];
Jloc[0] = J(q,0,0,e);
Jloc[1] = J(q,1,0,e);
Jloc[2] = J(q,0,1,e);
Jloc[3] = J(q,1,1,e);
kernels::CalcInverse<2>(Jloc, Jinv);
for (int c = 0; c < VDIM; c++)
{
const real_t u = D[c+VDIM*0];
const real_t v = D[c+VDIM*1];
const real_t JiU = Jinv[0]*u + Jinv[1]*v;
const real_t JiV = Jinv[2]*u + Jinv[3]*v;
if (q_layout == QVectorLayout::byVDIM)
{
der(c,0,q,e) = JiU;
der(c,1,q,e) = JiV;
}
if (q_layout == QVectorLayout::byNODES)
{
der(q,c,0,e) = JiU;
der(q,c,1,e) = JiV;
}
}
}
if (eval_flags & QI::DETERMINANTS)
{
if (VDIM == 2)
{
det(q, e) = kernels::Det<2>(D);
}
else
{
DeviceTensor<2> j(D, 3, 2);
const real_t dE = j(0,0)*j(0,0) + j(1,0)*j(1,0) + j(2,0)*j(2,0);
const real_t dF = j(0,0)*j(0,1) + j(1,0)*j(1,1) + j(2,0)*j(2,1);
const real_t dG = j(0,1)*j(0,1) + j(1,1)*j(1,1) + j(2,1)*j(2,1);
det(q,e) = std::sqrt(dE*dG - dF*dF);
}
}
}
}
});
}
// Template compute kernel for 2D quadrature interpolation:
// * non-tensor product version,
// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
// * assumes 'maps.mode == FULL'.
template <const int T_VDIM, const int T_ND, const int T_NQ>
static void Eval2D(const int NE, const int vdim, const QVectorLayout q_layout,
const GeometricFactors *geom, const DofToQuad &maps,
const Vector &e_vec, Vector &q_val, Vector &q_der,
Vector &q_det, const int eval_flags)
{
ImplEval2D<false, T_VDIM, T_ND, T_NQ>(NE, vdim, q_layout, nullptr, geom,
maps, e_vec, q_val, q_der, q_det,
eval_flags);
}
// Template compute kernel for 3D quadrature interpolation:
// * non-tensor product version,
// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
// * assumes 'maps.mode == FULL'.
template <bool Integral, const int T_VDIM, const int T_ND, const int T_NQ>
static void ImplEval3D(const int NE, const int vdim,
const QVectorLayout q_layout, const real_t *detJ_,
const GeometricFactors *geom, const DofToQuad &maps,
const Vector &e_vec, Vector &q_val, Vector &q_der,
Vector &q_det, const int eval_flags)
{
using QI = QuadratureInterpolator;
const int nd = maps.ndof;
const int nq = maps.nqpt;
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int NMAX = NQ > ND ? NQ : ND;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_ASSERT(maps.mode == DofToQuad::FULL, "internal error");
MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 3, "");
MFEM_VERIFY(ND <= QI::MAX_ND3D, "");
MFEM_VERIFY(NQ <= QI::MAX_NQ3D, "");
MFEM_VERIFY(VDIM == 3 || !(eval_flags & QI::DETERMINANTS), "");
if constexpr(Integral)
{
MFEM_VERIFY(!(eval_flags & (QI::DERIVATIVES | QI::PHYSICAL_DERIVATIVES |
QI::DETERMINANTS)),
"Integral FE does not support computing derivatives");
}
const auto B = Reshape(maps.B.Read(), NQ, ND);
const auto G = Reshape(maps.G.Read(), NQ, 3, ND);
const auto J = Reshape(geom ? geom->J.Read() : nullptr, NQ, 3, 3, NE);
auto E_ = e_vec.Read();
auto val = q_layout == QVectorLayout::byNODES ?
Reshape(q_val.Write(), NQ, VDIM, NE):
Reshape(q_val.Write(), VDIM, NQ, NE);
auto der = q_layout == QVectorLayout::byNODES ?
Reshape(q_der.Write(), NQ, VDIM, 3, NE):
Reshape(q_der.Write(), VDIM, 3, NQ, NE);
auto det = Reshape(q_det.Write(), NQ, NE);
mfem::forall_2D(NE, NMAX, 1, [=] MFEM_HOST_DEVICE(int e)
{
const auto E = Reshape(E_, ND, VDIM, NE);
const auto detJ = Reshape(detJ_, NQ, NE);
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int max_ND = T_ND ? T_ND : QI::MAX_ND3D;
constexpr int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM3D;
MFEM_SHARED real_t s_E[max_VDIM*max_ND];
MFEM_FOREACH_THREAD(d, x, ND)
{
for (int c = 0; c < VDIM; c++)
{
s_E[c + d * VDIM] = E(d, c, e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(q, x, NQ)
{
if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
{
real_t ed[max_VDIM];
for (int c = 0; c < VDIM; c++)
{
ed[c] = 0.0;
}
for (int d = 0; d < ND; ++d)
{
const real_t b = B(q,d);
for (int c = 0; c < VDIM; c++)
{
ed[c] += b * s_E[c + d * VDIM];
}
}
for (int c = 0; c < VDIM; c++)
{
if constexpr (Integral)
{
ed[c] /= detJ(q, e);
}
if (q_layout == QVectorLayout::byVDIM)
{
val(c, q, e) = ed[c];
}
if (q_layout == QVectorLayout::byNODES)
{
val(q, c, e) = ed[c];
}
}
}
if ((eval_flags & QI::DERIVATIVES) ||
(eval_flags & QI::PHYSICAL_DERIVATIVES) ||
(eval_flags & QI::DETERMINANTS))
{
// use MAX_VDIM3D to avoid "subscript out of range" warnings
real_t D[QI::MAX_VDIM3D*3];
for (int i = 0; i < 3*VDIM; i++)
{
D[i] = 0.0;
}
for (int d = 0; d < ND; ++d)
{
const real_t wx = G(q,0,d);
const real_t wy = G(q,1,d);
const real_t wz = G(q,2,d);
for (int c = 0; c < VDIM; c++)
{
real_t s_e = s_E[c+d*VDIM];
D[c+VDIM*0] += s_e * wx;
D[c+VDIM*1] += s_e * wy;
D[c+VDIM*2] += s_e * wz;
}
}
if (eval_flags & QI::DERIVATIVES)
{
for (int c = 0; c < VDIM; c++)
{
if (q_layout == QVectorLayout::byVDIM)
{
der(c,0,q,e) = D[c+VDIM*0];
der(c,1,q,e) = D[c+VDIM*1];
der(c,2,q,e) = D[c+VDIM*2];
}
if (q_layout == QVectorLayout::byNODES)
{
der(q,c,0,e) = D[c+VDIM*0];
der(q,c,1,e) = D[c+VDIM*1];
der(q,c,2,e) = D[c+VDIM*2];
}
}
}
if (eval_flags & QI::PHYSICAL_DERIVATIVES)
{
real_t Jloc[9], Jinv[9];
for (int col = 0; col < 3; col++)
{
for (int row = 0; row < 3; row++)
{
Jloc[row+3*col] = J(q,row,col,e);
}
}
kernels::CalcInverse<3>(Jloc, Jinv);
for (int c = 0; c < VDIM; c++)
{
const real_t u = D[c+VDIM*0];
const real_t v = D[c+VDIM*1];
const real_t w = D[c+VDIM*2];
const real_t JiU = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
const real_t JiV = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
const real_t JiW = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
if (q_layout == QVectorLayout::byVDIM)
{
der(c,0,q,e) = JiU;
der(c,1,q,e) = JiV;
der(c,2,q,e) = JiW;
}
if (q_layout == QVectorLayout::byNODES)
{
der(q,c,0,e) = JiU;
der(q,c,1,e) = JiV;
der(q,c,2,e) = JiW;
}
}
}
if (VDIM == 3 && (eval_flags & QI::DETERMINANTS))
{
// The check (VDIM == 3) should eliminate this block when VDIM is
// known at compile time and (VDIM != 3).
det(q,e) = kernels::Det<3>(D);
}
}
}
});
}
// Template compute kernel for 3D quadrature interpolation:
// * non-tensor product version,
// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
// * assumes 'maps.mode == FULL'.
template <const int T_VDIM, const int T_ND, const int T_NQ>
static void Eval3D(const int NE, const int vdim, const QVectorLayout q_layout,
const GeometricFactors *geom, const DofToQuad &maps,
const Vector &e_vec, Vector &q_val, Vector &q_der,
Vector &q_det, const int eval_flags)
{
ImplEval3D<false, T_VDIM, T_ND, T_NQ>(NE, vdim, q_layout, nullptr, geom,
maps, e_vec, q_val, q_der, q_det,
eval_flags);
}
} // namespace quadrature_interpolator
} // namespace internal
/// @cond Suppress_Doxygen_warnings
template<int DIM, QVectorLayout Q_LAYOUT,
int VDIM, int D1D, int Q1D, int NBZ>
template <int DIM, QVectorLayout Q_LAYOUT, int VDIM, int D1D, int Q1D, int NBZ>
QuadratureInterpolator::IntTensorEvalKernelType
QuadratureInterpolator::IntTensorEvalKernels::Kernel()
{
if constexpr (DIM == 1) { return internal::quadrature_interpolator::ImplValues1D<Q_LAYOUT, true>; }
else if constexpr (DIM == 2) { return internal::quadrature_interpolator::ImplValues2D<Q_LAYOUT, true, VDIM, D1D, Q1D, NBZ>; }
else if constexpr (DIM == 3) { return internal::quadrature_interpolator::ImplValues3D<Q_LAYOUT, true, VDIM, D1D, Q1D>; }
MFEM_ABORT("");
}
template <int DIM, QVectorLayout Q_LAYOUT, int VDIM, int D1D, int Q1D, int NBZ>
QuadratureInterpolator::TensorEvalKernelType
QuadratureInterpolator::TensorEvalKernels::Kernel()
{
@@ -209,6 +679,28 @@ QuadratureInterpolator::TensorEvalKernels::Kernel()
MFEM_ABORT("");
}
template <int DIM, int VDIM, int ND, int NQ>
QuadratureInterpolator::IntEvalKernelType
QuadratureInterpolator::IntEvalKernels::Kernel()
{
using namespace internal::quadrature_interpolator;
if constexpr (DIM == 1) { return ImplEval1D<true>; }
else if constexpr (DIM == 2) { return ImplEval2D<true,VDIM,ND,NQ>; }
else if constexpr (DIM == 3) { return ImplEval3D<true,VDIM,ND,NQ>; }
MFEM_ABORT("");
}
template <int DIM, int VDIM, int ND, int NQ>
QuadratureInterpolator::EvalKernelType
QuadratureInterpolator::EvalKernels::Kernel()
{
using namespace internal::quadrature_interpolator;
if constexpr (DIM == 1) { return Eval1D; }
else if constexpr (DIM == 2) { return Eval2D<VDIM,ND,NQ>; }
else if constexpr (DIM == 3) { return Eval3D<VDIM,ND,NQ>; }
MFEM_ABORT("");
}
/// @endcond
} // namespace mfem
+88 -46
View File
@@ -21,63 +21,105 @@ namespace quadrature_interpolator
void InitEvalByNodesKernels()
{
using k = QuadratureInterpolator::TensorEvalKernels;
// 2D
k::Specialization<2,QVectorLayout::byNODES,1,3,3>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,1,2,4>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,1,3,2>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,1,3,4>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,1,3,6>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,1,4,3>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,1,4,4>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 1, 3, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 1, 2, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 1, 3, 2, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 1, 3, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 1, 3, 6, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 1, 4, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 1, 4, 4, 1>();
k::Specialization<2,QVectorLayout::byNODES,2,2,2>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,2,3>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,2,4>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,2,5>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,2,6>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 2, 2, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 2, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 2, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 2, 5, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 2, 6, 1>();
k::Specialization<2,QVectorLayout::byNODES,2,3,3>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,3,4>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,3,6>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 3, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 3, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 3, 6, 1>();
k::Specialization<2,QVectorLayout::byNODES,2,4,3>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,4,4>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,4,5>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,4,6>::Opt<1>::Add();
k::Specialization<2,QVectorLayout::byNODES,2,4,7>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 4, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 4, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 4, 5, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 4, 6, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 4, 7, 1>();
k::Specialization<2,QVectorLayout::byNODES,2,5,6>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byNODES, 2, 5, 6, 1>();
// 3D
k::Specialization<3,QVectorLayout::byNODES,1,2,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,1,3,3>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,1,3,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,1,3,6>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,1,4,3>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,1,4,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,1,4,8>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 1, 2, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 1, 3, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 1, 3, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 1, 3, 6, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 1, 4, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 1, 4, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 1, 4, 8, 1>();
k::Specialization<3,QVectorLayout::byNODES,2,2,2>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,2,2,3>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,2,3,4>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 2, 2, 2, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 2, 2, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 2, 3, 4, 1>();
k::Specialization<3,QVectorLayout::byNODES,3,2,3>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,2,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,2,5>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,2,6>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 2, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 2, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 2, 5, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 2, 6, 1>();
k::Specialization<3,QVectorLayout::byNODES,3,3,3>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,3,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,3,5>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,3,6>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 3, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 3, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 3, 5, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 3, 6, 1>();
k::Specialization<3,QVectorLayout::byNODES,3,4,3>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,4,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,4,6>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,4,7>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byNODES,3,4,8>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 4, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 4, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 4, 6, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 4, 7, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byNODES, 3, 4, 8, 1>();
}
} // namespace quadrature_interpolator
+48 -25
View File
@@ -21,36 +21,59 @@ namespace quadrature_interpolator
void InitEvalByVDimKernels()
{
using k = QuadratureInterpolator::TensorEvalKernels;
// 2D
k::Specialization<2,QVectorLayout::byVDIM,1,2,4>::Opt<8>::Add();
k::Specialization<2,QVectorLayout::byVDIM,1,3,6>::Opt<4>::Add();
k::Specialization<2,QVectorLayout::byVDIM,1,4,8>::Opt<2>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byVDIM, 1, 2, 4, 8>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byVDIM, 1, 3, 6, 4>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byVDIM, 1, 4, 8, 2>();
k::Specialization<2,QVectorLayout::byVDIM,2,2,4>::Opt<8>::Add();
k::Specialization<2,QVectorLayout::byVDIM,2,3,4>::Opt<8>::Add();
k::Specialization<2,QVectorLayout::byVDIM,2,3,6>::Opt<4>::Add();
k::Specialization<2,QVectorLayout::byVDIM,2,4,6>::Opt<2>::Add();
k::Specialization<2,QVectorLayout::byVDIM,2,4,8>::Opt<2>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byVDIM, 2, 2, 4, 8>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byVDIM, 2, 3, 4, 8>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byVDIM, 2, 3, 6, 4>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byVDIM, 2, 4, 6, 2>();
QuadratureInterpolator::AddTensorEvalSpecializations<
2, QVectorLayout::byVDIM, 2, 4, 8, 2>();
// 3D
k::Specialization<3,QVectorLayout::byVDIM,1,2,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,1,3,6>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,1,4,8>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,2,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,3,6>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,4,8>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 1, 2, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 1, 3, 6, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 1, 4, 8, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 2, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 3, 6, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 4, 8, 1>();
k::Specialization<3,QVectorLayout::byVDIM,3,2,2>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,3,3>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,4,4>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,5,5>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,6,6>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,7,7>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,8,8>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,9,9>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 2, 2, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 3, 3, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 4, 4, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 5, 5, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 6, 6, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 7, 7, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 8, 8, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 9, 9, 1>();
k::Specialization<3,QVectorLayout::byVDIM,3,4,6>::Opt<1>::Add();
k::Specialization<3,QVectorLayout::byVDIM,3,3,4>::Opt<1>::Add();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 4, 6, 1>();
QuadratureInterpolator::AddTensorEvalSpecializations<
3, QVectorLayout::byVDIM, 3, 3, 4, 1>();
}
} // namespace quadrature_interpolator
+3 -2
View File
@@ -268,8 +268,9 @@ static void Derivatives3D(const int NE,
DeviceMatrix B(BG[0], D1D, Q1D);
DeviceMatrix G(BG[1], D1D, Q1D);
MFEM_SHARED real_t sm0[3][MQ1*MQ1*MQ1];
MFEM_SHARED real_t sm1[3][MQ1*MQ1*MQ1];
constexpr int MDQ = MD1 > MQ1 ? MD1 : MQ1;
MFEM_SHARED real_t sm0[3][MD1*MD1*MDQ];
MFEM_SHARED real_t sm1[3][MD1*MQ1*MQ1];
DeviceTensor<3> X(sm0[2], D1D, D1D, D1D);
DeviceTensor<3> DDQ0(sm0[0], D1D, D1D, Q1D);
DeviceTensor<3> DDQ1(sm0[1], D1D, D1D, Q1D);
+51 -54
View File
@@ -22,74 +22,71 @@ namespace quadrature_interpolator
template <bool P>
void InitGradByNodesKernels()
{
using k = QuadratureInterpolator::GradKernels;
constexpr auto L = QVectorLayout::byNODES;
// 2D
k::Specialization<2,L,P,1,3,3>::template Opt<16>::Add();
k::Specialization<2,L,P,1,3,4>::template Opt<16>::Add();
k::Specialization<2,L,P,1,4,3>::template Opt<16>::Add();
k::Specialization<2,L,P,1,4,4>::template Opt<16>::Add();
QuadratureInterpolator::AddGradSpecializations<2,L,P,1,3,3,16>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,1,3,4,16>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,1,4,3,16>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,1,4,4,16>();
k::Specialization<2,L,P,2,2,2>::template Opt<16>::Add();
k::Specialization<2,L,P,2,2,3>::template Opt<8>::Add();
k::Specialization<2,L,P,2,2,4>::template Opt<4>::Add();
k::Specialization<2,L,P,2,2,5>::template Opt<4>::Add();
k::Specialization<2,L,P,2,2,6>::template Opt<2>::Add();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,2,2,16>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,2,3,8>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,2,4,4>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,2,5,4>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,2,6,2>();
k::Specialization<2,L,P,2,3,3>::template Opt<2>::Add();
k::Specialization<2,L,P,2,3,4>::template Opt<4>::Add();
k::Specialization<2,L,P,2,4,3>::template Opt<4>::Add();
k::Specialization<2,L,P,2,3,6>::template Opt<2>::Add();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,3,3,2>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,3,4,4>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,4,3,4>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,3,6,2>();
k::Specialization<2,L,P,2,4,4>::template Opt<2>::Add();
k::Specialization<2,L,P,2,4,5>::template Opt<2>::Add();
k::Specialization<2,L,P,2,4,6>::template Opt<2>::Add();
k::Specialization<2,L,P,2,4,7>::template Opt<2>::Add();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,4,4,2>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,4,5,2>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,4,6,2>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,4,7,2>();
k::Specialization<2,L,P,2,5,6>::template Opt<2>::Add();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,5,6,2>();
// 3D
k::Specialization<3,L,P,1,2,4>::Add();
k::Specialization<3,L,P,1,3,3>::Add();
k::Specialization<3,L,P,1,3,4>::Add();
k::Specialization<3,L,P,1,3,6>::Add();
k::Specialization<3,L,P,1,4,4>::Add();
k::Specialization<3,L,P,1,4,8>::Add();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,2,4>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,3,3>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,3,4>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,3,6>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,4,4>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,4,8>();
k::Specialization<3,L,P,3,2,3>::Add();
k::Specialization<3,L,P,3,2,4>::Add();
k::Specialization<3,L,P,3,2,5>::Add();
k::Specialization<3,L,P,3,2,6>::Add();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,2,3>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,2,4>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,2,5>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,2,6>();
k::Specialization<3,L,P,3,3,3>::Add();
k::Specialization<3,L,P,3,3,4>::Add();
k::Specialization<3,L,P,3,3,5>::Add();
k::Specialization<3,L,P,3,3,6>::Add();
k::Specialization<3,L,P,3,4,4>::Add();
k::Specialization<3,L,P,3,4,6>::Add();
k::Specialization<3,L,P,3,4,7>::Add();
k::Specialization<3,L,P,3,4,8>::Add();
using k2 = QuadratureInterpolator::CollocatedGradKernels;
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,3,3>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,3,4>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,3,5>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,3,6>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,4,4>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,4,6>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,4,7>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,4,8>();
// 2D
k2::Specialization<2,L,P,1,2>::template Opt<16>::Add();
k2::Specialization<2,L,P,1,3>::template Opt<16>::Add();
k2::Specialization<2,L,P,1,4>::template Opt<16>::Add();
k2::Specialization<2,L,P,2,2>::template Opt<16>::Add();
k2::Specialization<2,L,P,2,3>::template Opt<4>::Add();
k2::Specialization<2,L,P,2,4>::template Opt<2>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,1,2,16>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,1,3,16>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,1,4,16>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,2,2,16>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,2,3,4>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,2,4,2>();
k2::Specialization<3,L,P,1,2>::Add();
k2::Specialization<3,L,P,1,3>::Add();
k2::Specialization<3,L,P,1,4>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,1,2>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,1,3>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,1,4>();
k2::Specialization<3,L,P,2,2>::Add();
k2::Specialization<3,L,P,2,3>::Add();
k2::Specialization<3,L,P,2,4>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,2,2>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,2,3>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,2,4>();
k2::Specialization<3,L,P,3,2>::Add();
k2::Specialization<3,L,P,3,3>::Add();
k2::Specialization<3,L,P,3,4>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,3,2>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,3,3>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,3,4>();
}
template void InitGradByNodesKernels<true>();
+28 -30
View File
@@ -22,47 +22,45 @@ namespace quadrature_interpolator
template <bool P>
void InitGradByVDimKernels()
{
using k = QuadratureInterpolator::GradKernels;
constexpr auto L = QVectorLayout::byVDIM;
// 2D
k::Specialization<2,L,P,1,3,4>::template Opt<8>::Add();
k::Specialization<2,L,P,1,4,6>::template Opt<4>::Add();
k::Specialization<2,L,P,1,5,8>::template Opt<2>::Add();
QuadratureInterpolator::AddGradSpecializations<2,L,P,1,3,4,8>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,1,4,6,4>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,1,5,8,2>();
k::Specialization<2,L,P,2,3,3>::template Opt<8>::Add();
k::Specialization<2,L,P,2,3,4>::template Opt<8>::Add();
k::Specialization<2,L,P,2,4,6>::template Opt<4>::Add();
k::Specialization<2,L,P,2,5,8>::template Opt<2>::Add();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,3,3,8>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,3,4,8>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,4,6,4>();
QuadratureInterpolator::AddGradSpecializations<2,L,P,2,5,8,2>();
// 3D
k::Specialization<3,L,P,1,3,4>::Add();
k::Specialization<3,L,P,1,4,6>::Add();
k::Specialization<3,L,P,1,5,8>::Add();
k::Specialization<3,L,P,3,3,4>::Add();
k::Specialization<3,L,P,3,4,6>::Add();
k::Specialization<3,L,P,3,5,8>::Add();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,3,4>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,4,6>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,1,5,8>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,3,4>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,4,6>();
QuadratureInterpolator::AddGradSpecializations<3,L,P,3,5,8>();
using k2 = QuadratureInterpolator::CollocatedGradKernels;
// 2D
k2::Specialization<2,L,P,1,2>::template Opt<16>::Add();
k2::Specialization<2,L,P,1,3>::template Opt<16>::Add();
k2::Specialization<2,L,P,1,4>::template Opt<16>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,1,2,16>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,1,3,16>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,1,4,16>();
k2::Specialization<2,L,P,2,2>::template Opt<16>::Add();
k2::Specialization<2,L,P,2,3>::template Opt<4>::Add();
k2::Specialization<2,L,P,2,4>::template Opt<2>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,2,2,16>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,2,3,4>();
QuadratureInterpolator::AddCollocatedGradSpecializations<2,L,P,2,4,2>();
// 3D
k2::Specialization<3,L,P,1,2>::Add();
k2::Specialization<3,L,P,1,3>::Add();
k2::Specialization<3,L,P,1,4>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,1,2>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,1,3>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,1,4>();
k2::Specialization<3,L,P,2,2>::Add();
k2::Specialization<3,L,P,2,3>::Add();
k2::Specialization<3,L,P,2,4>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,2,2>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,2,3>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,2,4>();
k2::Specialization<3,L,P,3,2>::Add();
k2::Specialization<3,L,P,3,3>::Add();
k2::Specialization<3,L,P,3,4>::Add();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,3,2>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,3,3>();
QuadratureInterpolator::AddCollocatedGradSpecializations<3,L,P,3,4>();
}
template void InitGradByVDimKernels<true>();
+352 -466
View File
@@ -69,8 +69,9 @@ QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
d_buffer.UseDevice(true);
if (fespace->GetNE() == 0) { return; }
MFEM_VERIFY(SupportsFESpace(fes),
"Only elements with MapType VALUE and H_DIV are supported!");
MFEM_VERIFY(
SupportsFESpace(fes),
"Only elements with MapType VALUE, INTEGRAL, or H_DIV are supported!");
}
QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
@@ -84,8 +85,9 @@ QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
{
d_buffer.UseDevice(true);
if (fespace->GetNE() == 0) { return; }
MFEM_VERIFY(SupportsFESpace(fes),
"Only elements with MapType VALUE and H_DIV are supported!");
MFEM_VERIFY(
SupportsFESpace(fes),
"Only elements with MapType VALUE, INTEGRAL, or H_DIV are supported!");
}
bool QuadratureInterpolator::SupportsFESpace(const FiniteElementSpace &fespace)
@@ -93,9 +95,9 @@ bool QuadratureInterpolator::SupportsFESpace(const FiniteElementSpace &fespace)
const FiniteElement *fe = fespace.GetTypicalFE();
const Mesh &mesh = *fespace.GetMesh();
return (fe->GetMapType() == FiniteElement::MapType::VALUE ||
fe->GetMapType() == FiniteElement::MapType::H_DIV)
&& (!fespace.IsVariableOrder())
&& (!mesh.IsMixedMesh());
fe->GetMapType() == FiniteElement::MapType::INTEGRAL ||
fe->GetMapType() == FiniteElement::MapType::H_DIV) &&
(!fespace.IsVariableOrder()) && (!mesh.IsMixedMesh());
}
namespace internal
@@ -108,16 +110,11 @@ namespace quadrature_interpolator
// * non-tensor product version,
// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
// * assumes 'maps.mode == FULL'.
static void Eval1D(const int NE,
const int vdim,
const QVectorLayout q_layout,
const GeometricFactors *geom,
const DofToQuad &maps,
const Vector &e_vec,
Vector &q_val,
Vector &q_der,
Vector &q_det,
const int eval_flags)
template <bool Integral>
void ImplEval1D(const int NE, const int vdim, const QVectorLayout q_layout,
const real_t *detJ_, const GeometricFactors *geom,
const DofToQuad &maps, const Vector &e_vec, Vector &q_val,
Vector &q_der, Vector &q_det, const int eval_flags)
{
using QI = QuadratureInterpolator;
@@ -126,13 +123,16 @@ static void Eval1D(const int NE,
MFEM_ASSERT(maps.mode == DofToQuad::FULL, "internal error");
MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 1, "");
MFEM_VERIFY(vdim == 1 || !(eval_flags & QI::DETERMINANTS), "");
MFEM_VERIFY(bool(geom) == bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
"'geom' must be given (non-null) only when evaluating physical"
" derivatives");
const auto B = Reshape(maps.B.Read(), nq, nd);
const auto G = Reshape(maps.G.Read(), nq, nd);
if constexpr(Integral)
{
MFEM_VERIFY(!(eval_flags & (QI::DERIVATIVES | QI::PHYSICAL_DERIVATIVES |
QI::DETERMINANTS)),
"Integral FE does not support computing derivatives");
}
const auto B_ = maps.B.Read();
const auto G_ = maps.G.Read();
const auto J = Reshape(geom ? geom->J.Read() : nullptr, nq, NE);
const auto E = Reshape(e_vec.Read(), nd, vdim, NE);
const auto E_ = e_vec.Read();
auto val = q_layout == QVectorLayout::byNODES ?
Reshape(q_val.Write(), nq, vdim, NE):
Reshape(q_val.Write(), vdim, nq, NE);
@@ -140,8 +140,12 @@ static void Eval1D(const int NE,
Reshape(q_der.Write(), nq, vdim, NE):
Reshape(q_der.Write(), vdim, nq, NE);
auto det = Reshape(q_det.Write(), nq, NE);
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
{
const auto B = Reshape(B_, nq, nd);
const auto G = Reshape(G_, nq, nd);
const auto E = Reshape(E_, nd, vdim, NE);
const auto detJ = Reshape(detJ_, nq, NE);
for (int q = 0; q < nq; ++q)
{
if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
@@ -151,10 +155,20 @@ static void Eval1D(const int NE,
real_t q_val = 0.0;
for (int d = 0; d < nd; ++d)
{
q_val += B(q,d)*E(d,c,e);
q_val += B(q, d) * E(d, c, e);
}
if constexpr (Integral)
{
q_val /= detJ(q, e);
}
if (q_layout == QVectorLayout::byVDIM)
{
val(c, q, e) = q_val;
}
if (q_layout == QVectorLayout::byNODES)
{
val(q, c, e) = q_val;
}
if (q_layout == QVectorLayout::byVDIM) { val(c,q,e) = q_val; }
if (q_layout == QVectorLayout::byNODES) { val(q,c,e) = q_val; }
}
}
if ((eval_flags & QI::DERIVATIVES) ||
@@ -166,7 +180,7 @@ static void Eval1D(const int NE,
real_t q_d = 0.0;
for (int d = 0; d < nd; ++d)
{
q_d += G(q,d)*E(d,c,e);
q_d += G(q, d) * E(d, c, e);
}
if (eval_flags & QI::PHYSICAL_DERIVATIVES)
{
@@ -174,8 +188,14 @@ static void Eval1D(const int NE,
}
if (eval_flags & QI::DERIVATIVES || eval_flags & QI::PHYSICAL_DERIVATIVES)
{
if (q_layout == QVectorLayout::byVDIM) { der(c,q,e) = q_d; }
if (q_layout == QVectorLayout::byNODES) { der(q,c,e) = q_d; }
if (q_layout == QVectorLayout::byVDIM)
{
der(c, q, e) = q_d;
}
if (q_layout == QVectorLayout::byNODES)
{
der(q, c, e) = q_d;
}
}
if (vdim == 1 && (eval_flags & QI::DETERMINANTS))
{
@@ -187,317 +207,17 @@ static void Eval1D(const int NE,
});
}
// Template compute kernel for 2D quadrature interpolation:
// * non-tensor product version,
// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
// * assumes 'maps.mode == FULL'.
template<const int T_VDIM, const int T_ND, const int T_NQ>
static void Eval2D(const int NE,
const int vdim,
const QVectorLayout q_layout,
const GeometricFactors *geom,
const DofToQuad &maps,
const Vector &e_vec,
Vector &q_val,
Vector &q_der,
Vector &q_det,
const int eval_flags)
{
using QI = QuadratureInterpolator;
template void
ImplEval1D<true>(const int NE, const int vdim, const QVectorLayout q_layout,
const real_t *detJ, const GeometricFactors *geom,
const DofToQuad &maps, const Vector &e_vec, Vector &q_val,
Vector &q_der, Vector &q_det, const int eval_flags);
const int nd = maps.ndof;
const int nq = maps.nqpt;
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int NMAX = NQ > ND ? NQ : ND;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_ASSERT(maps.mode == DofToQuad::FULL, "internal error");
MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 2, "");
MFEM_VERIFY(ND <= QI::MAX_ND2D, "");
MFEM_VERIFY(NQ <= QI::MAX_NQ2D, "");
MFEM_VERIFY(bool(geom) == bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
"'geom' must be given (non-null) only when evaluating physical"
" derivatives");
const auto B = Reshape(maps.B.Read(), NQ, ND);
const auto G = Reshape(maps.G.Read(), NQ, 2, ND);
const auto J = Reshape(geom ? geom->J.Read() : nullptr, NQ, 2, 2, NE);
const auto E = Reshape(e_vec.Read(), ND, VDIM, NE);
auto val = q_layout == QVectorLayout::byNODES ?
Reshape(q_val.Write(), NQ, VDIM, NE):
Reshape(q_val.Write(), VDIM, NQ, NE);
auto der = q_layout == QVectorLayout::byNODES ?
Reshape(q_der.Write(), NQ, VDIM, 2, NE):
Reshape(q_der.Write(), VDIM, 2, NQ, NE);
auto det = Reshape(q_det.Write(), NQ, NE);
mfem::forall_2D(NE, NMAX, 1, [=] MFEM_HOST_DEVICE (int e)
{
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int max_ND = T_ND ? T_ND : QI::MAX_ND2D;
constexpr int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM2D;
MFEM_SHARED real_t s_E[max_VDIM*max_ND];
MFEM_FOREACH_THREAD(d, x, ND)
{
for (int c = 0; c < VDIM; c++)
{
s_E[c+d*VDIM] = E(d,c,e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(q, x, NQ)
{
if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
{
real_t ed[max_VDIM];
for (int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
for (int d = 0; d < ND; ++d)
{
const real_t b = B(q,d);
for (int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
}
for (int c = 0; c < VDIM; c++)
{
if (q_layout == QVectorLayout::byVDIM) { val(c,q,e) = ed[c]; }
if (q_layout == QVectorLayout::byNODES) { val(q,c,e) = ed[c]; }
}
}
if ((eval_flags & QI::DERIVATIVES) ||
(eval_flags & QI::PHYSICAL_DERIVATIVES) ||
(eval_flags & QI::DETERMINANTS))
{
// use MAX_VDIM2D to avoid "subscript out of range" warnings
real_t D[QI::MAX_VDIM2D*2];
for (int i = 0; i < 2*VDIM; i++) { D[i] = 0.0; }
for (int d = 0; d < ND; ++d)
{
const real_t wx = G(q,0,d);
const real_t wy = G(q,1,d);
for (int c = 0; c < VDIM; c++)
{
real_t s_e = s_E[c+d*VDIM];
D[c+VDIM*0] += s_e * wx;
D[c+VDIM*1] += s_e * wy;
}
}
if (eval_flags & QI::DERIVATIVES)
{
for (int c = 0; c < VDIM; c++)
{
if (q_layout == QVectorLayout::byVDIM)
{
der(c,0,q,e) = D[c+VDIM*0];
der(c,1,q,e) = D[c+VDIM*1];
}
if (q_layout == QVectorLayout::byNODES)
{
der(q,c,0,e) = D[c+VDIM*0];
der(q,c,1,e) = D[c+VDIM*1];
}
}
}
if (eval_flags & QI::PHYSICAL_DERIVATIVES)
{
real_t Jloc[4], Jinv[4];
Jloc[0] = J(q,0,0,e);
Jloc[1] = J(q,1,0,e);
Jloc[2] = J(q,0,1,e);
Jloc[3] = J(q,1,1,e);
kernels::CalcInverse<2>(Jloc, Jinv);
for (int c = 0; c < VDIM; c++)
{
const real_t u = D[c+VDIM*0];
const real_t v = D[c+VDIM*1];
const real_t JiU = Jinv[0]*u + Jinv[1]*v;
const real_t JiV = Jinv[2]*u + Jinv[3]*v;
if (q_layout == QVectorLayout::byVDIM)
{
der(c,0,q,e) = JiU;
der(c,1,q,e) = JiV;
}
if (q_layout == QVectorLayout::byNODES)
{
der(q,c,0,e) = JiU;
der(q,c,1,e) = JiV;
}
}
}
if (eval_flags & QI::DETERMINANTS)
{
if (VDIM == 2) { det(q,e) = kernels::Det<2>(D); }
else
{
DeviceTensor<2> j(D, 3, 2);
const double E = j(0,0)*j(0,0) + j(1,0)*j(1,0) + j(2,0)*j(2,0);
const double F = j(0,0)*j(0,1) + j(1,0)*j(1,1) + j(2,0)*j(2,1);
const double G = j(0,1)*j(0,1) + j(1,1)*j(1,1) + j(2,1)*j(2,1);
det(q,e) = std::sqrt(E*G - F*F);
}
}
}
}
});
}
// Template compute kernel for 3D quadrature interpolation:
// * non-tensor product version,
// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
// * assumes 'maps.mode == FULL'.
template<const int T_VDIM, const int T_ND, const int T_NQ>
static void Eval3D(const int NE,
const int vdim,
const QVectorLayout q_layout,
const GeometricFactors *geom,
const DofToQuad &maps,
const Vector &e_vec,
Vector &q_val,
Vector &q_der,
Vector &q_det,
const int eval_flags)
{
using QI = QuadratureInterpolator;
const int nd = maps.ndof;
const int nq = maps.nqpt;
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int NMAX = NQ > ND ? NQ : ND;
const int VDIM = T_VDIM ? T_VDIM : vdim;
MFEM_ASSERT(maps.mode == DofToQuad::FULL, "internal error");
MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 3, "");
MFEM_VERIFY(ND <= QI::MAX_ND3D, "");
MFEM_VERIFY(NQ <= QI::MAX_NQ3D, "");
MFEM_VERIFY(VDIM == 3 || !(eval_flags & QI::DETERMINANTS), "");
MFEM_VERIFY(bool(geom) == bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
"'geom' must be given (non-null) only when evaluating physical"
" derivatives");
const auto B = Reshape(maps.B.Read(), NQ, ND);
const auto G = Reshape(maps.G.Read(), NQ, 3, ND);
const auto J = Reshape(geom ? geom->J.Read() : nullptr, NQ, 3, 3, NE);
const auto E = Reshape(e_vec.Read(), ND, VDIM, NE);
auto val = q_layout == QVectorLayout::byNODES ?
Reshape(q_val.Write(), NQ, VDIM, NE):
Reshape(q_val.Write(), VDIM, NQ, NE);
auto der = q_layout == QVectorLayout::byNODES ?
Reshape(q_der.Write(), NQ, VDIM, 3, NE):
Reshape(q_der.Write(), VDIM, 3, NQ, NE);
auto det = Reshape(q_det.Write(), NQ, NE);
mfem::forall_2D(NE, NMAX, 1, [=] MFEM_HOST_DEVICE (int e)
{
const int ND = T_ND ? T_ND : nd;
const int NQ = T_NQ ? T_NQ : nq;
const int VDIM = T_VDIM ? T_VDIM : vdim;
constexpr int max_ND = T_ND ? T_ND : QI::MAX_ND3D;
constexpr int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM3D;
MFEM_SHARED real_t s_E[max_VDIM*max_ND];
MFEM_FOREACH_THREAD(d, x, ND)
{
for (int c = 0; c < VDIM; c++)
{
s_E[c+d*VDIM] = E(d,c,e);
}
}
MFEM_SYNC_THREAD;
MFEM_FOREACH_THREAD(q, x, NQ)
{
if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
{
real_t ed[max_VDIM];
for (int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
for (int d = 0; d < ND; ++d)
{
const real_t b = B(q,d);
for (int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
}
for (int c = 0; c < VDIM; c++)
{
if (q_layout == QVectorLayout::byVDIM) { val(c,q,e) = ed[c]; }
if (q_layout == QVectorLayout::byNODES) { val(q,c,e) = ed[c]; }
}
}
if ((eval_flags & QI::DERIVATIVES) ||
(eval_flags & QI::PHYSICAL_DERIVATIVES) ||
(eval_flags & QI::DETERMINANTS))
{
// use MAX_VDIM3D to avoid "subscript out of range" warnings
real_t D[QI::MAX_VDIM3D*3];
for (int i = 0; i < 3*VDIM; i++) { D[i] = 0.0; }
for (int d = 0; d < ND; ++d)
{
const real_t wx = G(q,0,d);
const real_t wy = G(q,1,d);
const real_t wz = G(q,2,d);
for (int c = 0; c < VDIM; c++)
{
real_t s_e = s_E[c+d*VDIM];
D[c+VDIM*0] += s_e * wx;
D[c+VDIM*1] += s_e * wy;
D[c+VDIM*2] += s_e * wz;
}
}
if (eval_flags & QI::DERIVATIVES)
{
for (int c = 0; c < VDIM; c++)
{
if (q_layout == QVectorLayout::byVDIM)
{
der(c,0,q,e) = D[c+VDIM*0];
der(c,1,q,e) = D[c+VDIM*1];
der(c,2,q,e) = D[c+VDIM*2];
}
if (q_layout == QVectorLayout::byNODES)
{
der(q,c,0,e) = D[c+VDIM*0];
der(q,c,1,e) = D[c+VDIM*1];
der(q,c,2,e) = D[c+VDIM*2];
}
}
}
if (eval_flags & QI::PHYSICAL_DERIVATIVES)
{
real_t Jloc[9], Jinv[9];
for (int col = 0; col < 3; col++)
{
for (int row = 0; row < 3; row++)
{
Jloc[row+3*col] = J(q,row,col,e);
}
}
kernels::CalcInverse<3>(Jloc, Jinv);
for (int c = 0; c < VDIM; c++)
{
const real_t u = D[c+VDIM*0];
const real_t v = D[c+VDIM*1];
const real_t w = D[c+VDIM*2];
const real_t JiU = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
const real_t JiV = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
const real_t JiW = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
if (q_layout == QVectorLayout::byVDIM)
{
der(c,0,q,e) = JiU;
der(c,1,q,e) = JiV;
der(c,2,q,e) = JiW;
}
if (q_layout == QVectorLayout::byNODES)
{
der(q,c,0,e) = JiU;
der(q,c,1,e) = JiV;
der(q,c,2,e) = JiW;
}
}
}
if (VDIM == 3 && (eval_flags & QI::DETERMINANTS))
{
// The check (VDIM == 3) should eliminate this block when VDIM is
// known at compile time and (VDIM != 3).
det(q,e) = kernels::Det<3>(D);
}
}
}
});
}
template void
ImplEval1D<false>(const int NE, const int vdim, const QVectorLayout q_layout,
const real_t *detJ, const GeometricFactors *geom,
const DofToQuad &maps, const Vector &e_vec, Vector &q_val,
Vector &q_der, Vector &q_det, const int eval_flags);
} // namespace quadrature_interpolator
@@ -535,10 +255,20 @@ void QuadratureInterpolator::Mult(const Vector &e_vec,
const int nd = maps.ndof;
const int nq = maps.nqpt;
const GeometricFactors *geom = nullptr;
if (eval_flags & PHYSICAL_DERIVATIVES)
{
const int jacobians = GeometricFactors::JACOBIANS;
geom = fespace->GetMesh()->GetGeometricFactors(*ir, jacobians);
int jac_factors = 0;
if (eval_flags & PHYSICAL_DERIVATIVES)
{
jac_factors = GeometricFactors::JACOBIANS;
}
if (fe->GetMapType() == FiniteElement::MapType::INTEGRAL)
{
jac_factors |= GeometricFactors::DETERMINANTS;
}
if (jac_factors)
{
geom = fespace->GetMesh()->GetGeometricFactors(*ir, jac_factors);
}
}
MFEM_ASSERT(!(eval_flags & DETERMINANTS) || dim == vdim ||
@@ -552,29 +282,61 @@ void QuadratureInterpolator::Mult(const Vector &e_vec,
{
if (eval_flags & (VALUES | PHYSICAL_VALUES))
{
TensorEvalKernels::Run(dim, q_layout, vdim, nd, nq, ne, maps.B.Read(),
e_vec.Read(), q_val.Write(), vdim, nd, nq);
if (fe->GetMapType() == FiniteElement::MapType::INTEGRAL)
{
IntTensorEvalKernels::Run(dim, q_layout, vdim, nd, nq, ne,
maps.B.Read(), geom->detJ.Read(),
e_vec.Read(), q_val.Write(), vdim, nd, nq);
}
else
{
TensorEvalKernels::Run(dim, q_layout, vdim, nd, nq, ne,
maps.B.Read(), e_vec.Read(), q_val.Write(),
vdim, nd, nq);
}
}
if (eval_flags & (DERIVATIVES | PHYSICAL_DERIVATIVES))
{
const bool phys = (eval_flags & PHYSICAL_DERIVATIVES);
const real_t *J = phys ? geom->J.Read() : nullptr;
const int s_dim = phys ? sdim : dim;
GradKernels::Run(dim, q_layout, phys, vdim, nd, nq, ne,
maps.B.Read(), maps.G.Read(), J, e_vec.Read(),
q_der.Write(), s_dim, vdim, nd, nq);
if (fe->GetMapType() == FiniteElement::MapType::INTEGRAL)
{
MFEM_ABORT("");
}
else
{
GradKernels::Run(dim, q_layout, phys, vdim, nd, nq, ne,
maps.B.Read(), maps.G.Read(), J, e_vec.Read(),
q_der.Write(), s_dim, vdim, nd, nq);
}
}
if (eval_flags & DETERMINANTS)
{
DetKernels::Run(dim, vdim, nd, nq, ne, maps.B.Read(),
maps.G.Read(), e_vec.Read(), q_det.Write(), nd,
nq, &d_buffer);
if (fe->GetMapType() == FiniteElement::MapType::INTEGRAL)
{
MFEM_ABORT("");
}
else
{
DetKernels::Run(dim, vdim, nd, nq, ne, maps.B.Read(), maps.G.Read(),
e_vec.Read(), q_det.Write(), nd, nq, &d_buffer);
}
}
}
else // use_tensor_eval == false
{
EvalKernels::Run(dim, vdim, maps.ndof, maps.nqpt, ne,vdim, q_layout,
geom, maps, e_vec, q_val, q_der, q_det, eval_flags);
if (fe->GetMapType() == FiniteElement::MapType::INTEGRAL)
{
IntEvalKernels::Run(dim, vdim, maps.ndof, maps.nqpt, ne, vdim,
q_layout, geom->detJ.Read(), geom, maps, e_vec,
q_val, q_der, q_det, eval_flags);
}
else
{
EvalKernels::Run(dim, vdim, maps.ndof, maps.nqpt, ne, vdim, q_layout,
geom, maps, e_vec, q_val, q_der, q_det, eval_flags);
}
}
}
@@ -700,22 +462,41 @@ namespace
using namespace internal::quadrature_interpolator;
using EvalKernel = QuadratureInterpolator::EvalKernelType;
using TensorEvalKernel = QuadratureInterpolator::TensorEvalKernelType;
using GradKernel = QuadratureInterpolator::GradKernelType;
using CollocatedGradKernel = QuadratureInterpolator::CollocatedGradKernelType;
template <QVectorLayout Q_LAYOUT>
TensorEvalKernel FallbackTensorEvalKernel(int DIM)
template <QVectorLayout Q_LAYOUT> auto IntFallbackTensorEvalKernel(int DIM)
{
if (DIM == 1) { return Values1D<Q_LAYOUT>; }
else if (DIM == 2) { return Values2D<Q_LAYOUT>; }
else if (DIM == 3) { return Values3D<Q_LAYOUT>; }
else { MFEM_ABORT(""); }
if (DIM == 1)
{
return ImplValues1D<Q_LAYOUT, true>;
}
else if (DIM == 2)
{
return ImplValues2D<Q_LAYOUT, true>;
}
else if (DIM == 3)
{
return ImplValues3D<Q_LAYOUT, true>;
}
MFEM_ABORT("");
}
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
GradKernel GetGradKernel(int DIM)
template <QVectorLayout Q_LAYOUT> auto FallbackTensorEvalKernel(int DIM)
{
if (DIM == 1)
{
return Values1D<Q_LAYOUT>;
}
else if (DIM == 2)
{
return Values2D<Q_LAYOUT>;
}
else if (DIM == 3)
{
return Values3D<Q_LAYOUT>;
}
MFEM_ABORT("");
}
template <QVectorLayout Q_LAYOUT, bool GRAD_PHYS> auto GetGradKernel(int DIM)
{
if (DIM == 1) { return Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 2) { return Derivatives2D<Q_LAYOUT, GRAD_PHYS>; }
@@ -723,79 +504,185 @@ GradKernel GetGradKernel(int DIM)
else { MFEM_ABORT(""); }
}
template<QVectorLayout Q_LAYOUT>
GradKernel GetGradKernel(int DIM, bool GRAD_PHYS)
template <QVectorLayout Q_LAYOUT> auto GetGradKernel(int DIM, bool GRAD_PHYS)
{
if (GRAD_PHYS) { return GetGradKernel<Q_LAYOUT, true>(DIM); }
else { return GetGradKernel<Q_LAYOUT, false>(DIM); }
}
template<QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
CollocatedGradKernel GetCollocatedGradKernel(int DIM)
auto GetCollocatedGradKernel(int DIM)
{
if (DIM == 1) { return CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 2) { return CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS>; }
else if (DIM == 3) { return CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS>; }
else { MFEM_ABORT(""); }
if (DIM == 1)
{
return CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>;
}
else if (DIM == 2)
{
return CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS>;
}
else if (DIM == 3)
{
return CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS>;
}
MFEM_ABORT("");
}
template<QVectorLayout Q_LAYOUT>
CollocatedGradKernel GetCollocatedGradKernel(int DIM, bool GRAD_PHYS)
template <QVectorLayout Q_LAYOUT>
auto GetCollocatedGradKernel(int DIM, bool GRAD_PHYS)
{
if (GRAD_PHYS) { return GetCollocatedGradKernel<Q_LAYOUT, true>(DIM); }
else { return GetCollocatedGradKernel<Q_LAYOUT, false>(DIM); }
}
auto GetCollocatedGradKernel(int DIM, bool GRAD_PHYS, QVectorLayout Q_LAYOUT)
{
if (Q_LAYOUT == QVectorLayout::byNODES)
{
return GetCollocatedGradKernel<QVectorLayout::byNODES>(
DIM, GRAD_PHYS);
}
else
{
return GetCollocatedGradKernel<QVectorLayout::byVDIM>(
DIM, GRAD_PHYS);
}
}
} // namespace
template <int DIM, int VDIM, int ND, int NQ>
EvalKernel QuadratureInterpolator::EvalKernels::Kernel()
template <int DIM, bool Integral>
auto GetEvalKernelVDimFallback(int VDIM)
{
using namespace internal::quadrature_interpolator;
if constexpr (DIM == 1) { return Eval1D; }
else if constexpr (DIM == 2) { return Eval2D<VDIM,ND,NQ>; }
else if constexpr (DIM == 3) { return Eval3D<VDIM,ND,NQ>; }
if constexpr (Integral)
{
using EvalKernels = QuadratureInterpolator::IntEvalKernels;
if (VDIM == 1)
{
return EvalKernels::Kernel<DIM, 1, 0, 0>();
}
else if (VDIM == 2)
{
return EvalKernels::Kernel<DIM, 2, 0, 0>();
}
else if (VDIM == 3)
{
return EvalKernels::Kernel<DIM, 3, 0, 0>();
}
}
if constexpr (!Integral)
{
using EvalKernels = QuadratureInterpolator::EvalKernels;
if (VDIM == 1)
{
return EvalKernels::Kernel<DIM, 1, 0, 0>();
}
else if (VDIM == 2)
{
return EvalKernels::Kernel<DIM, 2, 0, 0>();
}
else if (VDIM == 3)
{
return EvalKernels::Kernel<DIM, 3, 0, 0>();
}
}
MFEM_ABORT("");
}
template <int DIM>
EvalKernel GetEvalKernelVDimFallback(int VDIM)
template auto GetEvalKernelVDimFallback<1, true>(int VDIM);
template auto GetEvalKernelVDimFallback<1, false>(int VDIM);
template auto GetEvalKernelVDimFallback<2, true>(int VDIM);
template auto GetEvalKernelVDimFallback<2, false>(int VDIM);
template auto GetEvalKernelVDimFallback<3, true>(int VDIM);
template auto GetEvalKernelVDimFallback<3, false>(int VDIM);
QuadratureInterpolator::IntEvalKernelType
QuadratureInterpolator::IntEvalKernels::Fallback(int DIM, int VDIM, int ND,
int NQ)
{
using EvalKernels = QuadratureInterpolator::EvalKernels;
if (VDIM == 1) { return EvalKernels::Kernel<DIM,1,0,0>(); }
else if (VDIM == 2) { return EvalKernels::Kernel<DIM,2,0,0>(); }
else if (VDIM == 3) { return EvalKernels::Kernel<DIM,3,0,0>(); }
else { MFEM_ABORT(""); }
if (DIM == 1)
{
return GetEvalKernelVDimFallback<1, true>(VDIM);
}
else if (DIM == 2)
{
return GetEvalKernelVDimFallback<2, true>(VDIM);
}
else if (DIM == 3)
{
return GetEvalKernelVDimFallback<3, true>(VDIM);
}
else
{
MFEM_ABORT("");
}
}
EvalKernel QuadratureInterpolator::EvalKernels::Fallback(
int DIM, int VDIM, int ND, int NQ)
QuadratureInterpolator::EvalKernelType
QuadratureInterpolator::EvalKernels::Fallback(int DIM, int VDIM, int ND, int NQ)
{
if (DIM == 1) { return GetEvalKernelVDimFallback<1>(VDIM); }
else if (DIM == 2) { return GetEvalKernelVDimFallback<2>(VDIM); }
else if (DIM == 3) { return GetEvalKernelVDimFallback<3>(VDIM); }
else { MFEM_ABORT(""); }
if (DIM == 1)
{
return GetEvalKernelVDimFallback<1, false>(VDIM);
}
else if (DIM == 2)
{
return GetEvalKernelVDimFallback<2, false>(VDIM);
}
else if (DIM == 3)
{
return GetEvalKernelVDimFallback<3, false>(VDIM);
}
else
{
MFEM_ABORT("");
}
}
TensorEvalKernel QuadratureInterpolator::TensorEvalKernels::Fallback(
int DIM, QVectorLayout Q_LAYOUT, int, int, int)
QuadratureInterpolator::IntTensorEvalKernelType
QuadratureInterpolator::IntTensorEvalKernels::Fallback(int DIM,
QVectorLayout Q_LAYOUT,
int, int, int)
{
if (Q_LAYOUT == QVectorLayout::byNODES) { return FallbackTensorEvalKernel<QVectorLayout::byNODES>(DIM); }
else { return FallbackTensorEvalKernel<QVectorLayout::byVDIM>(DIM); }
if (Q_LAYOUT == QVectorLayout::byNODES)
{
return IntFallbackTensorEvalKernel<QVectorLayout::byNODES>(DIM);
}
else
{
return IntFallbackTensorEvalKernel<QVectorLayout::byVDIM>(DIM);
}
}
GradKernel QuadratureInterpolator::GradKernels::Fallback(
int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int, int, int)
QuadratureInterpolator::TensorEvalKernelType
QuadratureInterpolator::TensorEvalKernels::Fallback(int DIM,
QVectorLayout Q_LAYOUT, int,
int, int)
{
if (Q_LAYOUT == QVectorLayout::byNODES)
{
return FallbackTensorEvalKernel<QVectorLayout::byNODES>(DIM);
}
else
{
return FallbackTensorEvalKernel<QVectorLayout::byVDIM>(DIM);
}
}
QuadratureInterpolator::GradKernelType
QuadratureInterpolator::GradKernels::Fallback(int DIM, QVectorLayout Q_LAYOUT,
bool GRAD_PHYS, int, int, int)
{
if (Q_LAYOUT == QVectorLayout::byNODES) { return GetGradKernel<QVectorLayout::byNODES>(DIM, GRAD_PHYS); }
else { return GetGradKernel<QVectorLayout::byVDIM>(DIM, GRAD_PHYS); }
}
CollocatedGradKernel QuadratureInterpolator::CollocatedGradKernels::Fallback(
int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int, int)
QuadratureInterpolator::CollocatedGradKernelType
QuadratureInterpolator::CollocatedGradKernels::Fallback(int DIM,
QVectorLayout Q_LAYOUT,
bool GRAD_PHYS, int,
int)
{
if (Q_LAYOUT == QVectorLayout::byNODES) { return GetCollocatedGradKernel<QVectorLayout::byNODES>(DIM, GRAD_PHYS); }
else { return GetCollocatedGradKernel<QVectorLayout::byVDIM>(DIM, GRAD_PHYS); }
return GetCollocatedGradKernel(DIM, GRAD_PHYS, Q_LAYOUT);
}
/// @endcond
@@ -806,98 +693,97 @@ namespace quadrature_interpolator
{
void InitEvalKernels()
{
using k = QuadratureInterpolator::EvalKernels;
// 2D, VDIM = 1
k::Specialization<2,1,1,1>::Add();
k::Specialization<2,1,1,4>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,1,1,1>();
QuadratureInterpolator::AddEvalSpecializations<2,1,1,4>();
// Q1
k::Specialization<2,1,4,4>::Add();
k::Specialization<2,1,4,9>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,1,4,4>();
QuadratureInterpolator::AddEvalSpecializations<2,1,4,9>();
// Q2
k::Specialization<2,1,9,9>::Add();
k::Specialization<2,1,9,16>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,1,9,9>();
QuadratureInterpolator::AddEvalSpecializations<2,1,9,16>();
// Q3
k::Specialization<2,1,16,16>::Add();
k::Specialization<2,1,16,25>::Add();
k::Specialization<2,1,16,36>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,1,16,16>();
QuadratureInterpolator::AddEvalSpecializations<2,1,16,25>();
QuadratureInterpolator::AddEvalSpecializations<2,1,16,36>();
// Q4
k::Specialization<2,1,25,25>::Add();
k::Specialization<2,1,25,36>::Add();
k::Specialization<2,1,25,49>::Add();
k::Specialization<2,1,25,64>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,1,25,25>();
QuadratureInterpolator::AddEvalSpecializations<2,1,25,36>();
QuadratureInterpolator::AddEvalSpecializations<2,1,25,49>();
QuadratureInterpolator::AddEvalSpecializations<2,1,25,64>();
// 3D, VDIM = 1
// Q0
k::Specialization<3,1,1,1>::Add();
k::Specialization<3,1,1,8>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,1,1,1>();
QuadratureInterpolator::AddEvalSpecializations<3,1,1,8>();
// Q1
k::Specialization<3,1,8,8>::Add();
k::Specialization<3,1,8,27>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,1,8,8>();
QuadratureInterpolator::AddEvalSpecializations<3,1,8,27>();
// Q2
k::Specialization<3,1,27,27>::Add();
k::Specialization<3,1,27,64>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,1,27,27>();
QuadratureInterpolator::AddEvalSpecializations<3,1,27,64>();
// Q3
k::Specialization<3,1,64,64>::Add();
k::Specialization<3,1,64,125>::Add();
k::Specialization<3,1,64,216>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,1,64,64>();
QuadratureInterpolator::AddEvalSpecializations<3,1,64,125>();
QuadratureInterpolator::AddEvalSpecializations<3,1,64,216>();
// Q4
k::Specialization<3,1,125,125>::Add();
k::Specialization<3,1,125,216>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,1,125,125>();
QuadratureInterpolator::AddEvalSpecializations<3,1,125,216>();
// 2D, VDIM = 3
// Q0
k::Specialization<2,3,1,1>::Add();
k::Specialization<2,3,1,4>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,3,1,1>();
QuadratureInterpolator::AddEvalSpecializations<2,3,1,4>();
// Q1
k::Specialization<2,3,4,4>::Add();
k::Specialization<2,3,4,9>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,3,4,4>();
QuadratureInterpolator::AddEvalSpecializations<2,3,4,9>();
// Q2
k::Specialization<2,3,9,4>::Add();
k::Specialization<2,3,9,9>::Add();
k::Specialization<2,3,9,16>::Add();
k::Specialization<2,3,9,25>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,3,9,4>();
QuadratureInterpolator::AddEvalSpecializations<2,3,9,9>();
QuadratureInterpolator::AddEvalSpecializations<2,3,9,16>();
QuadratureInterpolator::AddEvalSpecializations<2,3,9,25>();
// Q3
k::Specialization<2,3,16,16>::Add();
k::Specialization<2,3,16,25>::Add();
k::Specialization<2,3,16,36>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,3,16,16>();
QuadratureInterpolator::AddEvalSpecializations<2,3,16,25>();
QuadratureInterpolator::AddEvalSpecializations<2,3,16,36>();
// Q4
k::Specialization<2,3,25,25>::Add();
k::Specialization<2,3,25,36>::Add();
k::Specialization<2,3,25,49>::Add();
k::Specialization<2,3,25,64>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,3,25,25>();
QuadratureInterpolator::AddEvalSpecializations<2,3,25,36>();
QuadratureInterpolator::AddEvalSpecializations<2,3,25,49>();
QuadratureInterpolator::AddEvalSpecializations<2,3,25,64>();
// 2D, VDIM = 2
// Q1
k::Specialization<2,2,4,4>::Add();
k::Specialization<2,2,4,9>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,2,4,4>();
QuadratureInterpolator::AddEvalSpecializations<2,2,4,9>();
// Q2
k::Specialization<2,2,9,9>::Add();
k::Specialization<2,2,9,16>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,2,9,9>();
QuadratureInterpolator::AddEvalSpecializations<2,2,9,16>();
// Q3
k::Specialization<2,2,16,16>::Add();
k::Specialization<2,2,16,25>::Add();
k::Specialization<2,2,16,36>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,2,16,16>();
QuadratureInterpolator::AddEvalSpecializations<2,2,16,25>();
QuadratureInterpolator::AddEvalSpecializations<2,2,16,36>();
// Q4
k::Specialization<2,2,25,25>::Add();
k::Specialization<2,2,25,36>::Add();
k::Specialization<2,2,25,49>::Add();
k::Specialization<2,2,25,64>::Add();
QuadratureInterpolator::AddEvalSpecializations<2,2,25,25>();
QuadratureInterpolator::AddEvalSpecializations<2,2,25,36>();
QuadratureInterpolator::AddEvalSpecializations<2,2,25,49>();
QuadratureInterpolator::AddEvalSpecializations<2,2,25,64>();
// 3D, VDIM = 3
// Q1
k::Specialization<3,3,8,8>::Add();
k::Specialization<3,3,8,27>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,3,8,8>();
QuadratureInterpolator::AddEvalSpecializations<3,3,8,27>();
// Q2
k::Specialization<3,3,27,27>::Add();
k::Specialization<3,3,27,64>::Add();
k::Specialization<3,3,27,125>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,3,27,27>();
QuadratureInterpolator::AddEvalSpecializations<3,3,27,64>();
QuadratureInterpolator::AddEvalSpecializations<3,3,27,125>();
// Q3
k::Specialization<3,3,64,64>::Add();
k::Specialization<3,3,64,125>::Add();
k::Specialization<3,3,64,216>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,3,64,64>();
QuadratureInterpolator::AddEvalSpecializations<3,3,64,125>();
QuadratureInterpolator::AddEvalSpecializations<3,3,64,216>();
// Q4
k::Specialization<3,3,125,125>::Add();
k::Specialization<3,3,125,216>::Add();
QuadratureInterpolator::AddEvalSpecializations<3,3,125,125>();
QuadratureInterpolator::AddEvalSpecializations<3,3,125,216>();
}
} // namespace quadrature_Interpolator
+119 -16
View File
@@ -117,6 +117,10 @@ public:
FiniteElementSpace is a vector space) and their determinants are computed
and stored in @a q_det.
For Integral spaces, the flags VALUES requests the computation of the
scalar field values. The result is stored in @a q_val. Derivative types
are not supported.
For H(div)-conforming spaces, the flags VALUES / PHYSICAL_VALUES request
the computation of the vector field values in reference or physical
space, respectively. The flag PHYSICAL_MAGNITUDES requests the
@@ -159,26 +163,49 @@ public:
/// QuadratureInterpolator.
static bool SupportsFESpace(const FiniteElementSpace &fespace);
using TensorEvalKernelType = void(*)(const int, const real_t *, const real_t *,
real_t *, const int, const int, const int);
using GradKernelType = void(*)(const int, const real_t *, const real_t *,
const real_t *, const real_t *, real_t *,
const int, const int, const int, const int);
using CollocatedGradKernelType = void(*)(const int, const real_t *,
const real_t *, const real_t *,
real_t *, const int, const int,
const int);
using DetKernelType = void(*)(const int NE, const real_t *, const real_t *,
const real_t *, real_t *, const int, const int,
Vector *);
using EvalKernelType = void(*)(const int, const int, const QVectorLayout,
const GeometricFactors *, const DofToQuad &,
const Vector &, Vector &, Vector &, Vector &,
const int);
// value map types
using TensorEvalKernelType = void (*)(const int ne, const real_t *B,
const real_t *e_vec, real_t *q_val,
const int vdim, const int nd,
const int nq);
using GradKernelType = void (*)(const int ne, const real_t *B,
const real_t *G, const real_t *J,
const real_t *e_vec, real_t *q_der,
const int s_dim, const int v_dim,
const int nd, const int nq);
using CollocatedGradKernelType = void (*)(const int ne, const real_t *G,
const real_t *J,
const real_t *e_vec, real_t *q_der,
const int sdim, const int vdim,
const int d1d);
using DetKernelType = void (*)(const int NE, const real_t *B,
const real_t *G, const real_t *e_vec,
real_t *q_det, const int nd, const int nq,
Vector *d_buffer);
using EvalKernelType = void (*)(const int NE, const int vdim,
const QVectorLayout q_layout,
const GeometricFactors *geom,
const DofToQuad &maps, const Vector &e_vec,
Vector &q_val, Vector &q_der, Vector &q_det,
const int eval_flags);
// integral map types
using IntTensorEvalKernelType = void (*)(const int ne, const real_t *B,
const real_t *detJ,
const real_t *e_vec, real_t *q_val,
const int vdim, const int nd,
const int nq);
using IntEvalKernelType =
void (*)(const int NE, const int vdim, const QVectorLayout q_layout,
const real_t *detJ, const GeometricFactors *geom,
const DofToQuad &maps, const Vector &e_vec, Vector &q_val,
Vector &q_der, Vector &q_det, const int eval_flags);
using TensorEvalHDivKernelType =
void(*)(const int, const real_t *, const real_t *, const real_t *,
const real_t *, real_t *, const int, const int);
// value-type mapping
MFEM_REGISTER_KERNELS(TensorEvalKernels, TensorEvalKernelType,
(int, QVectorLayout, int, int, int), (int));
MFEM_REGISTER_KERNELS(GradKernels, GradKernelType,
@@ -187,8 +214,84 @@ public:
MFEM_REGISTER_KERNELS(EvalKernels, EvalKernelType, (int, int, int, int));
MFEM_REGISTER_KERNELS(CollocatedGradKernels, CollocatedGradKernelType,
(int, QVectorLayout, bool, int, int), (int));
// integral-type mapping
MFEM_REGISTER_KERNELS(IntTensorEvalKernels, IntTensorEvalKernelType,
(int, QVectorLayout, int, int, int), (int));
MFEM_REGISTER_KERNELS(IntEvalKernels, IntEvalKernelType, (int, int, int, int));
MFEM_REGISTER_KERNELS(TensorEvalHDivKernels, TensorEvalHDivKernelType,
(int, QVectorLayout, unsigned, int, int));
/// Adds specializations for TensorEvalKernels
template <int DIM, QVectorLayout Q_LAYOUT, int VDIM, int D1D, int Q1D,
int NBZ = 0>
static void AddTensorEvalSpecializations()
{
if constexpr (NBZ)
{
IntTensorEvalKernels::Specialization<DIM, Q_LAYOUT, VDIM, D1D,
Q1D>::template Opt<NBZ>::Add();
TensorEvalKernels::Specialization<DIM, Q_LAYOUT, VDIM, D1D,
Q1D>::template Opt<NBZ>::Add();
}
else if constexpr (NBZ == 0)
{
IntTensorEvalKernels::Specialization<DIM, Q_LAYOUT, VDIM, D1D,
Q1D>::Add();
TensorEvalKernels::Specialization<DIM, Q_LAYOUT, VDIM, D1D,
Q1D>::Add();
}
}
/// Adds specializations for EvalKernels
template <int DIM, int VDIM, int ND, int NQ>
static void AddEvalSpecializations()
{
IntEvalKernels::Specialization<DIM, VDIM, ND, NQ>::Add();
EvalKernels::Specialization<DIM, VDIM, ND, NQ>::Add();
}
/// Adds specializations for GradKernels
template <int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
int Q1D, int NBZ = 0>
static void AddGradSpecializations()
{
if constexpr (NBZ)
{
GradKernels::Specialization<DIM, Q_LAYOUT, GRAD_PHYS, VDIM, D1D,
Q1D>::template Opt<NBZ>::Add();
}
else if constexpr (NBZ == 0)
{
GradKernels::Specialization<DIM, Q_LAYOUT, GRAD_PHYS, VDIM, D1D,
Q1D>::Add();
}
}
/// Adds specializations for CollocatedGradKernels
template <int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
int NBZ = 0>
static void AddCollocatedGradSpecializations()
{
if constexpr (NBZ)
{
CollocatedGradKernels::Specialization<DIM, Q_LAYOUT, GRAD_PHYS, VDIM,
D1D>::template Opt<NBZ>::Add();
}
else if constexpr (NBZ == 0)
{
CollocatedGradKernels::Specialization<DIM, Q_LAYOUT, GRAD_PHYS, VDIM,
D1D>::Add();
}
}
/// Adds specializations for DetKernels
template <int DIM, int SDIM, int D1D, int Q1D>
static void AddDetSpecializations()
{
DetKernels::Specialization<DIM, SDIM, D1D, Q1D>::Add();
}
};
}
+17
View File
@@ -66,6 +66,23 @@ constexpr bool mfem_use_gpu = false;
#define MFEM_THREAD_SIZE(k) 1
#define MFEM_FOREACH_THREAD(i,k,N) for(int i=0; i<N; i++)
#define MFEM_FOREACH_THREAD_DIRECT(i,k,N) MFEM_FOREACH_THREAD(i,k,N)
// Assigns a thread block shaped (SX,SY,SZ) contiguous in x.
// Example (3,2,1) block:
// 0 (0,0), 1 (1,0), 2 (2,0)
// 3 (1,0), 4 (1,1), 5 (2,1)
#define MFEM_FOREACH_THREAD_DIRECT_3D(ix, iy, iz, k, SX, SY, SZ) \
for (int iz = 0; iz < SZ; ++iz) \
for (int iy = 0; iy < SY; ++iy) \
for (int ix = 0; ix < SX; ++ix)
// Assigns a thread block shaped (OX,OY,OZ) to work on items (SX,SY,SZ),
// contiguous in x. This intentionally offsets threads within the block to avoid
// shared memory bank conflicts.
// Example (3,2,1) block assigned to work on (2,2,1) items:
// 0 (0,0), 1 (1,0), 2 (N/A)
// 3 (1,0), 4 (1,1), 5 (N/A)
#define MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(ix, iy, iz, k, SX, SY, SZ, OX, \
OY, OZ) \
MFEM_FOREACH_THREAD_DIRECT_3D(ix, iy, iz, k, SX, SY, SZ)
#endif
// 'double' and 'float' atomicAdd implementation for previous versions of CUDA
+17
View File
@@ -49,6 +49,23 @@ constexpr bool mfem_use_gpu = true;
#define MFEM_THREAD_SIZE(k) blockDim.k
#define MFEM_FOREACH_THREAD(i,k,N) for(int i=threadIdx.k; i<N; i+=blockDim.k)
#define MFEM_FOREACH_THREAD_DIRECT(i,k,N) if(const int i=threadIdx.k; i<N)
// Assigns a thread block shaped (SX,SY,SZ) contiguous in x.
// Example (3,2,1) block:
// 0 (0,0), 1 (1,0), 2 (2,0)
// 3 (1,0), 4 (1,1), 5 (2,1)
#define MFEM_FOREACH_THREAD_DIRECT_3D(ix, iy, iz, k, SX, SY, SZ) \
if (int ix = threadIdx.k % (SX), iy = threadIdx.k / (SX), iz = iy / (SY); \
(iy %= (SY)), (threadIdx.k < (SX) * (SY) * (SZ)))
// Assigns a thread block shaped (OX,OY,OZ) to work on items (SX,SY,SZ),
// contiguous in x. This intentionally offsets threads within the block to avoid
// shared memory bank conflicts.
// Example (3,2,1) block assigned to work on (2,2,1) items:
// 0 (0,0), 1 (1,0), 2 (N/A)
// 3 (1,0), 4 (1,1), 5 (N/A)
#define MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(ix, iy, iz, k, SX, SY, SZ, OX, \
OY, OZ) \
if (int ix = threadIdx.k % (OX), iy = threadIdx.k / (OX), iz = iy / (OY); \
(ix < (SX)) && ((iy %= (OY)) < (SY)) && (iz < (SZ)))
#endif // defined(__CUDA_ARCH__)
#endif // defined(MFEM_USE_CUDA) && defined(__CUDACC__)
+2 -2
View File
@@ -480,8 +480,8 @@ template <typename DBODY>
void RajaHipWrap1D(const int N, DBODY &&d_body)
{
//true denotes asynchronous kernel
RAJA::forall<RAJA::hip_exec<MFEM_HIP_BLOCKS,true> >(RAJA::RangeSegment(0,N),
d_body);
RAJA::forall<RAJA::hip_exec<MFEM_HIP_BLOCKS, true> >(
Device::GetRajaResource(), RAJA::RangeSegment(0, N), d_body);
}
template <typename DBODY>
+19
View File
@@ -51,6 +51,25 @@ constexpr bool mfem_use_gpu = true;
for(int i=hipThreadIdx_ ##k; i<N; i+=hipBlockDim_ ##k)
#define MFEM_FOREACH_THREAD_DIRECT(i,k,N) \
if(const int i=hipThreadIdx_ ##k; i<N)
// Assigns a thread block shaped (SX,SY,SZ) contiguous in x.
// Example (3,2,1) block:
// 0 (0,0), 1 (1,0), 2 (2,0)
// 3 (1,0), 4 (1,1), 5 (2,1)
#define MFEM_FOREACH_THREAD_DIRECT_3D(ix, iy, iz, k, SX, SY, SZ) \
if (int ix = hipThreadIdx_##k % (SX), iy = hipThreadIdx_##k / (SX), \
iz = iy / (SY); \
(iy %= (SY)), (hipThreadIdx_##k < (SX) * (SY) * (SZ)))
// Assigns a thread block shaped (OX,OY,OZ) to work on items (SX,SY,SZ),
// contiguous in x. This intentionally offsets threads within the block to avoid
// shared memory bank conflicts.
// Example (3,2,1) block assigned to work on (2,2,1) items:
// 0 (0,0), 1 (1,0), 2 (N/A)
// 3 (1,0), 4 (1,1), 5 (N/A)
#define MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(ix, iy, iz, k, SX, SY, SZ, OX, \
OY, OZ) \
if (int ix = hipThreadIdx_##k % (OX), iy = hipThreadIdx_##k / (OX), \
iz = iy / (OY); \
(ix < (SX)) && ((iy %= (OY)) < (SY)) && (iz < (SZ)))
#endif // defined(__HIP_DEVICE_COMPILE__)
#endif // defined(MFEM_USE_HIP) && defined(__HIP__)
+13
View File
@@ -13,6 +13,7 @@
#include "native.hpp"
#include "gpu_blas.hpp"
#include "magma.hpp"
#include "../../general/reducers.hpp"
namespace mfem
{
@@ -119,4 +120,16 @@ void BatchedLinAlgBase::MultTranspose(const DenseTensor &A, const Vector &x,
AddMult(A, x, y, 1.0, 0.0, Op::T);
}
void VerifyBatchedLUInfo(const Array<int> &info_array, const char *message)
{
static Array<int> workspace;
int status = 0;
const int *d_info = info_array.Read();
mfem::reduce(
info_array.Size(), status,
[=] MFEM_HOST_DEVICE (int i, int &r) { r |= d_info[i]; },
BOrReducer<int> {}, true, workspace);
MFEM_VERIFY(status == 0, message);
}
}
+3
View File
@@ -141,6 +141,9 @@ public:
virtual ~BatchedLinAlgBase() { }
};
/// Check that all batched LU info values are zero.
void VerifyBatchedLUInfo(const Array<int> &info_array, const char *message);
} // namespace mfem
#endif
+6 -3
View File
@@ -126,7 +126,8 @@ void GPUBlasBatchedLinAlg::LUFactor(DenseTensor &A, Array<int> &P) const
const blasStatus_t status = MFEM_GPUBLAS_PREFIX(getrfBatched)(
GPUBlas::Handle(), n, d_A_ptrs, n, P.Write(),
info_array.Write(), n_mat);
MFEM_VERIFY(status == MFEM_BLAS_SUCCESS, "");
MFEM_VERIFY(status == MFEM_BLAS_SUCCESS, "GPU BLAS error.");
VerifyBatchedLUInfo(info_array, "Batch LU factorization failed");
}
void GPUBlasBatchedLinAlg::LUSolve(
@@ -189,12 +190,14 @@ void GPUBlasBatchedLinAlg::Invert(DenseTensor &A) const
status = MFEM_GPUBLAS_PREFIX(getrfBatched)(
GPUBlas::Handle(), n, d_LU_ptrs, n, P.Write(),
info_array.Write(), n_mat);
MFEM_VERIFY(status == MFEM_BLAS_SUCCESS, "");
MFEM_VERIFY(status == MFEM_BLAS_SUCCESS, "GPU BLAS error.");
VerifyBatchedLUInfo(info_array, "Batch LU factorization failed");
status = MFEM_GPUBLAS_PREFIX(getriBatched)(
GPUBlas::Handle(), n, d_LU_ptrs, n, P.ReadWrite(), d_A_ptrs, n,
info_array.Write(), n_mat);
MFEM_VERIFY(status == MFEM_BLAS_SUCCESS, "");
MFEM_VERIFY(status == MFEM_BLAS_SUCCESS, "GPU BLAS error.");
VerifyBatchedLUInfo(info_array, "Batch matrix inversion failed");
}
#endif
+6 -3
View File
@@ -99,7 +99,8 @@ void MagmaBatchedLinAlg::LUFactor(DenseTensor &A, Array<int> &P) const
const magma_int_t status = MFEM_MAGMA_PREFIX(getrf_batched)(
n, n, d_A_ptrs, n, d_P_ptrs,
info_array.Write(), n_mat, Magma::Queue());
MFEM_VERIFY(status == MAGMA_SUCCESS, "");
MFEM_VERIFY(status == MAGMA_SUCCESS, "MAGMA error.");
VerifyBatchedLUInfo(info_array, "Batch LU factorization failed");
}
void MagmaBatchedLinAlg::LUSolve(
@@ -169,12 +170,14 @@ void MagmaBatchedLinAlg::Invert(DenseTensor &A) const
status = MFEM_MAGMA_PREFIX(getrf_batched)(
n, n, d_LU_ptrs, n, d_P_ptrs, info_array.Write(), n_mat,
Magma::Queue());
MFEM_VERIFY(status == MAGMA_SUCCESS, "");
MFEM_VERIFY(status == MAGMA_SUCCESS, "MAGMA error.");
VerifyBatchedLUInfo(info_array, "Batch LU factorization failed");
status = MFEM_MAGMA_PREFIX(getri_outofplace_batched)(
n, d_LU_ptrs, n, d_P_ptrs, d_A_ptrs, n, info_array.Write(),
n_mat, Magma::Queue());
MFEM_VERIFY(status == MAGMA_SUCCESS, "");
MFEM_VERIFY(status == MAGMA_SUCCESS, "MAGMA error.");
VerifyBatchedLUInfo(info_array, "Batch matrix inversion failed");
}
} // namespace mfem
+11 -7
View File
@@ -246,6 +246,10 @@ SparseMatrix * ComplexSparseMatrix::GetSystemMatrix() const
const int nrows_i = (A_i)?A_i->Height():0;
const int nrows = std::max(nrows_r, nrows_i);
const int ncols_r = (A_r)?A_r->Width():0;
const int ncols_i = (A_i)?A_i->Width():0;
const int ncols = std::max(ncols_r, ncols_i);
const int *I_r = (A_r)?A_r->GetI():NULL;
const int *I_i = (A_i)?A_i->GetI():NULL;
@@ -280,7 +284,7 @@ SparseMatrix * ComplexSparseMatrix::GetSystemMatrix() const
J[I[i] + j] = J_r[I_r[i] + j];
D[I[i] + j] = D_r[I_r[i] + j];
J[I[i+nrows] + off_i + j] = J_r[I_r[i] + j] + nrows;
J[I[i+nrows] + off_i + j] = J_r[I_r[i] + j] + ncols;
D[I[i+nrows] + off_i + j] = factor*D_r[I_r[i] + j];
}
}
@@ -289,7 +293,7 @@ SparseMatrix * ComplexSparseMatrix::GetSystemMatrix() const
const int off_r = (I_r)?(I_r[i+1] - I_r[i]):0;
for (int j=0; j<I_i[i+1] - I_i[i]; j++)
{
J[I[i] + off_r + j] = J_i[I_i[i] + j] + nrows;
J[I[i] + off_r + j] = J_i[I_i[i] + j] + ncols;
D[I[i] + off_r + j] = -D_i[I_i[i] + j];
J[I[i+nrows] + j] = J_i[I_i[i] + j];
@@ -892,12 +896,12 @@ ComplexHypreParMatrix::getColStartStop(const HypreParMatrix * A_r,
HYPRE_BigInt loc_start_stop[2];
offd_col_start_stop = new HYPRE_BigInt[2 * num_recv_procs];
const HYPRE_BigInt * row_part = (A_r) ? A_r->RowPart() :
((A_i) ? A_i->RowPart() : NULL);
const HYPRE_BigInt * col_part = (A_r) ? A_r->ColPart() :
((A_i) ? A_i->ColPart() : NULL);
int row_part_ind = (HYPRE_AssumedPartitionCheck()) ? 0 : myid_;
loc_start_stop[0] = row_part[row_part_ind];
loc_start_stop[1] = row_part[row_part_ind+1];
int col_part_ind = (HYPRE_AssumedPartitionCheck()) ? 0 : myid_;
loc_start_stop[0] = col_part[col_part_ind];
loc_start_stop[1] = col_part[col_part_ind+1];
MPI_Request * req = new MPI_Request[send_procs.size()+recv_procs.size()];
MPI_Status * stat = new MPI_Status[send_procs.size()+recv_procs.size()];
+40 -9
View File
@@ -15,10 +15,20 @@
#ifdef MFEM_USE_CUDSS
#if CUDSS_VERSION >= 800
#ifdef MFEM_USE_SINGLE
#define CUDA_REAL_T CUDA_R_32F
#define CUDSS_REAL_T CUDSS_R_32F
#else
#define CUDA_REAL_T CUDA_R_64F
#define CUDSS_REAL_T CUDSS_R_64F
#endif
#define CUDSS_INT_T CUDSS_R_32I
#else
#ifdef MFEM_USE_SINGLE
#define CUDSS_REAL_T CUDA_R_32F
#else
#define CUDSS_REAL_T CUDA_R_64F
#endif
#define CUDSS_INT_T CUDA_R_32I
#endif
// Define a cuDSS error check macro, MFEM_CUDSS_CHECK(x), where x returns/is of
@@ -65,8 +75,13 @@ CuDSSSolver::CuDSSSolver(MPI_Comm comm_) : mpi_comm(comm_)
#endif
MFEM_CUDSS_CHECK(cudssSetCommLayer(handle, comm_lib));
#if CUDSS_VERSION >= 800
MFEM_CUDSS_CHECK(cudssDataSet(handle, solverData, CUDSS_DATA_COMM_HOST,
&mpi_comm, sizeof(MPI_Comm *)));
#else
MFEM_CUDSS_CHECK(cudssDataSet(handle, solverData, CUDSS_DATA_COMM,
&mpi_comm, sizeof(MPI_Comm *)));
#endif
}
#endif // MFEM_USE_MPI
@@ -257,11 +272,19 @@ void CuDSSSolver::SetMatrixCuDSS(int *csr_offsets, int *csr_columns,
CuMemcpyDtoD(csr_offsets_d, csr_offsets, (n_loc + 1) * sizeof(int));
CuMemcpyDtoD(csr_columns_d, csr_columns, nnz * sizeof(int));
#if CUDSS_VERSION >= 800
MFEM_CUDSS_CHECK(
cudssMatrixCreateCsr(
Ac.get(), n_global, n_global, nnz, csr_offsets_d, NULL,
csr_columns_d, csr_values_d, CUDA_R_32I, CUDA_REAL_T, mat_type, mview,
CUDSS_BASE_ZERO));
csr_columns_d, csr_values_d, CUDSS_INT_T, CUDSS_INT_T, CUDSS_REAL_T,
mat_type, mview, CUDSS_BASE_ZERO));
#else
MFEM_CUDSS_CHECK(
cudssMatrixCreateCsr(
Ac.get(), n_global, n_global, nnz, csr_offsets_d, NULL,
csr_columns_d, csr_values_d, CUDSS_INT_T, CUDSS_REAL_T,
mat_type, mview, CUDSS_BASE_ZERO));
#endif
}
else // !reorder_reuse
{
@@ -269,11 +292,19 @@ void CuDSSSolver::SetMatrixCuDSS(int *csr_offsets, int *csr_columns,
{
MFEM_CUDSS_CHECK(cudssMatrixDestroy(*Ac));
}
#if CUDSS_VERSION >= 800
MFEM_CUDSS_CHECK(
cudssMatrixCreateCsr(
Ac.get(), n_global, n_global, nnz, csr_offsets, NULL, csr_columns,
csr_values_d, CUDA_R_32I, CUDA_REAL_T, mat_type, mview,
CUDSS_BASE_ZERO));
Ac.get(), n_global, n_global, nnz, csr_offsets, NULL,
csr_columns, csr_values_d, CUDSS_INT_T, CUDSS_INT_T, CUDSS_REAL_T,
mat_type, mview, CUDSS_BASE_ZERO));
#else
MFEM_CUDSS_CHECK(
cudssMatrixCreateCsr(
Ac.get(), n_global, n_global, nnz, csr_offsets, NULL,
csr_columns, csr_values_d, CUDSS_INT_T, CUDSS_REAL_T,
mat_type, mview, CUDSS_BASE_ZERO));
#endif
}
#ifdef MFEM_USE_MPI
if (Mpi::IsInitialized())
@@ -334,10 +365,10 @@ void CuDSSSolver::SetNumRHS(int nrhs_) const
}
// Create empty RHS and solution vectors
MFEM_CUDSS_CHECK(cudssMatrixCreateDn(&xc, n_global, nrhs_, n_global, NULL,
CUDA_REAL_T, CUDSS_LAYOUT_COL_MAJOR));
CUDSS_REAL_T, CUDSS_LAYOUT_COL_MAJOR));
MFEM_CUDSS_CHECK(cudssMatrixCreateDn(&yc, n_global, nrhs_, n_global, NULL,
CUDA_REAL_T, CUDSS_LAYOUT_COL_MAJOR));
CUDSS_REAL_T, CUDSS_LAYOUT_COL_MAJOR));
#ifdef MFEM_USE_MPI
MFEM_CUDSS_CHECK(cudssMatrixSetDistributionRow1d(xc, row_start, row_end));
+1
View File
@@ -810,6 +810,7 @@ MINIAPPS_SUBDIRS = dpg/util hooke/operators hooke/preconditioners \
hooke/materials hooke/kernels
FORMAT_FILES += $(foreach dir,$(TESTS_SUBDIRS),tests/$(dir)/*.?pp)
FORMAT_FILES += $(foreach dir,$(UNIT_TESTS_SUBDIRS),tests/unit/$(dir)/*.?pp)
FORMAT_FILES += tests/unit/fem/specializations/*.?pp
FORMAT_FILES += $(foreach dir,$(MINIAPPS_SUBDIRS),miniapps/$(dir)/*.?pp)
FORMAT_FILES += config/cmake/config.hpp.in config/config.hpp.in mfem*.hpp
FORMAT_EXCLUDE = general/tinyxml2.cpp tests/unit/catch.hpp
+121 -10
View File
@@ -667,9 +667,84 @@ void Mesh::GetEdgeTransformation(int EdgeNo,
}
EdTr->SetFE(edge_el);
}
else
else // L2 Nodes (e.g., periodic mesh), go through the face containing the edge
{
MFEM_ABORT("Not implemented.");
// Search for a face that contains this edge
GetEdgeFaceTable();
Array<int> faces_e;
edge_face->GetRow(EdgeNo, faces_e);
MFEM_VERIFY(faces_e.Size() > 0, "Edge not found in any face!");
const int face_no = faces_e[0];
// Get edge local index and orientation
Array<int> edges_f, oris_f;
GetFaceEdges(face_no, edges_f, oris_f);
const int local_idx = edges_f.Find(EdgeNo);
MFEM_ASSERT(local_idx >= 0, "Edge not found on the face!");
const int edge_ori = oris_f[local_idx] > 0 ? 0 : 1;
// Get face information
const FaceInfo &face_info = faces_info[face_no];
// Get transformation from face to edge
IntegrationPointTransformation LocEdge;
int edge_info = EncodeFaceInfo(local_idx, edge_ori);
Element::Type face_type = GetFaceElementType(face_no);
switch (face_type)
{
case Element::TRIANGLE:
GetLocalSegToTriTransformation(LocEdge.Transf, edge_info);
break;
case Element::QUADRILATERAL:
GetLocalSegToQuadTransformation(LocEdge.Transf, edge_info);
break;
default:
MFEM_ABORT("Unsupported face type for edge transformation!");
}
// Get edge element
const int order = Nodes->FESpace()->GetElementOrder(face_info.Elem1No);
const L2_FECollection *l2_fec = dynamic_cast<const L2_FECollection*>
(Nodes->FESpace()->FEColl());
if (l2_fec)
{
// L2 elements do not have a defined trace space
if (!EdgeTransfElement || EdgeTransfElement->GetOrder() != order
|| EdgeTransfElement->GetBasisType() != l2_fec->GetBasisType())
{
EdgeTransfElement = make_unique<L2_SegmentElement>(
order, l2_fec->GetBasisType());
}
edge_el = EdgeTransfElement.get();
}
else
{
MFEM_ABORT("Unsupported finite element collection.");
}
// Map edge nodes to face reference space
IntegrationRule face_ir(edge_el->GetDof());
LocEdge.Transform(edge_el->GetNodes(), face_ir);
// Then, map from face to element
IntegrationPointTransformation Loc1;
GetLocalFaceTransformation(face_type,
GetElementType(face_info.Elem1No),
Loc1.Transf, face_info.Elem1Inf);
IntegrationRule elem_ir(edge_el->GetDof());
Loc1.Transf.ElementNo = face_info.Elem1No;
Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
Loc1.Transf.mesh = this;
Loc1.Transform(face_ir, elem_ir);
// Finally, get the physical coordinates
Nodes->GetVectorValues(Loc1.Transf, elem_ir, pm);
EdTr->SetFE(edge_el);
}
}
}
@@ -1824,8 +1899,8 @@ void Mesh::Init()
void Mesh::InitTables()
{
el_to_edge =
el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
el_to_edge = el_to_face = el_to_el = bel_to_edge = NULL;
face_edge = edge_face = edge_vertex = NULL;
face_to_elem = NULL;
}
@@ -1848,6 +1923,7 @@ void Mesh::DestroyTables()
}
delete face_edge;
delete edge_face;
delete edge_vertex;
delete face_to_elem;
@@ -1921,6 +1997,7 @@ void Mesh::ResetLazyData()
{
delete el_to_el; el_to_el = NULL;
delete face_edge; face_edge = NULL;
delete edge_face; edge_face = NULL;
delete face_to_elem; face_to_elem = NULL;
delete edge_vertex; edge_vertex = NULL;
DeleteGeometricFactors();
@@ -2845,6 +2922,7 @@ void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
// boundary element ordering
// - el_to_el - no need to rebuild
// - face_edge - no need to rebuild
// - edge_face - no need to rebuild
// - edge_vertex - no need to rebuild
// - geom_factors - no need to rebuild
@@ -3327,11 +3405,25 @@ void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
// loop over all elements
for (int i = 0; i < GetNE(); i++)
{
fes->GetElementInteriorDofs(i, old_dofs);
// No need to permute the dofs if there are fewer than two
if (old_dofs.Size() < 2)
{
offset += old_dofs.Size();
continue;
}
const int *old_v = old_elem_vert->GetRow(i);
const int *new_v = elements[i]->GetVertices();
const int *dof_ord;
int new_or;
const Geometry::Type geom = elements[i]->GetGeometryType();
if (geom == Geometry::CUBE || geom == Geometry::PRISM ||
geom == Geometry::PYRAMID)
{
offset += old_dofs.Size();
continue;
}
switch (geom)
{
case Geometry::SEGMENT:
@@ -3355,9 +3447,8 @@ void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
dof_ord = fec->DofOrderForOrientation(geom, new_or);
MFEM_VERIFY(dof_ord != NULL,
"FE collection '" << fec->Name()
<< "' does not define reordering for "
<< "' does not define reordering (" << new_or << ") for "
<< Geometry::Name[geom] << " elements!");
fes->GetElementInteriorDofs(i, old_dofs);
new_dofs.SetSize(old_dofs.Size());
for (int j = 0; j < new_dofs.Size(); j++)
{
@@ -4585,8 +4676,9 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
// Do NOT copy the element-to-element Table, el_to_el
el_to_el = NULL;
// Do NOT copy the face-to-edge Table, face_edge
// Do NOT copy the face-to-edge Table, face_edge and edge_face
face_edge = NULL;
edge_face = NULL;
face_to_elem = NULL;
// Copy the edge-to-vertex Table, edge_vertex
@@ -7116,7 +7208,8 @@ const FiniteElementSpace *Mesh::GetNodalFESpace() const
return ((Nodes) ? Nodes->FESpace() : NULL);
}
void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering,
int pyr_type)
{
if (order <= 0)
{
@@ -7129,11 +7222,12 @@ void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
if (discont)
{
const int type = 1; // Gauss-Lobatto points
nfec = new L2_FECollection(order, Dim, type);
nfec = new L2_FECollection(order, Dim, type, FiniteElement::VALUE,
pyr_type);
}
else
{
nfec = new H1_FECollection(order, Dim);
nfec = new H1_FECollection(order, Dim, BasisType::GaussLobatto, pyr_type);
}
FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
ordering);
@@ -8079,6 +8173,22 @@ Table *Mesh::GetFaceEdgeTable() const
return (face_edge);
}
Table *Mesh::GetEdgeFaceTable() const
{
if (edge_face)
{
return edge_face;
}
if (Dim != 3)
{
return NULL;
}
edge_face = Transpose(*GetFaceEdgeTable());
return edge_face;
}
Table *Mesh::GetEdgeVertexTable() const
{
if (edge_vertex)
@@ -11437,6 +11547,7 @@ void Mesh::Swap(Mesh& other, bool non_geometry)
mfem::Swap(bel_to_edge, other.bel_to_edge);
mfem::Swap(be_to_face, other.be_to_face);
mfem::Swap(face_edge, other.face_edge);
mfem::Swap(edge_face, other.edge_face);
mfem::Swap(face_to_elem, other.face_to_elem);
mfem::Swap(edge_vertex, other.edge_vertex);
+15 -4
View File
@@ -250,16 +250,18 @@ protected:
Table *bel_to_edge; // for 3D only
// Note that the following tables are owned by this class and should not be
// deleted by the caller. Of these three tables, only face_edge and
// deleted by the caller. Of these four tables, only face_edge, edge_face and
// edge_vertex are returned by access functions.
mutable Table *face_to_elem; // Used by FindFaceNeighbors, not returned.
mutable Table *face_edge; // Returned by GetFaceEdgeTable().
mutable Table *edge_face; // Returned by GetEdgeFaceTable().
mutable Table *edge_vertex; // Returned by GetEdgeVertexTable().
IsoparametricTransformation Transformation, Transformation2;
IsoparametricTransformation BdrTransformation;
IsoparametricTransformation FaceTransformation, EdgeTransformation;
FaceElementTransformations FaceElemTr;
mutable std::unique_ptr<L2_SegmentElement> EdgeTransfElement;
// refinement embeddings for forward compatibility with NCMesh
mutable CoarseFineTransformations CoarseFineTr;
@@ -1731,6 +1733,11 @@ public:
/// @note The returned object should NOT be deleted by the caller.
Table *GetFaceEdgeTable() const;
/// Returns the edge-to-face Table (3D)
///
/// @note The returned object should NOT be deleted by the caller.
Table *GetEdgeFaceTable() const;
/// Returns the edge-to-vertex Table (3D)
///
/// @note The returned object should NOT be deleted by the caller.
@@ -2425,9 +2432,13 @@ public:
finite element space (continuous is default).
@param[in] space_dim The space dimension (optional).
@param[in] ordering The Ordering of the finite element space
(Ordering::byVDIM is the default). */
virtual void SetCurvature(int order, bool discont = false, int space_dim = -1,
int ordering = 1);
(Ordering::byVDIM is the default).
@param[in] pyr_type Select Bergot (pyr_type = 0) or Fuentes
(pyr_type = 1) basis functions for pyramid
shaped elements. */
virtual void SetCurvature(int order, bool discont = false,
int space_dim = -1, int ordering = 1,
int pyr_type = 1);
/// @}
+6
View File
@@ -1354,22 +1354,27 @@ NURBSPatch::NURBSPatch(std::istream &input)
int pdim, dim, size = 1;
string ident;
skip_comment_lines(input, '#');
input >> ws >> ident >> pdim; // knotvectors
kv.SetSize(pdim);
for (int i = 0; i < pdim; i++)
{
skip_comment_lines(input, '#');
kv[i] = new KnotVector(input);
size *= kv[i]->GetNCP();
}
skip_comment_lines(input, '#');
input >> ws >> ident >> dim; // dimension
init(dim + 1);
skip_comment_lines(input, '#');
input >> ws >> ident; // controlpoints (homogeneous coordinates)
if (ident == "controlpoints" || ident == "controlpoints_homogeneous")
{
for (int j = 0, i = 0; i < size; i++)
{
skip_comment_lines(input, '#');
for (int d = 0; d <= dim; d++, j++)
{
input >> data[j];
@@ -1380,6 +1385,7 @@ NURBSPatch::NURBSPatch(std::istream &input)
{
for (int j = 0, i = 0; i < size; i++)
{
skip_comment_lines(input, '#');
for (int d = 0; d <= dim; d++)
{
input >> data[j+d];
+12 -3
View File
@@ -2031,18 +2031,20 @@ std::unique_ptr<ParGridFunction> ParMesh::GetJacobianDeterminantGF() const
return detgf;
}
void ParMesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
void ParMesh::SetCurvature(int order, bool discont, int space_dim, int ordering,
int pyrtype)
{
DeleteFaceNbrData();
space_dim = (space_dim == -1) ? spaceDim : space_dim;
FiniteElementCollection* nfec;
if (discont)
{
nfec = new L2_FECollection(order, Dim, BasisType::GaussLobatto);
nfec = new L2_FECollection(order, Dim, BasisType::GaussLobatto,
FiniteElement::VALUE, pyrtype);
}
else
{
nfec = new H1_FECollection(order, Dim);
nfec = new H1_FECollection(order, Dim, BasisType::GaussLobatto, pyrtype);
}
ParFiniteElementSpace* nfes = new ParFiniteElementSpace(this, nfec, space_dim,
ordering);
@@ -4864,6 +4866,13 @@ void ParMesh::Print(std::ostream &os, const std::string &comments) const
return;
}
if (pncmesh && pncmesh->using_scaling)
{
// For nodes scaling, we write the file in the format MFEM NC mesh v1.1.
Printer(os, "", comments);
return;
}
const Array<int>* s2l_face;
if (!pncmesh)
{
+1 -1
View File
@@ -563,7 +563,7 @@ public:
void ExchangeFaceNbrNodes();
void SetCurvature(int order, bool discont = false, int space_dim = -1,
int ordering = 1) override;
int ordering = 1, int pyrtype = 1) override;
std::unique_ptr<ParGridFunction> GetJacobianDeterminantGF() const;
+123 -55
View File
@@ -28,6 +28,48 @@ namespace mfem
using namespace bin_io;
static int GetHexEdgeSplit(const int* nodes, int v1, int v2);
static bool SameSplitScale(real_t a, real_t b)
{
#ifdef MFEM_USE_DOUBLE
constexpr real_t rel_tol = 1.0e-8;
#else
constexpr real_t rel_tol = 1.0e-5;
#endif
return std::abs(a - b) <= rel_tol *
std::max(real_t(1.0), std::max(std::abs(a), std::abs(b)));
}
static real_t DirectedHexEdgeScale(const int* nodes, const Refinement &ref,
int v0, int v1)
{
const int dir = GetHexEdgeSplit(nodes, v0, v1);
static const int split_edges[3][4][2] =
{
{{0, 1}, {3, 2}, {4, 5}, {7, 6}},
{{1, 2}, {0, 3}, {5, 6}, {4, 7}},
{{0, 4}, {1, 5}, {2, 6}, {3, 7}}
};
for (int i = 0; i < 4; i++)
{
const int a = nodes[split_edges[dir][i][0]];
const int b = nodes[split_edges[dir][i][1]];
if (a == v0 && b == v1)
{
return ref.s[dir];
}
if (a == v1 && b == v0)
{
return 1.0 - ref.s[dir];
}
}
MFEM_ABORT("Shared face edge does not match the refinement direction.");
return 0.0;
}
ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh,
const int *partitioning)
: NCMesh(ncmesh)
@@ -1555,7 +1597,7 @@ bool ParNCMesh::AnisotropicConflict(const Array<Refinement> &refinements,
ElementNeighborProcessors(elem, ranks);
for (int j = 0; j < ranks.Size(); j++)
{
send_ref[ranks[j]].AddRefinement(elem, ref.GetType());
send_ref[ranks[j]].AddRefinement(elem, ref);
}
}
@@ -1576,8 +1618,8 @@ bool ParNCMesh::AnisotropicConflict(const Array<Refinement> &refinements,
for (int i = 0; i < refinements.Size(); i++)
{
const Refinement &ref = refinements[i];
CheckRefinement(leaf_elements[ref.index], ref.GetType(), refinements,
elemToRef, conflicts);
CheckRefinement(leaf_elements[ref.index], ref, refinements, elemToRef,
conflicts);
}
// Receive (ghost layer) refinements from all neighbors
@@ -1593,7 +1635,9 @@ bool ParNCMesh::AnisotropicConflict(const Array<Refinement> &refinements,
// check the ghost refinements
for (int i = 0; i < msg.Size(); i++)
{
CheckRefinement(msg.elements[i], msg.values[i], refinements, elemToRef,
Refinement ghost_ref(msg.elements[i], msg.values[i].ref_type);
ghost_ref.SetScaleForType(msg.values[i].scale);
CheckRefinement(msg.elements[i], ghost_ref, refinements, elemToRef,
conflicts);
}
}
@@ -1749,7 +1793,7 @@ int FindHexFace(const int* no, int vn1, int vn2, int vn3, int vn4)
// Assumption: v1 and v2 are indices of hex vertices connected by an edge.
// The return value is {0,1,2} denoting split {X,Y,Z}.
int GetHexEdgeSplit(const int* nodes, int v1, int v2)
static int GetHexEdgeSplit(const int* nodes, int v1, int v2)
{
Array<int> v(2);
v[0] = v1;
@@ -1780,7 +1824,8 @@ int GetHexEdgeSplit(const int* nodes, int v1, int v2)
return edgeDir[edge];
}
void ParNCMesh::CheckRefAnisoFace(int elem, int vn1, int vn2, int vn3, int vn4,
void ParNCMesh::CheckRefAnisoFace(const Refinement &ref, int elem,
int vn1, int vn2, int vn3, int vn4,
const Array<Refinement> &refinements,
const std::map<int, int> &elemToRef,
std::set<int> &conflicts)
@@ -1798,11 +1843,11 @@ void ParNCMesh::CheckRefAnisoFace(int elem, int vn1, int vn2, int vn3, int vn4,
if (elemToRef.count(nghbIndex) > 0)
{
const int refIndex = elemToRef.at(nghbIndex);
const Refinement& ref = refinements[refIndex];
const Refinement& nghb_ref = refinements[refIndex];
bool refDir[3];
for (int i=0; i<3; ++i)
refDir[i] = ref.s[i] > real_t{0};
refDir[i] = nghb_ref.s[i] > real_t{0};
const int localFace = FindHexFace(nghb.node, vn1, vn2, vn3, vn4);
const int faceDir = GetHexFaceDir(localFace);
@@ -1834,30 +1879,50 @@ void ParNCMesh::CheckRefAnisoFace(int elem, int vn1, int vn2, int vn3, int vn4,
MFEM_ASSERT(cnt == 2 && hexSplitOnFace >= 0, "");
const int edgeSplit = GetHexEdgeSplit(nghb.node, vn1, vn2);
if (edgeSplit != hexSplitOnFace) { conflicts.insert(refIndex); }
if (edgeSplit != hexSplitOnFace)
{
conflicts.insert(refIndex);
}
else
{
const real_t elem_scale =
DirectedHexEdgeScale(elements[elem].node, ref, vn1, vn2);
const real_t nghb_scale =
DirectedHexEdgeScale(nghb.node, nghb_ref, vn1, vn2);
if (!SameSplitScale(elem_scale, nghb_scale))
{
conflicts.insert(refIndex);
}
}
}
}
// The else case is that the neighbor is not refined, so there is no need to
// check for conflicts.
}
void ParNCMesh::CheckRefIsoFace(int elem, int vn1, int vn2, int vn3, int vn4,
void ParNCMesh::CheckRefIsoFace(const Refinement &ref, int elem,
int vn1, int vn2, int vn3, int vn4,
int en1, int en2, int en3, int en4,
const Array<Refinement> &refinements,
const std::map<int, int> &elemToRef,
std::set<int> &conflicts)
{
CheckRefAnisoFace(elem, vn1, vn2, en2, en4, refinements, elemToRef, conflicts);
CheckRefAnisoFace(elem, en4, en2, vn3, vn4, refinements, elemToRef, conflicts);
CheckRefAnisoFace(elem, vn4, vn1, en1, en3, refinements, elemToRef, conflicts);
CheckRefAnisoFace(elem, en3, en1, vn2, vn3, refinements, elemToRef, conflicts);
CheckRefAnisoFace(ref, elem, vn1, vn2, en2, en4, refinements, elemToRef,
conflicts);
CheckRefAnisoFace(ref, elem, en4, en2, vn3, vn4, refinements, elemToRef,
conflicts);
CheckRefAnisoFace(ref, elem, vn4, vn1, en1, en3, refinements, elemToRef,
conflicts);
CheckRefAnisoFace(ref, elem, en3, en1, vn2, vn3, refinements, elemToRef,
conflicts);
}
void ParNCMesh::CheckRefinement(int elem, char ref_type,
void ParNCMesh::CheckRefinement(int elem, const Refinement &ref,
const Array<Refinement> &refinements,
const std::map<int, int> &elemToRef,
std::set<int> &conflicts)
{
const char ref_type = ref.GetType();
const Element &el = elements[elem];
MFEM_ASSERT(el.geom == Geometry::CUBE && el.ref_type == 0,
"Element must be an unrefined hexahedron");
@@ -1868,46 +1933,46 @@ void ParNCMesh::CheckRefinement(int elem, char ref_type,
// This follows the logic of NCMesh::RefineElement().
if (ref_type == Refinement::X) // split along X axis
{
CheckRefAnisoFace(elem, no[0], no[1], no[5], no[4], refinements,
CheckRefAnisoFace(ref, elem, no[0], no[1], no[5], no[4], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[2], no[3], no[7], no[6], refinements,
CheckRefAnisoFace(ref, elem, no[2], no[3], no[7], no[6], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[4], no[5], no[6], no[7], refinements,
CheckRefAnisoFace(ref, elem, no[4], no[5], no[6], no[7], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[3], no[2], no[1], no[0], refinements,
CheckRefAnisoFace(ref, elem, no[3], no[2], no[1], no[0], refinements,
elemToRef, conflicts);
}
else if (ref_type == Refinement::Y) // split along Y axis
{
CheckRefAnisoFace(elem, no[1], no[2], no[6], no[5], refinements,
CheckRefAnisoFace(ref, elem, no[1], no[2], no[6], no[5], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[3], no[0], no[4], no[7], refinements,
CheckRefAnisoFace(ref, elem, no[3], no[0], no[4], no[7], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[5], no[6], no[7], no[4], refinements,
CheckRefAnisoFace(ref, elem, no[5], no[6], no[7], no[4], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[0], no[3], no[2], no[1], refinements,
CheckRefAnisoFace(ref, elem, no[0], no[3], no[2], no[1], refinements,
elemToRef, conflicts);
}
else if (ref_type == Refinement::Z) // split along Z axis
{
CheckRefAnisoFace(elem, no[4], no[0], no[1], no[5], refinements,
CheckRefAnisoFace(ref, elem, no[4], no[0], no[1], no[5], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[5], no[1], no[2], no[6], refinements,
CheckRefAnisoFace(ref, elem, no[5], no[1], no[2], no[6], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[6], no[2], no[3], no[7], refinements,
CheckRefAnisoFace(ref, elem, no[6], no[2], no[3], no[7], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[7], no[3], no[0], no[4], refinements,
CheckRefAnisoFace(ref, elem, no[7], no[3], no[0], no[4], refinements,
elemToRef, conflicts);
}
else if (ref_type == Refinement::XY) // XY split
{
CheckRefAnisoFace(elem, no[0], no[1], no[5], no[4], refinements,
CheckRefAnisoFace(ref, elem, no[0], no[1], no[5], no[4], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[1], no[2], no[6], no[5], refinements,
CheckRefAnisoFace(ref, elem, no[1], no[2], no[6], no[5], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[2], no[3], no[7], no[6], refinements,
CheckRefAnisoFace(ref, elem, no[2], no[3], no[7], no[6], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[3], no[0], no[4], no[7], refinements,
CheckRefAnisoFace(ref, elem, no[3], no[0], no[4], no[7], refinements,
elemToRef, conflicts);
const int mid01 = GetMidEdgeNode(no[0], no[1]);
@@ -1920,20 +1985,20 @@ void ParNCMesh::CheckRefinement(int elem, char ref_type,
const int mid67 = GetMidEdgeNode(no[6], no[7]);
const int mid74 = GetMidEdgeNode(no[7], no[4]);
CheckRefIsoFace(elem, no[3], no[2], no[1], no[0], mid23, mid12, mid01,
CheckRefIsoFace(ref, elem, no[3], no[2], no[1], no[0], mid23, mid12, mid01,
mid30, refinements, elemToRef, conflicts);
CheckRefIsoFace(elem, no[4], no[5], no[6], no[7], mid45, mid56, mid67,
CheckRefIsoFace(ref, elem, no[4], no[5], no[6], no[7], mid45, mid56, mid67,
mid74, refinements, elemToRef, conflicts);
}
else if (ref_type == Refinement::XZ) // XZ split
{
CheckRefAnisoFace(elem, no[3], no[2], no[1], no[0], refinements,
CheckRefAnisoFace(ref, elem, no[3], no[2], no[1], no[0], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[2], no[6], no[5], no[1], refinements,
CheckRefAnisoFace(ref, elem, no[2], no[6], no[5], no[1], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[6], no[7], no[4], no[5], refinements,
CheckRefAnisoFace(ref, elem, no[6], no[7], no[4], no[5], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[7], no[3], no[0], no[4], refinements,
CheckRefAnisoFace(ref, elem, no[7], no[3], no[0], no[4], refinements,
elemToRef, conflicts);
const int mid01 = GetMidEdgeNode(no[0], no[1]);
@@ -1946,9 +2011,9 @@ void ParNCMesh::CheckRefinement(int elem, char ref_type,
const int mid26 = GetMidEdgeNode(no[2], no[6]);
const int mid37 = GetMidEdgeNode(no[3], no[7]);
CheckRefIsoFace(elem, no[0], no[1], no[5], no[4], mid01, mid15, mid45,
CheckRefIsoFace(ref, elem, no[0], no[1], no[5], no[4], mid01, mid15, mid45,
mid04, refinements, elemToRef, conflicts);
CheckRefIsoFace(elem, no[2], no[3], no[7], no[6], mid23, mid37, mid67,
CheckRefIsoFace(ref, elem, no[2], no[3], no[7], no[6], mid23, mid37, mid67,
mid26, refinements, elemToRef, conflicts);
}
else if (ref_type == Refinement::YZ) // YZ split
@@ -1963,18 +2028,18 @@ void ParNCMesh::CheckRefinement(int elem, char ref_type,
const int mid26 = GetMidEdgeNode(no[2], no[6]);
const int mid37 = GetMidEdgeNode(no[3], no[7]);
CheckRefAnisoFace(elem, no[4], no[0], no[1], no[5], refinements,
CheckRefAnisoFace(ref, elem, no[4], no[0], no[1], no[5], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[0], no[3], no[2], no[1], refinements,
CheckRefAnisoFace(ref, elem, no[0], no[3], no[2], no[1], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[3], no[7], no[6], no[2], refinements,
CheckRefAnisoFace(ref, elem, no[3], no[7], no[6], no[2], refinements,
elemToRef, conflicts);
CheckRefAnisoFace(elem, no[7], no[4], no[5], no[6], refinements,
CheckRefAnisoFace(ref, elem, no[7], no[4], no[5], no[6], refinements,
elemToRef, conflicts);
CheckRefIsoFace(elem, no[1], no[2], no[6], no[5], mid12, mid26, mid56,
CheckRefIsoFace(ref, elem, no[1], no[2], no[6], no[5], mid12, mid26, mid56,
mid15, refinements, elemToRef, conflicts);
CheckRefIsoFace(elem, no[3], no[0], no[4], no[7], mid30, mid04, mid74,
CheckRefIsoFace(ref, elem, no[3], no[0], no[4], no[7], mid30, mid04, mid74,
mid37, refinements, elemToRef, conflicts);
}
else if (ref_type == Refinement::XYZ) // XYZ split
@@ -1994,17 +2059,17 @@ void ParNCMesh::CheckRefinement(int elem, char ref_type,
const int mid26 = GetMidEdgeNode(no[2], no[6]);
const int mid37 = GetMidEdgeNode(no[3], no[7]);
CheckRefIsoFace(elem, no[3], no[2], no[1], no[0], mid23, mid12, mid01,
CheckRefIsoFace(ref, elem, no[3], no[2], no[1], no[0], mid23, mid12, mid01,
mid30, refinements, elemToRef, conflicts);
CheckRefIsoFace(elem, no[0], no[1], no[5], no[4], mid01, mid15, mid45,
CheckRefIsoFace(ref, elem, no[0], no[1], no[5], no[4], mid01, mid15, mid45,
mid04, refinements, elemToRef, conflicts);
CheckRefIsoFace(elem, no[1], no[2], no[6], no[5], mid12, mid26, mid56,
CheckRefIsoFace(ref, elem, no[1], no[2], no[6], no[5], mid12, mid26, mid56,
mid15, refinements, elemToRef, conflicts);
CheckRefIsoFace(elem, no[2], no[3], no[7], no[6], mid23, mid37, mid67,
CheckRefIsoFace(ref, elem, no[2], no[3], no[7], no[6], mid23, mid37, mid67,
mid26, refinements, elemToRef, conflicts);
CheckRefIsoFace(elem, no[3], no[0], no[4], no[7], mid30, mid04, mid74,
CheckRefIsoFace(ref, elem, no[3], no[0], no[4], no[7], mid30, mid04, mid74,
mid37, refinements, elemToRef, conflicts);
CheckRefIsoFace(elem, no[4], no[5], no[6], no[7], mid45, mid56, mid67,
CheckRefIsoFace(ref, elem, no[4], no[5], no[6], no[7], mid45, mid56, mid67,
mid74, refinements, elemToRef, conflicts);
}
else
@@ -2053,7 +2118,7 @@ void ParNCMesh::Refine(const Array<Refinement> &refinements)
ElementNeighborProcessors(elem, ranks);
for (int j = 0; j < ranks.Size(); j++)
{
send_ref[ranks[j]].AddRefinement(elem, ref.GetType());
send_ref[ranks[j]].AddRefinement(elem, ref);
}
}
@@ -2063,8 +2128,9 @@ void ParNCMesh::Refine(const Array<Refinement> &refinements)
// do local refinements
for (int i = 0; i < refinements.Size(); i++)
{
const Refinement &ref = refinements[i];
NCMesh::RefineElement(leaf_elements[ref.index], ref.GetType());
Refinement ref_i = refinements[i];
ref_i.index = leaf_elements[refinements[i].index];
NCMesh::RefineElement(ref_i);
}
// receive (ghost layer) refinements from all neighbors
@@ -2080,7 +2146,9 @@ void ParNCMesh::Refine(const Array<Refinement> &refinements)
// do the ghost refinements
for (int i = 0; i < msg.Size(); i++)
{
NCMesh::RefineElement(msg.elements[i], msg.values[i]);
Refinement ghost_ref(msg.elements[i], msg.values[i].ref_type);
ghost_ref.SetScaleForType(msg.values[i].scale);
NCMesh::RefineElement(ghost_ref);
}
}
+25 -8
View File
@@ -497,11 +497,27 @@ protected: // implementation
/** Used by ParNCMesh::Refine() to inform neighbors about refinements at
* the processor boundary. This keeps their ghost layers synchronized.
*/
class NeighborRefinementMessage : public ElementValueMessage<char, false,
VarMessageTag::NEIGHBOR_REFINEMENT_VM>
struct NeighborRefinement
{
char ref_type;
real_t scale[3];
};
class NeighborRefinementMessage
: public ElementValueMessage<NeighborRefinement, false,
VarMessageTag::NEIGHBOR_REFINEMENT_VM>
{
public:
void AddRefinement(int elem, char ref_type) { Add(elem, ref_type); }
void AddRefinement(int elem, const Refinement &ref)
{
NeighborRefinement data{};
data.ref_type = ref.GetType();
for (int i = 0; i < 3; i++)
{
data.scale[i] = ref.s[i];
}
Add(elem, data);
}
typedef std::map<int, NeighborRefinementMessage> Map;
};
@@ -602,7 +618,8 @@ protected: // implementation
/** For the face with ordered vertices vn* and neighboring element @a elem,
check whether the other neighboring element (if it exists) is marked for
a horizontal refinement conflicting with a vertical split. */
void CheckRefAnisoFace(int elem, int vn1, int vn2, int vn3, int vn4,
void CheckRefAnisoFace(const Refinement &ref, int elem,
int vn1, int vn2, int vn3, int vn4,
const Array<Refinement> &refinements,
const std::map<int, int> &elemToRef,
std::set<int> &conflicts);
@@ -611,7 +628,8 @@ protected: // implementation
neighboring element @a elem, check whether the other neighboring element
(if it exists) is marked for a refinement conflicting with an isotropic
refinement of the face. */
void CheckRefIsoFace(int elem, int vn1, int vn2, int vn3, int vn4,
void CheckRefIsoFace(const Refinement &ref, int elem,
int vn1, int vn2, int vn3, int vn4,
int en1, int en2, int en3, int en4,
const Array<Refinement> &refinements,
const std::map<int, int> &elemToRef,
@@ -622,9 +640,8 @@ protected: // implementation
const std::map<int, int> &elemToRef,
std::set<int> &conflicts);
/** Check whether the refinement of the element with index @a elem and type
@a ref_type would cause a conflict. */
void CheckRefinement(int elem, char ref_type,
/// Check whether the input refinement would cause a conflict.
void CheckRefinement(int elem, const Refinement &ref,
const Array<Refinement> &refinements,
const std::map<int, int> &elemToRef,
std::set<int> &conflicts);
+5
View File
@@ -151,6 +151,10 @@ if (MFEM_USE_MPI)
MAIN phpref.cpp
LIBRARIES mfem)
add_mfem_miniapp(pref321
MAIN pref321.cpp
LIBRARIES mfem)
# Add parallel tests.
if (MFEM_ENABLE_TESTING)
set(PARALLEL_TESTS
@@ -160,6 +164,7 @@ if (MFEM_USE_MPI)
fit-node-position
pminimal-surface
phpref
pref321
)
# Meshing miniapps that return MFEM_SKIP_RETURN_VALUE in some cases:
set(SKIP_TESTS)
+3 -1
View File
@@ -24,7 +24,7 @@ SEQ_MINIAPPS = mobius-strip klein-bottle toroid trimmer twist mesh-explorer\
shaper extruder mesh-optimizer minimal-surface polar-nc reflector\
ref321 mesh-quality hpref
PAR_MINIAPPS = pmesh-optimizer pminimal-surface pmesh-fitting fit-node-position\
phpref mesh-bounding-boxes
phpref pref321 mesh-bounding-boxes
ifeq ($(MFEM_USE_MPI),NO)
MINIAPPS = $(SEQ_MINIAPPS)
else
@@ -99,6 +99,8 @@ hpref-test-seq: hpref
@$(call mfem-test,$<,, Serial hp-refinement)
phpref-test-par: phpref
@$(call mfem-test,$<, $(RUN_MPI), Parallel hp-refinement)
pref321-test-par: pref321
@$(call mfem-test,$<, $(RUN_MPI), Parallel 3:1 refinement)
mesh-bounding-boxes-test-par: mesh-bounding-boxes
@$(call mfem-test,$<, $(RUN_MPI), Parallel bounding boxes)
ref321-test-seq: ref321
+336
View File
@@ -0,0 +1,336 @@
// 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.
//
// -----------------------------------------------------------------
// 3:1 Refinement Miniapp: Parallel 3:1 anisotropic mesh refinements
// -----------------------------------------------------------------
//
// This miniapp performs random 3:1 refinements of a quadrilateral or hexahedral
// mesh. A diffusion equation is solved in an H1 finite element space defined on
// the refined mesh, and its continuity is verified across local and shared
// faces.
//
// Compile with: make pref321
//
// Sample runs: mpirun -np 4 pref321 -mm -dim 2 -o 2 -r 100
// mpirun -np 4 pref321 -mm -dim 3 -o 2 -r 100
// mpirun -np 4 pref321 -m ../../data/star.mesh -o 2 -r 100
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
real_t CheckH1Continuity(ParGridFunction &x);
// Find the two children of parent element `elem` after its refinement in one
// direction.
void FindChildren(const Mesh &mesh, int elem, Array<int> &children)
{
const CoarseFineTransformations &cf = mesh.ncmesh->GetRefinementTransforms();
MFEM_ASSERT(mesh.GetNE() == cf.embeddings.Size(), "");
// Note that row `elem` of the table constructed by cf.MakeCoarseToFineTable
// is an alternative to this global loop, but constructing the table is also
// a global operation with global storage.
for (int i = 0; i < mesh.GetNE(); i++)
{
const int p = cf.embeddings[i].parent;
if (p == elem)
{
children.Append(i);
}
}
}
// Refine 3:1 via 2 refinements with scalings 2/3 and 1/2.
void Refine31(Mesh &mesh, int elem, char type)
{
Array<Refinement> refs; // Refinement is defined in ncmesh.hpp
refs.Append(Refinement(elem, type, 2.0 / 3.0));
mesh.GeneralRefinement(refs);
// Find the elements with parent `elem`
Array<int> children;
FindChildren(mesh, elem, children);
MFEM_ASSERT(children.Size() == 2, "");
const int elem1 = children[0];
refs.SetSize(0);
refs.Append(Refinement(elem1, type)); // Default scaling of 0.5
mesh.GeneralRefinement(refs);
}
// Randomly select elements for 3:1 refinements in random directions.
void TestAnisoRefRandom(int num_refs, int dim, ParMesh &mesh, int myid,
int seed = 0)
{
std::mt19937 gen(seed);
for (int i = 0; i < num_refs; i++)
{
const int elem = gen() % mesh.GetNE();
const int t = gen() % dim;
auto type = t == 0 ? Refinement::X :
(t == 1 ? Refinement::Y : Refinement::Z);
// In 3D, check for conflicts in the parallel refinements.
if (dim == 3)
{
std::set<int> conflicts; // Indices in refs of conflicting elements
Array<Refinement> refs;
refs.Append(Refinement(elem, type));
const bool conflict = mesh.AnisotropicConflict(refs, conflicts);
if (conflict)
{
if (myid == 0)
cout << "Anisotropic conflict on iteration " << i
<< ", retrying\n";
i--;
continue;
}
}
Refine31(mesh, elem, type);
}
mesh.EnsureNodes();
mesh.SetScaledNCMesh();
}
int main(int argc, char *argv[])
{
Mpi::Init(argc, argv);
Hypre::Init();
const int num_procs = Mpi::WorldSize();
const int myid = Mpi::WorldRank();
// 1. Parse command-line options.
const char *mesh_file = "../../data/star.mesh";
int order = 1;
bool visualization = true;
bool makeMesh = false;
int num_refs = 1;
int tdim = 2; // Mesh dimension for Cartesian meshes.
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&makeMesh, "-mm", "--make-mesh", "-no-mm",
"--no-make-mesh", "Create Cartesian mesh");
args.AddOption(&tdim, "-dim", "--dimension", "Dimension for Cartesian mesh");
args.AddOption(&num_refs, "-r", "--refs", "Number of 3:1 refinements");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 2. Create or read the serial mesh on all ranks, then apply the same
// deterministic 3:1 refinement sequence before partitioning it.
Mesh mesh;
if (makeMesh)
{
mesh = tdim == 3 ? Mesh::MakeCartesian3D(2, 2, 2, Element::HEXAHEDRON) :
Mesh::MakeCartesian2D(2, 2, Element::QUADRILATERAL);
}
else
{
mesh = Mesh::LoadFromFile(mesh_file, 1, 1);
}
const int dim = mesh.Dimension();
mesh.EnsureNCMesh();
mesh.SetScaledNCMesh();
// 3. Partition the refined serial mesh.
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
TestAnisoRefRandom(num_refs, dim, pmesh, myid, myid);
// 4. Define a parallel H1 finite element space and report its global size.
H1_FECollection fec(order, dim);
ParFiniteElementSpace fespace(&pmesh, &fec);
if (myid == 0)
{
cout << "Number of finite element unknowns: "
<< fespace.GlobalTrueVSize() << endl;
}
// 5. Assemble and solve the Poisson problem, following ex1p.
ParGridFunction x(&fespace);
x = 0.0;
ParLinearForm b(&fespace);
ConstantCoefficient one(1.0);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
b.Assemble();
ParBilinearForm a(&fespace);
a.AddDomainIntegrator(new DiffusionIntegrator());
a.Assemble();
OperatorPtr A;
Vector B, X;
Array<int> ess_tdof_list;
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 0;
pmesh.MarkExternalBoundaries(ess_bdr);
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
HypreBoomerAMG M;
CGSolver cg(MPI_COMM_WORLD);
cg.SetPreconditioner(M);
cg.SetOperator(*A);
cg.SetRelTol(1e-12);
cg.SetMaxIter(2000);
cg.SetPrintLevel(1);
cg.Mult(B, X);
a.RecoverFEMSolution(X, b, x);
// 6. Verify the continuity of the solution in H1 over local and shared
// faces and compute the global maximum jump.
const real_t h1err = CheckH1Continuity(x);
if (myid == 0)
{
cout << "Error of H1 continuity: " << h1err << endl;
}
MFEM_VERIFY(h1err < 1.0e-7, "H1 discontinuity found");
// 7. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh.Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 8. Send the parallel solution to GLVis.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << pmesh << x << flush;
}
return 0;
}
real_t CheckH1Continuity(ParGridFunction &x)
{
const ParFiniteElementSpace *pfes = x.ParFESpace();
ParMesh *pmesh = pfes->GetParMesh();
const int dim = pmesh->Dimension();
real_t errorMax = 0.0;
// Shared-face values require face-neighbor data.
x.ExchangeFaceNbrData();
// First handle faces for which both elements are local to this rank.
for (int f = 0; f < pmesh->GetNumFaces(); f++)
{
const auto info = pmesh->GetFaceInformation(f);
if (!info.IsLocal())
{
continue;
}
FaceElementTransformations *FT = pmesh->GetFaceElementTransformations(f);
const int faceOrder = dim == 3 ? pfes->GetFaceOrder(f) :
pfes->GetEdgeOrder(f);
const IntegrationRule &ir = IntRules.Get(FT->FaceGeom, 2 * faceOrder);
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &fip = ir.IntPoint(i);
IntegrationPoint ip1, ip2;
FT->Loc1.Transform(fip, ip1);
FT->Loc2.Transform(fip, ip2);
const real_t v1 = x.GetValue(*FT->Elem1, ip1);
const real_t v2 = x.GetValue(*FT->Elem2, ip2);
errorMax = std::max(errorMax, std::abs(v1 - v2));
}
}
// Then check partition interfaces. Conforming shared faces are handled on
// the lower-rank side, while shared slave nonconforming faces are handled
// only on the slave side and therefore do not need additional filtering.
for (int sf = 0; sf < pmesh->GetNSharedFaces(); sf++)
{
const int f = pmesh->GetSharedFace(sf);
const auto info = pmesh->GetFaceInformation(f);
if (!info.IsShared())
{
continue;
}
FaceElementTransformations *FT = pmesh->GetSharedFaceTransformations(sf);
const int faceOrder = dim == 3 ? pfes->GetFaceOrder(f) :
pfes->GetEdgeOrder(f);
const IntegrationRule &ir = IntRules.Get(FT->FaceGeom, 2 * faceOrder);
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &fip = ir.IntPoint(i);
IntegrationPoint ip1, ip2;
FT->Loc1.Transform(fip, ip1);
FT->Loc2.Transform(fip, ip2);
const real_t v1 = x.GetValue(*FT->Elem1, ip1);
const real_t v2 = x.GetValue(*FT->Elem2, ip2);
errorMax = std::max(errorMax, std::abs(v1 - v2));
}
}
MPI_Allreduce(MPI_IN_PLACE, &errorMax, 1, MFEM_MPI_REAL_T, MPI_MAX,
pmesh->GetComm());
return errorMax;
}
+5 -13
View File
@@ -71,22 +71,14 @@ void Refine31(Mesh & mesh, int elem, char type)
mesh.GeneralRefinement(refs);
}
// Deterministic, somewhat random integer generator
int MyRand(int & s)
{
s++;
const double a = 1000 * sin(s * 1.1234 * M_PI);
return int(std::abs(a));
}
// Randomly select elements for 3:1 refinements in random directions.
void TestAnisoRefRandom(int iter, int dim, Mesh & mesh)
void TestAnisoRefRandom(int num_refs, int dim, Mesh & mesh)
{
int seed = 0;
for (int i = 0; i < iter; i++)
std::mt19937 gen(1);
for (int i = 0; i < num_refs; i++)
{
const int elem = MyRand(seed) % mesh.GetNE();
const int t = MyRand(seed) % dim;
const auto elem = gen() % mesh.GetNE();
const auto t = gen() % dim;
auto type = t == 0 ? Refinement::X :
(t == 1 ? Refinement::Y : Refinement::Z);
Refine31(mesh, elem, type);
+6
View File
@@ -9,6 +9,12 @@
# terms of the BSD-3 license. We welcome feedback and contributions, see file
# CONTRIBUTING.md for details.
add_mfem_miniapp(g_eqdsk_viewer
MAIN g_eqdsk_viewer.cpp
EXTRA_SOURCES g_eqdsk_data.cpp
EXTRA_HEADERS g_eqdsk_data.hpp plasma.hpp ${MFEM_MINIAPPS_COMMON_HEADERS}
LIBRARIES mfem mfem-common)
if (MFEM_USE_MPI)
list(APPEND PLASMA_COMMON_SOURCES)
+211
View File
@@ -0,0 +1,211 @@
SGRRATEI 01/01/2025 #1 0ms 3 20 40
1.000000000E+00 2.000000000E+00 1.000000000E+00 5.000000000E-01 0.000000000E+00
1.104715063E+00 5.225686728E-06-9.087992965E+00 0.000000000E+00 1.000000000E+00
3.335115355E+05-9.087992965E+00 0.000000000E+00 1.104715063E+00 0.000000000E+00
5.225686728E-06 0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00
9.784708692E-01 9.806991943E-01 9.828024193E-01 9.847813458E-01 9.866367217E-01
9.883692428E-01 9.899795542E-01 9.914682512E-01 9.928358810E-01 9.940829432E-01
9.952098911E-01 9.962171323E-01 9.971050296E-01 9.978739015E-01 9.985240230E-01
9.990556259E-01 9.994688994E-01 9.997639901E-01 9.999410027E-01 1.000000000E+00
4.707754379E+04 4.225242157E+04 3.768811677E+04 3.338462939E+04 2.934195942E+04
2.556010688E+04 2.203907174E+04 1.877885403E+04 1.577945373E+04 1.304087085E+04
1.056310539E+04 8.346157347E+03 6.390026719E+03 4.694713508E+03 3.260217714E+03
2.086539337E+03 1.173678377E+03 5.216348342E+02 1.304087085E+02 0.000000000E+00
-4.353196346E-02-4.114710095E-02-3.877798694E-02-3.642358799E-02-3.408289990E-02
-3.175494531E-02-2.943877149E-02-2.713344826E-02-2.483806598E-02-2.255173364E-02
-2.027357702E-02-1.800273697E-02-1.573836773E-02-1.347963528E-02-1.122571577E-02
-8.975794007E-03-6.729061934E-03-4.484717187E-03-2.241961644E-03-0.000000000E+00
9.415508757E+04 8.919955665E+04 8.424402572E+04 7.928849480E+04 7.433296387E+04
6.937743295E+04 6.442190202E+04 5.946637110E+04 5.451084017E+04 4.955530925E+04
4.459977832E+04 3.964424740E+04 3.468871647E+04 2.973318555E+04 2.477765462E+04
1.982212370E+04 1.486659277E+04 9.911061850E+03 4.955530925E+03 0.000000000E+00
-3.910241380E-01-3.370349374E-01-3.032206099E-01-2.833941950E-01-2.709124845E-01
-2.589045274E-01-2.408148723E-01-2.113596788E-01-1.679192587E-01-1.122605207E-01
-5.229150156E-02-3.313845027E-03 1.199143413E-02-3.426047302E-02-1.700331905E-01
-4.150011731E-01-7.696358166E-01-1.203902834E+00-1.649387010E+00-1.999925152E+00
-1.925695622E-01-1.748346049E-01-1.691266514E-01-1.701675452E-01-1.715397928E-01
-1.659119623E-01-1.456077592E-01-1.036478534E-01-3.533092381E-02 5.970389126E-02
1.751878198E-01 2.962216198E-01 3.983584318E-01 4.487753542E-01 4.105383363E-01
2.505857725E-01-4.884633508E-02-4.770899859E-01-9.837399355E-01-1.474339619E+00
2.166315348E-02-1.102851387E-03-2.831065458E-02-5.546599960E-02-7.618766318E-02
-8.237925771E-02-6.477862541E-02-1.405299099E-02 7.743811746E-02 2.132045638E-01
3.897048312E-01 5.934227400E-01 7.987616348E-01 9.678852363E-01 1.053770529E+00
1.007512540E+00 7.901446298E-01 3.878102911E-01-1.728443713E-01-8.142430666E-01
2.411392375E-01 1.747358186E-01 1.103546220E-01 5.181206754E-02 5.588785514E-03
-1.923578803E-02-1.146084602E-02 4.113304468E-02 1.498681805E-01 3.223534496E-01
5.588811278E-01 8.484640691E-01 1.165346084E+00 1.467240961E+00 1.696851978E+00
1.788184124E+00 1.678546763E+00 1.325771819E+00 7.280476985E-01-5.875813012E-02
4.562990380E-01 3.439881454E-01 2.385637023E-01 1.432261283E-01 6.461505077E-02
1.290331417E-02 1.448926330E-03 4.574285831E-02 1.613919171E-01 3.609574823E-01
6.496681822E-01 1.020362387E+00 1.448488467E+00 1.888534307E+00 2.273730093E+00
2.521039729E+00 2.543035410E+00 2.266964141E+00 1.659051976E+00 7.490835809E-01
6.589958226E-01 4.991505383E-01 3.490864277E-01 2.113878302E-01 9.282362412E-02
4.651701261E-03-3.753931076E-02-1.476326317E-02 9.331703089E-02 3.049501109E-01
6.313711445E-01 1.070656937E+00 1.601160717E+00 2.175992078E+00 2.720663983E+00
3.136428575E+00 3.311623934E+00 3.142190847E+00 2.560153749E+00 1.565395650E+00
8.427963399E-01 6.342571609E-01 4.361842129E-01 2.504754676E-01 8.390705039E-02
-5.130487543E-02-1.374118370E-01-1.518716892E-01-6.933566292E-02 1.347294416E-01
4.785698497E-01 9.669780041E-01 1.583175086E+00 2.281269353E+00 2.981657583E+00
3.572374734E+00 3.919441608E+00 3.888257701E+00 3.375670467E+00 2.348486607E+00
1.003140271E+00 7.451051663E-01 4.959126068E-01 2.566355010E-01 3.385060138E-02
-1.595013481E-01-3.037145085E-01-3.727832712E-01-3.362296400E-01-1.627893604E-01
1.736969869E-01 6.862115526E-01 1.364964594E+00 2.167824224E+00 3.013335205E+00
3.779769521E+00 4.313957864E+00 4.452847541E+00 4.058327204E+00 3.061671981E+00
1.137365128E+00 8.293536487E-01 5.262966190E-01 2.282463102E-01-5.869372598E-02
-3.211771932E-01-5.378523046E-01-6.794765186E-01-7.104791334E-01-5.925787521E-01
-2.909412188E-01 2.169977855E-01 9.305878226E-01 1.814416755E+00 2.788864587E+00
3.726574504E+00 4.459237386E+00 4.798518474E+00 4.572628903E+00 3.675635708E+00
1.244611695E+00 8.865011676E-01 5.273739090E-01 1.660289873E-01-1.922188349E-01
-5.339924512E-01-8.366835819E-01-1.068145986E+00-1.187890541E+00-1.150497326E+00
-9.118739899E-01-4.386474144E-01 2.797067814E-01 1.217442845E+00 2.300606858E+00
3.400695883E+00 4.338887158E+00 4.905511692E+00 4.897269966E+00 4.170164958E+00
1.325631269E+00 9.177537088E-01 5.011092625E-01 7.300028320E-02-3.623736298E-01
-7.920000920E-01-1.192445606E+00-1.529067475E+00-1.756748529E+00-1.822973413E+00
-1.674020591E+00-1.264731297E+00-5.716334778E-01 3.919046896E-01 1.561272647E+00
2.811295637E+00 3.957459998E+00 4.773149919E+00 5.026398786E+00 4.535133275E+00
1.382519568E+00 9.258003322E-01 4.511913373E-01-4.572686077E-02-5.621735094E-01
-1.085880267E+00-1.593023216E+00-2.046909304E+00-2.398174860E+00-2.587412144E+00
-2.551140860E+00-2.231766925E+00-1.591501157E+00-6.290735117E-01 6.034811432E-01
1.988428128E+00 3.340201296E+00 4.419719356E+00 4.969646189E+00 4.770667398E+00
1.418403250E+00 9.145173783E-01 3.827290445E-01-1.832800729E-01-7.823963566E-01
-1.403422928E+00-2.022546791E+00-2.601474899E+00-3.087043844E+00-3.413308233E+00
-3.507162143E+00-3.298318507E+00-2.733827400E+00-1.796161496E+00-5.222552154E-01
9.810231774E-01 2.531156764E+00 3.880848348E+00 4.750925106E+00 4.886498468E+00
1.437103919E+00 8.886239873E-01 3.018699076E-01-3.314779846E-01-1.012137361E+00
-1.730227221E+00-2.462280919E+00-3.168828947E+00-3.793395216E+00-4.263991651E+00
-4.498294398E+00-4.413504634E+00-3.941288135E+00-3.047034463E+00-1.750973347E+00
-1.466326055E-01 1.589788832E+00 3.206515141E+00 4.406106379E+00 4.900563280E+00
1.442801674E+00 8.533119757E-01 2.153661342E-01-4.813638998E-01-1.239485158E+00
-2.050570243E+00-2.891743239E+00-3.722729788E+00-4.484246464E+00-5.098883769E+00
-5.475783196E+00-5.520279043E+00-5.149107296E+00-4.310641572E+00-3.007869332E+00
-1.319645546E+00 5.863673938E-01 2.456925688E+00 3.979764627E+00 4.836980711E+00
1.439716341E+00 8.138721012E-01 1.301159276E-01-6.237874768E-01-1.452273520E+00
-2.348385346E+00-3.289975383E+00-4.236266930E+00-5.125675247E+00-5.876101086E+00
-6.389099647E+00-6.559246706E+00-6.289497376E+00-5.512208788E+00-4.213722607E+00
-2.458127258E+00-4.035022091E-01 1.697591881E+00 3.521261516E+00 4.723577581E+00
1.431820151E+00 7.753367344E-01 5.270779132E-02-7.499966727E-01-1.638857755E+00
-2.608282055E+00-3.636876158E+00-4.683586303E+00-5.685020856E+00-6.555215726E+00
-7.189331085E+00-7.472729897E+00-7.296402003E+00-6.578594532E+00-5.290716634E+00
-3.483232525E+00-1.304782694E+00 9.940036866E-01 3.080485788E+00 4.589173208E+00
1.422591282E+00 7.421562942E-01-1.100563552E-02-8.522020247E-01-1.788863321E+00
-2.816536419E+00-3.914501953E+00-5.041578424E+00-6.133043547E+00-7.099968471E+00
-7.832519316E+00-8.208777881E+00-8.110180067E+00-7.443587519E+00-6.168205808E+00
-4.323151304E+00-2.048874175E+00 4.063205511E-01 2.703595819E+00 4.460849974E+00
1.414813950E+00 7.179237979E-01-5.628015260E-02-9.240774770E-01-1.893856117E+00
-2.961982431E+00-4.108241194E+00-5.291406587E+00-6.445882623E+00-7.480732414E+00
-8.282695715E+00-8.724816600E+00-8.681873871E+00-8.052739203E+00-6.787981369E+00
-4.918586303E+00-2.578986186E+00-1.549450246E-02 2.429109334E+00 4.361436888E+00
1.410427849E+00 7.051587764E-01-7.977847127E-02-9.611662324E-01-1.947889219E+00
-3.036741970E+00-4.207778410E+00-5.419763372E+00-6.606668398E+00-7.676543111E+00
-8.514384415E+00-8.990661063E+00-8.976734576E+00-8.367358201E+00-7.108627276E+00
-5.227287344E+00-2.854588356E+00-2.357101966E-01 2.284656177E+00 4.307414559E+00
1.410427849E+00 7.051587764E-01-7.977847127E-02-9.611662324E-01-1.947889219E+00
-3.036741970E+00-4.207778410E+00-5.419763372E+00-6.606668398E+00-7.676543111E+00
-8.514384415E+00-8.990661063E+00-8.976734576E+00-8.367358201E+00-7.108627276E+00
-5.227287344E+00-2.854588356E+00-2.357101966E-01 2.284656177E+00 4.307414559E+00
1.414813950E+00 7.179237979E-01-5.628015260E-02-9.240774770E-01-1.893856117E+00
-2.961982431E+00-4.108241194E+00-5.291406587E+00-6.445882623E+00-7.480732414E+00
-8.282695715E+00-8.724816600E+00-8.681873871E+00-8.052739203E+00-6.787981369E+00
-4.918586303E+00-2.578986186E+00-1.549450246E-02 2.429109334E+00 4.361436888E+00
1.422591282E+00 7.421562942E-01-1.100563552E-02-8.522020247E-01-1.788863321E+00
-2.816536419E+00-3.914501953E+00-5.041578424E+00-6.133043547E+00-7.099968471E+00
-7.832519316E+00-8.208777881E+00-8.110180067E+00-7.443587519E+00-6.168205808E+00
-4.323151304E+00-2.048874175E+00 4.063205511E-01 2.703595819E+00 4.460849974E+00
1.431820151E+00 7.753367344E-01 5.270779132E-02-7.499966727E-01-1.638857755E+00
-2.608282055E+00-3.636876158E+00-4.683586303E+00-5.685020856E+00-6.555215726E+00
-7.189331085E+00-7.472729897E+00-7.296402003E+00-6.578594532E+00-5.290716634E+00
-3.483232525E+00-1.304782694E+00 9.940036866E-01 3.080485788E+00 4.589173208E+00
1.439716341E+00 8.138721012E-01 1.301159276E-01-6.237874768E-01-1.452273520E+00
-2.348385346E+00-3.289975383E+00-4.236266930E+00-5.125675247E+00-5.876101086E+00
-6.389099647E+00-6.559246706E+00-6.289497376E+00-5.512208788E+00-4.213722607E+00
-2.458127258E+00-4.035022091E-01 1.697591881E+00 3.521261516E+00 4.723577581E+00
1.442801674E+00 8.533119757E-01 2.153661342E-01-4.813638998E-01-1.239485158E+00
-2.050570243E+00-2.891743239E+00-3.722729788E+00-4.484246464E+00-5.098883769E+00
-5.475783196E+00-5.520279043E+00-5.149107296E+00-4.310641572E+00-3.007869332E+00
-1.319645546E+00 5.863673938E-01 2.456925688E+00 3.979764627E+00 4.836980711E+00
1.437103919E+00 8.886239873E-01 3.018699076E-01-3.314779846E-01-1.012137361E+00
-1.730227221E+00-2.462280919E+00-3.168828947E+00-3.793395216E+00-4.263991651E+00
-4.498294398E+00-4.413504634E+00-3.941288135E+00-3.047034463E+00-1.750973347E+00
-1.466326055E-01 1.589788832E+00 3.206515141E+00 4.406106379E+00 4.900563280E+00
1.418403250E+00 9.145173783E-01 3.827290445E-01-1.832800729E-01-7.823963566E-01
-1.403422928E+00-2.022546791E+00-2.601474899E+00-3.087043844E+00-3.413308233E+00
-3.507162143E+00-3.298318507E+00-2.733827400E+00-1.796161496E+00-5.222552154E-01
9.810231774E-01 2.531156764E+00 3.880848348E+00 4.750925106E+00 4.886498468E+00
1.382519568E+00 9.258003322E-01 4.511913373E-01-4.572686077E-02-5.621735094E-01
-1.085880267E+00-1.593023216E+00-2.046909304E+00-2.398174860E+00-2.587412144E+00
-2.551140860E+00-2.231766925E+00-1.591501157E+00-6.290735117E-01 6.034811432E-01
1.988428128E+00 3.340201296E+00 4.419719356E+00 4.969646189E+00 4.770667398E+00
1.325631269E+00 9.177537088E-01 5.011092625E-01 7.300028320E-02-3.623736298E-01
-7.920000920E-01-1.192445606E+00-1.529067475E+00-1.756748529E+00-1.822973413E+00
-1.674020591E+00-1.264731297E+00-5.716334778E-01 3.919046896E-01 1.561272647E+00
2.811295637E+00 3.957459998E+00 4.773149919E+00 5.026398786E+00 4.535133275E+00
1.244611695E+00 8.865011676E-01 5.273739090E-01 1.660289873E-01-1.922188349E-01
-5.339924512E-01-8.366835819E-01-1.068145986E+00-1.187890541E+00-1.150497326E+00
-9.118739899E-01-4.386474144E-01 2.797067814E-01 1.217442845E+00 2.300606858E+00
3.400695883E+00 4.338887158E+00 4.905511692E+00 4.897269966E+00 4.170164958E+00
1.137365128E+00 8.293536487E-01 5.262966190E-01 2.282463102E-01-5.869372598E-02
-3.211771932E-01-5.378523046E-01-6.794765186E-01-7.104791334E-01-5.925787521E-01
-2.909412188E-01 2.169977855E-01 9.305878226E-01 1.814416755E+00 2.788864587E+00
3.726574504E+00 4.459237386E+00 4.798518474E+00 4.572628903E+00 3.675635708E+00
1.003140271E+00 7.451051663E-01 4.959126068E-01 2.566355010E-01 3.385060138E-02
-1.595013481E-01-3.037145085E-01-3.727832712E-01-3.362296400E-01-1.627893604E-01
1.736969869E-01 6.862115526E-01 1.364964594E+00 2.167824224E+00 3.013335205E+00
3.779769521E+00 4.313957864E+00 4.452847541E+00 4.058327204E+00 3.061671981E+00
8.427963399E-01 6.342571609E-01 4.361842129E-01 2.504754676E-01 8.390705039E-02
-5.130487543E-02-1.374118370E-01-1.518716892E-01-6.933566292E-02 1.347294416E-01
4.785698497E-01 9.669780041E-01 1.583175086E+00 2.281269353E+00 2.981657583E+00
3.572374734E+00 3.919441608E+00 3.888257701E+00 3.375670467E+00 2.348486607E+00
6.589958226E-01 4.991505383E-01 3.490864277E-01 2.113878302E-01 9.282362412E-02
4.651701261E-03-3.753931076E-02-1.476326317E-02 9.331703089E-02 3.049501109E-01
6.313711445E-01 1.070656937E+00 1.601160717E+00 2.175992078E+00 2.720663983E+00
3.136428575E+00 3.311623934E+00 3.142190847E+00 2.560153749E+00 1.565395650E+00
4.562990380E-01 3.439881454E-01 2.385637023E-01 1.432261283E-01 6.461505077E-02
1.290331417E-02 1.448926330E-03 4.574285831E-02 1.613919171E-01 3.609574823E-01
6.496681822E-01 1.020362387E+00 1.448488467E+00 1.888534307E+00 2.273730093E+00
2.521039729E+00 2.543035410E+00 2.266964141E+00 1.659051976E+00 7.490835809E-01
2.411392375E-01 1.747358186E-01 1.103546220E-01 5.181206754E-02 5.588785514E-03
-1.923578803E-02-1.146084602E-02 4.113304468E-02 1.498681805E-01 3.223534496E-01
5.588811278E-01 8.484640691E-01 1.165346084E+00 1.467240961E+00 1.696851978E+00
1.788184124E+00 1.678546763E+00 1.325771819E+00 7.280476985E-01-5.875813012E-02
2.166315348E-02-1.102851387E-03-2.831065458E-02-5.546599960E-02-7.618766318E-02
-8.237925771E-02-6.477862541E-02-1.405299099E-02 7.743811746E-02 2.132045638E-01
3.897048312E-01 5.934227400E-01 7.987616348E-01 9.678852363E-01 1.053770529E+00
1.007512540E+00 7.901446298E-01 3.878102911E-01-1.728443713E-01-8.142430666E-01
-1.925695622E-01-1.748346049E-01-1.691266514E-01-1.701675452E-01-1.715397928E-01
-1.659119623E-01-1.456077592E-01-1.036478534E-01-3.533092381E-02 5.970389126E-02
1.751878198E-01 2.962216198E-01 3.983584318E-01 4.487753542E-01 4.105383363E-01
2.505857725E-01-4.884633508E-02-4.770899859E-01-9.837399355E-01-1.474339619E+00
-3.910241380E-01-3.370349374E-01-3.032206099E-01-2.833941950E-01-2.709124845E-01
-2.589045274E-01-2.408148723E-01-2.113596788E-01-1.679192587E-01-1.122605207E-01
-5.229150156E-02-3.313845027E-03 1.199143413E-02-3.426047302E-02-1.700331905E-01
-4.150011731E-01-7.696358166E-01-1.203902834E+00-1.649387010E+00-1.999925152E+00
1.000000000E+00 1.050395383E+00 1.108778414E+00 1.174574361E+00 1.246881957E+00
1.327322223E+00 1.420854260E+00 1.523601296E+00 1.644396040E+00 1.782867911E+00
1.944699895E+00 2.137823164E+00 2.371490866E+00 2.660870810E+00 3.022189358E+00
3.498374954E+00 4.155225142E+00 5.164243345E+00 7.000356534E+00 9.663564712E+00
60 11
8.000000000E-01 8.000000000E-01 7.743225129E-01 7.532775834E-01 7.502189395E-01
7.047911204E-01 7.277457261E-01 6.546541578E-01 7.069555012E-01 6.029841077E-01
6.878969518E-01 5.499019727E-01 6.706147099E-01 4.955320618E-01 6.551492475E-01
4.400017001E-01 6.415367820E-01 3.834409301E-01 6.298091915E-01 3.259822075E-01
6.199939400E-01 2.677600906E-01 6.121140130E-01 2.089109256E-01 6.061878641E-01
1.495725272E-01 6.022293713E-01 8.988385560E-02 6.002478046E-01 2.998469153E-02
6.002478046E-01-2.998469153E-02 6.022293713E-01-8.988385560E-02 6.061878641E-01
-1.495725272E-01 6.121140130E-01-2.089109256E-01 6.199939400E-01-2.677600906E-01
6.298091915E-01-3.259822075E-01 6.415367820E-01-3.834409301E-01 6.551492475E-01
-4.400017001E-01 6.706147099E-01-4.955320618E-01 6.878969518E-01-5.499019727E-01
7.069555012E-01-6.029841077E-01 7.277457261E-01-6.546541578E-01 7.502189395E-01
-7.047911204E-01 7.743225129E-01-7.532775834E-01 8.000000000E-01-8.000000000E-01
8.000000000E-01-8.000000000E-01 8.770324613E-01-7.532775834E-01 9.493431816E-01
-7.047911204E-01 1.016762822E+00-6.546541578E-01 1.079133497E+00-6.029841077E-01
1.136309145E+00-5.499019727E-01 1.188155870E+00-4.955320618E-01 1.234552257E+00
-4.400017001E-01 1.275389654E+00-3.834409301E-01 1.310572426E+00-3.259822075E-01
1.340018180E+00-2.677600906E-01 1.363657961E+00-2.089109256E-01 1.381436408E+00
-1.495725272E-01 1.393311886E+00-8.988385560E-02 1.399256586E+00-2.998469153E-02
1.399256586E+00 2.998469153E-02 1.393311886E+00 8.988385560E-02 1.381436408E+00
1.495725272E-01 1.363657961E+00 2.089109256E-01 1.340018180E+00 2.677600906E-01
1.310572426E+00 3.259822075E-01 1.275389654E+00 3.834409301E-01 1.234552257E+00
4.400017001E-01 1.188155870E+00 4.955320618E-01 1.136309145E+00 5.499019727E-01
1.079133497E+00 6.029841077E-01 1.016762822E+00 6.546541578E-01 9.493431816E-01
7.047911204E-01 8.770324613E-01 7.532775834E-01 8.000000000E-01 8.000000000E-01
5.200000000E-01 0.000000000E+00 5.800000000E-01-6.000000000E-01 5.500000000E-01-9.000000000E-01 1.250000000E+00-9.000000000E-01 1.400000000E+00-6.000000000E-01 1.480000000E+00 0.000000000E+00 1.400000000E+00 6.000000000E-01 1.250000000E+00 9.000000000E-01 5.500000000E-01 9.000000000E-01 5.800000000E-01 6.000000000E-01 5.200000000E-01 0.000000000E+00
+211
View File
@@ -0,0 +1,211 @@
SGRRATEI 01/01/2025 #1 0ms 3 20 40
1.000000000E+00 2.000000000E+00 1.000000000E+00 5.000000000E-01 0.000000000E+00
1.109022415E+00-9.616366848E-06-3.831437870E+00 0.000000000E+00 1.000000000E+00
4.810231190E+05-3.831437870E+00 0.000000000E+00 1.109022415E+00 0.000000000E+00
-9.616366848E-06 0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00
9.695197187E-01 9.726876680E-01 9.756749097E-01 9.784830989E-01 9.811137731E-01
9.835683566E-01 9.858481646E-01 9.879544073E-01 9.898881924E-01 9.916505289E-01
9.932423294E-01 9.946644126E-01 9.959175056E-01 9.970022456E-01 9.979191815E-01
9.986687756E-01 9.992514045E-01 9.996673601E-01 9.999168504E-01 1.000000000E+00
6.634939148E+04 5.954903834E+04 5.311627185E+04 4.705109202E+04 4.135349885E+04
3.602349233E+04 3.106107247E+04 2.646623926E+04 2.223899271E+04 1.837933282E+04
1.488725959E+04 1.176277301E+04 9.005873082E+03 6.616559816E+03 4.594833205E+03
2.940693251E+03 1.654139954E+03 7.351733128E+02 1.837933282E+02 0.000000000E+00
-6.191881812E-02-5.846888325E-02-5.505154200E-02-5.166451510E-02-4.830561217E-02
-4.497272375E-02-4.166381400E-02-3.837691381E-02-3.511011443E-02-3.186156146E-02
-2.862944924E-02-2.541201545E-02-2.220753614E-02-1.901432083E-02-1.583070797E-02
-1.265506044E-02-9.485761281E-03-6.321209542E-03-3.159816165E-03-0.000000000E+00
1.326987830E+05 1.257146365E+05 1.187304900E+05 1.117463436E+05 1.047621971E+05
9.777805061E+04 9.079390414E+04 8.380975766E+04 7.682561119E+04 6.984146472E+04
6.285731825E+04 5.587317178E+04 4.888902530E+04 4.190487883E+04 3.492073236E+04
2.793658589E+04 2.095243942E+04 1.396829294E+04 6.984146472E+03 0.000000000E+00
6.027880359E-01 5.444336242E-01 4.929843721E-01 4.468606903E-01 4.053015659E-01
3.683453893E-01 3.367530737E-01 3.118362535E-01 2.951519289E-01 2.880365841E-01
2.909818720E-01 3.029033791E-01 3.204224066E-01 3.373590566E-01 3.447032023E-01
3.313561860E-01 2.858795818E-01 1.993086623E-01 6.876738196E-02-9.881690647E-02
6.744595449E-01 5.996140461E-01 5.328634336E-01 4.723627302E-01 4.172570594E-01
3.677070698E-01 3.248508780E-01 2.906574776E-01 2.676201889E-01 2.582462461E-01
2.643256985E-01 2.860143822E-01 3.208428141E-01 3.628585676E-01 4.022050156E-01
4.255007017E-01 4.173644838E-01 3.632813892E-01 2.536864244E-01 8.866344730E-02
7.343619131E-01 6.436962062E-01 5.614219261E-01 4.855364655E-01 4.151880501E-01
3.507641660E-01 2.939113975E-01 2.474323310E-01 2.149930564E-01 2.005771397E-01
2.076460507E-01 2.380192080E-01 2.905729286E-01 3.599724996E-01 4.357778205E-01
5.023656375E-01 5.401375751E-01 5.283698530E-01 4.497523801E-01 2.961440598E-01
7.809349798E-01 6.751996950E-01 5.772531276E-01 4.850226141E-01 3.977360480E-01
3.160900969E-01 2.423462144E-01 1.802896324E-01 1.349679043E-01 1.121217192E-01
1.172407810E-01 1.542315062E-01 2.237783488E-01 3.216158548E-01 4.370886419E-01
5.525253624E-01 6.440313440E-01 6.842364433E-01 6.472434068E-01 5.154640263E-01
8.135690035E-01 6.934582174E-01 5.796763578E-01 4.701407046E-01 3.642092103E-01
2.629430672E-01 1.692957439E-01 8.815231453E-02 2.611713847E-02-9.063055012E-03
-9.538719707E-03 3.109598996E-02 1.158088422E-01 2.419024963E-01 3.989659604E-01
5.676148854E-01 7.197683473E-01 8.211947470E-01 8.367934603E-01 7.384898454E-01
8.325216321E-01 6.985747478E-01 5.687238375E-01 4.409043702E-01 3.146255305E-01
1.913389993E-01 7.473585748E-02-2.911651568E-02-1.119191647E-01-1.637085739E-01
-1.739780585E-01-1.334333429E-01-3.635127414E-02 1.166660483E-01 3.159822862E-01
5.409560343E-01 7.596023466E-01 9.308263465E-01 1.009936725E+00 9.575352010E-01
8.387863256E-01 6.913340506E-01 5.450887024E-01 3.979996591E-01 2.497191168E-01
1.020859215E-01-4.045731398E-02-1.706141808E-01-2.782935795E-01-3.511479324E-01
-3.757593010E-01-3.395926987E-01-2.337188599E-01-5.611233175E-02 1.849391381E-01
4.680854372E-01 7.578657830E-01 1.006514653E+00 1.159586428E+00 1.165738769E+00
8.339278564E-01 6.730837162E-01 5.100416932E-01 3.427308098E-01 1.709112396E-01
-3.221170684E-03-1.744881056E-01-3.343523364E-01-4.708744696E-01-5.692032028E-01
-6.128066860E-01-5.856071769E-01-4.750595001E-01-2.759990290E-01 5.221341658E-03
3.471489908E-01 7.113877498E-01 1.043861665E+00 1.280418325E+00 1.357377573E+00
8.199015377E-01 6.455959983E-01 4.653253241E-01 2.769394057E-01 8.024954100E-02
-1.222439302E-01-3.246688374E-01-5.172678502E-01-6.862382215E-01-8.141557599E-01
-8.812308347E-01-8.676042109E-01-7.567658125E-01-5.399480748E-01-2.210043304E-01
1.791358869E-01 6.197548661E-01 1.040961106E+00 1.369135452E+00 1.528097841E+00
7.988723691E-01 6.109227609E-01 4.130347848E-01 2.029036972E-01-1.967987208E-02
-2.519798567E-01-4.874929551E-01-7.152912061E-01-9.197329238E-01-1.080803941E+00
-1.175377832E+00-1.179650378E+00-1.072877456E+00-8.422994956E-01-4.887614330E-01
-3.206461911E-02 4.853974608E-01 9.985106689E-01 1.424598500E+00 1.675050854E+00
7.730484943E-01 5.712548386E-01 3.554945030E-01 1.232251820E-01-1.258618115E-01
-3.888726160E-01-6.587503270E-01-9.234698604E-01-1.165611778E+00-1.362607208E+00
-1.487983287E+00-1.513912701E+00-1.415245061E+00-1.174939292E+00-7.904115839E-01
-2.797893042E-01 3.134946132E-01 9.197564239E-01 1.447814952E+00 1.796927636E+00
7.445404658E-01 5.287952464E-01 2.951382949E-01 4.070929804E-02-2.349767287E-01
-5.289477637E-01-8.336791693E-01-1.136141025E+00-1.417230568E+00-1.651910893E+00
-1.810425157E+00-1.860937968E+00-1.773831419E+00-1.527614344E+00-1.115971166E+00
-5.549039664E-01 1.117031538E-01 8.102732738E-01 1.441789269E+00 1.893892967E+00
7.152541434E-01 4.856531808E-01 2.343995042E-01-4.175359515E-02-3.435345212E-01
-6.679672634E-01-1.007147349E+00-1.347145717E+00-1.667299880E+00-1.940240855E+00
-2.133063162E+00-2.210036310E+00-2.137134706E+00-1.888385838E+00-1.453579841E+00
-8.462660998E-01-1.102730351E-01 6.775958354E-01 1.411245424E+00 1.967425855E+00
6.868209862E-01 4.437629001E-01 1.756156706E-01-1.213017723E-01-4.480113960E-01
-8.015956403E-01-1.173854475E+00-1.550073727E+00-1.908179626E+00-2.218653210E+00
-2.445647332E+00-2.549748880E+00-2.492710924E+00-2.244196046E+00-1.790094098E+00
-1.141319885E+00-3.412468720E-01 5.307237428E-01 1.362241297E+00 2.020079621E+00
6.605654332E-01 4.048286553E-01 1.209502842E-01-1.952062579E-01-5.449842404E-01
-9.255704167E-01-1.328545300E+00-1.738527527E+00-2.132201008E+00-2.478121003E+00
-2.737773949E+00-2.868374135E+00-2.827766422E+00-2.581516128E+00-2.111771066E+00
-1.426787661E+00-5.692100125E-01 3.795334026E-01 1.301701384E+00 2.055179962E+00
6.375053763E-01 3.702941358E-01 7.233227099E-02-2.609627702E-01-6.312576177E-01
-1.035869585E+00-1.466224516E+00-1.906392149E+00-2.331999433E+00-2.709937370E+00
-2.999364174E+00-3.154523523E+00-3.129786863E+00-2.887037341E+00-2.405002017E+00
-1.689415837E+00-7.820514975E-01 2.341342187E-01 1.236899458E+00 2.076483242E+00
6.183787457E-01 3.413326511E-01 3.141219456E-02-3.163699380E-01-7.039792622E-01
-1.128869268E+00-1.582363062E+00-2.048097697E+00-2.500841167E+00-2.906113655E+00
-3.221139041E+00-3.397675320E+00-3.387166510E+00-3.148365134E+00-2.657051631E+00
-1.916729591E+00-9.682880687E-01 1.042108382E-01 1.174925970E+00 2.087819678E+00
6.036871942E-01 3.188526756E-01-4.670925182E-04-3.595932281E-01-7.607407379E-01
-1.201485317E+00-1.673086529E+00-2.158861549E+00-2.632926762E+00-3.059751018E+00
-3.395064527E+00-3.588695197E+00-3.589801388E+00-3.354675138E+00-2.856758537E+00
-2.097750017E+00-1.117760284E+00-1.606164268E-03 1.122175768E+00 2.092746840E+00
5.937469493E-01 3.035125582E-01-2.228838311E-02-3.892147630E-01-7.996606775E-01
-1.251293437E+00-1.735337138E+00-2.234898256E+00-2.723655399E+00-3.165365399E+00
-3.514741855E+00-3.720293832E+00-3.729611788E+00-3.497292139E+00-2.995154781E+00
-2.223629545E+00-1.222250664E+00-7.630060271E-02 1.083890305E+00 2.094237915E+00
5.887371279E-01 2.957381914E-01-3.336989801E-02-4.042696576E-01-8.194487014E-01
-1.276623310E+00-1.767002017E+00-2.273586775E+00-2.769836332E+00-3.219148153E+00
-3.575721206E+00-3.787395338E+00-3.800963568E+00-3.570157560E+00-3.065966683E+00
-2.288166411E+00-1.275984954E+00-1.149259009E-01 1.063784750E+00 2.094426631E+00
5.887371279E-01 2.957381914E-01-3.336989801E-02-4.042696576E-01-8.194487014E-01
-1.276623310E+00-1.767002017E+00-2.273586775E+00-2.769836332E+00-3.219148153E+00
-3.575721206E+00-3.787395338E+00-3.800963568E+00-3.570157560E+00-3.065966683E+00
-2.288166411E+00-1.275984954E+00-1.149259009E-01 1.063784750E+00 2.094426631E+00
5.937469493E-01 3.035125582E-01-2.228838311E-02-3.892147630E-01-7.996606775E-01
-1.251293437E+00-1.735337138E+00-2.234898256E+00-2.723655399E+00-3.165365399E+00
-3.514741855E+00-3.720293832E+00-3.729611788E+00-3.497292139E+00-2.995154781E+00
-2.223629545E+00-1.222250664E+00-7.630060271E-02 1.083890305E+00 2.094237915E+00
6.036871942E-01 3.188526756E-01-4.670925182E-04-3.595932281E-01-7.607407379E-01
-1.201485317E+00-1.673086529E+00-2.158861549E+00-2.632926762E+00-3.059751018E+00
-3.395064527E+00-3.588695197E+00-3.589801388E+00-3.354675138E+00-2.856758537E+00
-2.097750017E+00-1.117760284E+00-1.606164268E-03 1.122175768E+00 2.092746840E+00
6.183787457E-01 3.413326511E-01 3.141219456E-02-3.163699380E-01-7.039792622E-01
-1.128869268E+00-1.582363062E+00-2.048097697E+00-2.500841167E+00-2.906113655E+00
-3.221139041E+00-3.397675320E+00-3.387166510E+00-3.148365134E+00-2.657051631E+00
-1.916729591E+00-9.682880687E-01 1.042108382E-01 1.174925970E+00 2.087819678E+00
6.375053763E-01 3.702941358E-01 7.233227099E-02-2.609627702E-01-6.312576177E-01
-1.035869585E+00-1.466224516E+00-1.906392149E+00-2.331999433E+00-2.709937370E+00
-2.999364174E+00-3.154523523E+00-3.129786863E+00-2.887037341E+00-2.405002017E+00
-1.689415837E+00-7.820514975E-01 2.341342187E-01 1.236899458E+00 2.076483242E+00
6.605654332E-01 4.048286553E-01 1.209502842E-01-1.952062579E-01-5.449842404E-01
-9.255704167E-01-1.328545300E+00-1.738527527E+00-2.132201008E+00-2.478121003E+00
-2.737773949E+00-2.868374135E+00-2.827766422E+00-2.581516128E+00-2.111771066E+00
-1.426787661E+00-5.692100125E-01 3.795334026E-01 1.301701384E+00 2.055179962E+00
6.868209862E-01 4.437629001E-01 1.756156706E-01-1.213017723E-01-4.480113960E-01
-8.015956403E-01-1.173854475E+00-1.550073727E+00-1.908179626E+00-2.218653210E+00
-2.445647332E+00-2.549748880E+00-2.492710924E+00-2.244196046E+00-1.790094098E+00
-1.141319885E+00-3.412468720E-01 5.307237428E-01 1.362241297E+00 2.020079621E+00
7.152541434E-01 4.856531808E-01 2.343995042E-01-4.175359515E-02-3.435345212E-01
-6.679672634E-01-1.007147349E+00-1.347145717E+00-1.667299880E+00-1.940240855E+00
-2.133063162E+00-2.210036310E+00-2.137134706E+00-1.888385838E+00-1.453579841E+00
-8.462660998E-01-1.102730351E-01 6.775958354E-01 1.411245424E+00 1.967425855E+00
7.445404658E-01 5.287952464E-01 2.951382949E-01 4.070929804E-02-2.349767287E-01
-5.289477637E-01-8.336791693E-01-1.136141025E+00-1.417230568E+00-1.651910893E+00
-1.810425157E+00-1.860937968E+00-1.773831419E+00-1.527614344E+00-1.115971166E+00
-5.549039664E-01 1.117031538E-01 8.102732738E-01 1.441789269E+00 1.893892967E+00
7.730484943E-01 5.712548386E-01 3.554945030E-01 1.232251820E-01-1.258618115E-01
-3.888726160E-01-6.587503270E-01-9.234698604E-01-1.165611778E+00-1.362607208E+00
-1.487983287E+00-1.513912701E+00-1.415245061E+00-1.174939292E+00-7.904115839E-01
-2.797893042E-01 3.134946132E-01 9.197564239E-01 1.447814952E+00 1.796927636E+00
7.988723691E-01 6.109227609E-01 4.130347848E-01 2.029036972E-01-1.967987208E-02
-2.519798567E-01-4.874929551E-01-7.152912061E-01-9.197329238E-01-1.080803941E+00
-1.175377832E+00-1.179650378E+00-1.072877456E+00-8.422994956E-01-4.887614330E-01
-3.206461911E-02 4.853974608E-01 9.985106689E-01 1.424598500E+00 1.675050854E+00
8.199015377E-01 6.455959983E-01 4.653253241E-01 2.769394057E-01 8.024954100E-02
-1.222439302E-01-3.246688374E-01-5.172678502E-01-6.862382215E-01-8.141557599E-01
-8.812308347E-01-8.676042109E-01-7.567658125E-01-5.399480748E-01-2.210043304E-01
1.791358869E-01 6.197548661E-01 1.040961106E+00 1.369135452E+00 1.528097841E+00
8.339278564E-01 6.730837162E-01 5.100416932E-01 3.427308098E-01 1.709112396E-01
-3.221170684E-03-1.744881056E-01-3.343523364E-01-4.708744696E-01-5.692032028E-01
-6.128066860E-01-5.856071769E-01-4.750595001E-01-2.759990290E-01 5.221341658E-03
3.471489908E-01 7.113877498E-01 1.043861665E+00 1.280418325E+00 1.357377573E+00
8.387863256E-01 6.913340506E-01 5.450887024E-01 3.979996591E-01 2.497191168E-01
1.020859215E-01-4.045731398E-02-1.706141808E-01-2.782935795E-01-3.511479324E-01
-3.757593010E-01-3.395926987E-01-2.337188599E-01-5.611233175E-02 1.849391381E-01
4.680854372E-01 7.578657830E-01 1.006514653E+00 1.159586428E+00 1.165738769E+00
8.325216321E-01 6.985747478E-01 5.687238375E-01 4.409043702E-01 3.146255305E-01
1.913389993E-01 7.473585748E-02-2.911651568E-02-1.119191647E-01-1.637085739E-01
-1.739780585E-01-1.334333429E-01-3.635127414E-02 1.166660483E-01 3.159822862E-01
5.409560343E-01 7.596023466E-01 9.308263465E-01 1.009936725E+00 9.575352010E-01
8.135690035E-01 6.934582174E-01 5.796763578E-01 4.701407046E-01 3.642092103E-01
2.629430672E-01 1.692957439E-01 8.815231453E-02 2.611713847E-02-9.063055012E-03
-9.538719707E-03 3.109598996E-02 1.158088422E-01 2.419024963E-01 3.989659604E-01
5.676148854E-01 7.197683473E-01 8.211947470E-01 8.367934603E-01 7.384898454E-01
7.809349798E-01 6.751996950E-01 5.772531276E-01 4.850226141E-01 3.977360480E-01
3.160900969E-01 2.423462144E-01 1.802896324E-01 1.349679043E-01 1.121217192E-01
1.172407810E-01 1.542315062E-01 2.237783488E-01 3.216158548E-01 4.370886419E-01
5.525253624E-01 6.440313440E-01 6.842364433E-01 6.472434068E-01 5.154640263E-01
7.343619131E-01 6.436962062E-01 5.614219261E-01 4.855364655E-01 4.151880501E-01
3.507641660E-01 2.939113975E-01 2.474323310E-01 2.149930564E-01 2.005771397E-01
2.076460507E-01 2.380192080E-01 2.905729286E-01 3.599724996E-01 4.357778205E-01
5.023656375E-01 5.401375751E-01 5.283698530E-01 4.497523801E-01 2.961440598E-01
6.744595449E-01 5.996140461E-01 5.328634336E-01 4.723627302E-01 4.172570594E-01
3.677070698E-01 3.248508780E-01 2.906574776E-01 2.676201889E-01 2.582462461E-01
2.643256985E-01 2.860143822E-01 3.208428141E-01 3.628585676E-01 4.022050156E-01
4.255007017E-01 4.173644838E-01 3.632813892E-01 2.536864244E-01 8.866344730E-02
6.027880359E-01 5.444336242E-01 4.929843721E-01 4.468606903E-01 4.053015659E-01
3.683453893E-01 3.367530737E-01 3.118362535E-01 2.951519289E-01 2.880365841E-01
2.909818720E-01 3.029033791E-01 3.204224066E-01 3.373590566E-01 3.447032023E-01
3.313561860E-01 2.858795818E-01 1.993086623E-01 6.876738196E-02-9.881690647E-02
1.000000000E+00 1.050035307E+00 1.107285429E+00 1.171072127E+00 1.241305586E+00
1.318263580E+00 1.405184527E+00 1.505114754E+00 1.616506900E+00 1.730427615E+00
1.891151823E+00 2.065212169E+00 2.268460038E+00 2.512075631E+00 2.811055433E+00
3.186196537E+00 3.671181078E+00 4.326097962E+00 5.264420087E+00 6.784828742E+00
60 11
1.400000000E+00 0.000000000E+00 1.397733920E+00 8.503478852E-02 1.390961356E+00
1.691060989E-01 1.379759043E+00 2.512613696E-01 1.364253909E+00 3.305697486E-01
1.344621633E+00 4.061326403E-01 1.321084655E+00 4.770938868E-01 1.293909660E+00
5.426494690E-01 1.263404552E+00 6.020566159E-01 1.229914964E+00 6.546422207E-01
1.193820348E+00 6.998104676E-01 1.155529670E+00 7.370495823E-01 1.115476779E+00
7.659376307E-01 1.074115490E+00 7.861472997E-01 1.031914442E+00 7.974496056E-01
9.893517914E-01 7.997164889E-01 9.469097891E-01 7.929222648E-01 9.050693201E-01
7.771439146E-01 8.643044536E-01 7.525602133E-01 8.250770718E-01 7.194497041E-01
7.878316368E-01 6.781875423E-01 7.529901540E-01 6.292412446E-01 7.209473915E-01
5.731653922E-01 6.920664066E-01 5.105953469E-01 6.666744324E-01 4.422400523E-01
6.450591700E-01 3.688740012E-01 6.274655290E-01 2.913284602E-01 6.140928525E-01
2.104820514E-01 6.050926581E-01 1.272507968E-01 6.005669217E-01 4.257773987E-02
6.005669217E-01-4.257773987E-02 6.050926581E-01-1.272507968E-01 6.140928525E-01
-2.104820514E-01 6.274655290E-01-2.913284602E-01 6.450591700E-01-3.688740012E-01
6.666744324E-01-4.422400523E-01 6.920664066E-01-5.105953469E-01 7.209473915E-01
-5.731653922E-01 7.529901540E-01-6.292412446E-01 7.878316368E-01-6.781875423E-01
8.250770718E-01-7.194497041E-01 8.643044536E-01-7.525602133E-01 9.050693201E-01
-7.771439146E-01 9.469097891E-01-7.929222648E-01 9.893517914E-01-7.997164889E-01
1.031914442E+00-7.974496056E-01 1.074115490E+00-7.861472997E-01 1.115476779E+00
-7.659376307E-01 1.155529670E+00-7.370495823E-01 1.193820348E+00-6.998104676E-01
1.229914964E+00-6.546422207E-01 1.263404552E+00-6.020566159E-01 1.293909660E+00
-5.426494690E-01 1.321084655E+00-4.770938868E-01 1.344621633E+00-4.061326403E-01
1.364253909E+00-3.305697486E-01 1.379759043E+00-2.512613696E-01 1.390961356E+00
-1.691060989E-01 1.397733920E+00-8.503478852E-02 1.400000000E+00-1.959434879E-16
5.200000000E-01 0.000000000E+00 5.800000000E-01-6.000000000E-01 5.500000000E-01-9.000000000E-01 1.250000000E+00-9.000000000E-01 1.400000000E+00-6.000000000E-01 1.480000000E+00 0.000000000E+00 1.400000000E+00 6.000000000E-01 1.250000000E+00 9.000000000E-01 5.500000000E-01 9.000000000E-01 5.800000000E-01 6.000000000E-01 5.200000000E-01 0.000000000E+00
+826
View File
@@ -0,0 +1,826 @@
// 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 <limits>
#include "plasma.hpp"
#include "g_eqdsk_data.hpp"
using namespace std;
namespace mfem
{
namespace plasma
{
G_EQDSK_Data::G_EQDSK_Data(istream &is, int logging)
: logging_(logging), init_flag_(0)
{
/// The following file format is taken from the C-Mod Wiki at
/// https://cmodwiki.psfc.mit.edu/index.php/G_EQDSK
real_t XDUM = 0.0;
const int buflen = 1024;
char buf[buflen];
is.getline(buf, buflen);
istringstream iss(buf);
string word;
iss >> std::ws;
while (!iss.eof())
{
iss >> word;
CASE_.push_back(word);
iss >> std::ws;
}
NW_ = to_int(CASE_[CASE_.size()-2]);
NH_ = to_int(CASE_[CASE_.size()-1]);
is >> RDIM_ >> ZDIM_ >> RCENTR_ >> RLEFT_ >> ZMID_;
is >> RMAXIS_ >> ZMAXIS_ >> SIMAG_ >> SIBRY_ >> BCENTR_;
is >> CURRENT_ >> SIMAG_ >> XDUM >> RMAXIS_ >> XDUM;
is >> ZMAXIS_ >> XDUM >> SIBRY_ >> XDUM >> XDUM;
FPOL_.resize(NW_);
PRES_.resize(NW_);
FFPRIM_.resize(NW_);
PPRIME_.resize(NW_);
PSIRZ_.resize(NW_ * NH_);
QPSI_.resize(NW_);
for (int i=0; i<NW_; i++) { is >> FPOL_[i]; }
for (int i=0; i<NW_; i++) { is >> PRES_[i]; }
for (int i=0; i<NW_; i++) { is >> FFPRIM_[i]; }
for (int i=0; i<NW_; i++) { is >> PPRIME_[i]; }
for (int j=0; j<NH_; j++)
{
for (int i=0; i<NW_; i++)
{
is >> PSIRZ_[NH_ * i + j];
}
}
for (int i=0; i<NW_; i++) { is >> QPSI_[i]; }
is >> NBBBS_ >> LIMITR_;
RBBBS_.resize(NBBBS_);
ZBBBS_.resize(NBBBS_);
RLIM_.resize(LIMITR_);
ZLIM_.resize(LIMITR_);
for (int i=0; i<NBBBS_; i++) { is >> RBBBS_[i] >> ZBBBS_[i]; }
for (int i=0; i<LIMITR_; i++) { is >> RLIM_[i] >> ZLIM_[i]; }
if (logging_ > 0) { checkPsiBoundary(); }
dr_ = RDIM_ / (NW_ - 1);
dz_ = ZDIM_ / (NH_ - 1);
dpsi_ = (SIBRY_ - SIMAG_) / (NW_ - 1);
}
void G_EQDSK_Data::PrintInfo(ostream & out) const
{
out << endl << "G EQDSK File Info:" << endl;
out << "Size of grid: " << NW_ << " x " << NH_ << endl;
out << "Number of boundary points: " << NBBBS_ << endl;
out << "Number of limiter points: " << LIMITR_ << endl;
out << endl;
out << "Range of R: " << RLEFT_ << " -> " << RLEFT_ + RDIM_ << endl;
out << "Range of Z: " << ZMID_ - 0.5 * ZDIM_
<< " -> " << ZMID_ + 0.5 * ZDIM_ << endl;
out << "Location of magnetic axis: "
<< "(" << RMAXIS_ << "," << ZMAXIS_ << ")" << endl;
out << "Poloidal flux at magnetic axis: " << SIMAG_ << endl;
out << "Poloidal flux at plasma boundary: " << SIBRY_ << endl;
out << "R in meter of vacuum toroidal magnetic field BCENTR: "
<< RCENTR_ << endl;
out << "Vacuum toroidal magnetic field in Tesla at RCENTR: "
<< BCENTR_ << endl;
out << "Plasma current in Ampere: " << CURRENT_ << endl << endl;
}
void G_EQDSK_Data::DumpGnuPlotData(const string &file) const
{
real_t fmin = std::numeric_limits<real_t>::max();
real_t fmax = -std::numeric_limits<real_t>::max();
real_t pmin = std::numeric_limits<real_t>::max();
real_t pmax = -std::numeric_limits<real_t>::max();
real_t ffmin = std::numeric_limits<real_t>::max();
real_t ffmax = -std::numeric_limits<real_t>::max();
real_t ppmin = std::numeric_limits<real_t>::max();
real_t ppmax = -std::numeric_limits<real_t>::max();
real_t qmin = std::numeric_limits<real_t>::max();
real_t qmax = -std::numeric_limits<real_t>::max();
ostringstream oss_dat, oss_inp;
oss_inp << file << ".inp";
oss_dat << file << ".dat";
ofstream ofs_inp(oss_inp.str().c_str());
ofstream ofs_dat(oss_dat.str().c_str());
for (int i=0; i<NW_; i++)
{
ofs_dat << real_t(i) / (NW_ - 1)
<< '\t' << FPOL_[i]
<< '\t' << PRES_[i]
<< '\t' << FFPRIM_[i]
<< '\t' << PPRIME_[i]
<< '\t' << QPSI_[i]
<< '\n';
fmin = min(FPOL_[i], fmin);
fmax = max(FPOL_[i], fmax);
pmin = min(PRES_[i], pmin);
pmax = max(PRES_[i], pmax);
ffmin = min(FFPRIM_[i], ffmin);
ffmax = max(FFPRIM_[i], ffmax);
ppmin = min(PPRIME_[i], ppmin);
ppmax = max(PPRIME_[i], ppmax);
qmin = min(QPSI_[i], qmin);
qmax = max(QPSI_[i], qmax);
}
ofs_dat << "\n\n";
for (int i=0; i<NW_; i++)
{
for (int j=0; j<NH_; j++)
{
ofs_dat << RLEFT_ + RDIM_ * i / (NW_ - 1)
<< '\t' << ZMID_ - 0.5 * ZDIM_ + ZDIM_ * j / (NH_ - 1)
<< '\t' << PSIRZ_[NH_ * i + j]
<< '\n';
}
ofs_dat << '\n';
}
ofs_dat << "\n\n";
for (int i=0; i<NBBBS_; i++)
{
ofs_dat << RBBBS_[i] << '\t' << ZBBBS_[i] << '\n';
}
ofs_dat << "\n\n";
for (int i=0; i<LIMITR_; i++)
{
ofs_dat << RLIM_[i] << '\t' << ZLIM_[i] << '\n';
}
ofs_dat.close();
ofs_inp << "set xrange [0:1];\n";
ofs_inp << "set yrange [" << fmin << ":" << fmax << "];\n";
ofs_inp << "plot '" << oss_dat.str()
<< "' index 0 using 1:2 w l t 'FPOL';\n";
ofs_inp << "pause -1;\n";
ofs_inp << "set yrange [" << pmin << ":" << pmax << "];\n";
ofs_inp << "plot '" << oss_dat.str()
<< "' index 0 using 1:3 w l t 'PRES';\n";
ofs_inp << "pause -1;\n";
ofs_inp << "set yrange [" << ffmin << ":" << ffmax << "];\n";
ofs_inp << "plot '" << oss_dat.str()
<< "' index 0 using 1:4 w l t 'FFPRIME';\n";
ofs_inp << "pause -1;\n";
ofs_inp << "set yrange [" << ppmin << ":" << ppmax << "];\n";
ofs_inp << "plot '" << oss_dat.str()
<< "' index 0 using 1:5 w l t 'PPRIME';\n";
ofs_inp << "pause -1;\n";
ofs_inp << "set yrange [" << qmin << ":" << qmax << "];\n";
ofs_inp << "plot '" << oss_dat.str()
<< "' index 0 using 1:6 w l t 'QPSI';\n";
ofs_inp << "pause -1;\n";
ofs_inp << "unset xrange\n";
ofs_inp << "unset yrange\n";
ofs_inp << "set view map;\n";
ofs_inp << "unset surface;\n";
ofs_inp << "set contour base;\n";
ofs_inp << "set cntrparam levels 20;\n";
ofs_inp << "set size ratio -1;\n";
ofs_inp << "set nokey;\n";
ofs_inp << "splot '" << oss_dat.str()
<< "' index 1 with lines pal t 'PSIRZ';\n";
ofs_inp << "set key;\n";
ofs_inp << "pause -1;\n";
ofs_inp << "set size ratio -1;\n";
ofs_inp << "plot '" << oss_dat.str()
<< "' index 2 using 1:2 w l t 'BOUNDARY',";
ofs_inp << " '" << oss_dat.str()
<< "' index 3 using 1:2 w l t 'LIMITER';\n";
ofs_inp.close();
}
void G_EQDSK_Data::checkPsiBoundary()
{
real_t psi_avg = 0.0;
real_t psi_dif = 0.0;
real_t psi_min = std::numeric_limits<real_t>::max();
real_t psi_max = std::numeric_limits<real_t>::min();
Vector rz(2);
real_t psi = 0.0;
for (int i=0; i<NBBBS_; i++)
{
rz[0] = RBBBS_[i];
rz[1] = ZBBBS_[i];
psi = this->InterpPsiRZ(rz);
psi_min = std::min(psi, psi_min);
psi_max = std::max(psi, psi_max);
psi_avg += psi;
psi_dif += abs(psi - SIBRY_);
}
psi_avg /= NBBBS_;
psi_dif /= NBBBS_;
if (logging_ > 1)
{
mfem::out << psi_min << " <= (Psi on plasma boundary) <= "
<< psi_max << endl;
mfem::out << "Average of Psi on plasma boundary: " << psi_avg << endl;
mfem::out << "Average of |Psi - SIBRY| on plasma boundary: "
<< psi_dif << endl;
}
MFEM_VERIFY(psi_dif < 1e-2 * abs(SIMAG_), "Psi differs from its imposed "
"boundary value more than expected.");
}
real_t G_EQDSK_Data::InterpFPolRZ(const Vector &rz)
{
real_t psi = InterpPsiRZ(rz);
if (!checkFlag(FPOL))
{
initInterpPsi(FPOL_, FPOL_t_);
setFlag(FPOL);
}
return interpPsi(psi, FPOL_, FPOL_t_);
}
real_t G_EQDSK_Data::InterpPresRZ(const Vector &rz)
{
real_t psi = InterpPsiRZ(rz);
if (!checkFlag(PRES))
{
initInterpPsi(PRES_, PRES_t_);
setFlag(PRES);
}
return interpPsi(psi, PRES_, PRES_t_);
}
real_t G_EQDSK_Data::InterpFFPrimeRZ(const Vector &rz)
{
real_t psi = InterpPsiRZ(rz);
if (!checkFlag(FFPRIM))
{
initInterpPsi(FFPRIM_, FFPRIM_t_);
setFlag(FFPRIM);
}
return interpPsi(psi, FFPRIM_, FFPRIM_t_);
}
real_t G_EQDSK_Data::InterpPPrimeRZ(const Vector &rz)
{
real_t psi = InterpPsiRZ(rz);
if (!checkFlag(PPRIME))
{
initInterpPsi(PPRIME_, PPRIME_t_);
setFlag(PPRIME);
}
return interpPsi(psi, PPRIME_, PPRIME_t_);
}
real_t G_EQDSK_Data::InterpPsiRZ(const Vector &rz)
{
if (!checkFlag(PSIRZ))
{
initInterpRZ(PSIRZ_, PSIRZ_c_, PSIRZ_d_, PSIRZ_e_);
setFlag(PSIRZ);
}
return interpRZ(rz, PSIRZ_, PSIRZ_c_, PSIRZ_d_, PSIRZ_e_);
}
real_t G_EQDSK_Data::InterpQRZ(const Vector &rz)
{
real_t psi = InterpPsiRZ(rz);
if (!checkFlag(QPSI))
{
initInterpPsi(QPSI_, QPSI_t_);
setFlag(QPSI);
}
return interpPsi(psi, QPSI_, QPSI_t_);
}
void G_EQDSK_Data::InterpNxGradPsiRZ(const Vector &rz, Vector &nxdp)
{
if (!checkFlag(PSIRZ))
{
initInterpRZ(PSIRZ_, PSIRZ_c_, PSIRZ_d_, PSIRZ_e_);
setFlag(PSIRZ);
}
interpNxGradRZ(rz, PSIRZ_, PSIRZ_c_, PSIRZ_d_, PSIRZ_e_, nxdp);
}
void G_EQDSK_Data::InterpBPolRZ(const Vector &rz, Vector &bpol)
{
InterpNxGradPsiRZ(rz, bpol);
if (rz[0] > 1e-6 * RDIM_) { bpol /= rz[0]; }
}
real_t G_EQDSK_Data::InterpBTorRZ(const Vector &rz)
{
if (rz[0] > 1e-6 * RDIM_)
{
return InterpFPolRZ(rz) / rz[0];
}
else
{
return 0.0;
}
}
real_t G_EQDSK_Data::InterpJTorRZ(const Vector &rz)
{
if (rz[0] > 1e-6 * RDIM_)
{
return InterpPPrimeRZ(rz) * rz[0] +
InterpFFPrimeRZ(rz) / rz[0] / mu0_;
}
else
{
return 0.0;
}
}
void G_EQDSK_Data::initInterpRZ(const std::vector<real_t> &v,
ShiftedDenseMatrix &c,
ShiftedDenseMatrix &d,
ShiftedDenseMatrix &e)
{
ExtendedDenseMatrix ve(&v[0], NW_, NH_);
c.SetSize(NW_ + 3, NH_ + 2); c.SetShifts(2, 1); c = 0.0;
d.SetSize(NW_ + 2, NH_ + 3); d.SetShifts(1, 2); d = 0.0;
e.SetSize(NW_ + 1, NH_ + 1); e.SetShifts(1, 1); e = 0.0;
// x-directed divided differences
for (int i=-1; i<NW_; i++)
{
c(i,-1) = (ve(i+1,-1) - ve(i,-1)) / dr_;
}
for (int j=0; j<NH_; j++)
{
for (int i=-2; i<=NW_; i++)
{
c(i,j) = (ve(i+1,j) - ve(i,j)) / dr_;
}
}
for (int i=-1; i<NW_; i++)
{
c(i,NH_) = (ve(i+1,NH_) - ve(i,NH_)) / dr_;
}
// y-directed divided differences
for (int j=-1; j<NH_; j++)
{
d(-1,j) = (ve(-1,j+1) - ve(-1,j)) / dz_;
}
for (int i=0; i<NW_; i++)
{
for (int j=-2; j<=NH_; j++)
{
d(i,j) = (ve(i,j+1) - ve(i,j)) / dz_;
}
}
for (int j=-1; j<NH_; j++)
{
d(NW_,j) = (ve(NW_,j+1) - ve(NW_,j)) / dz_;
}
// Second order divided differences
for (int i=-1; i<NW_; i++)
{
for (int j=-1; j<NH_; j++)
{
e(i,j) = (c(i,j+1) - c(i,j)) / dz_;
}
}
}
real_t G_EQDSK_Data::interpRZ(const Vector &rz,
const std::vector<real_t> &v,
const ShiftedDenseMatrix &c,
const ShiftedDenseMatrix &d,
const ShiftedDenseMatrix &e)
{
real_t r = rz[0];
real_t z = rz[1];
real_t rs = (r - RLEFT_) / RDIM_;
real_t zs = (z - ZMID_ + 0.5 * ZDIM_) / ZDIM_;
int i = std::max(0, std::min((int)floor(real_t(NW_-1) * rs), NW_-2));
int j = std::max(0, std::min((int)floor(real_t(NH_-1) * zs), NH_-2));
// Compute corners of local patch
real_t r0 = RLEFT_ + RDIM_ * i / (NW_ - 1);
real_t r1 = r0 + RDIM_ / (NW_ - 1);
real_t z0 = ZMID_ - 0.5 * ZDIM_ + ZDIM_ * j / (NH_ - 1);
real_t z1 = z0 + ZDIM_ / (NH_ - 1);
// Prepare position dependent factors
real_t wra = (r1 - r) / dr_;
real_t wrb = (r - r0) / dr_;
real_t wrc = (1.0 + 2.0 * wra);
real_t wrd = (1.0 + 2.0 * wrb);
real_t wra2 = wra * wra;
real_t wrb2 = wrb * wrb;
real_t wza = (z1 - z) / dz_;
real_t wzb = (z - z0) / dz_;
real_t wzc = (1.0 + 2.0 * wza);
real_t wzd = (1.0 + 2.0 * wzb);
real_t wza2 = wza * wza;
real_t wzb2 = wzb * wzb;
// Extract variable values at corners of local patch
real_t p00 = v[NH_ * i + j];
real_t p10 = v[NH_ * (i + 1) + j];
real_t p01 = v[NH_ * i + j + 1];
real_t p11 = v[NH_ * (i + 1) + j + 1];
real_t var = p00 * wra2 * wrd * wza2 * wzd
+ p10 * wrb2 * wrc * wza2 * wzd
+ p01 * wra2 * wrd * wzb2 * wzc
+ p11 * wrb2 * wrc * wzb2 * wzc;
// Compute dvar/dx at corners of local patch
real_t wx00a = fabs(c(i-1,j) - c(i-2,j));
real_t wx00b = fabs(c(i+1,j) - c(i,j));
real_t wx10a = fabs(c(i,j) - c(i-1,j));
real_t wx10b = fabs(c(i+2,j) - c(i+1,j));
real_t wx01a = fabs(c(i-1,j+1) - c(i-2,j+1));
real_t wx01b = fabs(c(i+1,j+1) - c(i,j+1));
real_t wx11a = fabs(c(i,j+1) - c(i-1,j+1));
real_t wx11b = fabs(c(i+2,j+1) - c(i+1,j+1));
if (wx00a == 0.0 && wx00b == 0.0) { wx00a = 1.0; wx00b = 1.0; }
if (wx10a == 0.0 && wx10b == 0.0) { wx10a = 1.0; wx10b = 1.0; }
if (wx01a == 0.0 && wx01b == 0.0) { wx01a = 1.0; wx01b = 1.0; }
if (wx11a == 0.0 && wx11b == 0.0) { wx11a = 1.0; wx11b = 1.0; }
real_t px00 = (wx00b * c(i-1,j) + wx00a * c(i,j)) / (wx00b + wx00a);
real_t px10 = (wx10b * c(i,j) + wx10a * c(i+1,j)) / (wx10b + wx10a);
real_t px01 = (wx01b * c(i-1,j+1) + wx01a * c(i,j+1)) / (wx01b + wx01a);
real_t px11 = (wx11b * c(i,j+1) + wx11a * c(i+1,j+1)) / (wx11b + wx11a);
real_t varx = px00 * wra2 * wrb * wza2 * wzd
- px10 * wrb2 * wra * wza2 * wzd
+ px01 * wrb * wra2 * wzb2 * wzc
- px11 * wra * wrb2 * wzb2 * wzc;
var += varx * dr_;
// Compute dvar/dy at corners of local patch
real_t wy00a = fabs(d(i,j-1) - d(i,j-2));
real_t wy00b = fabs(d(i,j+1) - d(i,j));
real_t wy10a = fabs(d(i+1,j-1) - d(i+1,j-2));
real_t wy10b = fabs(d(i+1,j+1) - d(i+1,j));
real_t wy01a = fabs(d(i,j) - d(i,j-1));
real_t wy01b = fabs(d(i,j+2) - d(i,j+1));
real_t wy11a = fabs(d(i+1,j) - d(i+1,j-1));
real_t wy11b = fabs(d(i+1,j+2) - d(i+1,j+1));
if (wy00a == 0.0 && wy00b == 0.0) { wy00a = 1.0; wy00b = 1.0; }
if (wy10a == 0.0 && wy10b == 0.0) { wy10a = 1.0; wy10b = 1.0; }
if (wy01a == 0.0 && wy01b == 0.0) { wy01a = 1.0; wy01b = 1.0; }
if (wy11a == 0.0 && wy11b == 0.0) { wy11a = 1.0; wy11b = 1.0; }
real_t py00 = (wy00b * d(i,j-1) + wy00a * d(i,j)) / (wy00b + wy00a);
real_t py10 = (wy10b * d(i+1,j-1) + wy10a * d(i+1,j)) / (wy10b + wy10a);
real_t py01 = (wy01b * d(i,j) + wy01a * d(i,j+1)) / (wy01b + wy01a);
real_t py11 = (wy11b * d(i+1,j) + wy11a * d(i+1,j)) / (wy11b + wy11a);
real_t vary = py00 * wra2 * wrd * wza2 * wzb
+ py10 * wrb2 * wrc * wza2 * wzb
- py01 * wra2 * wrd * wza * wzb2
- py11 * wrb2 * wrc * wza * wzb2;
var += vary * dz_;
// Compute d^2var/dxdy at corners of local patch
real_t pxy00 = (wx00b * (wy00b * e(i-1,j-1) + wy00a * e(i-1,j)) +
wx00a * (wy00b * e(i,j-1) + wy00a * e(i,j))) /
((wx00b + wx00a) * (wy00b + wy00a));
real_t pxy10 = (wx10b * (wy10b * e(i,j-1) + wy10a * e(i,j)) +
wx10a * (wy10b * e(i+1,j-1) + wy10a * e(i+1,j))) /
((wx10b + wx10a) * (wy10b + wy10a));
real_t pxy01 = (wx01b * (wy01b * e(i-1,j) + wy01a * e(i-1,j+1)) +
wx01a * (wy01b * e(i,j) + wy01a * e(i,j+1))) /
((wx01b + wx01a) * (wy01b + wy01a));
real_t pxy11 = (wx11b * (wy11b * e(i,j) + wy11a * e(i,j+1)) +
wx11a * (wy11b * e(i+1,j) + wy11a * e(i+1,j+1))) /
((wx11b + wx11a) * (wy11b + wy11a));
real_t varxy = pxy00 * wra2 * wrb * wza2 * wzb
- pxy10 * wra * wrb2 * wza2 * wzb
- pxy01 * wra2 * wrb * wza * wzb2
+ pxy11 * wra * wrb2 * wza * wzb2;
var += dr_ * dz_ * varxy;
return var;
}
void G_EQDSK_Data::interpNxGradRZ(const Vector &rz,
const std::vector<real_t> &v,
const ShiftedDenseMatrix &c,
const ShiftedDenseMatrix &d,
const ShiftedDenseMatrix &e,
Vector &b)
{
b.SetSize(2);
b = 0.0;
real_t r = rz[0];
real_t z = rz[1];
real_t rs = (r - RLEFT_) / RDIM_;
real_t zs = (z - ZMID_ + 0.5 * ZDIM_) / ZDIM_;
int i = std::max(0, std::min((int)floor(real_t(NW_-1) * rs), NW_-2));
int j = std::max(0, std::min((int)floor(real_t(NH_-1) * zs), NH_-2));
// Compute corners of local patch
real_t r0 = RLEFT_ + RDIM_ * i / (NW_ - 1);
real_t r1 = r0 + RDIM_ / (NW_ - 1);
real_t z0 = ZMID_ - 0.5 * ZDIM_ + ZDIM_ * j / (NH_ - 1);
real_t z1 = z0 + ZDIM_ / (NH_ - 1);
// Prepare position dependent factors
real_t wra = (r1 - r) / dr_, dwra = -1.0 / dr_;
real_t wrb = (r - r0) / dr_, dwrb = 1.0 / dr_;
real_t wrc = (1.0 + 2.0 * wra), dwrc = 2.0 * dwra;
real_t wrd = (1.0 + 2.0 * wrb), dwrd = 2.0 * dwrb;
real_t wra2 = wra * wra, dwra2 = 2.0 * wra * dwra;
real_t wrb2 = wrb * wrb, dwrb2 = 2.0 * wrb * dwrb;
real_t wza = (z1 - z) / dz_, dwza = -1.0 / dz_;
real_t wzb = (z - z0) / dz_, dwzb = 1.0 / dz_;
real_t wzc = (1.0 + 2.0 * wza), dwzc = 2.0 * dwza;
real_t wzd = (1.0 + 2.0 * wzb), dwzd = 2.0 * dwzb;
real_t wza2 = wza * wza, dwza2 = 2.0 * wza * dwza;
real_t wzb2 = wzb * wzb, dwzb2 = 2.0 * wzb * dwzb;
// Extract var values at corners of local patch
real_t p00 = v[NH_ * i + j];
real_t p10 = v[NH_ * (i + 1) + j];
real_t p01 = v[NH_ * i + j + 1];
real_t p11 = v[NH_ * (i + 1) + j + 1];
b[0] -=
(p00 * wra2 * wrd + p10 * wrb2 * wrc ) * (dwza2 * wzd + wza2 * dwzd)
+ (p01 * wra2 * wrd + p11 * wrb2 * wrc) * (dwzb2 * wzc + wzb2 * dwzc);
b[1] +=
(p00 * wza2 * wzd + p01 * wzb2 * wzc) * (dwra2 * wrd + wra2 * dwrd)
+ (p10 * wza2 * wzd + p11 * wzb2 * wzc) * (dwrb2 * wrc + wrb2 * dwrc);
// Compute dvar/dx at corners of local patch
real_t wx00a = fabs(c(i-1,j) - c(i-2,j));
real_t wx00b = fabs(c(i+1,j) - c(i,j));
real_t wx10a = fabs(c(i,j) - c(i-1,j));
real_t wx10b = fabs(c(i+2,j) - c(i+1,j));
real_t wx01a = fabs(c(i-1,j+1) - c(i-2,j+1));
real_t wx01b = fabs(c(i+1,j+1) - c(i,j+1));
real_t wx11a = fabs(c(i,j+1) - c(i-1,j+1));
real_t wx11b = fabs(c(i+2,j+1) - c(i+1,j+1));
if (wx00a == 0.0 && wx00b == 0.0) { wx00a = 1.0; wx00b = 1.0; }
if (wx10a == 0.0 && wx10b == 0.0) { wx10a = 1.0; wx10b = 1.0; }
if (wx01a == 0.0 && wx01b == 0.0) { wx01a = 1.0; wx01b = 1.0; }
if (wx11a == 0.0 && wx11b == 0.0) { wx11a = 1.0; wx11b = 1.0; }
real_t px00 = (wx00b * c(i-1,j) + wx00a * c(i,j)) / (wx00b + wx00a);
real_t px10 = (wx10b * c(i,j) + wx10a * c(i+1,j)) / (wx10b + wx10a);
real_t px01 = (wx01b * c(i-1,j+1) + wx01a * c(i,j+1)) / (wx01b + wx01a);
real_t px11 = (wx11b * c(i,j+1) + wx11a * c(i+1,j+1)) / (wx11b + wx11a);
b[0] -= dr_ *
((px00 * wra2 * wrb - px10 * wrb2 * wra) *
(dwza2 * wzd + wza2 * dwzd) +
(px01 * wrb * wra2 - px11 * wra * wrb2) *
(dwzb2 * wzc + wzb2 * dwzc));
b[1] += dr_ *
((px00 * wza2 * wzd + px01 * wzb2 * wzc) *
(dwra2 * wrb + wra2 * dwrb ) -
(px10 * wza2 * wzd + px11 * wzb2 * wzc) *
(dwra * wrb2 + wra * dwrb2));
// Compute dvar/dy at corners of local patch
real_t wy00a = fabs(d(i,j-1) - d(i,j-2));
real_t wy00b = fabs(d(i,j+1) - d(i,j));
real_t wy10a = fabs(d(i+1,j-1) - d(i+1,j-2));
real_t wy10b = fabs(d(i+1,j+1) - d(i+1,j));
real_t wy01a = fabs(d(i,j) - d(i,j-1));
real_t wy01b = fabs(d(i,j+2) - d(i,j+1));
real_t wy11a = fabs(d(i+1,j) - d(i+1,j-1));
real_t wy11b = fabs(d(i+1,j+2) - d(i+1,j+1));
if (wy00a == 0.0 && wy00b == 0.0) { wy00a = 1.0; wy00b = 1.0; }
if (wy10a == 0.0 && wy10b == 0.0) { wy10a = 1.0; wy10b = 1.0; }
if (wy01a == 0.0 && wy01b == 0.0) { wy01a = 1.0; wy01b = 1.0; }
if (wy11a == 0.0 && wy11b == 0.0) { wy11a = 1.0; wy11b = 1.0; }
real_t py00 = (wy00b * d(i,j-1) + wy00a * d(i,j)) / (wy00b + wy00a);
real_t py10 = (wy10b * d(i+1,j-1) + wy10a * d(i+1,j)) / (wy10b + wy10a);
real_t py01 = (wy01b * d(i,j) + wy01a * d(i,j+1)) / (wy01b + wy01a);
real_t py11 = (wy11b * d(i+1,j) + wy11a * d(i+1,j)) / (wy11b + wy11a);
b[0] -= dz_ *
((py00 * wra2 * wrd + py10 * wrb2 * wrc) *
(dwza2 * wzb + wza2 * dwzb) -
(py01 * wra2 * wrd + py11 * wrb2 * wrc) *
(dwza * wzb2 + wza * dwzb2));
b[1] += dz_ *
((py00 * wza2 * wzb - py01 * wza * wzb2) *
(dwra2 * wrd + wra2 * dwrd) +
(py10 * wza2 * wzb - py11 * wza * wzb2) *
(dwrb2 * wrc + wrb2 * dwrc));
// Compute d^2var/dxdy at corners of local patch
real_t pxy00 = (wx00b * (wy00b * e(i-1,j-1) + wy00a * e(i-1,j)) +
wx00a * (wy00b * e(i,j-1) + wy00a * e(i,j))) /
((wx00b + wx00a) * (wy00b + wy00a));
real_t pxy10 = (wx10b * (wy10b * e(i,j-1) + wy10a * e(i,j)) +
wx10a * (wy10b * e(i+1,j-1) + wy10a * e(i+1,j))) /
((wx10b + wx10a) * (wy10b + wy10a));
real_t pxy01 = (wx01b * (wy01b * e(i-1,j) + wy01a * e(i-1,j+1)) +
wx01a * (wy01b * e(i,j) + wy01a * e(i,j+1))) /
((wx01b + wx01a) * (wy01b + wy01a));
real_t pxy11 = (wx11b * (wy11b * e(i,j) + wy11a * e(i,j+1)) +
wx11a * (wy11b * e(i+1,j) + wy11a * e(i+1,j+1))) /
((wx11b + wx11a) * (wy11b + wy11a));
b[0] -= dr_ * dz_ * ((pxy00 * wra2 * wrb - pxy10 * wra * wrb2)
* (dwza2 * wzb + wza2 * dwzb) +
(pxy11 * wra * wrb2 - pxy01 * wra2 * wrb)
* (dwza * wzb2 + wza * dwzb2));
b[1] += dr_ * dz_ * ((pxy00 * wza2 * wzb - pxy01 * wza * wzb2)
* (dwra2 * wrb + wra2 * dwrb) +
(pxy11 * wza * wzb2 - pxy10 * wza2 * wzb)
* (dwra * wrb2 + wra * dwrb2));
}
void G_EQDSK_Data::initInterpPsi(const std::vector<real_t> &v,
std::vector<real_t> &t)
{
// Initialize the divided differences
ShiftedVector m(NW_-1, 2); m = 0.0;
m(-2) = -2.0 * v[2] + 5.0 * v[1] - 3.0 * v[0];
m(-1) = -1.0 * v[2] + 3.0 * v[1] - 2.0 * v[0];
for (int i=0; i<NW_-1; i++)
{
m(i) = v[i+1] - v[i];
}
m(NW_-1) = 2.0 * v[NW_-1] - 3.0 * v[NW_-2] + v[NW_-3];
m(NW_) = 3.0 * v[NW_-1] - 5.0 * v[NW_-2] + 2.0 * v[NW_-3];
// Initialize the Slopes
t.resize(NW_);
for (int i=0; i<NW_; i++)
{
if (m(i+1) == m(i) && m(i-1) == m(i-2))
{
if (m(i) == m(i-1))
{
t[i] = m(i) * dpsi_;
}
else
{
t[i] = 0.5 * (m(i-1) + m(i)) * dpsi_;
}
}
else
{
t[i] = (fabs(m(i+1) - m(i)) * m(i-1) +
fabs(m(i-1) - m(i-2)) * m(i)) * dpsi_ /
(fabs(m(i+1) - m(i)) + fabs(m(i-1) - m(i-2)));
}
}
}
real_t G_EQDSK_Data::interpPsi(real_t psi, const vector<real_t> &v,
const vector<real_t> &t)
{
real_t psimin = std::min(SIMAG_, SIBRY_);
real_t psimax = std::max(SIMAG_, SIBRY_);
// Psi constrained to be between psimin and psimax
real_t psic = std::max(psimin, std::min(psi, psimax));
// Psi scaled to the range 0 -> 1
real_t psis = (psic - SIMAG_) / (SIBRY_ - SIMAG_);
// Located the bin containing psis counting from 0
int i0 = std::max(0, std::min((int)floor(real_t(NW_-1) * psis), NW_-2));
int i1 = i0 + 1;
// Compute ends of local patch
real_t psi0 = SIMAG_ + (SIBRY_ - SIMAG_) * i0 / (NW_ - 1);
real_t psi1 = psi0 + (SIBRY_ - SIMAG_) / (NW_ - 1);
// Prepare position dependent factors
real_t wra = (psi1 - psic) / dpsi_;
real_t wrb = (psic - psi0) / dpsi_;
real_t wrc = (1.0 + 2.0 * wra);
real_t wrd = (1.0 + 2.0 * wrb);
real_t wra2 = wra * wra;
real_t wrb2 = wrb * wrb;
// Extract variable values at ends of local patch
const real_t &p0 = v[i0];
const real_t &p1 = v[i1];
real_t var = p0 * wra2 * wrd + p1 * wrb2 * wrc;
// Extract dvar/dx at ends of local patch
const real_t &px0 = t[i0];
const real_t &px1 = t[i1];
real_t varx = px0 * wra2 * wrb - px1 * wrb2 * wra;
var += varx * dpsi_;
return var;
}
void G_EQDSK_Data::ExtendedDenseMatrix::init()
{
// Populate four corners
SW_ = 3.0 * ((*this)(0,0) - (*this)(1,1)) + (*this)(2,2);
SE_ = 3.0 * ((*this)(m_-1,0) - (*this)(m_-2,1)) + (*this)(m_-3,2);
NW_ = 3.0 * ((*this)(0,n_-1) - (*this)(1,n_-2)) + (*this)(2,n_-3);
NE_ = 3.0 * ((*this)(m_-1,n_-1) - (*this)(m_-2,n_-2))
+ (*this)(m_-3,n_-3);
// Populate lowest rows
for (int j=0; j<n_; j++)
{
S_(1,j) = 3.0 * ((*this)(0,j) - (*this)(1,j)) + (*this)(2,j);
S_(0,j) = 3.0 * (2.0 * (*this)(0,j) + (*this)(2,j)) - 8.0 * (*this)(1,j);
}
// Populate highest rows
for (int j=0; j<n_; j++)
{
N_(1,j) = 3.0 * (2.0 * (*this)(m_-1,j) + (*this)(m_-3,j))
- 8.0 * (*this)(m_-2,j);
N_(0,j) = 3.0 * ((*this)(m_-1,j) - (*this)(m_-2,j)) + (*this)(m_-3,j);
}
// Populate lowest columns
for (int i=0; i<m_; i++)
{
W_(i,0) = 3.0 * (2.0 * (*this)(i,0) + (*this)(i,2)) - 8.0 * (*this)(i,1);
W_(i,1) = 3.0 * ((*this)(i,0) - (*this)(i,1)) + (*this)(i,2);
}
// Populate highest columns
for (int i=0; i<m_; i++)
{
E_(i,0) = 3.0 * ((*this)(i,n_-1) - (*this)(i,n_-2)) + (*this)(i,n_-3);
E_(i,1) = 3.0 * (2.0 * (*this)(i,n_-1) + (*this)(i,n_-3))
- 8.0 * (*this)(i,n_-2);
}
}
} // namespace plasma
} // namespace mfem
+587
View File
@@ -0,0 +1,587 @@
// 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_G_EQDSK_DATA_HPP
#define MFEM_G_EQDSK_DATA_HPP
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include "mfem.hpp"
#include "../../general/text.hpp"
namespace mfem
{
namespace plasma
{
/// Class for reading and interpolating data stored in ASCII files
/// following the G_EQDSK format as described in the C-Mod Wiki at
/// https://cmodwiki.psfc.mit.edu/index.php/G_EQDSK
///
/// G_EQDSK files contain four types of data:
///
/// 1) A poloidal flux function, Psi, stored as a uniform 2D grid
/// of data values along with information describing the grid
/// and values of the flux at the magnetic axis (SIMAG) and the
/// plasma boundary (SIBRY).
///
/// 2) Five 1D fields which are functions of Psi. These fields are
/// defined on a uniform grid of points ranging from Psi = 0 to
/// Psi = SIMAG.
///
/// 3) Curve data describing the location of the plasma boundary
/// and location of the limiter.
///
/// 4) A handful of individual data values specifiying things like
/// the total plasma current and the location of the magnetic
/// axis.
///
/// The interpolation scheme is described in "A Method of Bivariate
/// Interpolation and Smooth Surface Fitting Based on Local
/// Procedures" by Hiroshi Akima and published in the Communications
/// of the ACM, Numerical Mathematics, Volume 17, Number 1, January
/// 1974.
class G_EQDSK_Data
{
public:
G_EQDSK_Data(std::istream &is, int logging = 0);
// Number of points in radial direction
int GetNumPtsR() const { return NW_; }
// Number of points in z direction
int GetNumPtsZ() const { return NH_; }
// Width of domain in radial dimension (in meters)
real_t GetRExtent() const { return RDIM_; }
// Height of domain in z dimension (in meters)
real_t GetZExtent() const { return ZDIM_; }
// Radial coordinate at innermost edge of domain (in meters)
real_t GetRMin() const { return RLEFT_; }
// Z coordinate of the middle of the domain (in meters)
real_t GetZMid() const { return ZMID_; }
// R coordinate of the magnetic axis (in meters)
real_t GetRMagAxis() const { return RMAXIS_; }
// Z coordinate of the magnetic axis (in meters)
real_t GetZMagAxis() const { return ZMAXIS_; }
// Value of poloidal flux at the magnetic axis (in Weber / rad)
real_t GetPsiMagAxis() const {return SIMAG_; }
// Value of poloidal flux at the plasma boundary (in Weber / rad)
real_t GetPsiBdry() const {return SIBRY_; }
// Value of plasma current (in Ampere)
real_t GetPlasmaCurrent() const {return CURRENT_; }
// Values of poloidal flux (in Weber / rad) on the full grid in a
// flattened array with z-direction cycling the fastest
std::vector<real_t> & GetPsi() { return PSIRZ_ ;}
// Print a text block to the output stream containing basic
// information about the domain and the fields defined in the eqdsk
// file.
void PrintInfo(std::ostream &out = std::cout) const;
// Create a GnuPlot input file and associated data file for
// visualizing the fields stored in the eqdsk file.
void DumpGnuPlotData(const std::string &file) const;
// In the following interpolation functions the Vector argument rz
// is a two component vector containing first the radial coordinate
// and nex the z coordinate both expressed in meters.
// Interpolate the toroidal field function, F(Psi(rz) / SIMAG)
// (in Tesla meters), at the point rz
real_t InterpFPolRZ(const Vector &rz);
// Interpolate the pressure, P(Psi(rz) / SIMAG) (in N / m^2), at the
// point rz
real_t InterpPresRZ(const Vector &rz);
// Interpolate the function, F(Psi(rz) / SIMAG) * F'(Psi / SIMAG)
// (in (m T)^2 / (Weber / rad)), at the point rz
real_t InterpFFPrimeRZ(const Vector &rz);
// Interpolate the function, P'(Psi(rz) / SIMAG)
// (in (N / m^2) / (Weber / rad)), at the point rz
real_t InterpPPrimeRZ(const Vector &rz);
// Interpolate the poloidal flux function, Psi(rz) (in Weber / rad), at
// the point rz
real_t InterpPsiRZ(const Vector &rz);
// Interpolate the safety factor, q(Psi(rz) / SIMAG), at the point rz
real_t InterpQRZ(const Vector &rz);
// Interpolate the toroidal magnetic fleid (in Tesla) at the
// point rz
// B_T = F(Psi(rz) / SIMAG) / r
real_t InterpBTorRZ(const Vector &rz);
// Interpolate the toroidal current density (in Ampere / m^2) at
// the point rz
// J_T = r P'((Psi(rz) / SIMAG) + FF'(Psi(rz) / SIMAG) / (r mu0)
real_t InterpJTorRZ(const Vector &rz);
// Interpolate the rotated gradient of Psi (in Tesla) at the
// point rz
// nxdp = (n x Grad Psi(rz))
// where n is the unit vector in the toroidal direction
void InterpNxGradPsiRZ(const Vector &rz, Vector &nxdp);
// Interpolate the poloidal magnetic field (in Tesla) at the
// point rz
// B_P = (n x Grad Psi(rz)) / r
// where n is the unit vector in the toroidal direction
void InterpBPolRZ(const Vector &rz, Vector &b);
int GetNumBoundaryPts() const { return NBBBS_; }
const std::vector<real_t> & GetBoundaryRVals() const { return RBBBS_; }
const std::vector<real_t> & GetBoundaryZVals() const { return ZBBBS_; }
int GetNumLimiterPts() const { return LIMITR_; }
const std::vector<real_t> & GetLimiterRVals() const { return RLIM_; }
const std::vector<real_t> & GetLimiterZVals() const { return ZLIM_; }
private:
class ShiftedVector;
class ShiftedDenseMatrix;
class ExtendedDenseMatrix;
enum FieldType {FPOL, PRES, FFPRIM, PPRIME, PSIRZ, QPSI/*, BTOR*/};
int logging_;
int init_flag_;
inline bool checkFlag(int flag) { return (init_flag_ >> flag) & 1; }
inline void setFlag(int flag) { init_flag_ |= (1 << flag); }
inline void clearFlag(int flag) { init_flag_ &= ~(1 << flag); }
void checkPsiBoundary();
void initInterpPsi(const std::vector<real_t> &v,
std::vector<real_t> &t);
void initInterpRZ(const std::vector<real_t> &v,
ShiftedDenseMatrix &c,
ShiftedDenseMatrix &d,
ShiftedDenseMatrix &e);
real_t interpRZ(const Vector &rz,
const std::vector<real_t> &v,
const ShiftedDenseMatrix &c,
const ShiftedDenseMatrix &d,
const ShiftedDenseMatrix &e);
void interpNxGradRZ(const Vector &rz,
const std::vector<real_t> &v,
const ShiftedDenseMatrix &c,
const ShiftedDenseMatrix &d,
const ShiftedDenseMatrix &e,
Vector &b);
real_t interpPsi(real_t psi, const std::vector<real_t> &v,
const std::vector<real_t> &t);
/// The following variable names are taken from the C-Mod Wiki at
/// https://cmodwiki.psfc.mit.edu/index.php/G_EQDSK
std::vector<std::string> CASE_; // Identification character string
int NW_; // Number of horizontal R grid points
int NH_; // Number of vertical Z grid points
real_t RDIM_; // Horizontal dimension in meter of computational box
real_t ZDIM_; // Vertical dimension in meter of computational box
real_t RLEFT_; // Minimum R in meter of rectangular computational box
real_t ZMID_; // Z of center of computational box in meter
real_t RMAXIS_; // R of magnetic axis in meter
real_t ZMAXIS_; // Z of magnetic axis in meter
real_t SIMAG_; // poloidal flux at magnetic axis in Weber /rad
real_t SIBRY_; // poloidal flux at the plasma boundary in Weber /rad
real_t RCENTR_; // R in meter of vacuum toroidal magnetic field BCENTR
real_t BCENTR_; // Vacuum toroidal magnetic field in Tesla at RCENTR
real_t CURRENT_; // Plasma current in Ampere
// Poloidal current function in m-T, F = RBT on flux grid
std::vector<real_t> FPOL_;
// Plasma pressure in nt / m^2 on uniform flux grid
std::vector<real_t> PRES_;
// FF(ψ) in (mT)^2 / (Weber /rad) on uniform flux grid
std::vector<real_t> FFPRIM_;
// P(ψ) in (nt /m^2) / (Weber /rad) on uniform flux grid
std::vector<real_t> PPRIME_;
// Poloidal flux in Weber / rad on the rectangular grid points
std::vector<real_t> PSIRZ_;
// q values on uniform flux grid from axis to boundary
std::vector<real_t> QPSI_;
int NBBBS_; // Number of boundary points
std::vector<real_t> RBBBS_; // R of boundary points in meter
std::vector<real_t> ZBBBS_; // Z of boundary points in meter
int LIMITR_; // Number of limiter points
std::vector<real_t> RLIM_; // R of surrounding limiter contour in meter
std::vector<real_t> ZLIM_; // Z of surrounding limiter contour in meter
class ShiftedVector : public Vector
{
private:
int si_;
public:
ShiftedVector()
: si_(0) {}
ShiftedVector(int s, int si)
: Vector(s+2*si), si_(si) {}
void SetShift(int si) { si_ = si; }
ShiftedVector &operator=(real_t c)
{ Vector::operator=(c); return *this; }
inline real_t &operator()(int i)
{ return Vector::operator()(i + si_); }
inline const real_t &operator()(int i) const
{ return Vector::operator()(i + si_); }
};
class ShiftedDenseMatrix : public DenseMatrix
{
private:
int si_, sj_;
public:
ShiftedDenseMatrix()
: si_(0), sj_(0) {}
ShiftedDenseMatrix(int m, int n, int si, int sj)
: DenseMatrix(m+2*si, n+2*sj), si_(si), sj_(sj) {}
void SetShifts(int si, int sj) { si_ = si; sj_ = sj; }
ShiftedDenseMatrix &operator=(real_t c)
{ DenseMatrix::operator=(c); return *this; }
inline real_t &operator()(int i, int j)
{ return DenseMatrix::operator()(i + si_, j + sj_); }
inline const real_t &operator()(int i, int j) const
{ return DenseMatrix::operator()(i + si_, j + sj_); }
};
class ExtendedDenseMatrix
{
private:
int m_, n_;
const real_t *C_;
DenseMatrix N_;
DenseMatrix S_;
DenseMatrix E_;
DenseMatrix W_;
real_t SW_, SE_, NW_, NE_, DUMMY_;
void init();
public:
ExtendedDenseMatrix(const real_t *C, int m, int n)
: m_(m), n_(n), C_(C),
N_(2, n), S_(2, n),
E_(m, 2), W_(m, 2),
SW_(0.0), SE_(0.0), NW_(0.0), NE_(0.0), DUMMY_(0.0)
{ N_ = 0.0; S_ = 0.0; E_ = 0.0; W_ = 0.0; init(); }
const real_t &operator()(int i, int j) const
{
if (i >= 0 && i < m_ && j >= 0 && j < n_)
{
return C_[n_ * i + j];
}
else if (i >= 0 && i < m_)
{
if (j < 0)
{
return W_(i, j + 2);
}
else
{
return E_(i, j - n_);
}
}
else if (j >= 0 && j < n_)
{
if (i < 0)
{
return S_(i + 2, j);
}
else
{
return N_(i - m_, j);
}
}
else if (i == -1 && j == -1)
{
return SW_;
}
else if (i == -1 && j == n_)
{
return SE_;
}
else if (i == m_ && j == -1)
{
return NW_;
}
else if (i == m_ && j == n_)
{
return NE_;
}
return DUMMY_;
}
};
// Divided differences for Akima's interpolation method
real_t dr_, dz_, dpsi_;
std::vector<real_t> FPOL_t_;
std::vector<real_t> PRES_t_;
std::vector<real_t> FFPRIM_t_;
std::vector<real_t> PPRIME_t_;
ShiftedDenseMatrix PSIRZ_c_;
ShiftedDenseMatrix PSIRZ_d_;
ShiftedDenseMatrix PSIRZ_e_;
std::vector<real_t> QPSI_t_;
};
class G_EQDSK_Psi_Coefficient : public Coefficient
{
private:
G_EQDSK_Data &eqdsk;
public:
G_EQDSK_Psi_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
real_t Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
return eqdsk.InterpPsiRZ(transip);
}
};
class G_EQDSK_FPol_Coefficient : public Coefficient
{
private:
G_EQDSK_Data &eqdsk;
public:
G_EQDSK_FPol_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
real_t Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
return eqdsk.InterpFPolRZ(transip);
}
};
class G_EQDSK_Pres_Coefficient : public Coefficient
{
private:
G_EQDSK_Data &eqdsk;
public:
G_EQDSK_Pres_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
real_t Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
return eqdsk.InterpPresRZ(transip);
}
};
class G_EQDSK_Q_Coefficient : public Coefficient
{
private:
G_EQDSK_Data &eqdsk;
public:
G_EQDSK_Q_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
real_t Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
return eqdsk.InterpQRZ(transip);
}
};
class G_EQDSK_BTor_Coefficient : public Coefficient
{
private:
G_EQDSK_Data &eqdsk;
public:
G_EQDSK_BTor_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
real_t Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
return eqdsk.InterpBTorRZ(transip);
}
};
class G_EQDSK_JTor_Coefficient : public Coefficient
{
private:
G_EQDSK_Data &eqdsk;
public:
G_EQDSK_JTor_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
real_t Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
return eqdsk.InterpJTorRZ(transip);
}
};
class G_EQDSK_NxGradPsi_Coefficient : public VectorCoefficient
{
private:
G_EQDSK_Data &eqdsk;
public:
G_EQDSK_NxGradPsi_Coefficient(G_EQDSK_Data &g_eqdsk)
: VectorCoefficient(2), eqdsk(g_eqdsk) {}
void Eval(Vector &b, ElementTransformation & T,
const IntegrationPoint & ip)
{
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
eqdsk.InterpNxGradPsiRZ(transip, b);
}
};
class G_EQDSK_BPol_Coefficient : public VectorCoefficient
{
private:
G_EQDSK_Data &eqdsk;
public:
G_EQDSK_BPol_Coefficient(G_EQDSK_Data &g_eqdsk)
: VectorCoefficient(2), eqdsk(g_eqdsk) {}
void Eval(Vector &b, ElementTransformation & T,
const IntegrationPoint & ip)
{
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
eqdsk.InterpBPolRZ(transip, b);
}
};
class G_EQDSK_BField_VecCoefficient : public VectorCoefficient
{
private:
G_EQDSK_Data &eqdsk;
bool unit_;
public:
G_EQDSK_BField_VecCoefficient(G_EQDSK_Data &g_eqdsk, bool unit)
: VectorCoefficient(3), eqdsk(g_eqdsk), unit_(unit) {}
void Eval(Vector &V, ElementTransformation & T,
const IntegrationPoint & ip)
{
V.SetSize(3);
Vector b;
b.SetSize(2);
real_t x[3];
Vector transip(x, 3);
T.Transform(ip, transip);
eqdsk.InterpBPolRZ(transip, b);
real_t btor = eqdsk.InterpBTorRZ(transip);
V[0] = b[0];
V[1] = b[1];
V[2] = btor;
if ( unit_ )
{
real_t bmag = sqrt(V * V);
V /= bmag;
}
}
};
} // namespace plasma
} // namespace mfem
#endif // MFEM_G_EQDSK_DATA_HPP
+361
View File
@@ -0,0 +1,361 @@
// 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 "mfem.hpp"
#include "../common/fem_extras.hpp"
#include "g_eqdsk_data.hpp"
using namespace std;
using namespace mfem;
using namespace mfem::common;
using namespace mfem::plasma;
void ShiftMesh(real_t x0, real_t y0, Mesh &mesh);
int main(int argc, char *argv[])
{
const char *eqdsk_file = "";
const char *mesh_file = "";
int order = 1;
bool visualization = true;
bool visit = false;
bool paraview = false;
bool binary = false;
int precision = 8;
cout.precision(precision);
OptionsParser args(argc, argv);
args.AddOption(&eqdsk_file, "-eqdsk", "--eqdsk-file",
"G EQDSK input file.");
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
"--no-visit-datafiles",
"Save data files for VisIt (visit.llnl.gov) visualization.");
args.AddOption(&paraview, "-paraview", "--paraview-datafiles", "-no-paraview",
"--no-paraview-datafiles",
"Save data files for ParaView (paraview.org) visualization.");
args.AddOption(&binary, "-binary", "--binary-datafiles", "-ascii",
"--ascii-datafiles",
"Use binary (Sidre) or ascii format for VisIt data files.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
named_ifgzstream ieqdsk(eqdsk_file);
if (!ieqdsk)
{
return 1;
}
G_EQDSK_Data eqdsk(ieqdsk);
eqdsk.PrintInfo();
eqdsk.DumpGnuPlotData("gnuplot_eqdsk");
G_EQDSK_Psi_Coefficient psiCoef(eqdsk);
G_EQDSK_FPol_Coefficient fPolCoef(eqdsk);
G_EQDSK_Pres_Coefficient presCoef(eqdsk);
G_EQDSK_Q_Coefficient qCoef(eqdsk);
G_EQDSK_NxGradPsi_Coefficient nxGradPsiCoef(eqdsk);
G_EQDSK_BPol_Coefficient BPolCoef(eqdsk);
G_EQDSK_BTor_Coefficient BTorCoef(eqdsk);
G_EQDSK_JTor_Coefficient JTorCoef(eqdsk);
Mesh mesh;
if (strcmp(mesh_file, "") == 0)
{
mesh = Mesh::MakeCartesian2D(eqdsk.GetNumPtsR(),
eqdsk.GetNumPtsZ(),
Element::QUADRILATERAL,
false,
eqdsk.GetRExtent(),
eqdsk.GetZExtent());
real_t zmin = eqdsk.GetZMid() - eqdsk.GetZExtent()/2.0;
ShiftMesh(eqdsk.GetRMin(), zmin, mesh);
}
else
{
mesh = Mesh(mesh_file);
}
H1_FECollection fec_h1(order, 2);
FiniteElementSpace fes_h1(&mesh, &fec_h1);
FiniteElementSpace fes_h1v(&mesh, &fec_h1, 2);
GridFunction psi(&fes_h1);
psi.ProjectCoefficient(psiCoef);
GridFunction nxGradPsi(&fes_h1v);
nxGradPsi.ProjectCoefficient(nxGradPsiCoef);
GridFunction fPol(&fes_h1);
fPol.ProjectCoefficient(fPolCoef);
GridFunction pres(&fes_h1);
pres.ProjectCoefficient(presCoef);
GridFunction q(&fes_h1);
q.ProjectCoefficient(qCoef);
GridFunction BPol(&fes_h1v);
BPol.ProjectCoefficient(BPolCoef);
GridFunction BTor(&fes_h1);
BTor.ProjectCoefficient(BTorCoef);
GridFunction JTor(&fes_h1);
JTor.ProjectCoefficient(JTorCoef);
int xPos = 0, yPos = 0, w = 400, h = 300, b = 30, m = 65;
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
char skeys[] = "mmaaAcjR";
char vkeys[] = "vvvmmaaAcjR";
socketstream sock_fpol;
VisualizeField(sock_fpol, vishost, visport, fPol, "Current Flux",
xPos, yPos, w, h, skeys);
xPos += w;
socketstream sock_pres;
VisualizeField(sock_pres, vishost, visport, pres, "Pressure",
xPos, yPos, w, h, "mmaaAcjR");
xPos += w;
socketstream sock_psi;
VisualizeField(sock_psi, vishost, visport, psi, "Poloidal Flux",
xPos, yPos, w, h, "mmaaAcjR");
xPos += w;
socketstream sock_q;
VisualizeField(sock_q, vishost, visport, q, "Safety Factor (q)",
xPos, yPos, w, h, "mmaaAcjR");
xPos = 0; yPos += h + b + m;
socketstream sock_bpol;
VisualizeField(sock_bpol, vishost, visport, BPol, "Poloidal B",
xPos, yPos, w, h, vkeys, true);
xPos += w;
socketstream sock_btor;
VisualizeField(sock_btor, vishost, visport, BTor, "Toroidal B",
xPos, yPos, w, h, "mmaaAcjR");
xPos += w;
socketstream sock_jtor;
VisualizeField(sock_jtor, vishost, visport, JTor, "Toroidal J",
xPos, yPos, w, h, "mmaaAcjR");
xPos = 0; yPos += h + b;
}
Array<DataCollection*> dc(2); dc = NULL;
if (visit)
{
#ifdef MFEM_USE_SIDRE
if (binary)
{
dc[0] = new SidreDataCollection("G_EQDSK_Viewer", &mesh);
}
else
#else
{
dc[0] = new VisItDataCollection("G_EQDSK_Viewer", &mesh);
dc[0]->SetPrecision(precision);
}
#endif
}
if (paraview)
{
ParaViewDataCollection *pd =
new ParaViewDataCollection("G_EQDSK_Viewer", &mesh);
pd->SetPrefixPath("ParaView");
pd->SetHighOrderOutput(true);
if (binary) { pd->SetDataFormat(VTKFormat::BINARY); }
dc[1] = pd;
}
for (int i=0; i<2; i++)
{
if (dc[i] == NULL) { continue; }
dc[i]->SetCycle(0);
dc[i]->SetTime(0.0);
dc[i]->RegisterField("Psi", &psi);
dc[i]->RegisterField("FPol", &fPol);
dc[i]->RegisterField("Pres", &pres);
dc[i]->RegisterField("Q", &q);
dc[i]->RegisterField("nxGradPsi", &nxGradPsi);
dc[i]->RegisterField("BPol", &BPol);
dc[i]->RegisterField("BTor", &BTor);
dc[i]->RegisterField("JTor", &JTor);
dc[i]->Save();
}
delete dc[0];
delete dc[1];
{
int nbdr = eqdsk.GetNumBoundaryPts();
const vector<real_t> &r = eqdsk.GetBoundaryRVals();
const vector<real_t> &z = eqdsk.GetBoundaryZVals();
Mesh bdr(1, nbdr, nbdr-1, 2, 2);
for (int i=0; i<nbdr; i++)
{
bdr.AddVertex(r[i], z[i]);
}
for (int i=1; i<nbdr; i++)
{
bdr.AddSegment(i-1, i);
}
bdr.AddBdrPoint(0);
bdr.AddBdrPoint(nbdr-1);
bdr.FinalizeMesh();
if (visualization)
{
socketstream sock;
char vishost[] = "localhost";
int visport = 19916;
VisualizeMesh(sock, vishost, visport, bdr, "Plasma Boundary",
xPos, yPos, w, h, "aaA");
xPos += w;
}
if (visit)
{
#ifdef MFEM_USE_SIDRE
if (binary)
{
SidreDataCollection sd("G_EQDSK_Viewer_Boundary", &bdr);
sd.Save();
}
else
#else
{
VisItDataCollection vd("G_EQDSK_Viewer_Boundary", &bdr);
vd.SetPrecision(precision);
vd.Save();
}
#endif
}
if (paraview)
{
ParaViewDataCollection pd("G_EQDSK_Viewer_Boundary", &bdr);
pd.SetPrefixPath("ParaView");
pd.SetHighOrderOutput(true);
if (binary) { pd.SetDataFormat(VTKFormat::BINARY); }
pd.Save();
}
}
{
int nlim = eqdsk.GetNumLimiterPts();
const vector<real_t> &r = eqdsk.GetLimiterRVals();
const vector<real_t> &z = eqdsk.GetLimiterZVals();
Mesh lim(1, nlim, nlim-1, 2, 2);
for (int i=0; i<nlim; i++)
{
lim.AddVertex(r[i], z[i]);
}
for (int i=1; i<nlim; i++)
{
lim.AddSegment(i-1, i);
}
lim.AddBdrPoint(0);
lim.AddBdrPoint(nlim-1);
lim.FinalizeMesh();
if (visualization)
{
socketstream sock;
char vishost[] = "localhost";
int visport = 19916;
VisualizeMesh(sock, vishost, visport, lim, "Limiter",
xPos, yPos, w, h, "aaA");
xPos += w;
}
if (visit)
{
#ifdef MFEM_USE_SIDRE
if (binary)
{
SidreDataCollection sd("G_EQDSK_Viewer_Limiter", &lim);
sd.Save();
}
else
#else
{
VisItDataCollection vd("G_EQDSK_Viewer_Limiter", &lim);
vd.SetPrecision(precision);
vd.Save();
}
#endif
}
if (paraview)
{
ParaViewDataCollection pd("G_EQDSK_Viewer_Limiter", &lim);
pd.SetPrefixPath("ParaView");
pd.SetHighOrderOutput(true);
if (binary) { pd.SetDataFormat(VTKFormat::BINARY); }
pd.Save();
}
}
}
void ShiftMesh(real_t x0, real_t y0, Mesh &mesh)
{
class ShiftCoef : public VectorCoefficient
{
private:
real_t xs_, ys_;
public:
ShiftCoef(real_t xs, real_t ys) : VectorCoefficient(2), xs_(xs), ys_(ys) {}
void Eval(Vector &v, ElementTransformation &T, const IntegrationPoint &ip)
{
T.Transform(ip, v);
v[0] += xs_;
v[1] += ys_;
}
};
ShiftCoef shift(x0, y0);
mesh.Transform(shift);
}
+17 -6
View File
@@ -18,7 +18,7 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_MINIAPPS =
SEQ_MINIAPPS = g_eqdsk_viewer
PAR_MINIAPPS =
ifeq ($(MFEM_USE_MPI),NO)
MINIAPPS = $(SEQ_MINIAPPS)
@@ -39,11 +39,14 @@ SUBDIRS_TPRINT = $(addsuffix /test-print,$(PLASMA_SUBDIRS))
.PHONY: all lib-common clean clean-build clean-exec
.PRECIOUS: %.o
COMMON_O = g_eqdsk_data.o
COMMON_LIB = -L$(MFEM_BUILD_DIR)/miniapps/common -lmfem-common
# If MFEM_SHARED is set, add the ../common rpath
COMMON_LIB += $(if $(MFEM_SHARED:YES=),,\
$(MFEM_XLINKER)-rpath,$(abspath $(MFEM_BUILD_DIR)/miniapps/common))
$(if $(MFEM_USE_CUDA:YES=),$(CXX_XLINKER),$(CUDA_XLINKER))-rpath,$(abspath\
$(MFEM_BUILD_DIR)/miniapps/common))
# Remove built-in rules
%: %.cpp
@@ -53,15 +56,22 @@ all: $(MINIAPPS) $(SUBDIRS_ALL)
.PHONY: $(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_TEST_NOCLEAN) \
$(SUBDIRS_CLEAN) $(SUBDIRS_TPRINT)
# Rules for building the miniapps
%: $(SRC)%.cpp $(COMMON_O) $(MFEM_LIB_FILE) $(CONFIG_MK) | lib-common
$(MFEM_CXX) $(MFEM_LINK_FLAGS) $< -o $@ $(COMMON_O) $(COMMON_LIB) \
$(MFEM_LIBS)
# Rules for compiling miniapp dependencies
$(COMMON_O) $(addsuffix _solver.o,$(MINIAPPS)): \
%.o: $(SRC)%.cpp $(SRC)%.hpp $(CONFIG_MK)
$(MFEM_CXX) $(MFEM_FLAGS) -c $(<) -o $(@)
$(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_TEST_NOCLEAN) $(SUBDIRS_CLEAN):
$(MAKE) -C $(@D) $(@F)
$(SUBDIRS_TPRINT):
@$(MAKE) -C $(@D) $(@F)
# Rules for building the miniapps
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) | lib-common
$(MFEM_CXX) $(MFEM_LINK_FLAGS) $< -o $@ $(COMMON_LIB) $(MFEM_LIBS)
# Rule for building lib-common
lib-common:
$(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common
@@ -88,3 +98,4 @@ clean-build:
rm -rf *.dSYM *.TVD.*breakpoints
clean-exec:
@rm -rf G_EQDSK_Viewer_* gnuplot_eqdsk.*
-1
View File
@@ -59,4 +59,3 @@ typedef std::complex<real_t> complex_t;
} // namespace mfem
#endif // MFEM_PLASMA_HPP
+211
View File
@@ -0,0 +1,211 @@
SGRRATEI 01/01/2025 #1 0ms 3 20 40
1.000000000E+00 2.000000000E+00 1.000000000E+00 5.000000000E-01 0.000000000E+00
1.105630563E+00 3.500092352E-02 2.347299201E+01 0.000000000E+00 1.000000000E+00
4.093014437E+05 2.347299201E+01 0.000000000E+00 1.105630563E+00 0.000000000E+00
3.500092352E-02 0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00
9.738254114E-01 9.765403940E-01 9.791016917E-01 9.815105078E-01 9.837679622E-01
9.858750948E-01 9.878328675E-01 9.896421668E-01 9.913038055E-01 9.928185251E-01
9.941869971E-01 9.954098248E-01 9.964875442E-01 9.974206257E-01 9.982094750E-01
9.988544337E-01 9.993557806E-01 9.997137315E-01 9.999284406E-01 1.000000000E+00
5.710133214E+04 5.124884104E+04 4.571270080E+04 4.049291144E+04 3.558947294E+04
3.100238532E+04 2.673164857E+04 2.277726268E+04 1.913922767E+04 1.581754353E+04
1.281221026E+04 1.012322786E+04 7.750596330E+03 5.694315671E+03 3.954385882E+03
2.530806965E+03 1.423578918E+03 6.327017412E+02 1.581754353E+02 0.000000000E+00
-5.305270078E-02-5.012071900E-02-4.721240459E-02-4.432615176E-02-4.146040916E-02
-3.861367525E-02-3.578449395E-02-3.297145057E-02-3.017316804E-02-2.738830324E-02
-2.461554357E-02-2.185360373E-02-1.910122258E-02-1.635716013E-02-1.362019471E-02
-1.088912014E-02-8.162743045E-03-5.439880231E-03-2.719356078E-03-0.000000000E+00
1.142026643E+05 1.081919977E+05 1.021813312E+05 9.617066466E+04 9.015999812E+04
8.414933158E+04 7.813866504E+04 7.212799850E+04 6.611733196E+04 6.010666541E+04
5.409599887E+04 4.808533233E+04 4.207466579E+04 3.606399925E+04 3.005333271E+04
2.404266617E+04 1.803199962E+04 1.202133308E+04 6.010666541E+03 0.000000000E+00
1.177939031E+00 7.114757766E-01 3.462248040E-01 5.354204611E-02-1.920202929E-01
-4.129262653E-01-6.282055905E-01-8.521376374E-01-1.092012071E+00-1.345131509E+00
-1.595544748E+00-1.811409078E+00-1.944310502E+00-1.932184779E+00-1.707470864E+00
-1.211535856E+00-4.150082925E-01 6.586307082E-01 1.911775275E+00 3.162156344E+00
1.061937089E+00 6.633173301E-01 3.492668082E-01 9.315032283E-02-1.304531101E-01
-3.458479130E-01-5.756143723E-01-8.390126101E-01-1.149238113E+00-1.509585272E+00
-1.908915919E+00-2.317294334E+00-2.683185289E+00-2.934087898E+00-2.982678795E+00
-2.740175983E+00-2.137415484E+00-1.151880382E+00 1.642429581E-01 1.663372295E+00
8.051939480E-01 5.069112372E-01 2.743284476E-01 8.370657885E-02-8.974129464E-02
-2.719121972E-01-4.891295045E-01-7.663397670E-01-1.123909079E+00-1.572938455E+00
-2.109368849E+00-2.707664515E+00-3.315512301E+00-3.851636238E+00-4.209280562E+00
-4.267839746E+00-3.914144066E+00-3.072748961E+00-1.741194852E+00-2.206373816E-02
4.386618733E-01 2.671699153E-01 1.423176570E-01 4.390607362E-02-5.171653318E-02
-1.717821368E-01-3.464493081E-01-6.068989469E-01-9.817630445E-01-1.491645200E+00
-2.141844861E+00-2.913964020E+00-3.757840297E+00-4.586112160E+00-5.274458926E+00
-5.670818478E+00-5.616224816E+00-4.977901073E+00-3.691687034E+00-1.806058709E+00
-4.298567177E-03-2.885908269E-02-2.408384075E-02-6.214900590E-03 2.635241343E-03
-2.582736598E-02-1.255823084E-01-3.344252645E-01-6.901634068E-01-1.224454514E+00
-1.954213674E+00-2.871118150E+00-3.930618618E+00-5.042932053E+00-6.069530696E+00
-6.829272879E+00-7.118023483E+00-6.743823605E+00-5.575998604E+00-3.601125638E+00
-4.904906367E-01-3.541583261E-01-2.023319275E-01-4.707332712E-02 9.136750994E-02
1.839291606E-01 1.929332900E-01 7.375989635E-02-2.212853526E-01-7.362958772E-01
-1.501990597E+00-2.523186013E+00-3.764838139E+00-5.139247280E+00-6.498368268E+00
-7.636196547E+00-8.306311506E+00-8.258154862E+00-7.291916149E+00-5.325855281E+00
-9.891517976E-01-6.836808359E-01-3.717549013E-01-6.118268240E-02 2.299116539E-01
4.720201133E-01 6.239925947E-01 6.343426860E-01 4.449799758E-01-1.810539076E-03
-7.526144758E-01-1.828479362E+00-3.208038614E+00-4.810814863E+00-6.485007525E+00
-8.005508573E+00-9.088448866E+00-9.427424816E+00-8.752906042E+00-6.909813980E+00
-1.473771796E+00-9.959343881E-01-5.149915677E-01-3.452799782E-02 4.296819687E-01
8.480325882E-01 1.176224437E+00 1.356019748E+00 1.318626308E+00 9.917412651E-01
3.110382488E-01-7.637621813E-01-2.229234570E+00-4.017630769E+00-5.979886299E+00
-7.878690259E+00-9.399094337E+00-1.018339893E+01-9.893563051E+00-8.297535837E+00
-1.923358234E+00-1.274118331E+00-6.190449342E-01 4.241617768E-02 6.970427222E-01
1.315504578E+00 1.850755536E+00 2.238061887E+00 2.397821839E+00 2.242420073E+00
1.688171532E+00 6.727868194E-01-8.223908342E-01-2.747908855E+00-4.964257479E+00
-7.229487499E+00-9.204966355E+00-1.048758220E+01-1.067347645E+01-9.451344740E+00
-2.323104633E+00-1.506765900E+00-6.759012096E-01 1.740804302E-01 1.032700577E+00
1.871293443E+00 2.640527557E+00 3.269546701E+00 3.668019576E+00 3.732554236E+00
3.358812466E+00 2.460076739E+00 9.918161564E-01-1.020108269E+00-3.452453075E+00
-6.066340582E+00-8.507319402E+00-1.033357420E+01-1.107925638E+01-1.035282773E+01
-2.664471122E+00-1.687890207E+00-6.827027259E-01 3.596274997E-01 1.431550261E+00
2.505452940E+00 3.530213458E+00 4.429318046E+00 5.101959709E+00 5.428780921E+00
5.283882595E+00 4.554194090E+00 3.166091448E+00 1.117147246E+00-1.491830392E+00
-4.432367149E+00-7.341965785E+00-9.747121227E+00-1.112459668E+01-1.100287931E+01
-2.944738080E+00-1.816674081E+00-6.415005103E-01 5.931963199E-01 1.882965615E+00
3.201616345E+00 4.496734579E+00 5.686676598E+00 6.660570233E+00 7.283188581E+00
7.406605934E+00 6.890087547E+00 5.628476275E+00 3.587263544E+00 8.396022394E-01
-2.402899635E+00-5.776849067E+00-8.783877585E+00-1.084839190E+01-1.142033969E+01
-3.166134203E+00-1.896779380E+00-5.586445387E-01 8.645161131E-01 2.371494866E+00
3.937845874E+00 5.510336076E+00 7.002752880E+00 8.294707488E+00 9.235489503E+00
9.655166287E+00 9.384741989E+00 8.286038706E+00 6.289838350E+00 3.437717133E+00
-8.075321028E-02-3.907350460E+00-7.525051779E+00-1.031106577E+01-1.163935097E+01
-3.334669430E+00-1.935377409E+00-4.438947453E-01 1.159817788E+00 2.877890628E+00
4.687875792E+00 6.536138946E+00 8.332465883E+00 9.947618768E+00 1.121607806E+01
1.194643788E+01 1.194163044E+01 1.103005146E+01 9.106506552E+00 6.178640076E+00
2.410438564E+00-1.849670608E+00-6.071264098E+00-9.589395893E+00-1.170564693E+01
-3.458817908E+00-1.942017179E+00-3.093519611E-01 1.462951722E+00 3.380383697E+00
5.422650509E+00 7.536054524E+00 9.626930107E+00 1.155795906E+01 1.314976842E+01
1.419053815E+01 1.445614268E+01 1.374230350E+01 1.190806493E+01 8.926518370E+00
4.934346872E+00 2.672349659E-01-4.535068265E+00-8.770225658E+00-1.167206778E+01
-3.548196371E+00-1.927451469E+00-1.683142698E-01 1.756611464E+00 3.856096505E+00
6.112041329E+00 8.470924349E+00 1.083614428E+01 1.306315655E+01 1.495995902E+01
1.629589474E+01 1.682162166E+01 1.630211309E+01 1.456238365E+01 1.154214088E+01
7.350954429E+00 2.310587678E+00-3.032682981E+00-7.943532064E+00-1.159364507E+01
-3.612369480E+00-1.902532645E+00-3.416086848E-02 2.023562298E+00 4.282487674E+00
6.726617299E+00 9.302735925E+00 1.191177809E+01 1.440289942E+01 1.657294315E+01
1.817448446E+01 1.893559777E+01 1.859356268E+01 1.694255836E+01 1.389180895E+01
9.525810665E+00 4.152947024E+00-1.675532760E+00-7.195361659E+00-1.152263127E+01
-3.659888135E+00-1.877272235E+00 8.064666376E-02 2.247781331E+00 4.638723390E+00
7.239346930E+00 9.996763752E+00 1.280986971E+01 1.552251082E+01 1.792207710E+01
1.974689233E+01 2.070579945E+01 2.051246236E+01 1.893474235E+01 1.585584220E+01
1.133888571E+01 5.680950215E+00-5.622075887E-01-6.601153114E+00-1.150384995E+01
-3.697632389E+00-1.860132684E+00 1.653751070E-01 2.415430773E+00 4.906883382E+00
7.627118007E+00 1.052349470E+01 1.349325702E+01 1.637598974E+01 1.895153030E+01
2.094685366E+01 2.205553690E+01 2.197257081E+01 2.044512383E+01 1.733613236E+01
1.269240556E+01 6.803013202E+00 2.285826261E-01-6.219933983E+00-1.157071687E+01
-3.730491265E+00-1.857589350E+00 2.115959967E-01 2.515606446E+00 5.072927797E+00
7.871980905E+00 1.086021634E+01 1.393358738E+01 1.692852212E+01 1.961937366E+01
2.172498135E+01 2.292810207E+01 2.291065737E+01 2.140557651E+01 1.826222886E+01
1.351712669E+01 7.455453684E+00 6.435576415E-01-6.089813048E+00-1.174223127E+01
-3.761371558E+00-1.873968915E+00 2.135078960E-01 2.540827286E+00 5.127374233E+00
7.962045089E+00 1.099217427E+01 1.411278363E+01 1.715830588E+01 1.989981072E+01
2.205143928E+01 2.328989944E+01 2.329007266E+01 2.177760782E+01 1.859554648E+01
1.377662221E+01 7.606612427E+00 6.585296979E-01-6.225093469E+00-1.202116407E+01
-3.791490666E+00-1.911540109E+00 1.680110330E-01 2.487256301E+00 5.065659571E+00
7.891986670E+00 1.091323759E+01 1.402388427E+01 1.705758364E+01 1.978441808E+01
2.191739820E+01 2.313211229E+01 2.310260165E+01 2.155435103E+01 1.833142069E+01
1.346929542E+01 7.258694626E+00 2.799266470E-01-6.615212606E+00-1.239358030E+01
-3.820878312E+00-1.970807023E+00 7.456425210E-02 2.354666889E+00 4.888186740E+00
7.663154519E+00 1.062604784E+01 1.367122044E+01 1.663283261E+01 1.928233088E+01
2.133519587E+01 2.247081246E+01 2.236849430E+01 2.076048600E+01 1.749888920E+01
1.262799924E+01 6.447217361E+00-4.559222017E-01-7.225580581E+00-1.282973439E+01
-3.848991491E+00-2.050936655E+00-6.512725250E-02 2.146188553E+00 4.600080065E+00
7.283291332E+00 1.014166289E+01 1.306993852E+01 1.590411969E+01 1.841938220E+01
2.033721296E+01 2.134552973E+01 2.113469622E+01 1.945011906E+01 1.615823925E+01
1.131731051E+01 5.238120693E+00-1.485673552E+00-8.000251170E+00-1.328627499E+01
-3.875338057E+00-2.150242329E+00-2.475329332E-01 1.867881232E+00 4.210692584E+00
6.765911862E+00 9.478741185E+00 1.224492114E+01 1.490368573E+01 1.723627585E+01
1.897356375E+01 1.981640216E+01 1.947142584E+01 1.770279405E+01 1.439651648E+01
9.628673275E+00 3.722766155E+00-2.723810795E+00-8.866225270E+00-1.370959898E+01
-3.900007644E+00-2.266644041E+00-4.677614828E-01 1.528196641E+00 3.732923227E+00
6.129401538E+00 8.662340621E+00 1.122919771E+01 1.367387342E+01 1.578593608E+01
1.730877932E+01 1.796012480E+01 1.746735709E+01 1.561793473E+01 1.232133201E+01
7.673774441E+00 2.011195548E+00-4.069078223E+00-9.739068744E+00-1.404010861E+01
-3.924023591E+00-2.398035334E+00-7.200067369E-01 1.137387716E+00 3.182410201E+00
5.395913565E+00 7.722428677E+00 1.006196670E+01 1.226455371E+01 1.413022949E+01
1.541772644E+01 1.586499240E+01 1.522375896E+01 1.330812440E+01 1.005342068E+01
5.576636546E+00 2.241444128E-01-5.412036085E+00-1.052943124E+01-1.421705809E+01
-3.949454495E+00-2.542502924E+00-9.979222946E-01 7.069235958E-01 2.576669018E+00
4.590150437E+00 6.692214307E+00 8.786372669E+00 1.073023468E+01 1.233629223E+01
1.338105163E+01 1.362538857E+01 1.284800990E+01 1.089170363E+01 7.718485117E+00
3.464998876E+00-1.515610191E+00-6.643185284E+00-1.114998745E+01-1.418363094E+01
-3.979256188E+00-2.698367977E+00-1.294887519E+00 2.489584160E-01 1.934239644E+00
3.738116641E+00 5.606417678E+00 7.447191213E+00 9.127051556E+00 1.047271535E+01
1.128046570E+01 1.133610480E+01 1.044694098E+01 8.485207794E+00 5.438904548E+00
1.461602678E+00-3.091944768E+00-7.661071980E+00-1.152229191E+01-1.389187001E+01
-4.016850914E+00-2.864044197E+00-1.604146536E+00-2.241112683E-01 1.273898011E+00
2.865923368E+00 4.499590437E+00 6.088573689E+00 7.509837123E+00 8.605843241E+00
9.194186653E+00 9.086875972E+00 8.120465300E+00 6.196168770E+00 3.325888584E+00
-3.240034153E-01-4.403506209E+00-8.379786406E+00-1.158304470E+01-1.330709073E+01
-4.065486440E+00-3.037734815E+00-1.918822347E+00-6.999816548E-01 6.139739607E-01
1.998714410E+00 3.404587974E+00 4.751991854E+00 5.929458212E+00 6.796423679E+00
7.192839193E+00 6.957494890E+00 5.955921640E+00 4.116771010E+00 1.472617199E+00
-1.802565272E+00-5.370675409E+00-8.735316260E+00-1.128930792E+01-1.241144279E+01
-4.127449814E+00-3.217015136E+00-2.231827841E+00-1.166667513E+00-2.819799411E-02
1.159766364E+00 2.351277206E+00 3.474501101E+00 4.430577848E+00 5.096815722E+00
5.336068777E+00 5.013819256E+00 4.023501957E+00 2.318783269E+00-5.116971402E-02
-2.910644185E+00-5.940889782E+00-8.690299713E+00-1.062228866E+01-1.120634490E+01
-4.203235039E+00-3.398366877E+00-2.535712222E+00-1.612632387E+00-6.366850978E-01
3.697974838E-01 1.365540530E+00 2.287412293E+00 3.049966071E+00 3.548915381E+00
3.670070593E+00 3.304913826E+00 2.373047603E+00 8.500896067E-01-1.202779494E+00
-3.614186892E+00-6.091958209E+00-8.236839977E+00-9.589407101E+00-9.713596789E+00
-4.290778163E+00-3.576742698E+00-2.822493099E+00-2.026849804E+00-1.197225471E+00
-3.535002237E-01 4.686108471E-01 1.215428449E+00 1.815438588E+00 2.182902917E+00
2.226163321E+00 1.861484244E+00 1.032396256E+00-2.669763141E-01-1.968150648E+00
-3.909918455E+00-5.833148754E+00-7.397184068E+00-8.224491749E+00-7.975065939E+00
-4.384875340E+00-3.745242651E+00-3.083530003E+00-2.398830761E+00-1.697378506E+00
-9.957099940E-01-3.232539991E-01 2.762663994E-01 7.454546190E-01 1.016853765E+00
1.020459654E+00 6.956632448E-01 7.347095482E-03-1.035422001E+00-2.361341617E+00
-3.824490342E+00-5.203991097E+00-6.222222620E+00-6.586078401E+00-6.050948439E+00
-4.476888583E+00-3.894978023E+00-3.309493489E+00-2.718656353E+00-2.126584605E+00
-1.545741319E+00-9.987741727E-01-5.192520663E-01-1.506429331E-01 5.719217068E-02
5.460577895E-02-1.978882146E-01-7.168054582E-01-1.481575987E+00-2.422003763E+00
-3.411478000E+00-4.270900179E+00-4.787924263E+00-4.753925197E+00-4.016704838E+00
-4.554820792E+00-4.015182505E+00-3.490475381E+00-2.977052429E+00-2.476167439E+00
-1.995716824E+00-1.551366984E+00-1.166687615E+00-8.718068197E-01-7.000927896E-01
-6.825136301E-01-8.396957198E-01-1.172330775E+00-1.651449890E+00-2.211061872E+00
-2.746475866E+00-3.121883414E+00-3.189965874E+00-2.823984049E+00-1.958867057E+00
-4.603807992E+00-4.093607026E+00-3.616270651E+00-3.165536031E+00-2.739312360E+00
-2.340737292E+00-1.978638221E+00-1.667124626E+00-1.423984835E+00-1.267600894E+00
-1.212274719E+00-1.262214897E+00-1.404973257E+00-1.605789134E+00-1.804951596E+00
-1.920672159E+00-1.859729673E+00-1.536948455E+00-9.021790676E-01 3.000631406E-02
-4.607035449E+00-4.117205045E+00-3.676841544E+00-3.276651652E+00-2.911050569E+00
-2.578570662E+00-2.281713129E+00-2.026061651E+00-1.818469520E+00-1.664216751E+00
-1.563240181E+00-1.505881440E+00-1.469052924E+00-1.414208492E+00-1.288862796E+00
-1.033391503E+00-5.941846495E-01 5.731167636E-02 9.025721545E-01 1.856887103E+00
-4.547039198E+00-4.073082299E+00-3.662951516E+00-3.304300534E+00-2.988270833E+00
-2.709309505E+00-2.464479642E+00-2.252158241E+00-2.070047391E+00-1.912547284E+00
-1.767768432E+00-1.614788936E+00-1.422144468E+00-1.148868356E+00-7.495037445E-01
-1.841629701E-01 5.663134332E-01 1.481862283E+00 2.485604631E+00 3.433969848E+00
1.000000000E+00 1.052063172E+00 1.110825146E+00 1.175313684E+00 1.246728314E+00
1.329465325E+00 1.421360710E+00 1.524560763E+00 1.640637648E+00 1.780226739E+00
1.940075364E+00 2.127842689E+00 2.354934271E+00 2.628982190E+00 2.978396113E+00
3.421740456E+00 4.029874510E+00 4.918435235E+00 6.433511058E+00 8.575101979E+00
60 11
1.400000000E+00 0.000000000E+00 1.394544521E+00 1.316756722E-01 1.378326897E+00
2.597595754E-01 1.351789500E+00 3.807579144E-01 1.315656204E+00 4.913701702E-01
1.270912629E+00 5.885791285E-01 1.218779263E+00 6.697331826E-01 1.160678170E+00
7.326186613E-01 1.098194195E+00 7.755202128E-01 1.033031738E+00 7.972675944E-01
9.669682618E-01 7.972675944E-01 9.018058051E-01 7.755202128E-01 8.393218301E-01
7.326186613E-01 7.812207368E-01 6.697331826E-01 7.290873713E-01 5.885791285E-01
6.843437962E-01 4.913701702E-01 6.482104995E-01 3.807579144E-01 6.216731033E-01
2.597595754E-01 6.054554786E-01 1.316756722E-01 6.000000000E-01 9.797174393E-17
6.000000000E-01 1.084348500E-16 6.002466000E-01-5.253082994E-02 6.009855315E-01
-1.048766012E-01 6.022141911E-01-1.568529072E-01 6.039282505E-01-2.082766426E-01
6.061216714E-01-2.589666491E-01 6.087867266E-01-3.087443528E-01 6.119140275E-01
-3.574343941E-01 6.154925571E-01-4.048652448E-01 6.195097087E-01-4.508698128E-01
6.239513305E-01-4.952860305E-01 6.288017752E-01-5.379574260E-01 6.340439555E-01
-5.787336739E-01 6.396594039E-01-6.174711254E-01 6.456283379E-01-6.540333138E-01
6.519297299E-01-6.882914358E-01 6.585413809E-01-7.201248050E-01 6.654399990E-01
-7.494212768E-01 6.726012815E-01-7.760776440E-01 6.800000000E-01-8.000000000E-01
6.800000000E-01-8.000000000E-01 7.465884669E-01-7.760776440E-01 8.110400088E-01
-7.494212768E-01 8.731275722E-01-7.201248050E-01 9.326324313E-01-6.882914358E-01
9.893449591E-01-6.540333138E-01 1.043065365E+00-6.174711254E-01 1.093604401E+00
-5.787336739E-01 1.140784023E+00-5.379574260E-01 1.184438026E+00-4.952860305E-01
1.224412622E+00-4.508698128E-01 1.260566986E+00-4.048652448E-01 1.292773752E+00
-3.574343941E-01 1.320919461E+00-3.087443528E-01 1.344904957E+00-2.589666491E-01
1.364645745E+00-2.082766426E-01 1.380072280E+00-1.568529072E-01 1.391130217E+00
-1.048766012E-01 1.397780600E+00-5.253082994E-02 1.400000000E+00-2.168697000E-16
5.200000000E-01 0.000000000E+00 5.800000000E-01-6.000000000E-01 5.500000000E-01-9.000000000E-01 1.250000000E+00-9.000000000E-01 1.400000000E+00-6.000000000E-01 1.480000000E+00 0.000000000E+00 1.400000000E+00 6.000000000E-01 1.250000000E+00 9.000000000E-01 5.500000000E-01 9.000000000E-01 5.800000000E-01 6.000000000E-01 5.200000000E-01 0.000000000E+00
+1
View File
@@ -56,3 +56,4 @@ add_benchmark(elasticity)
add_benchmark(tmop)
add_benchmark(vector)
add_benchmark(virtuals)
add_benchmark(nlvc)
+244
View File
@@ -0,0 +1,244 @@
// 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 "bench.hpp" // IWYU pragma: keep
#ifdef MFEM_USE_BENCHMARK
#include <cassert>
#include <cstdlib>
#include <functional>
#include "fem/qinterp/grad.hpp"
using namespace mfem;
// Custom benchmark arguments generator ///////////////////////////////////////
static void CustomArguments(bm::Benchmark *b) noexcept
{
constexpr int MAX_NDOFS = 8 * 1024 * (mfem_use_gpu ? 1024 : 8);
const auto orders = { 6, 5, 4, 3, 2, 1 };
constexpr auto ndofs = [](int n) constexpr noexcept -> int
{
return (n + 1) * (n + 1) * (n + 1);
};
constexpr auto inc = [](int n) constexpr noexcept -> int
{
return n < 160 ? 4 : n < 240 ? 8 : n < 320 ? 16 : 32;
};
for (auto p : orders)
{
for (int n = (mfem_use_gpu ? 16 : 8); ndofs(n) <= MAX_NDOFS; n += inc(n))
{
b->Args({p, n});
}
}
}
/// Basic Kernels Specializations /////////////////////////////////////////////
static void AddBasicKernelSpecializations()
{
using Grad = QuadratureInterpolator::GradKernels;
// 2D
Grad::Specialization<2, QVectorLayout::byNODES, false, 2,2,7>::Add();
Grad::Specialization<2, QVectorLayout::byNODES, false, 2,2,8>::Add();
Grad::Specialization<2, QVectorLayout::byNODES, false, 2,2,10>::Add();
// 3D
Grad::Specialization<3, QVectorLayout::byNODES, false, 3,2,7>::Add();
Grad::Specialization<3, QVectorLayout::byNODES, false, 3,2,9>::Add();
Grad::Specialization<3, QVectorLayout::byNODES, false, 3,2,10>::Add();
}
/// VectorConvectionNLFBenchmark //////////////////////////////////////////////
template <int DIM>
struct VectorConvectionNLFBenchmark
{
const int p, c, q, n, nx, ny, nz;
const std::function<Mesh()> MakeCartesianMesh = [&]()
{
if constexpr (DIM == 2)
{
return Mesh::MakeCartesian2D(nx, ny, Element::QUADRILATERAL);
}
else
{
return Mesh::MakeCartesian3D(nx, ny, nz, Element::HEXAHEDRON);
}
};
Mesh mesh;
H1_FECollection fec;
FiniteElementSpace fes;
const Geometry::Type geom_type;
IntegrationRules irs;
const IntegrationRule *ir;
ConstantCoefficient const_coeff { M_2_SQRTPI };
NonlinearFormIntegrator *nlfi;
NonlinearForm nlf;
Operator *grad;
GridFunction x, dx, y_pa;
Vector xe, dxe, ye;
const int dofs;
const int q1d;
double mdofs{};
VectorConvectionNLFBenchmark(int p, int side):
p(p), c(side), q(2 * p + 3), n((assert(c >= p), c / p)),
nx(n + (p * (n + 1) * p * n * p * n < c * c * c ? 1 : 0)),
ny(n + (p * (n + 1) * p * (n + 1) * p * n < c * c * c ? 1 : 0)), nz(n),
mesh(MakeCartesianMesh()),
fec(p, DIM),
fes(&mesh, &fec, DIM),
geom_type(mesh.GetTypicalElementGeometry()),
irs(0, Quadrature1D::GaussLegendre),
ir(&irs.Get(geom_type, q)),
nlfi(new VectorConvectionNLFIntegrator(const_coeff)),
nlf(&fes),
x(&fes),
dx(&fes),
y_pa(&fes),
dofs(fes.GetTrueVSize()),
q1d(IntRules.Get(Geometry::SEGMENT, ir->GetOrder()).GetNPoints())
{
MFEM_VERIFY(q1d*q1d*(DIM == 3 ? q1d : 1) == ir->GetNPoints(), "");
nlf.SetAssemblyLevel(AssemblyLevel::PARTIAL);
nlf.AddDomainIntegrator(nlfi);
nlf.Setup();
dx.Randomize(0x9e3779b9), x.Randomize(0x100001b3);
grad = &nlf.GetGradient(x);
const Table &el2dof = fes.GetElementToDofTable();
const int e_size = el2dof.Size_of_connections()*fes.GetVDim();
const auto R = fes.GetElementRestriction(ElementDofOrdering::LEXICOGRAPHIC);
MFEM_VERIFY(e_size == R->Height(), "Input/Output E-vector size mismatch!");
xe.SetSize(R->Height()), dxe.SetSize(R->Height()), ye.SetSize(R->Height());
xe.UseDevice(true), dxe.UseDevice(true), ye.UseDevice(true);
xe.Randomize(0x100001b3), dxe.Randomize(0x9e3779b9), ye = 0.0;
mdofs = 0.0;
}
void Setup()
{
nlfi->AssembleGradPA(xe, fes);
MFEM_DEVICE_SYNC;
mdofs += this->MDofs();
}
void AddMult()
{
nlf.AddMult(x, y_pa);
MFEM_DEVICE_SYNC;
mdofs += this->MDofs();
}
void AddMultPA()
{
nlfi->AddMultPA(xe, ye);
MFEM_DEVICE_SYNC;
mdofs += this->MDofs();
}
void AddMultGrad()
{
grad->Mult(dx, y_pa);
MFEM_DEVICE_SYNC;
mdofs += this->MDofs();
}
void AddMultGradPA()
{
nlfi->AddMultGradPA(dxe, ye);
MFEM_DEVICE_SYNC;
mdofs += this->MDofs();
}
void AssembleGradDiagonal()
{
grad->AssembleDiagonal(ye);
MFEM_DEVICE_SYNC;
mdofs += this->MDofs();
}
[[nodiscard]] double SumMdofs() const noexcept { return mdofs; }
[[nodiscard]] double MDofs() const noexcept { return 1e-6 * dofs; }
};
///////////////////////////////////////////////////////////////////////////////
#define RegisterVectorConvectionNLFBenchmark(Benchmark, DIM) \
static void Benchmark##DIM##d(bm::State &state) \
{ \
const auto order = static_cast<int>(state.range(0)); \
const auto side = static_cast<int>(state.range(1)); \
VectorConvectionNLFBenchmark<DIM> ker(order, side); \
while (state.KeepRunning()) { ker.Benchmark(); } \
bm::Counter::Flags flags = bm::Counter::kIsRate; \
state.counters["MDof/s"] = bm::Counter(ker.SumMdofs(), flags); \
state.counters["Dofs"] = bm::Counter(ker.dofs); \
state.counters["p"] = bm::Counter(order); \
} \
BENCHMARK(Benchmark##DIM##d) \
->Apply(CustomArguments) \
->Unit(bm::kMillisecond)
RegisterVectorConvectionNLFBenchmark(Setup,3);
RegisterVectorConvectionNLFBenchmark(AddMult,3);
RegisterVectorConvectionNLFBenchmark(AddMultPA,3);
RegisterVectorConvectionNLFBenchmark(AddMultGrad,3);
RegisterVectorConvectionNLFBenchmark(AddMultGradPA,3);
RegisterVectorConvectionNLFBenchmark(AssembleGradDiagonal,3);
RegisterVectorConvectionNLFBenchmark(Setup,2);
RegisterVectorConvectionNLFBenchmark(AddMult,2);
RegisterVectorConvectionNLFBenchmark(AddMultPA,2);
RegisterVectorConvectionNLFBenchmark(AddMultGrad,2);
RegisterVectorConvectionNLFBenchmark(AddMultGradPA,2);
RegisterVectorConvectionNLFBenchmark(AssembleGradDiagonal,2);
/// main //////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
AddBasicKernelSpecializations();
bm::ConsoleReporter CR;
bm::Initialize(&argc, argv);
// Device setup, cpu by default
std::string device_context = "cpu";
const auto global_context = bmi::GetGlobalContext();
if (global_context != nullptr)
{
const auto device = global_context->find("device");
if (device != global_context->end())
{
mfem::out << device->first << " : "
<< device->second << std::endl;
device_context = device->second;
}
}
Device device(device_context.c_str());
device.Print();
if (bm::ReportUnrecognizedArguments(argc, argv)) { return EXIT_FAILURE; }
bm::RunSpecifiedBenchmarks(&CR);
return EXIT_SUCCESS;
}
#endif // MFEM_USE_BENCHMARK
+1 -1
View File
@@ -21,7 +21,7 @@ MFEM_LIB_FILE = mfem_is_not_built
-include $(CONFIG_MK)
SEQ_TESTS = bench_assembly_levels bench_ceed bench_dg_amr bench_elasticity \
bench_tmop bench_vector bench_virtuals
bench_nlvc bench_tmop bench_vector bench_virtuals
PAR_TESTS =
ifeq ($(MFEM_USE_MPI),NO)
TESTS = $(SEQ_TESTS)
+18
View File
@@ -82,6 +82,7 @@ set(UNIT_TESTS_SRCS
mesh/test_face_orientations.cpp
mesh/test_fms.cpp
mesh/test_geometric_factors.cpp
mesh/test_ho_rw.cpp
mesh/test_mesh.cpp
mesh/test_ncmesh.cpp
mesh/test_nurbs.cpp
@@ -139,6 +140,7 @@ set(UNIT_TESTS_SRCS
fem/test_lor_batched.cpp
fem/test_lor_dg.cpp
fem/test_lor.cpp
fem/test_mixedsesqform.cpp
fem/test_nonlinearform.cpp
fem/test_operatorjacobismoother.cpp
fem/test_oscillation.cpp
@@ -147,6 +149,8 @@ set(UNIT_TESTS_SRCS
fem/test_pa_grad.cpp
fem/test_pa_idinterp.cpp
fem/test_pa_kernels.cpp
fem/test_pa_nlvc.cpp
fem/test_pa_vecdiv.cpp
fem/test_pa_simplices.cpp
fem/test_particleset.cpp
fem/test_pgridfunc_save_serial.cpp
@@ -165,6 +169,20 @@ set(UNIT_TESTS_SRCS
fem/test_transfer.cpp
fem/test_var_order.cpp
fem/test_white_noise.cpp
fem/specializations/test_diffusion_integ.cpp
fem/specializations/test_mass_integ.cpp
fem/specializations/test_convection_integ.cpp
fem/specializations/test_vecmass_integ.cpp
fem/specializations/test_curlcurl_integ.cpp
fem/specializations/test_vecdiffusion_integ.cpp
fem/specializations/test_dgtrace_integ.cpp
fem/specializations/test_dgdiffusion_integ.cpp
fem/specializations/test_dgmassinv.cpp
fem/specializations/test_qinterp_det.cpp
fem/specializations/test_qinterp_eval.cpp
fem/specializations/test_qinterp_grad.cpp
fem/specializations/test_qinterp_tensoreval.cpp
fem/specializations/test_qinterp_eval_hdiv.cpp
enzyme/compatibility.cpp
# The following are tested separately (keep the comment as a reminder).
# This list can be updated using (in bash):
+379
View File
@@ -0,0 +1,379 @@
MFEM NC mesh v1.0
# NCMesh supported geometry types:
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
# PYRAMID = 7
dimension
3
rank
0
# rank attr geom ref_type nodes/children
elements
75
0 1 5 0 0 1 5 4 16 17 21 20
0 1 5 0 16 17 21 20 32 33 37 36
-1 1 5 7 59 60 61 62 63 64 65 66
0 1 5 0 1 2 6 5 17 18 22 21
-1 1 5 7 27 28 29 30 31 32 33 34
0 1 5 0 21 22 26 25 37 38 42 41
-1 1 5 7 43 44 45 46 47 48 49 50
0 1 5 0 4 5 9 8 20 21 25 24
0 1 5 0 8 9 13 12 24 25 29 28
0 1 5 0 24 25 29 28 40 41 45 44
0 1 5 0 9 10 14 13 25 26 30 29
-1 1 5 7 67 68 69 70 71 72 73 74
0 1 5 0 41 42 46 45 57 58 62 61
0 1 5 0 40 41 45 44 56 57 61 60
0 1 5 0 36 37 41 40 52 53 57 56
-1 1 5 7 35 36 37 38 39 40 41 42
0 1 5 0 32 33 37 36 48 49 53 52
0 1 5 0 33 34 38 37 49 50 54 53
0 1 5 0 34 35 39 38 50 51 55 54
0 1 5 0 38 39 43 42 54 55 59 58
0 1 5 0 42 43 47 46 58 59 63 62
0 1 5 0 26 27 31 30 42 43 47 46
0 1 5 0 10 11 15 14 26 27 31 30
0 1 5 0 6 7 11 10 22 23 27 26
-1 1 5 7 51 52 53 54 55 56 57 58
0 1 5 0 18 19 23 22 34 35 39 38
0 1 5 0 2 3 7 6 18 19 23 22
0 1 5 0 5 94 208 99 74 209 214 212
0 1 5 0 94 6 97 208 209 96 210 214
0 1 5 0 208 97 10 98 214 210 103 211
0 1 5 0 99 208 98 9 212 214 211 104
0 1 5 0 74 209 214 212 21 86 213 102
0 1 5 0 209 96 210 214 86 22 100 213
0 1 5 0 214 210 103 211 213 100 26 101
0 1 5 0 212 214 211 104 102 213 101 25
0 1 5 0 37 89 269 107 156 270 275 273
0 1 5 0 89 38 105 269 270 159 271 275
0 1 5 0 269 105 42 106 275 271 144 272
0 1 5 0 107 269 106 41 273 275 272 143
0 1 5 0 156 270 275 273 53 157 274 153
0 1 5 0 270 159 271 275 157 54 158 274
0 1 5 0 275 271 144 272 274 158 58 139
0 1 5 0 273 275 272 143 153 274 139 57
0 1 5 0 20 70 330 111 83 331 336 334
0 1 5 0 70 21 102 330 331 82 332 336
0 1 5 0 330 102 25 110 336 332 109 333
0 1 5 0 111 330 110 24 334 336 333 114
0 1 5 0 83 331 336 334 36 78 335 113
0 1 5 0 331 82 332 336 78 37 107 335
0 1 5 0 336 332 109 333 335 107 41 112
0 1 5 0 334 336 333 114 113 335 112 40
0 1 5 0 22 198 387 100 91 388 393 391
0 1 5 0 198 23 199 387 388 201 389 393
0 1 5 0 387 199 27 186 393 389 189 390
0 1 5 0 100 387 186 26 391 393 390 108
0 1 5 0 91 388 393 391 38 170 392 105
0 1 5 0 388 201 389 393 170 39 176 392
0 1 5 0 393 389 189 390 392 176 43 177
0 1 5 0 391 393 390 108 105 392 177 42
0 1 5 0 17 84 444 69 81 445 450 448
0 1 5 0 84 18 85 444 445 90 446 450
0 1 5 0 444 85 22 86 450 446 91 447
0 1 5 0 69 444 86 21 448 450 447 82
0 1 5 0 81 445 450 448 33 87 449 77
0 1 5 0 445 90 446 450 87 34 88 449
0 1 5 0 450 446 91 447 449 88 38 89
0 1 5 0 448 450 447 82 77 449 89 37
0 1 5 0 25 101 497 121 109 498 503 501
0 1 5 0 101 26 133 497 498 108 499 503
0 1 5 0 497 133 30 134 503 499 138 500
0 1 5 0 121 497 134 29 501 503 500 129
0 1 5 0 109 498 503 501 41 106 502 126
0 1 5 0 498 108 499 503 106 42 136 502
0 1 5 0 503 499 138 500 502 136 46 137
0 1 5 0 501 503 500 129 126 502 137 45
# attr geom nodes
boundary
72
1 3 4 5 1 0
1 3 0 1 17 16
1 3 4 0 16 20
1 3 16 17 33 32
1 3 20 16 32 36
1 3 5 6 2 1
1 3 1 2 18 17
1 3 8 9 5 4
1 3 8 4 20 24
1 3 12 13 9 8
1 3 13 12 28 29
1 3 12 8 24 28
1 3 29 28 44 45
1 3 28 24 40 44
1 3 13 14 10 9
1 3 14 13 29 30
1 3 46 45 61 62
1 3 57 58 62 61
1 3 45 44 60 61
1 3 44 40 56 60
1 3 56 57 61 60
1 3 40 36 52 56
1 3 52 53 57 56
1 3 32 33 49 48
1 3 36 32 48 52
1 3 48 49 53 52
1 3 33 34 50 49
1 3 49 50 54 53
1 3 34 35 51 50
1 3 35 39 55 51
1 3 50 51 55 54
1 3 39 43 59 55
1 3 54 55 59 58
1 3 43 47 63 59
1 3 47 46 62 63
1 3 58 59 63 62
1 3 27 31 47 43
1 3 31 30 46 47
1 3 14 15 11 10
1 3 11 15 31 27
1 3 15 14 30 31
1 3 10 11 7 6
1 3 7 11 27 23
1 3 18 19 35 34
1 3 19 23 39 35
1 3 6 7 3 2
1 3 2 3 19 18
1 3 3 7 23 19
2 3 99 208 94 5
2 3 208 97 6 94
2 3 98 10 97 208
2 3 9 98 208 99
2 3 53 157 274 153
2 3 157 54 158 274
2 3 274 158 58 139
2 3 153 274 139 57
2 3 111 20 83 334
2 3 24 111 334 114
2 3 334 83 36 113
2 3 114 334 113 40
2 3 23 199 389 201
2 3 199 27 189 389
2 3 201 389 176 39
2 3 389 189 43 176
2 3 17 84 445 81
2 3 84 18 90 445
2 3 81 445 87 33
2 3 445 90 34 87
2 3 30 134 500 138
2 3 134 29 129 500
2 3 138 500 137 46
2 3 500 129 45 137
# vert_id p1 p2
vertex_parents
102
69 17 21
70 20 21
74 5 21
77 33 37
78 36 37
81 17 33
82 21 37
83 20 36
84 17 18
85 18 22
86 21 22
87 33 34
88 34 38
89 37 38
90 18 34
91 22 38
94 5 6
96 6 22
97 6 10
98 9 10
99 5 9
100 22 26
101 25 26
102 21 25
103 10 26
104 9 25
105 38 42
106 41 42
107 37 41
108 26 42
109 25 41
110 24 25
111 20 24
112 40 41
113 36 40
114 24 40
121 25 29
126 41 45
129 29 45
133 26 30
134 29 30
136 42 46
137 45 46
138 30 46
139 57 58
143 41 57
144 42 58
153 53 57
156 37 53
157 53 54
158 54 58
159 38 54
170 38 39
176 39 43
177 42 43
186 26 27
189 27 43
198 22 23
199 23 27
201 23 39
208 97 99
209 74 96
210 96 103
211 103 104
212 74 104
213 100 102
214 209 211
269 105 107
270 156 159
271 144 159
272 143 144
273 143 156
274 153 158
275 270 272
330 102 111
331 82 83
332 82 109
333 109 114
334 83 114
335 107 113
336 331 333
387 100 199
388 91 201
389 189 201
390 108 189
391 91 108
392 105 176
393 388 390
444 69 85
445 81 90
446 90 91
447 82 91
448 81 82
449 77 88
450 445 447
497 121 133
498 108 109
499 108 138
500 129 138
501 109 129
502 126 136
503 498 500
# root element orientation
root_state
27
0
1
1
15
15
6
6
22
15
8
12
10
10
18
18
13
7
22
22
15
16
16
16
7
8
6
21
# top-level node coordinates
coordinates
64
3
0 0 0
0.33333333 0 0
0.66666667 0 0
1 0 0
0 0.33333333 0
0.33333333 0.33333333 0
0.66666667 0.33333333 0
1 0.33333333 0
0 0.66666667 0
0.33333333 0.66666667 0
0.66666667 0.66666667 0
1 0.66666667 0
0 1 0
0.33333333 1 0
0.66666667 1 0
1 1 0
0 0 0.33333333
0.33333333 0 0.33333333
0.66666667 0 0.33333333
1 0 0.33333333
0 0.33333333 0.33333333
0.33333333 0.33333333 0.33333333
0.66666667 0.33333333 0.33333333
1 0.33333333 0.33333333
0 0.66666667 0.33333333
0.33333333 0.66666667 0.33333333
0.66666667 0.66666667 0.33333333
1 0.66666667 0.33333333
0 1 0.33333333
0.33333333 1 0.33333333
0.66666667 1 0.33333333
1 1 0.33333333
0 0 0.66666667
0.33333333 0 0.66666667
0.66666667 0 0.66666667
1 0 0.66666667
0 0.33333333 0.66666667
0.33333333 0.33333333 0.66666667
0.66666667 0.33333333 0.66666667
1 0.33333333 0.66666667
0 0.66666667 0.66666667
0.33333333 0.66666667 0.66666667
0.66666667 0.66666667 0.66666667
1 0.66666667 0.66666667
0 1 0.66666667
0.33333333 1 0.66666667
0.66666667 1 0.66666667
1 1 0.66666667
0 0 1
0.33333333 0 1
0.66666667 0 1
1 0 1
0 0.33333333 1
0.33333333 0.33333333 1
0.66666667 0.33333333 1
1 0.33333333 1
0 0.66666667 1
0.33333333 0.66666667 1
0.66666667 0.66666667 1
1 0.66666667 1
0 1 1
0.33333333 1 1
0.66666667 1 1
1 1 1
mfem_mesh_end
+555
View File
@@ -0,0 +1,555 @@
MFEM NC mesh v1.0
# NCMesh supported geometry types:
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
# PYRAMID = 7
dimension
3
rank
0
# rank attr geom ref_type nodes/children
elements
258
0 1 4 0 21 0 5 1
0 1 4 0 21 0 1 17
0 1 4 0 21 0 17 16
0 1 4 0 21 0 4 5
0 1 4 0 21 0 20 4
0 1 4 0 21 0 16 20
0 1 4 0 22 1 6 2
0 1 4 0 22 1 2 18
0 1 4 0 22 1 18 17
0 1 4 0 22 1 5 6
0 1 4 0 22 1 21 5
0 1 4 0 22 1 17 21
0 1 4 0 23 2 7 3
0 1 4 0 23 2 3 19
0 1 4 0 23 2 19 18
0 1 4 0 23 2 6 7
0 1 4 0 23 2 22 6
0 1 4 0 23 2 18 22
0 1 4 0 25 4 9 5
0 1 4 0 25 4 5 21
0 1 4 0 25 4 21 20
0 1 4 0 25 4 8 9
0 1 4 0 25 4 24 8
0 1 4 0 25 4 20 24
-1 1 4 7 170 171 172 173 174 175 176 177
0 1 4 0 26 5 6 22
0 1 4 0 26 5 22 21
-1 1 4 7 162 163 164 165 166 167 168 169
0 1 4 0 26 5 25 9
0 1 4 0 26 5 21 25
0 1 4 0 27 6 11 7
0 1 4 0 27 6 7 23
0 1 4 0 27 6 23 22
0 1 4 0 27 6 10 11
0 1 4 0 27 6 26 10
0 1 4 0 27 6 22 26
0 1 4 0 29 8 13 9
0 1 4 0 29 8 9 25
0 1 4 0 29 8 25 24
0 1 4 0 29 8 12 13
0 1 4 0 29 8 28 12
0 1 4 0 29 8 24 28
0 1 4 0 30 9 14 10
0 1 4 0 30 9 10 26
0 1 4 0 30 9 26 25
0 1 4 0 30 9 13 14
0 1 4 0 30 9 29 13
0 1 4 0 30 9 25 29
0 1 4 0 31 10 15 11
0 1 4 0 31 10 11 27
0 1 4 0 31 10 27 26
0 1 4 0 31 10 14 15
0 1 4 0 31 10 30 14
0 1 4 0 31 10 26 30
0 1 4 0 37 16 21 17
0 1 4 0 37 16 17 33
0 1 4 0 37 16 33 32
0 1 4 0 37 16 20 21
0 1 4 0 37 16 36 20
0 1 4 0 37 16 32 36
0 1 4 0 38 17 22 18
-1 1 4 7 226 227 228 229 230 231 232 233
-1 1 4 7 234 235 236 237 238 239 240 241
0 1 4 0 38 17 21 22
0 1 4 0 38 17 37 21
0 1 4 0 38 17 33 37
0 1 4 0 39 18 23 19
0 1 4 0 39 18 19 35
0 1 4 0 39 18 35 34
0 1 4 0 39 18 22 23
0 1 4 0 39 18 38 22
0 1 4 0 39 18 34 38
0 1 4 0 41 20 25 21
0 1 4 0 41 20 21 37
0 1 4 0 41 20 37 36
0 1 4 0 41 20 24 25
-1 1 4 7 202 203 204 205 206 207 208 209
-1 1 4 7 194 195 196 197 198 199 200 201
0 1 4 0 42 21 26 22
0 1 4 0 42 21 22 38
0 1 4 0 42 21 38 37
0 1 4 0 42 21 25 26
0 1 4 0 42 21 41 25
0 1 4 0 42 21 37 41
-1 1 4 7 210 211 212 213 214 215 216 217
-1 1 4 7 218 219 220 221 222 223 224 225
0 1 4 0 43 22 39 38
0 1 4 0 43 22 26 27
0 1 4 0 43 22 42 26
0 1 4 0 43 22 38 42
0 1 4 0 45 24 29 25
0 1 4 0 45 24 25 41
0 1 4 0 45 24 41 40
0 1 4 0 45 24 28 29
0 1 4 0 45 24 44 28
0 1 4 0 45 24 40 44
0 1 4 0 46 25 30 26
0 1 4 0 46 25 26 42
0 1 4 0 46 25 42 41
-1 1 4 7 250 251 252 253 254 255 256 257
-1 1 4 7 242 243 244 245 246 247 248 249
0 1 4 0 46 25 41 45
0 1 4 0 47 26 31 27
0 1 4 0 47 26 27 43
0 1 4 0 47 26 43 42
0 1 4 0 47 26 30 31
0 1 4 0 47 26 46 30
0 1 4 0 47 26 42 46
0 1 4 0 53 32 37 33
0 1 4 0 53 32 33 49
0 1 4 0 53 32 49 48
0 1 4 0 53 32 36 37
0 1 4 0 53 32 52 36
0 1 4 0 53 32 48 52
0 1 4 0 54 33 38 34
0 1 4 0 54 33 34 50
0 1 4 0 54 33 50 49
0 1 4 0 54 33 37 38
0 1 4 0 54 33 53 37
0 1 4 0 54 33 49 53
0 1 4 0 55 34 39 35
0 1 4 0 55 34 35 51
0 1 4 0 55 34 51 50
0 1 4 0 55 34 38 39
0 1 4 0 55 34 54 38
0 1 4 0 55 34 50 54
0 1 4 0 57 36 41 37
0 1 4 0 57 36 37 53
0 1 4 0 57 36 53 52
0 1 4 0 57 36 40 41
0 1 4 0 57 36 56 40
0 1 4 0 57 36 52 56
0 1 4 0 58 37 42 38
0 1 4 0 58 37 38 54
-1 1 4 7 178 179 180 181 182 183 184 185
0 1 4 0 58 37 41 42
0 1 4 0 58 37 57 41
-1 1 4 7 186 187 188 189 190 191 192 193
0 1 4 0 59 38 43 39
0 1 4 0 59 38 39 55
0 1 4 0 59 38 55 54
0 1 4 0 59 38 42 43
0 1 4 0 59 38 58 42
0 1 4 0 59 38 54 58
0 1 4 0 61 40 45 41
0 1 4 0 61 40 41 57
0 1 4 0 61 40 57 56
0 1 4 0 61 40 44 45
0 1 4 0 61 40 60 44
0 1 4 0 61 40 56 60
0 1 4 0 62 41 46 42
0 1 4 0 62 41 42 58
0 1 4 0 62 41 58 57
0 1 4 0 62 41 45 46
0 1 4 0 62 41 61 45
0 1 4 0 62 41 57 61
0 1 4 0 63 42 47 43
0 1 4 0 63 42 43 59
0 1 4 0 63 42 59 58
0 1 4 0 63 42 46 47
0 1 4 0 63 42 62 46
0 1 4 0 63 42 58 62
0 1 4 0 26 125 132 126
0 1 4 0 125 5 115 128
0 1 4 0 132 115 9 133
0 1 4 0 126 128 133 10
0 1 4 0 125 133 132 126
0 1 4 0 125 133 126 128
0 1 4 0 125 133 128 115
0 1 4 0 125 133 115 132
0 1 4 0 26 125 126 127
0 1 4 0 125 5 128 95
0 1 4 0 126 128 10 129
0 1 4 0 127 95 129 6
0 1 4 0 125 129 126 127
0 1 4 0 125 129 127 95
0 1 4 0 125 129 95 128
0 1 4 0 125 129 128 126
0 1 4 0 58 305 308 309
0 1 4 0 305 37 283 262
0 1 4 0 308 283 54 284
0 1 4 0 309 262 284 53
0 1 4 0 305 284 308 309
0 1 4 0 305 284 309 262
0 1 4 0 305 284 262 283
0 1 4 0 305 284 283 308
0 1 4 0 58 305 309 311
0 1 4 0 305 37 262 297
0 1 4 0 309 262 53 298
0 1 4 0 311 297 298 57
0 1 4 0 305 298 309 311
0 1 4 0 305 298 311 297
0 1 4 0 305 298 297 262
0 1 4 0 305 298 262 309
0 1 4 0 41 213 217 219
0 1 4 0 213 20 191 220
0 1 4 0 217 191 36 222
0 1 4 0 219 220 222 40
0 1 4 0 213 222 217 219
0 1 4 0 213 222 219 220
0 1 4 0 213 222 220 191
0 1 4 0 213 222 191 217
0 1 4 0 41 213 219 218
0 1 4 0 213 20 220 124
0 1 4 0 219 220 40 221
0 1 4 0 218 124 221 24
0 1 4 0 213 221 219 218
0 1 4 0 213 221 218 124
0 1 4 0 213 221 124 220
0 1 4 0 213 221 220 219
0 1 4 0 43 230 231 232
0 1 4 0 230 22 141 110
0 1 4 0 231 141 27 140
0 1 4 0 232 110 140 23
0 1 4 0 230 140 231 232
0 1 4 0 230 140 232 110
0 1 4 0 230 140 110 141
0 1 4 0 230 140 141 231
0 1 4 0 43 230 232 233
0 1 4 0 230 22 110 211
0 1 4 0 232 110 23 204
0 1 4 0 233 211 204 39
0 1 4 0 230 204 232 233
0 1 4 0 230 204 233 211
0 1 4 0 230 204 211 110
0 1 4 0 230 204 110 232
0 1 4 0 38 193 195 196
0 1 4 0 193 17 93 197
0 1 4 0 195 93 18 198
0 1 4 0 196 197 198 34
0 1 4 0 193 198 195 196
0 1 4 0 193 198 196 197
0 1 4 0 193 198 197 93
0 1 4 0 193 198 93 195
0 1 4 0 38 193 196 199
0 1 4 0 193 17 197 184
0 1 4 0 196 197 34 200
0 1 4 0 199 184 200 33
0 1 4 0 193 200 196 199
0 1 4 0 193 200 199 184
0 1 4 0 193 200 184 197
0 1 4 0 193 200 197 196
0 1 4 0 46 247 253 252
0 1 4 0 247 25 239 150
0 1 4 0 253 239 45 238
0 1 4 0 252 150 238 29
0 1 4 0 247 238 253 252
0 1 4 0 247 238 252 150
0 1 4 0 247 238 150 239
0 1 4 0 247 238 239 253
0 1 4 0 46 247 252 248
0 1 4 0 247 25 150 165
0 1 4 0 252 150 29 168
0 1 4 0 248 165 168 30
0 1 4 0 247 168 252 248
0 1 4 0 247 168 248 165
0 1 4 0 247 168 165 150
0 1 4 0 247 168 150 252
# attr geom nodes
boundary
144
1 2 0 5 1
1 2 0 1 17
1 2 0 17 16
1 2 0 4 5
1 2 0 20 4
1 2 0 16 20
1 2 1 6 2
1 2 1 2 18
1 2 1 18 17
1 2 1 5 6
1 2 2 7 3
1 2 23 3 7
1 2 2 3 19
1 2 23 19 3
1 2 2 19 18
1 2 2 6 7
1 2 4 9 5
1 2 4 8 9
1 2 4 24 8
1 2 4 20 24
1 2 6 11 7
1 2 27 7 11
1 2 27 23 7
1 2 6 10 11
1 2 8 13 9
1 2 8 12 13
1 2 29 13 12
1 2 8 28 12
1 2 29 12 28
1 2 8 24 28
1 2 9 14 10
1 2 9 13 14
1 2 30 14 13
1 2 30 13 29
1 2 10 15 11
1 2 31 11 15
1 2 31 27 11
1 2 10 14 15
1 2 31 15 14
1 2 31 14 30
1 2 16 17 33
1 2 16 33 32
1 2 16 36 20
1 2 16 32 36
1 2 39 19 23
1 2 18 19 35
1 2 39 35 19
1 2 18 35 34
1 2 45 29 28
1 2 24 44 28
1 2 45 28 44
1 2 24 40 44
1 2 47 27 31
1 2 47 43 27
1 2 47 31 30
1 2 47 30 46
1 2 32 33 49
1 2 32 49 48
1 2 53 48 49
1 2 32 52 36
1 2 32 48 52
1 2 53 52 48
1 2 33 34 50
1 2 33 50 49
1 2 54 49 50
1 2 54 53 49
1 2 55 35 39
1 2 34 35 51
1 2 55 51 35
1 2 34 51 50
1 2 55 50 51
1 2 55 54 50
1 2 57 52 53
1 2 36 56 40
1 2 36 52 56
1 2 57 56 52
1 2 59 39 43
1 2 59 55 39
1 2 59 54 55
1 2 59 58 54
1 2 61 56 57
1 2 61 45 44
1 2 40 60 44
1 2 61 44 60
1 2 40 56 60
1 2 61 60 56
1 2 62 57 58
1 2 62 46 45
1 2 62 45 61
1 2 62 61 57
1 2 63 43 47
1 2 63 59 43
1 2 63 58 59
1 2 63 47 46
1 2 63 46 62
1 2 63 62 58
2 2 5 115 128
2 2 115 9 133
2 2 128 133 10
2 2 133 128 115
2 2 5 128 95
2 2 128 10 129
2 2 95 129 6
2 2 129 95 128
2 2 58 309 308
2 2 308 284 54
2 2 309 53 284
2 2 284 308 309
2 2 58 311 309
2 2 309 298 53
2 2 311 57 298
2 2 298 309 311
2 2 20 191 220
2 2 191 36 222
2 2 220 222 40
2 2 222 220 191
2 2 20 220 124
2 2 220 40 221
2 2 124 221 24
2 2 221 124 220
2 2 43 232 231
2 2 231 140 27
2 2 232 23 140
2 2 140 231 232
2 2 43 233 232
2 2 232 204 23
2 2 233 39 204
2 2 204 232 233
2 2 17 93 197
2 2 93 18 198
2 2 197 198 34
2 2 198 197 93
2 2 17 197 184
2 2 197 34 200
2 2 184 200 33
2 2 200 184 197
2 2 46 252 253
2 2 253 238 45
2 2 252 29 238
2 2 238 253 252
2 2 46 248 252
2 2 252 168 29
2 2 248 30 168
2 2 168 252 248
# vert_id p1 p2
vertex_parents
54
93 17 18
95 5 6
110 22 23
115 5 9
124 20 24
125 5 26
126 10 26
127 6 26
128 5 10
129 6 10
132 9 26
133 9 10
140 23 27
141 22 27
150 25 29
165 25 30
168 29 30
184 17 33
191 20 36
193 17 38
195 18 38
196 34 38
197 17 34
198 18 34
199 33 38
200 33 34
204 23 39
211 22 39
213 20 41
217 36 41
218 24 41
219 40 41
220 20 40
221 24 40
222 36 40
230 22 43
231 27 43
232 23 43
233 39 43
238 29 45
239 25 45
247 25 46
248 30 46
252 29 46
253 45 46
262 37 53
283 37 54
284 53 54
297 37 57
298 53 57
305 37 58
308 54 58
309 53 58
311 57 58
# top-level node coordinates
coordinates
64
3
0 0 0
0.33333333 0 0
0.66666667 0 0
1 0 0
0 0.33333333 0
0.33333333 0.33333333 0
0.66666667 0.33333333 0
1 0.33333333 0
0 0.66666667 0
0.33333333 0.66666667 0
0.66666667 0.66666667 0
1 0.66666667 0
0 1 0
0.33333333 1 0
0.66666667 1 0
1 1 0
0 0 0.33333333
0.33333333 0 0.33333333
0.66666667 0 0.33333333
1 0 0.33333333
0 0.33333333 0.33333333
0.33333333 0.33333333 0.33333333
0.66666667 0.33333333 0.33333333
1 0.33333333 0.33333333
0 0.66666667 0.33333333
0.33333333 0.66666667 0.33333333
0.66666667 0.66666667 0.33333333
1 0.66666667 0.33333333
0 1 0.33333333
0.33333333 1 0.33333333
0.66666667 1 0.33333333
1 1 0.33333333
0 0 0.66666667
0.33333333 0 0.66666667
0.66666667 0 0.66666667
1 0 0.66666667
0 0.33333333 0.66666667
0.33333333 0.33333333 0.66666667
0.66666667 0.33333333 0.66666667
1 0.33333333 0.66666667
0 0.66666667 0.66666667
0.33333333 0.66666667 0.66666667
0.66666667 0.66666667 0.66666667
1 0.66666667 0.66666667
0 1 0.66666667
0.33333333 1 0.66666667
0.66666667 1 0.66666667
1 1 0.66666667
0 0 1
0.33333333 0 1
0.66666667 0 1
1 0 1
0 0.33333333 1
0.33333333 0.33333333 1
0.66666667 0.33333333 1
1 0.33333333 1
0 0.66666667 1
0.33333333 0.66666667 1
0.66666667 0.66666667 1
1 0.66666667 1
0 1 1
0.33333333 1 1
0.66666667 1 1
1 1 1
mfem_mesh_end
@@ -0,0 +1,14 @@
/// Tests which make sure adding user-defined kernel specializations work.
/// These tests are compile/link-only tests
#include "mfem.hpp"
#include "unit_tests.hpp"
#include "fem/integ/bilininteg_convection_kernels.hpp"
TEST_CASE("Convection Kernel Specializations", "[Specializations]")
{
using namespace mfem;
ConvectionIntegrator::AddSpecialization<2, 2, 4>();
}
@@ -0,0 +1,14 @@
/// Tests which make sure adding user-defined kernel specializations work.
/// These tests are compile/link-only tests
#include "mfem.hpp"
#include "unit_tests.hpp"
#include "fem/integ/bilininteg_hcurl_kernels.hpp"
TEST_CASE("CurlCurl Kernel Specializations", "[Specializations]")
{
using namespace mfem;
CurlCurlIntegrator::AddSpecialization<3, 2, 4>();
}

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